使用Start-Process使用param运行脚本块命令

时间:2019-03-05 01:19:29

标签: powershell

为什么Powershell在设置位置时会认为$dirnull,而在写输出时却不会呢?

$command = {
    param($dir)
    Set-Location $dir
    Write-Output $dir
}

# run the command as administrator
Start-Process powershell -Verb RunAs -ArgumentList "-NoExit -Command $command 'C:\inetpub\wwwroot'"

这将产生以下输出:

Set-Location : Cannot process argument because the value of argument "path" is null. Change the value of argument
"path" to a non-null value.
At line:3 char:2
+  Set-Location $dir
+  ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Set-Location], PSArgumentNullException
    + FullyQualifiedErrorId : ArgumentNull,Microsoft.PowerShell.Commands.SetLocationCommand

C:\inetpub\wwwroot

我也尝试过:

$command = {
    param($dir)
    Set-Location $dir
    Write-Output $dir
}

$outerCommand = {
    Invoke-Command -ScriptBlock $command -ArgumentList 'C:\inetpub\wwwroot'
}

# run the command as administrator
Start-Process powershell -Verb RunAs -ArgumentList "-NoExit -Command $outerCommand"

但是我得到了:

Invoke-Command : Cannot validate argument on parameter 'ScriptBlock'. The argument is null. Provide a valid value for
the argument, and then try running the command again.
At line:2 char:30
+  Invoke-Command -ScriptBlock $command 'C:\inetpub\wwwroot'
+                              ~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Invoke-Command], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.InvokeCommandCommand

可能的线索:如果我设置一个局部变量而不是使用参数,那么它可以完美地工作:

$command = {
    $dir = 'C:\inetpub\wwwroot'
    Set-Location $dir
    Write-Output $dir
}

# run the command as administrator
Start-Process powershell -Verb RunAs -ArgumentList "-NoExit -Command $command"

类似的问/答未能完全回答我的问题:

2 个答案:

答案 0 :(得分:2)

$command脚本块{ ... }),而字符串化脚本块会导致其文字内容,但不包括封闭的{}

因此,您的可扩展字符串"-NoExit -Command $command 'C:\inetpub\wwwroot'"实际上扩展为以下字符串-请注意原始脚本块周围缺少的{ ... }

 -NoExit -Command 
    param($dir)
    Set-Location $dir
    Write-Output $dir
 'C:\inetpub\wwwroot'

由于丢失了封闭的{},由powershell产生的新Start-Process进程悄悄地忽略了孤立的param($dir)语句,并且因此新进程没有$dir变量(假设它也不是 automatic 变量),命令失败,因为Set-Location $dir等于{{1} },失败。 [1]

请注意,您永远不能将脚本块这样传递给Set-Location $null-所有参数都必须为 strings ,因为只有字符串可以传递给外部流程


您遇到的最简单的解决方案是:

  • Start-Process引用括在$command 的可扩展字符串中,以补偿由于字符串化导致的此附件丢失

  • 附加{ ... } ,以确保在新过程中调用生成的脚本块。

这是一个可行的解决方案:

&

重要:虽然手边的特定脚本块并不需要,但是任何已嵌入Start-Process powershell -Verb RunAs -ArgumentList ` "-NoExit -Command & { $command } 'C:\inetpub\wwwroot'" 个字符的脚本块。不会被目标进程正确解析为整个"字符串的一部分;为防止这种情况,它们必须以"..." 的形式转义,这是外部程序所期望的-包括通过CLI进行的PowerShell:

\"

[1]在 Windows PowerShell 中失败;在PowerShell Core 中,它等于# Script block with embedded " chars. $command = { param($dir) Set-Location $dir "Current dir: $dir" } # Embed the script block with " escaped as \" Start-Process powershell -Verb RunAs -ArgumentList ` "-NoExit -Command & { $($command -replace '"', '\"') } 'C:\inetpub\wwwroot'" 不带参数,它将更改为当前用户的主文件夹。

答案 1 :(得分:0)

我遇到了类似的问题,但我想将 Start-Process -ArgumentList 所需的所有命令放入一个变量中。感谢上面mklement0 的回答,我设法找到了解决方案。

这里有一个稍微替代的答案,它在 -Command [powershell.exe] [link 1 ]:

Here-String