尝试 Catch 在 Powershell 脚本中不起作用

问题描述 投票:0回答:4

我似乎无法让这个 try-catch 工作。我确信这很简单,但此刻我的大脑太煎熬了。请帮忙!

param(
[String[]]$RemoteServicesVMs = ('VmThatThrowsError')
)

function getWinServiceStatus
{

#Get-WmiObject "win32_service" 
    try{

        Get-WmiObject "win32_service" | Where-Object {$_.startname -notlike "NT*" -and $_.startname -notlike "local*" } | Format-Table -property PSComputerName, name, state, status, startname

    }  
    catch{

        wite-host "Failed"

    }

}

$PassWordEnc = convertto-securestring $RemotePassWord -asplaintext -force
$MyCred = New-Object -TypeName System.Management.Automation.PSCredential ArgumentList $RemoteUserName,$PassWordEnc

foreach($RemoteServicesVM in $RemoteServicesVMs){

    Invoke-Command -ComputerName $RemoteServicesVM -Port 5985 -Authentication Negotiate -ScriptBlock ${function:getWinServiceStatus} -Credential $MyCred

}
powershell try-catch
4个回答
53
投票

Try/Catch 只会在终止异常时“触发”。默认情况下,PowerShell 中的大多数 cmdlet 不会引发终止异常。您可以使用

-ErrorAction
或 -ea 参数设置错误操作:

Do-Thing 'Stuff' -ErrorAction Stop

这么说......我认为

Get-WmiObject
永远不会产生终止错误。如果它没有找到任何东西,它就不会返回任何东西。在这种情况下,您可以在 try 块中添加 if 条件,然后手动抛出:

Try {
    $Obj = Get-WmiObject "win32_service" | Where ...
    if ($null -eq $Obj) {
        throw
    }
}
Catch {
    # Error Handling
}

22
投票
  1. 您的 catch 语句有一个拼写错误。应该是

    Write-Host

  2. Powershell 中的尝试捕获与大多数其他编程语言不同。 Powershell 中有两种类型的错误:终止错误和非终止错误。默认情况下,非终止错误将不会触发您的 catch 处理。

因此,如果您想 force powershell 捕获错误,无论它是什么类型,您可以将

-ErrorAction Stop
附加到您的
Invoke-Command
行。

例如:

Invoke-Command -ComputerName $RemoteServicesVM -Port 5985 -Authentication Negotiate -ScriptBlock ${function:getWinServiceStatus} -Credential $MyCred -ErrorAction Stop

或者(从下面的链接复制):

也可以使用 ErrorActionPreference 变量将所有错误视为终止。您可以对正在使用的脚本或整个 PowerShell 会话执行此操作。要在脚本中设置它,请将第一行设置为 $ErrorActionPreference = Stop。要为会话设置它,请在 PowerShell 控制台中输入 $ErrorActionPreference = Stop。

在此处查看更多信息:http://www.vexasoft.com/blogs/powershell/7255220-powershell-tutorial-try-catch-finally-and-error-handling-in-powershell


1
投票

我稍微修改了你的函数参数,但对于你的答案,我不得不说,因为你使用的是 notlike 你的 get-wmiobject 没有返回任何错误。

如果数据也不存在,它将显示为空白。您可以通过将输出放入变量并显示输出来缩小问题范围。

您应该使用 -eq 和通配符来处理它。

为了缩小问题范围,请使用以下方法:

$erroractionpreference = stop;
function getWinServiceStatusparam(
[String[]]$RemoteServicesVMs = ('VmThatThrowsError')
)
{

#Get-WmiObject "win32_service" 
    try{

       $a=  Get-WmiObject "win32_service" | Where-Object {$_.startname -notlike "NT*" -and $_.startname -notlike "local*" } | Format-Table -property PSComputerName, name, state, status, startname
       Write-Host $a
    }  
    catch{

        wite-host "Failed"

    }

}

$PassWordEnc = convertto-securestring $RemotePassWord -asplaintext -force
$MyCred = New-Object -TypeName System.Management.Automation.PSCredential ArgumentList $RemoteUserName,$PassWordEnc

foreach($RemoteServicesVM in $RemoteServicesVMs){

    Invoke-Command -ComputerName $RemoteServicesVM -Port 5985 -Authentication Negotiate -ScriptBlock ${function:getWinServiceStatus} -Credential $MyCred

}

希望有帮助。


1
投票

您可以检查最后一个命令是否成功运行,然后处理它,而不是尝试/捕获:

Get-WmiObject "win32_service"
if(!$?){
  if($error[0].exception.message -match "invalid class"){ write-warning "The class doesn't exist"}
  else{ throw $error[0] }
}
© www.soinside.com 2019 - 2024. All rights reserved.