为什么PowerShell不允许在本地使用Invoke-Command
时使用using
作用域?根据文档,using
修饰符只能用于远程命令。
从PowerShell 3.0开始,您可以使用Using作用域修饰符来标识远程命令中的局部变量。
在本地运行Invoke-Command
时可以演示此行为:
$myServerName = 'www.google.com'
Invoke-Command { ping $using:myServerName }
这将引发以下错误:
无法检索Using变量。Using变量只能与脚本工作流中的Invoke-Command、Start-Job或InlineScript一起使用。当Using变量与Invoke-Command一起使用时,只有在远程计算机上调用脚本块时,Using变量才有效。
这个错误表明远程使用using
修饰符只在远程使用Invoke-Command
时有效。那么,如果我们尝试使用Start-Job
运行同样的操作,会发生什么呢?
$myServerName = 'www.google.com'
$j = Start-Job { ping $using:myServerName }
while( $j.State -eq 'Running' ){ Start-Sleep -s 1 }
Receive-Job $j
它不会抛出错误,并且得到了预期的输出:
Pinging www.google.com [172.217.6.132] with 32 bytes of data:
Reply from 172.217.6.132: bytes=32 time=20ms TTL=56
Reply from 172.217.6.132: bytes=32 time=19ms TTL=56
Reply from 172.217.6.132: bytes=32 time=19ms TTL=56
Reply from 172.217.6.132: bytes=32 time=19ms TTL=56
为什么文档声明using
作用域修饰符只能远程工作,而它显然也可以在本地上下文中使用?同样,如果它在本地Start-Job
上下文中工作,是什么阻止它在本地Invoke-Command
中工作?
3条答案
按热度按时间bq3bfh9z1#
当使用"using"时是这样的,因为using的定义规定,
从PowerShell 3.0开始,您可以使用Using作用域修饰符来标识远程命令中的局部变量
无论何时使用
$using
,都必须提供-ComputerName
或-Session
参数,无论目标服务器是本地服务器还是远程服务器。前。
$using:
仅在少数特定上下文中受支持,这些上下文有一个共同点:正在当前运行空间之外运行的代码-所有其他上下文既不需要也不支持它。(@mklement0)[
Invoke-Command
、Start-Job
和InlineScript
是支持使用$using:
在当前本地会话中传递变量的已知上下文。]有关可以在何处使用
$using
的文档hjzp0vay2#
注:此答案不包括PowerShell * 工作流 ,因为它们是PowerShell [Core] v6+ 中不再支持的 * 过时技术-请参阅this blog post。
对于执行 out-of-runspace 的任何东西,即 * 不直接在调用者的runspace(线程)中执行,您需要
$using:
作用域以便嵌入来自调用者作用域的变量 * 值 *[1],以便out-of-runspace代码可以访问它。$using:
。Invoke-Command
调用,例如您的调用(由于缺少-ComputerName
或-Session
参数);然而,这种呼吁很少有必要(见下文)。超出运行空间上下文概述:
*远程执行的命令,从
Invoke-Command
的-ComputerName
参数开始。Invoke-Command
-这是 * 不使用 *-ComputerName
或-Session
时发生的情况-既不需要也不支持$using:
引用(它在调用者作用域的 * 子作用域 * 中运行,或者,使用-NoNewScope
时,直接在调用者的作用域中运行)。Invoke-Command
几乎没有必要,因为&
,调用(执行)操作符(在子作用域中执行),和.
,(点-)源操作符(直接在调用者的作用域中执行),是更简洁和有效的替代方法。-ComputerName
参数将 local 计算机作为目标,则该命令仍被视为远程执行,即它通过PowerShell的远程处理基础架构,并且适用与真正远程执行相同的规则。*后台作业,从
Start-Job
开始*线程作业,通过
Start-ThreadJob
启动。使用
-Parallel
交换机的ForEach-Object
。远程执行的命令和后台作业 * 在进程外运行*[2],对于跨越这些进程边界的值,它们经历了基于XML的序列化和反序列化,这通常涉及类型保真度的损失-在输入和输出上都是如此。
$using:
嵌入的值,还适用于通过-ArgumentList
(-Args
)参数作为 arguments 传递给Invoke-Command [-ComputerName]
和Start-Job
的值。线程作业则相反,因为它们在同一进程 * 的不同运行空间(线程)* 中运行,接收
$using:
变量值作为其原始活动对象,并以类似方式返回此类对象。警告是,如果运行空间(线程)都访问给定的可变引用类型示例,则可能需要跨运行空间(线程)的显式同步*-这在
ForEach-Object -Parallel
中最有可能发生。[1]注意,这意味着运行空间外的代码 * 永远不能修改调用者作用域 * 中的变量。(但不在远程处理期间和后台作业中),如果变量 value 恰好是 reference type 的示例(例如集合类型),则有可能在另一线程中修改该示例,这需要跨线程同步修改,如果多个线程执行修改。
[2]与远程命令不同,后台作业在 * 同一台计算机 * 上运行,但在(隐藏的)PowerShell * 子进程 * 中运行。
xam8gpfp3#
如果不是远程,则不需要使用:
请注意,您必须是admin才能在localhost上调用。