$Using:var 在 Invoke-Command 中的 Start-Job 中 [英] $Using:var in Start-Job within Invoke-Command
问题描述
我使用的是 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 toStart-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,
{ ... }
withStart-Job
, as in your attempt, the$using:
references do not refer to theInvoke-Command
script block's scope, but to the scope of the caller ofInvoke-Command
, i.e. to the variables visible to the code that makes the overallInvoke-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屋!