पहली त्रुटि पर PowerShell स्क्रिप्ट को कैसे रोकें?


250

मैं चाहता हूं कि मेरी पावरशेल स्क्रिप्ट तब बंद हो जाए जब कोई भी कमांड मैं फेल हो जाए (जैसे set -eबैश में)। मैं Powershell कमांड ( New-Object System.Net.WebClient) और प्रोग्राम्स ( .\setup.exe) दोनों का उपयोग कर रहा हूं ।

जवाबों:


303

$ErrorActionPreference = "Stop" आपको वहां का हिस्सा मिलेगा (यानी यह cmdlets के लिए बहुत अच्छा काम करता है)।

हालाँकि, $LastExitCodeEXE के लिए आपको हर exe आह्वान के बाद खुद को जाँचना होगा और यह निर्धारित करना होगा कि यह विफल है या नहीं। दुर्भाग्य से मुझे नहीं लगता कि PowerShell यहाँ मदद कर सकता है क्योंकि Windows पर, EXE बहुत "" सफलता "या" विफलता "" निकास कोड का गठन करने पर सुसंगत नहीं हैं। अधिकांश 0 के UNIX मानक का अनुसरण करते हुए सफलता का संकेत देते हैं लेकिन सभी ऐसा नहीं करते हैं। की जाँच करें इस ब्लॉग पोस्ट में CheckLastExitCode समारोह । आपको यह उपयोगी लग सकता है।


3
क्या $ErrorActionPreference = "Stop"अच्छी तरह से व्यवहार किए गए कार्यक्रमों के लिए काम करता है (कि सफलता पर 0 वापसी)?
एंड्रेस रिओप्रियो

14
नहीं, यह EXEs के लिए बिल्कुल भी काम नहीं करता है। यह केवल PowerShell cmdlets के लिए काम करता है जो इन-प्रोसेस चलाते हैं। यह एक तरह का दर्द है लेकिन आपको प्रत्येक EXE आह्वान के बाद $ LastExitCode की जांच करनी है, यह जांच लें कि अपेक्षित निकास कोड के खिलाफ है और यदि वह परीक्षण विफलता को इंगित करता है, तो आपको स्क्रिप्ट के निष्पादन को समाप्त करने के लिए फेंकना होगा, throw "$exe failed with exit code $LastExitCode"जहां $ exe सिर्फ पथ है EXE।
कीथ हिल

2
स्वीकार किया जाता है क्योंकि इसमें बाहरी कार्यक्रमों के साथ काम करने के तरीके के बारे में जानकारी शामिल है।
एंड्रेस रिओप्रियो

4
मैंने इसके बारे में एक फ़ीचर रिक्वेस्ट यहाँ दी: connect.microsoft.com/PowerShell/feedback/details/751703/…
Helephant

5
ध्यान दें कि psake में एक कमांड है, जिसे "exec" कहा जाता है, जिसे आप LastExitCode के लिए एक चेक के साथ बाहरी प्रोग्राम में कॉल रैप करने के लिए उपयोग कर सकते हैं और एक त्रुटि प्रदर्शित कर सकते हैं (और यदि संभव हो तो रोकें)
enorl76

68

आपको $ErrorActionPreference = "Stop"अपनी स्क्रिप्ट की शुरुआत में बयान का उपयोग करके इसे पूरा करने में सक्षम होना चाहिए ।

की डिफ़ॉल्ट सेटिंग $ErrorActionPreferenceहै Continue, यही कारण है कि आप अपनी स्क्रिप्ट देख रहे हैं त्रुटियों के होने के बाद भी चलते रहें।


21
यह केवल cmdlets को प्रभावित नहीं करता है।
जोए

18

अफसोस की बात है कि न्यू-रेग्के और क्लीयर-डिस्क जैसे छोटी गाड़ी सीडलेट्स के कारण , इनमें से कोई भी उत्तर पर्याप्त नहीं है। मैंने वर्तमान में अपनी पवित्रता बनाए रखने के लिए किसी भी शिल्पी लिपि के शीर्ष पर निम्नलिखित पंक्तियों को बसाया है।

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction']='Stop'

और फिर किसी भी देशी कॉल को यह उपचार मिलता है:

native_call.exe
$native_call_success = $?
if (-not $native_call_success)
{
    throw 'error making native call'
}

यह देशी कॉल पैटर्न धीरे-धीरे मेरे लिए काफी सामान्य होता जा रहा है कि मुझे इसे अधिक संक्षिप्त बनाने के विकल्पों पर ध्यान देना चाहिए। मैं अभी भी एक नौसिखिया नौसिखिया हूँ, इसलिए सुझावों का स्वागत है।


14

आपको पॉवरशेल फ़ंक्शंस के लिए और exe कॉलिंग के लिए थोड़ी अलग त्रुटि से निपटने की आवश्यकता है, और आपको अपनी स्क्रिप्ट के कॉलर को यह बताना सुनिश्चित करना होगा कि यह विफल हो गया है। Execलाइब्रेरी Psake के शीर्ष पर बिल्डिंग , एक स्क्रिप्ट जिसमें नीचे की संरचना है, सभी त्रुटियों पर बंद हो जाएगी, और अधिकांश स्क्रिप्ट के लिए बेस टेम्पलेट के रूप में उपयोग करने योग्य है।

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
}

उदाहरण के लिए: यह एक Cmdlet पैरामीटर के रूप में व्याख्या करने की कोशिश कर रहा है Exec { sqlite3.exe -bail some.db "$SQL" }, -bailएक त्रुटि का कारण बनता है? उद्धरणों में चीजों को लपेटना काम नहीं लगता है। कोई विचार?
rcoup

क्या इस कोड को केंद्रीय कहीं रखने का एक तरीका है ताकि आप किसी प्रकार का # प्रयोग कर सकें जब आप Exec पद्धति का उपयोग करना चाहें?
NickG

10

@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

यहाँ मुख्य अंतर हैं:

  1. यह क्रिया-संज्ञा (नकल Invoke-Command) का उपयोग करता है
  2. तात्पर्य है कि यह कवर के तहत कॉल ऑपरेटर का उपयोग करता है
  3. -ErrorActioncmdlets में निर्मित से मिमिक व्यवहार
  4. नए संदेश के साथ अपवाद को फेंकने के बजाय एक ही निकास कोड के साथ बाहर निकलता है

1
आप पैरामीटर / चर कैसे पास करते हैं? जैसेInvoke-Call { dotnet build $something }
माइकल ब्लेक

1
@MichaelBlake आपकी जांच इतनी सही है, जिससे एक परम पार्थरथ इस दृष्टिकोण को स्वर्ण बना देगा। मैं पास-थ्रू सपोर्ट करने के लिए Invoke-Call को समायोजित करने के लिए adamtheautomator.com/pass-hashtables-invoke-command-argument का निरीक्षण कर रहा हूं । यदि मैं सफल होता हूं, तो मैं यहां एक और उत्तर के रूप में पोस्ट करूंगा।
मैक्सिम वी। पावलोव

आप आह्वान के दौरान स्प्लैटिंग ऑपरेटर का उपयोग क्यों करते हैं? आपको क्या मिलता है? & @ScriptBlockऔर & $ScriptBlockएक ही काम करते दिखाई देते हैं। इस मामले में क्या अंतर है यह Google को पता नहीं
चल पाया है

6

मैं शक्तिकरण के लिए नया हूँ, लेकिन यह सबसे प्रभावी प्रतीत होता है:

doSomething -arg myArg
if (-not $?) {throw "Failed to doSomething"}

2

मेरा उसी चीज़ को ढूंढते हुए यहाँ तक आना हुआ। $ ErrorActionPreference = "रोकें" मेरे शेल को तुरंत मार देता है जब मैं समाप्त होने से पहले त्रुटि संदेश (पॉज़) देखता हूं। मेरे बैच की संवेदनाओं पर पानी फेरना:

IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF

मैंने पाया कि यह मेरी विशेष ps1 स्क्रिप्ट के लिए बहुत समान है:

Import-PSSession $Session
If ($? -ne "True") {Pause; Exit}

0

किसी अन्य कमांड / स्क्रिप्टब्लॉक रैपर के बिना भी ट्रिक करने के stderrलिए पुनर्निर्देशित stdoutकरना, हालाँकि मुझे कोई स्पष्टीकरण नहीं मिल सकता है कि यह इस तरह से क्यों काम करता है ..

# test.ps1

$ErrorActionPreference = "Stop"

aws s3 ls s3://xxx
echo "==> pass"

aws s3 ls s3://xxx 2>&1
echo "shouldn't be here"

यह उम्मीद के अनुसार निम्नलिखित आउटपुट करेगा (कमांड aws s3 ...रिटर्न $LASTEXITCODE = 255)

PS> .\test.ps1

An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
==> pass
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.