3

我正在使用Invoke-Command,并且在-ScriptBlock我正在使用的范围内Start-Job。我必须使用$Using:varwithinStart-Job但会话正在查找本地会话中声明的变量(之前声明Invoke-Command)。这是我正在做的一个非常简短的示例:

Invoke-Command -ComputerName $computer -ScriptBlock {
    $sourcePath = 'C:\Source'
    $destPath = 'C:\dest.zip'
    $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
    $includeBaseDirectory = $false
    Start-Job -Name "compress_archive" -ScriptBlock {
        Add-Type -AssemblyName System.IO.Compression.FileSystem
        [System.IO.Compression.ZipFile]::CreateFromDirectory("$using:sourcePath","$using:destPathTemp",$using:compressionLevel,$using:includeBaseDirectory)
    }
}

Invoke-Command : The value of the using variable '$using:sourcePath' cannot be retrieved because it has not been set in the local session.
At line:1 char:1
+ Invoke-Command -ComputerName vode-fbtest -ScriptBlock {
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Invoke-Command], RuntimeException
    + FullyQualifiedErrorId : UsingVariableIsUndefined,Microsoft.PowerShell.Commands.InvokeCommandCommand

$using如果我在调用变量时省略了,Start-Job -ScriptBlock {}那么我会得到一个Cannot find an overload for "CreateFromDirectory" and the argument count: "4".错误,因为变量没有在那个范围内定义。

有没有一种方法可以用于远程$using会话中的变量而不是本地变量,或者我可以指定另一个范围来从远程会话中获取变量?我可以在修复此问题之前在本地声明这些变量,但由于变量包含动态值(所有这些都在 a 中,其数据是在远程计算机上检索的,所以我需要做大量工作)如果我无法完成这项工作,请重组整个脚本)。Invoke-Commandforeach ($obj in $objects)

如果这有什么不同,我在 Windows Server 2012 R2(源主机和-ComputerName调用命令的主机)上使用 PS v5.1。

查看这个答案,我发现您可以将变量公开给较低级别​​的脚本块,但我需要从远程会话中实际声明变量。该值需要来自运行远程会话的计算机。您能否在远程会话中声明变量,使其可用于顶级脚本块中的脚本块?

4

1 回答 1

2

PetSerAl就像以前无数次一样,在对该问题的简短评论中提供了关键指针:

你需要:

  • 用于[scriptblock]::Create()创建脚本块以Start-Job 动态传递,从字符串

  • 在脚本块进行[scriptblock]::Create()调用,因为只有这样才能确保其中声明的变量通过范围说明符在-created 脚本块 中引用的变量。Invoke-Command[scriptblock]::Create()$using:

    • 相比之下,如果您使用脚本块文字,{ ... }Start-Job您的尝试一样,$using:引用不是Invoke-Command脚本块的范围,而是指调用者的范围Invoke-Command,即对使整体Invoke-Command通话。
    • 理想情况下,$using:...引用的扩展将足够智能以处理嵌套范围,如本例所示,但在 PowerShell Core 7.0.0-preview.3 中并非如此。

警告:正如 PetSerAl 指出的那样,如果您使用Invoke-Command命令范围的临时会话(通过 using 暗示) - 而不是在 with 之前创建并传递给with-ComputerName的长期会话-调用返回时后台作业将终止,在它(可能)有机会完成之前。虽然您可以通过管道调用,但只有在您开始多项工作时才值得。New-PSSessionInvoke-Command-SessionInvoke-CommandStart-Job... | Receive-Job -Wait -AutoRemove

所以:

Invoke-Command -ComputerName $computer -ScriptBlock {

    # Inside this remotely executing script block, define the variables
    # that the script block passed to Start-Job below will reference:
    $sourcePath = 'C:\Source'
    $destPath = 'C:\dest.zip'
    $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
    $includeBaseDirectory = $false

    # Define the Start-Job script block as *literal* (here-)*string*, so as 
    # to defer interpretation of the $using: references, and then
    # construct a script block from it using [scriptblock]::Create(), which
    # ties the $using: references to *this* scope.
    $jobSb = [scriptblock]::Create(
@'
        Add-Type -AssemblyName System.IO.Compression.FileSystem
        [System.IO.Compression.ZipFile]::CreateFromDirectory("$using:sourcePath","$using:destPathTemp",$using:compressionLevel,$using:includeBaseDirectory)
'@
    )

    Start-Job -Name "compress_archive" -ScriptBlock $jobSb

}
于 2019-09-01T17:35:48.330 回答