【问题标题】:Running script-block command with param using Start-Process使用 Start-Process 运行带有参数的脚本块命令
【发布时间】:2019-07-26 09:42:50
【问题描述】:

为什么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"

类似的 Q/As 并没有完全回答我的问题:

【问题讨论】:

  • 您是否有任何理由将 $command 专门传递给它,而不仅仅是像 $arguments = "-NoExit Set-Location 'C:\inetpub\wwwroot'" Start-Process powershell -Verb RunAs -ArgumentList $arguments 那样在参数变量中指定位置
  • @OwainEsau,这是一个精简的例子。我的真实脚本太大太复杂,无法轻松放入字符串。

标签: powershell


【解决方案1】:

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

这是一个稍微替代的答案,其中包括powershell.exe-Command(和任何其他参数),在Here-String [link 1] [link 2] 中:

$commandString = @'
    -NoExit -Command & {
        Write-Host -ForegroundColor Green \"Hello, new window!\"
        Set-Location -Path \"c:\\\"
        Get-ChildItem
        Start-Sleep -Seconds 3
    }
'@

Start-Process -FilePath "powershell.exe" -ArgumentList $commandString

【讨论】:

    【解决方案2】:

    $command 是一个脚本块 ({ ... }),字符串化一个脚本块会产生其文字内容,不包括封闭的{}

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

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

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

    请注意,您永远不能将脚本块 传递给 Start-Process - 所有参数都必须是 字符串,因为只有字符串可以传递给外部进程


    在您的情况下,最简单的解决方案是:

    • $command 引用包含在 { ... } 中的可扩展字符串中,以补偿由于字符串化导致的此附件的损失

    • 添加&以确保在新进程中调用生成的脚本块。

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

    Start-Process powershell -Verb RunAs -ArgumentList `
      "-NoExit -Command & { $command } 'C:\inetpub\wwwroot'"
    

    重要提示:虽然手头的特定脚本块不需要,但任何具有嵌入" 字符的脚本块。目标进程无法将其作为整个"..." 字符串的一部分正确解析;为了防止这种情况,它们必须转义为 \",这是外部程序所期望的 - 包括通过其 CLI 的 PowerShell:

    # 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] 在 Windows PowerShell 中失败;在PowerShell Core中,相当于Set-Location不带参数,会变成当前用户的home文件夹。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多