Tôi muốn tập lệnh PowerShell của tôi dừng khi bất kỳ lệnh nào tôi chạy không thành công (như set -e
trong bash). Tôi đang sử dụng cả hai lệnh Powershell ( New-Object System.Net.WebClient
) và chương trình ( .\setup.exe
).
Tôi muốn tập lệnh PowerShell của tôi dừng khi bất kỳ lệnh nào tôi chạy không thành công (như set -e
trong bash). Tôi đang sử dụng cả hai lệnh Powershell ( New-Object System.Net.WebClient
) và chương trình ( .\setup.exe
).
Câu trả lời:
$ErrorActionPreference = "Stop"
sẽ giúp bạn trở thành một phần của cách đó (nghĩa là điều này hoạt động rất tốt cho các lệnh ghép ngắn).
Tuy nhiên, đối với EXE, bạn sẽ cần tự kiểm tra $LastExitCode
sau mỗi lần gọi exe và xác định xem điều đó có thất bại hay không. Thật không may, tôi không nghĩ PowerShell có thể giúp đỡ ở đây vì trên Windows, EXE không nhất quán khủng khiếp về những gì cấu thành mã thoát "thành công" hay "thất bại". Hầu hết tuân theo tiêu chuẩn UNIX là 0 chỉ ra thành công nhưng không phải tất cả đều làm được. Kiểm tra chức năng CheckLastExitCode trong bài đăng trên blog này . Bạn có thể thấy nó hữu ích.
throw "$exe failed with exit code $LastExitCode"
$ exe chỉ là đường dẫn đến EXE.
Bạn sẽ có thể thực hiện điều này bằng cách sử dụng câu lệnh $ErrorActionPreference = "Stop"
ở đầu tập lệnh của bạn.
Cài đặt mặc định $ErrorActionPreference
là Continue
, đó là lý do tại sao bạn thấy các tập lệnh của mình tiếp tục xảy ra sau khi xảy ra lỗi.
Đáng buồn thay, do các lệnh ghép ngắn lỗi như New-RegKey và Clear-Disk , không có câu trả lời nào trong số này là đủ. Hiện tại tôi đã giải quyết các dòng sau ở đầu bất kỳ kịch bản quyền hạn nào để duy trì sự tỉnh táo của mình.
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction']='Stop'
và sau đó bất kỳ cuộc gọi bản địa nào cũng được điều trị này:
native_call.exe
$native_call_success = $?
if (-not $native_call_success)
{
throw 'error making native call'
}
Mô hình cuộc gọi bản địa đó đang dần trở nên đủ phổ biến đối với tôi mà có lẽ tôi nên xem xét các lựa chọn để làm cho nó ngắn gọn hơn. Tôi vẫn là một người mới sử dụng năng lực, vì vậy các đề xuất đều được chào đón.
Bạn cần xử lý lỗi hơi khác nhau đối với các hàm powershell và để gọi exe, và bạn cần chắc chắn nói với người gọi về tập lệnh của mình rằng nó đã bị lỗi. Xây dựng Exec
từ thư viện Psake, một tập lệnh có cấu trúc bên dưới sẽ dừng trên tất cả các lỗi và có thể sử dụng làm mẫu cơ sở cho hầu hết các tập lệnh.
Set-StrictMode -Version latest
$ErrorActionPreference = "Stop"
# Taken from psake https://github.com/psake/psake
<#
.SYNOPSIS
This is a helper function that runs a scriptblock and checks the PS variable $lastexitcode
to see if an error occcured. If an error is detected then an exception is thrown.
This function allows you to run command-line programs without having to
explicitly check the $lastexitcode variable.
.EXAMPLE
exec { svn info $repository_trunk } "Error executing SVN. Please verify SVN command-line client is installed"
#>
function Exec
{
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)][scriptblock]$cmd,
[Parameter(Position=1,Mandatory=0)][string]$errorMessage = ("Error executing command {0}" -f $cmd)
)
& $cmd
if ($lastexitcode -ne 0) {
throw ("Exec: " + $errorMessage)
}
}
Try {
# Put all your stuff inside here!
# powershell functions called as normal and try..catch reports errors
New-Object System.Net.WebClient
# call exe's and check their exit code using Exec
Exec { setup.exe }
} Catch {
# tell the caller it has all gone wrong
$host.SetShouldExit(-1)
throw
}
Exec { sqlite3.exe -bail some.db "$SQL" }
, -bail
nguyên nhân gây ra lỗi vì nó cố gắng diễn giải nó như một tham số Cmdlet? Gói mọi thứ trong dấu ngoặc kép dường như không hoạt động. Có ý kiến gì không?
Một sửa đổi nhỏ cho câu trả lời từ @alastairtree:
function Invoke-Call {
param (
[scriptblock]$ScriptBlock,
[string]$ErrorAction = $ErrorActionPreference
)
& @ScriptBlock
if (($lastexitcode -ne 0) -and $ErrorAction -eq "Stop") {
exit $lastexitcode
}
}
Invoke-Call -ScriptBlock { dotnet build . } -ErrorAction Stop
Sự khác biệt chính ở đây là:
Invoke-Command
)-ErrorAction
hành vi bắt chước từ được xây dựng trong cmdletsInvoke-Call { dotnet build $something }
& @ScriptBlock
và & $ScriptBlock
xuất hiện để làm điều tương tự. Không thể google được sự khác biệt trong trường hợp này
Tôi đến đây để tìm kiếm điều tương tự. $ ErrorActionPreference = "Stop" giết chết shell của tôi ngay lập tức khi tôi muốn xem thông báo lỗi (tạm dừng) trước khi nó kết thúc. Trở lại với sự nhạy cảm hàng loạt của tôi:
IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF
Tôi thấy rằng điều này hoạt động khá giống với kịch bản ps1 cụ thể của tôi:
Import-PSSession $Session
If ($? -ne "True") {Pause; Exit}
Chuyển hướng stderr
tới stdout
dường như cũng làm các trick mà không cần bất kỳ lệnh / wrappers scriptblock khác mặc dù tôi không thể tìm thấy một lời giải thích lý do tại sao nó hoạt động như vậy ..
# test.ps1
$ErrorActionPreference = "Stop"
aws s3 ls s3://xxx
echo "==> pass"
aws s3 ls s3://xxx 2>&1
echo "shouldn't be here"
Điều này sẽ xuất ra như sau như mong đợi (lệnh aws s3 ...
trả về $LASTEXITCODE = 255
)
PS> .\test.ps1
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
==> pass
$ErrorActionPreference = "Stop"
hoạt động cho các chương trình hoạt động tốt (trả về 0 khi thành công) không?