首页 > 解决方案 > PowerShell:使用 Try-Catch 调用命令

问题描述

我正在使用以下代码来输出一批计算机的状态:

$Win2k8r2Computers = "Server1", "Server2", "Server3", "Server4"

$results = Invoke-Command -ComputerName $Win2k8r2Computers { #}
    $props = @{}
    Try {
        <#If ($PSVersionTable.PSVersion.Major -eq "2") {
            $props.Add('Message',"Server (Win2008r2) is currently running an incompatible version of PowerShell (v2.1)")
            }#>
        If (Get-Service | Where-Object { $_.Name -eq "W3SVC" } -ErrorAction Stop) {
            $props.Add('Message', "IIS is installed (Win2008r2)")
        }
        Else {
            $props.Add('Message', "IIS is NOT installed (Win2008r2)")
        }
    }
    catch {
        $props.Add('Message', 'Error: {0}' -f $_)
    }
    New-Object -Type PSObject -Prop $Props
}

除了 catch 似乎没有实际捕获并将错误返回到 $results 变量之外,它按预期工作。我错过了什么?

标签: powershelltry-catchinvoke-command

解决方案


在您当前的代码中,您仅将参数传递-ErrorActionWhere-Object. 因此,您只会捕获Where-Objectcmdlet 的错误。Get-Servicewoud 仍然使用默认ErrorAction值运行Continue

要将两者的 Get-Service错误Where-Object转换为可以捕获的终止错误,请传递-ErrorAction 'Stop'给它们两者......

If (Get-Service -ErrorAction Stop | Where-Object { $_.Name -eq "W3SVC" } -ErrorAction Stop)

...或者(更有效地)$ErrorActionPreference在脚本开头设置变量并删除-ErrorAction参数:

$Win2k8r2Computers = "Server1", "Server2", "Server3", "Server4"

$results = Invoke-Command -ComputerName $Win2k8r2Computers { #}
    $props = @{}
    Try {
        $ErrorActionPreference = 'Stop'

        <#If ($PSVersionTable.PSVersion.Major -eq "2") {
            $props.Add('Message',"Server (Win2008r2) is currently running an incompatible version of PowerShell (v2.1)")
            }#>
        If (Get-Service | Where-Object { $_.Name -eq "W3SVC" }) {
            $props.Add('Message', "IIS is installed (Win2008r2)")
        }
        Else {
            $props.Add('Message', "IIS is NOT installed (Win2008r2)")
        }
    }
    catch {
        $props.Add('Message', 'Error: {0}' -f $_)
    }
    New-Object -Type PSObject -Prop $Props
}

警告:

$ErrorActionPreference被 PowerShell 脚本模块中的 cmdlet 忽略,除非他们特别注意处理它。请参阅此答案以获取一些见解。

但在这种情况下它可以工作,因为这两个 cmdlet 都是在 C# 模块中实现的。


推荐阅读