Powershell 警告和错误处理

Powershell warning and error handling

我正在编写以下代码来替换下面的批处理脚本。

$Script:srcpath = ((Get-Location).Path)
$Script:configure = "$Script:srcpath\qtbase\configure.bat"

if (Get-Item "$Script:srcpath\qtbase\configure.bat" -WarningAction (Write-Warning "$Script:configure not found. Did you forget to run 'init-repository'?")) {
    continue
}

我正在尝试重写qt配置批处理脚本:

set "srcpath=%~dp0"
set "configure=%srcpath%qtbase\configure.bat"
if not exist "%configure%" (
    echo %configure% not found. Did you forget to run "init-repository"? >&2
    exit /b 1
)

if not exist qtbase mkdir qtbase || exit /b 1

echo + cd qtbase
cd qtbase || exit /b 1

echo + %configure% -top-level %*
call %configure% -top-level %*
set err=%errorlevel%

cd ..

exit /b %err%

我在 PowerShell 中遇到的错误如下:

Get-Item : Cannot bind parameter 'WarningAction' to the target. Exception setting
"WarningAction": "Object reference not set to an instance of an object."
At line:4 char:67
+ ... rningAction (Write-Warning "$Script:configure not found. Did you forg ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (:) [Get-Item], ParameterBindingException
    + FullyQualifiedErrorId : ParameterBindingFailed,Microsoft.PowerShell.Commands.GetItemCommand

问题是抛出的错误是错误的,因为正在调用的警告应该取代它告诉人们该项目不存在。所以 运行 "init-repository".

PowerShell 中没有一个好东西,"if not exist"。

好的,有,但是看起来像这样:

catch [System.Management.Automation.ItemNotFoundException]

我上班有问题。

为什么我在有人问之前就这样做是因为我觉得微软会在一段时间内逐步淘汰 CMD 更新脚本是件好事。

为什么不起作用

WarningAction 不是这样的。

来自about_CommonParameters documentation

Determines how the cmdlet responds to a warning from the command. "Continue" is the default value. This parameter works only when the command generates a warning message. For example, this parameter works when a command contains the Write-Warning cmdlet.

所以基本上WarningAction的值默认是Continue,可以设置为InquireSilentlyContinueStop。它设置的值决定采取什么操作 if Get-item 命令抛出警告,而不是写什么警告如果 Get-item 抛出警告。

您可以更改 preference variable $WarningPreference 以在当前范围内设置 WarningAction,或者在范围修饰符之前。


如何让它工作

Test-Path

我第二 使用 Test-Path。这将 return TrueFalse,具体取决于它是否找到文件。

if (-not (Test-Path -Path "$Script:srcpath\qtbase\configure.bat")){
    Write-Warning 'Does not exist!'
    # do other stuff
    continue
}else{
    Get-Item $configure
}

try/catch

您可以尝试直接在 try/catch 中捕获 Get-Item 抛出的异常。与 WarningAction 类似,还有 ErrorAction 决定在抛出错误时要做什么。需要终止错误,所以 ErrorAction 设置为 Stop.

try{
    Get-Item $configure -ErrorAction Stop
}catch [System.Management.Automation.ItemNotFoundException]{
    Write-Output "Item not found"
    # do other stuff
}catch{
    Write-Output "Some other error"
    $Error[0] # prints last error
}