使用 Invoke-Command/Start-Job 和 PSRemoting
Working with Invoke-Command/Start-Job and PSRemoting
我正在使用一个脚本,该脚本远程连接到一系列服务器并执行来自一系列 PoSh 函数的命令。我将需要保留同步处理,并且只想添加对函数执行异步操作的功能。
如何使用 Start-Job
或 Invoke-Command -AsJob
将其转换为从主要函数调用的作业?这些函数是 PowerShell 模块的一部分,如果有区别的话。
我已经尝试了几个在这里看到的各种示例,但它们似乎并没有实际处理函数。
例如,对于下面的函数,我试过:
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'
原同步函数:
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
可能会失败,因为 Start-Job
没有与您的脚本相同的工作目录,因此您需要更改工作目录或使用模块的绝对路径。
Start-Job
中的$scriptblock
是什么?它从未被创造。请记住,$scriptblock
需要使用 $args[0] , $args[1] ..
来访问使用 -ArgumentList
传入的值或在脚本块的开头定义参数 (param($server,$filepath...)
)。
您可以尝试这样的操作:
#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'
我使用 ([scriptblock]::Create("Import-Module $module"))
生成 InitializationScript 以确保 $module
变量扩展为文件路径,因为 $module
在新的作业线程中不可用。如果您想对模块路径进行硬编码,可以将其替换为 -InitializationScript { Import-Module c:\mymodule\down.psm1 }
。
我正在使用一个脚本,该脚本远程连接到一系列服务器并执行来自一系列 PoSh 函数的命令。我将需要保留同步处理,并且只想添加对函数执行异步操作的功能。
如何使用 Start-Job
或 Invoke-Command -AsJob
将其转换为从主要函数调用的作业?这些函数是 PowerShell 模块的一部分,如果有区别的话。
我已经尝试了几个在这里看到的各种示例,但它们似乎并没有实际处理函数。
例如,对于下面的函数,我试过:
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'
原同步函数:
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
可能会失败,因为Start-Job
没有与您的脚本相同的工作目录,因此您需要更改工作目录或使用模块的绝对路径。Start-Job
中的$scriptblock
是什么?它从未被创造。请记住,$scriptblock
需要使用$args[0] , $args[1] ..
来访问使用-ArgumentList
传入的值或在脚本块的开头定义参数 (param($server,$filepath...)
)。
您可以尝试这样的操作:
#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'
我使用 ([scriptblock]::Create("Import-Module $module"))
生成 InitializationScript 以确保 $module
变量扩展为文件路径,因为 $module
在新的作业线程中不可用。如果您想对模块路径进行硬编码,可以将其替换为 -InitializationScript { Import-Module c:\mymodule\down.psm1 }
。