使用 Invoke-Command/Start-Job 和 PSRemoting

Working with Invoke-Command/Start-Job and PSRemoting

我正在使用一个脚本,该脚本远程连接到一系列服务器并执行来自一系列 PoSh 函数的命令。我将需要保留同步处理,并且只想添加对函数执行异步操作的功能。

如何使用 Start-JobInvoke-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
}
  1. Import-Module .\down.psm1 可能会失败,因为 Start-Job 没有与您的脚本相同的工作目录,因此您需要更改工作目录或使用模块的绝对路径。
  2. 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 }