12

PowerShell Script 結束執行的正確姿勢

 2 years ago
source link: https://blog.darkthread.net/blog/ps-exit-issue/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
PowerShell Script 結束執行的正確姿勢-黑暗執行緒

在 PowerShell 中想提前結束程式有好幾種寫法,例如 return、exit,之前沒認真比過差異,胡亂用踩了坑,特整理筆記備忘。

先用以下 Test-ExitScript.ps1 程式示範,依傳入參數模擬四種提前結束 Script 的做法 - return、break、exit 及 [Environment]::Exit(),程式最後有個 Write-Host 'You should not see this',正常狀況不會顯示,用以驗證程式已提前中止。

param([string]$method = 'return')
Write-Host "Terminating script with '$method'"
if ($method -eq 'nothing') {
    # do nothing
}
elseif ($method -eq 'return') {
    return
}
elseif ($method -eq 'break') {
    break
}
elseif ($method -eq 'exit') {
    exit
}
elseif ($method -eq 'dos-exit') {
    [Environment]::Exit(255)
}
else {
    throw "Unkown method - $method"
}
Write-Host 'You should not see this'

第一組測試用 powershell .\\Test-ExitScript.ps1 xxxx方式執行,四種方法都正確提前結束程式。

但如果使用 PowerShell 主控台 或先執行 PowerShell.exe 進入互動模式,結果則有點不同。如下圖,我在 Cmder 先輸入 powershell 進入互動模式,接著呼叫 .\Test-ExitScript.ps1 xxxx 進行測試,return、break、exit 都正常,但 [Environment]::Exit() 會結束 PowerShell 互動模式回到 Cmder:

有趣的是,如果把同樣程式包成 Function 裡,結果又會不相同。

function TestExit($method) {
    Write-Host "Terminating script with '$method'"
    if ($method -eq 'nothing') {
        # do nothing
    }
    elseif ($method -eq 'return') {
        return
    }
    elseif ($method -eq 'break') {
        break
    }
    elseif ($method -eq 'exit') {
        exit
    }
    elseif ($method -eq 'dos-exit') {
        [Environment]::Exit(255)
    }
    else {
        throw "Unkown method - $method"
    }
    Write-Host 'You should not see this'
}

實測如下,先執行 powershell (1) 進入互動模式,用 . .\Test-ExitScriptInFunc.ps1 載入 function TestExit($method) 函式 (2),接著呼叫 TestExit xxxx 測試不同退出方法 (3),發現 exit (4) 跟 [Environment]::Exit() 都會導致 PowerShell 互動環境結束:

由結果來看,若以排程執行單一 .ps1,四個方法都可提前結束執行,但 break 原本用於跳出 loop、while,移作他用易造成別人困惑,不推。exit 關鍵字 及 [Environment]::Exit() 搭配 Exit Code,可供 .BAT 判斷 %ERRORLEVEL% 做不同處理,有額外的應用場合。

但在 PowerShell 互動模式執行 .ps1 時,[Environment]::Exit() 有中止 PowerShell 互動環境的副作用。

如果要在 function 結束執行,建議乖乖用 return 就好,exit 跟 [Environment]::Exit() 都會強迫關閉 PowerShell 環境。我這次踩到的雷便是發生將 .ps1 包成 PowerShell 模組的過程,原本 .ps1 中用 exit 相安無事,改成 function 後安裝成模組,呼叫函式時發現 PowerShell 主控台會閃退,經過一番研究才搞懂是怎麼一回事。

大家如果有在 .ps1 使用 exit,改寫成函式或模組時,要留意這個小坑。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK