启动 powershell 不会接受变量作为参数

start powershell wont accept variable as parameter

问题

被调用的 powershell 脚本将接受参数,但不是所有参数:

当前设置和代码:

我有一个公共文件夹,其中有两个 .ps1 脚本:

Workmanager.ps1 调用 Dowork.ps1:

$targetPath="M:\target"
echo "target path: $targetPath"

start powershell {.\DoWork.ps1 -target $targetPath -tempdrive D:\}

输出(如预期):

target path: M:\target

DoWork.ps1 包含一些起始代码:

param 
(
    [string]$tempdrive, 
    [string]$target, 
    [int] $threads = 8,
    [int] $queuelength = -1
)
echo "variables:"
echo "temp drive: $tempdrive"
echo "target path: $target"

意外地,$target 没有被分配。以前我有一个名为 $targetpath 的变量,它也不起作用。

variables:
temp drive: D:\
target path:

调查结果

看来问题出在 Workmanager 上。ps1。将参数指定为固定字符串而不是变量将加载参数。有什么解决办法吗?

start powershell {.\DoWork.ps1 -target "foo" -tempdrive D:\}

当您使用 ScriptBlock 作为 powershell.exe 的参数时,直到新会话开始 之后才会计算变量。 $targetPath 尚未在 Workmanager.ps1 调用的子 PowerShell 进程中设置,因此它没有任何价值。 这实际上是 ScriptBlock 通常的预期行为,在其他情况下也是如此

powershell -?的帮助文本中提到了解决方案:

[-Command { - | <script-block> [-args <arg-array>] <========== THIS GUY
              | <string> [<CommandParameters>] } ]

您必须提供 -args 参数,该参数将在执行时传递给 ScriptBlock(用 , 分隔多个参数)。传递的参数按位置传递,并且必须像使用 $args 数组手动处理函数的参数一样被引用。例如:

$name = 'Bender'
& powershell { Write-Output "Hello, $($args[0])" } -args $name

但是,尤其是对于更复杂的 ScriptBlock 主体,必须记住 $args[i] 的哪个索引包含您在给定时间想要的值是一件很痛苦的事情。幸运的是,我们可以使用一些小技巧在 ScriptBlock 中定义参数来帮助:

$name = 'Bender'
& powershell { param($name) Write-Output "Hello, $name" } -args $name

这将按预期打印 Hello, Bender


一些额外的提示:

  • ScriptBlock 可以是多行的,就像定义一个函数一样。方法。由于简单,上面的示例是单行的。

  • A ScriptBlock 只是一个未命名的函数,这就是为什么在其中定义参数和引用参数的方式相同。

  • 为了在 powershell.exe -Command 之外举例说明这种行为,Invoke-Command 需要您在 similar fashion 中将变量传递给它的 ScriptBlock。但是请注意,答案使用已经定义的函数体作为 ScriptBlock (这是完全有效的)

  • 您无需使用 Start-Process here (start is its alias), at least as demonstrated in your example. You can simply use the call operator & unless you need to do something more complex than "run the program and wait for it to finish". 获取更多信息。

  • 如果您选择将 string 传递给 powershell.exe,则无需提供参数,您的变量将在当前的 PowerShell 进程中呈现。但是,可能打算在子进程中设置的任何其他未转义变量也是如此,因此请谨慎使用此方法。就个人而言,我更喜欢使用 ScriptBlock 无论如何,只处理额外的参数定义和参数。

  • 当您不执行呈现为字符串的路径时,使用调用 & 运算符是可选的。在上面的例子中可以省略,但这样更有用:

    & "C:\The\Program Path\Contains\spaces.exe"
    
    & $programPathAsAVariable