【问题标题】:Handle errors in ScriptBlock in Invoke-Command Cmdlet在 Invoke-Command Cmdlet 中处理 ScriptBlock 中的错误
【发布时间】:2012-09-18 00:45:05
【问题描述】:

我正在尝试使用 powershell 在远程计算机上安装服务。

到目前为止,我有以下内容:

Invoke-Command -ComputerName  $remoteComputerName -ScriptBlock {
         param($password=$password,$username=$username) 
         $secpasswd = ConvertTo-SecureString $password -AsPlainText -Force
         $credentials = New-Object System.Management.Automation.PSCredential ($username, $secpasswd)
         New-Service -Name "XXX" -BinaryPathName "c:\XXX.exe" -DisplayName "XXX XXX XXX" -Description "XXXXXX." -Credential $credentials -ErrorVariable errortext 
         Write-Host("Error in: " + $errortext)
        } -ArgumentList $password,$username -ErrorVariable errortext 


Write-Host("Error out: " + $errortext)

当执行 New-Service 时出现错误时,$errortext ErrorVariable 会在 ScriptBlock 内正确设置,因为文本:“Error in: 显示错误。

Invoke-Command 的 ErrorVariable 未设置(这是我预期的)。

我的问题是:

是否可以将 Invoke-Command 的 ErrorVariable 设置为我在 ScriptBlock 中遇到的错误?

我知道我也可以使用 InstalUtil、WMI 和 SC 来安装该服务,但目前不相关。

【问题讨论】:

    标签: powershell error-handling invoke-command


    【解决方案1】:

    不,您无法将 Invoke-Command 调用中的 Errorvariable 设置为与脚本块中相同的设置。

    但如果您的目标是“检测和处理脚本块中的错误,并将错误返回到 Invoke-Command 调用者的上下文”,那么只需手动执行:

    $results = Invoke-Command -ComputerName server.contoso.com -ScriptBlock {
       try
       {
           New-Service -ErrorAction 1
       }
       catch
       {
           <log to file, do cleanup, etc>
           return $_
       }
       <do stuff that should only execute when there are no failures>
    }
    

    $results 现在包含错误信息。

    【讨论】:

    • @latkin,您应该在这个答案中指出,这样做的原因是您正在处理一个正常的非终止错误并将其转换为一个终止错误,以便您可以捕获错误一个 try/catch 语句。将值 Stop 用于 -ErrorAction 而不是 1 会更清楚。
    【解决方案2】:

    Invoke-Command 参数列表是一种单向处理。您可以在脚本中输出错误变量,例如在脚本块的最后一行放置:

    $errortext
    

    或者更好的是,根本不通过 -ErrorVariable 捕获错误。即使通过远程连接,脚本块输出(包括错误)也会流回调用者。

    C:\> Invoke-Command -cn localhost { Get-Process xyzzy } -ErrorVariable errmsg 2>$null
    C:\> $errmsg
    Cannot find a process with the name "xyzzy". Verify the process name and call the cmdlet again.
        + CategoryInfo          : ObjectNotFound: (xyzzy:String) [Get-Process], ProcessCommandException
        + FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
        + PSComputerName        : localhost
    

    总的来说,我认为最好将错误保留在错误流中,与正常输出分开。

    【讨论】:

    • 我使用 ErrorVariable 来检查是否发生了错误。执行命令后,我检查它,如果它不为空,我将其写入文件,然后取消整个脚本的执行。
    • 但是您仍然希望将错误信息返回给调用者,对吗?如果是这样,您可以在脚本块的末尾输出错误记录。
    • 是的,但我不需要视觉信息。我需要一些逻辑来判断命令失败,以便中止脚本。
    • 在这种情况下,请在执行 Invoke-Command 后立即检查 $?。这是确定命令是失败还是成功的典型方法。
    • 我试过 $?技术,它在我的情况下不起作用。我在 Invoke-Command 中使用错误的帐户名调用了 subinacl.exe,但后来 $?仍然返回 True。使用 exe 调用,我想将退出代码传回是必要的。
    【解决方案3】:

    这几乎肯定不是“正确”的答案,但当我希望 Invoke-Command 在脚本中引发错误时,我会使用它。

    $error.Clear()
    Invoke-Command -ComputerName localhost -ScriptBlock {Command-ThatFails}
    $if ($error.Count -gt 0) { throw $error[0] }
    

    如果您想将错误保留在变量中,您可以执行以下操作:

    $error.Clear()
    Invoke-Command -ComputerName localhost -ScriptBlock {Command-ThatFails}
    $if ($error.Count -gt 0) { $myErrorVariable = $error[0] }
    

    【讨论】:

    • 如果它有效就不要敲它,这只是我需要的简单的东西,谢谢
    【解决方案4】:

    从最严格的意义上来说,我相信答案是否定的,你不能将 Invoke-Command 的 ErrorVariable 设置为脚本块内 ErrorVariable 的内容。 ErrorVariable 仅适用于它所附加的命令。

    但是,您可以将脚本块中的变量传递给 Invoke-Command 的范围。在您的代码中,您使用-ErrorVariable errortext 运行您的新服务命令。相反,在“脚本”范围内创建变量,方法是在变量名称前加上“脚本:”,如下所示:-ErrorVariable script:errortext。这使得变量在脚本块外部和内部都可用。

    现在您的最后一行 Write-Host("Error out: " + $errortext) 将输出在脚本块内部生成的错误。

    更多信息herehere

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-22
      • 1970-01-01
      • 1970-01-01
      • 2012-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-03
      相关资源
      最近更新 更多