I'm working with a script that remotes into a series of servers and executes commands from a series of PoSh functions. I will need to retain the synchronous processing and would simply like to add the capability of performing an async operation on the function.
How can I transform this to be called as a job from a primary function using Start-Job
or Invoke-Command -AsJob
? These functions are part of a PowerShell module, if that makes a difference.
I've tried a couple of various examples I've seen here, but they do not seem to actually process the function.
For example, for the below function, I've tried:
foreach($s in $servers)
{
if($lbFileLocation -eq $true)
{
#Rename-LoadBalancerFile -ServerName $server -Revert $false -filePath $filePath -cred $cred - #sync function works great
Start-Job -Name 'RenLb' -InitializationScript {Import-Module '.\Down.psm1'} $ScriptBlock -ArgumentList $server,$false,$lbFileLocation,$Cred | Out-Null
}
}
Write-Host 'Waiting for LB rename.'
While (Get-Job -Name 'RenLb' | where { $_.State -eq 'Running' } )
{
Start-Sleep 1
}
Write-Host 'completed'
Original, synchronous function:
function Rename-LoadBalancerFile
{
param
(
[string]
[Parameter(Mandatory=$true)]
$ServerName,
[bool]
[Parameter(Mandatory=$true)]
$Revert,
[string]
[Parameter(Mandatory=$true)]
$filePath,
[PSCredential]
[Parameter(Mandatory=$false)]
$cred
)
$scriptBlock = {
param
(
[bool]
[Parameter(Mandatory=$true)]
$Revert,
[string]
[Parameter(Mandatory=$true)]
$filePath
)
if(Test-Path $filePath -eq $true)
{
Write-Host 'file tested true'
if($Revert -eq $true)
{
$fileName = [IO.Path]::GetFileName($filePath)
$directory = [IO.Path]::GetDirectoryName($filePath)
Rename-Item -Path "$directory\file.txt" -NewName $fileName
}
else
{
Rename-Item -Path $filePath -NewName 'file.txt'
}
}
}
$session = New-PSSession -ComputerName $ServerName -Authentication Credssp -Credential $cred
Invoke-Command -Session $session -ScriptBlock $scriptBlock -ArgumentList $Revert, $filePath
Remove-PSSession $session
}
Import-Module .\down.psm1
will probably fail because Start-Job
doesn't have the same working directory as your script, so you need to either change the working directory or use absolute path to the module.$scriptblock
in Start-Job
? It's never created. Remember that $scriptblock
needs to use $args[0] , $args[1] ..
to access the values passed in using -ArgumentList
or define the parameters (param($server,$filepath...)
) in the beginning of the scriptblock.You could try something like this:
#Get full path for module
$module = Resolve-Path ".\Down.psm1"
#Create scriptblock
$scriptblock = { Rename-LoadBalancerFile -ServerName $args[0] -Revert $args[1] -filePath $args[2] -cred $args[3] }
foreach($s in $servers)
{
Start-Job -Name "RenLb" -InitializationScript ([scriptblock]::Create("Import-Module $module")) -ScriptBlock $scriptblock -ArgumentList $s,$false,$lbFileLocation,$Cred | Out-Null
}
Write-Host 'Waiting for LB rename.'
While (Get-Job -Name 'RenLb' | where { $_.State -eq 'Running' } )
{
Start-Sleep 1
}
Write-Host 'completed'
I used ([scriptblock]::Create("Import-Module $module"))
to generate the InitializationScript to make sure that the $module
-variable was expanded to a filepath since $module
isn't available in the new job-thread. You can replaced it with -InitializationScript { Import-Module c:\mymodule\down.psm1 }
if you want to hardcode the modulepath.