$Using:var 在 Invoke-Command 中的 Start-Job 中 [英] $Using:var in Start-Job within Invoke-Command

查看:76
本文介绍了$Using:var 在 Invoke-Command 中的 Start-Job 中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是 Invoke-Command,并且在 -ScriptBlock 中我使用的是 Start-Job.我必须在 Start-Job 中使用 $Using:var 但会话正在寻找本地会话中声明的变量(在 Invoke-Command 之前声明)代码>).这是我正在做的一个非常简短的例子:

I am using Invoke-Command, and within the -ScriptBlock I am using Start-Job. I have to use $Using:var within Start-Job but the session is looking for the declared variables in the local session (declared before Invoke-Command). Here's a very brief example of what I'm doing:

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

如果我在 Start-Job -ScriptBlock {} 中调用变量时省略 $using 然后我得到一个 Cannot find a Overload for "CreateFromDirectory" 和参数计数:4". 错误,因为变量未在该范围内定义.

If I omit $using when calling variables in the Start-Job -ScriptBlock {} then I get a Cannot find an overload for "CreateFromDirectory" and the argument count: "4". error because the variables are not defined in that scope.

有没有办法在 remote 会话中使用 $using 变量而不是本地变量,或者我可以指定的另一个作用域可以从远程会话?我可以在 Invoke-Command 之前在本地声明这些变量来解决这个问题,但由于变量包含动态值(所有这些都在 foreach ($$objects 中的 obj),其数据是在远程计算机上检索的,因此如果我无法完成这项工作,我将需要重构整个脚本).

Is there a way to use $using for variables within the remote session rather than the local one, or possibly another scope I can specify that would source variables from the remote session? I could declare these variables locally before the Invoke-Command to fix this but that would require a significant bit of work due to the variables containing dynamic values (all of this is in a foreach ($obj in $objects), the data for which is retrieved on the remote computer so I would need to restructure the whole script if I can't make this work).

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

I'm using PS v5.1 on Windows Server 2012 R2 (both source host and -ComputerName host on which the command is invoked) if that makes any difference.

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

Looking at this answer I see that you can expose variables to lower level script blocks but I need to actually declare the variable from within the remote session. The value needs to come from the computer on which the remote session is running. Can you declare the variable from within the remote session in a fashion that makes it available to script blocks within the top-level script block?

推荐答案

PetSerAl 和之前无数次一样,已经提供对该问题的简短评论中的关键指针:

PetSerAl, as countless times before, has provided the crucial pointer in a terse comment on the question:

您需要:

  • 使用 [scriptblock]::Create() 创建脚本块以动态地从字符串传递给 Start-Job em>

  • use [scriptblock]::Create() to create the script block to pass to Start-Job dynamically, from a string

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

make the [scriptblock]::Create() call inside the Invoke-Command script block, because only that ensures that the variables declared in there are the ones referenced in the [scriptblock]::Create()-created script block via the $using: scope specifier.

  • 相比之下,如果您使用 脚本块文字{ ... }Start-Job,就像您尝试的那样,$using: 引用不是引用Invoke-Command 脚本块的范围,而是调用者的范围Invoke-Command,即对进行整体 Invoke-Command 调用的代码可见的变量.
  • 理想情况下,$using:... 引用的扩展足够智能以处理 嵌套 范围,就像在这种情况下一样,但事实并非如此PowerShell Core 7.0.0-preview.3.
  • By contrast, if you use a script-block literal, { ... } with Start-Job, as in your attempt, the $using: references do not refer to the Invoke-Command script block's scope, but to the scope of the caller of Invoke-Command, i.e. to the variables visible to the code that makes the overall Invoke-Command call.
  • Ideally, the expansion of $using:... references would be smart enough to handle nested scopes, as in this case, but that is not the case as of PowerShell Core 7.0.0-preview.3.

警告:正如 PetSerAl 所指出的,如果您将 Invoke-Command命令范围的临时会话一起使用(暗示使用-ComputerName) - 而不是使用 New-PSSession 创建并传递给 Invoke-Command 的更长寿命的 session> 使用 -Session - 当 Invoke-Command 调用返回时,后台作业被终止,然后它(可能)有机会完成.虽然您可以通过管道将 Start-Job 调用传递给 ... |Receive-Job -Wait -AutoRemove,只有当您开始多个作业时,这才值得.

Caveat: As PetSerAl points out, if you use Invoke-Command with a command-scoped ad-hoc session (implied by using -ComputerName) - rather than a longer-lived session created prior with New-PSSession and passed to Invoke-Command with -Session - the background job gets terminated when the Invoke-Command call returns, before it (likely) has a chance to finish. While you could pipe the Start-Job call to ... | Receive-Job -Wait -AutoRemove, that would only be worth it if you started multiple jobs.

因此:

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

}

这篇关于$Using:var 在 Invoke-Command 中的 Start-Job 中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆