【问题标题】:How to stop powershell script when error occurs?发生错误时如何停止powershell脚本?
【发布时间】:2022-11-10 22:13:31
【问题描述】:

我有一个“主”powershell 脚本,它执行多个在 VM 上安装应用程序的脚本。我正在尝试在主脚本上实现错误控制,这意味着:

如果安装应用程序的脚本之一失败,则不会执行其余脚本。

这是我的主要脚本:

try{
    powershell.exe -ExecutionPolicy Unrestricted -File 'C:\\TEST\\Scripts\\App1.ps1'    
    powershell.exe -ExecutionPolicy Unrestricted -File 'C:\\TEST\\Scripts\\App2.ps1'    
    powershell.exe -ExecutionPolicy Unrestricted -File 'C:\\TEST\\Scripts\\App3.ps1'    
 
}catch
{
  Write-Host "Error"

}

这是安装应用程序的脚本之一(App2.ps1)的示例(所有脚本都遵循与此相同的逻辑)

#Set logging 
$logFile = "C:\TEST\Logs\" + (get-date -format 'yyyyMMdd') + '_softwareinstall.log'
function Write-Log {
    Param($message)
    Write-Output "$(get-date -format 'yyyyMMdd HH:mm:ss') $message" | Out-File -Encoding utf8 $logFile -Append
}


#Install APP2 
$file = Test-Path "C:\TEST\Apps\APP2\APP2 x64 7.2.1.msi"
if($file)
{
   try{
        Write-Log "Installing App2"
        Start-Process msiexec.exe -Wait -ArgumentList '/i "C:\TEST\Apps\APP2\App2 x64 7.2.1.msi" ALLUSERS=1 AddLocal=MiniDriver,PKCS,UserConsole,Troubleshooting,Help /qn /norestart' 
        if(Test-Path -Path "C:\Program Files\HID Global\APP2\ac.app2.exe")
        {
            Write-Log "App2 installed"
        }
        else
        {
            Write-Log "There was a problem while installing App2"
        throw "There was a problem while installing App2"
        }
    }catch
    {
        Write-Log "[ERROR] There was a problem while starting the installation for App2"
        throw "[ERROR] There was a problem while starting the installation for App2"
    }
}
else
{
     Write-Log "Installation file for App2 not found"
     throw "Installation file for App2 not found"
}

这是输出:

(出于保密目的,我模糊了应用程序的名称)

安装APP2的脚本出现异常时,为什么主脚本继续执行? 不应该停止并显示写在主脚本中 catch 部分的消息吗?

先感谢您

【问题讨论】:

  • 尝试将$ErrorActionPreference = 'Stop' 添加到脚本的开头
  • 就是这样!非常感谢。我不知道这是这么简单的事情
  • 很好的交易。乐意效劳。
  • 顺便说一句:\ 在 PowerShell 中没有特殊含义,因此它永远不需要转义为 \\;例如,C:\TEST\Scripts\App1.ps1 工作得很好。

标签: powershell


【解决方案1】:

按照建议,我在脚本的开头添加了$ErrorActionPreference = 'Stop'

$ErrorActionPreference = 'Stop'

try{
    powershell.exe -ExecutionPolicy Unrestricted -File 'C:\TEST\Scripts\APP1.ps1'    
    powershell.exe -ExecutionPolicy Unrestricted -File 'C:\TEST\Scripts\APP2.ps1'    
    powershell.exe -ExecutionPolicy Unrestricted -File 'C:\TEST\Scripts\APP3.ps1'    
 
}catch
{
  Write-Host "Error"

}

并且输出只是消息“错误”,在 catch 部分中指示。

谢谢@Doug Maurer

【讨论】:

    【解决方案2】:

    在撰写本文时,your own answer,它依赖于标准错误输出,是不是有效的 -除了在以下情况下

    它适用于这些特定情况依靠不受欢迎的行为,已在PowerShell (Core) 7+ 中修复

    • 在上述情况下,标准错误输出自外部程序不恰当地通过 PowerShell 路由错误output stream,尽管不能假定 stderr 输出代表错误(它通常用于状态或进度消息 - 任何除了数据;外部程序是否失败的唯一可靠指标是它的进程退出代码)。

    • 正是这种通过 PowerShell 错误流的不适当路由使得 stderr 输出容易受到$ErrorActionPreference = 'Stop' 的影响


    退后一步

    • 从 PowerShell,很少需要调用自己的 CLIpowershell.exe(在Windows PowerShell),这需要创建另一个 PowerShell 实例作为子进程,这不仅成本高昂,而且意味着任何输出都被接收为文本仅,放弃 PowerShell 对 .NET 数据类型的丰富支持(除非您使用脚本块,但有限制 - 见下文)。

      • 通常,你会只需调用.ps1 文件直接地, 为有效进行中执行;例如,作为独立语句,C:TESTScriptsApp1.ps1

      • 如果您确实需要通过 PowerShell CLI 调用(根据情况可能是各自的其他PowerShell 版本的 CLI),使用script block ({ ... }),您将获得最佳集成,它使用幕后序列化和反序列化,将子会话的特定于 PowerShell 的输出流映射到调用者的输出流,因此 $ErrorActionPreference = 'Stop' 的行为与您在进程中调用脚本的方式相同;例如,powershell.exe { C:TESTScriptsApp1.ps1 };此外,序列化/反序列化试图保留数据类型as much as possible


    考虑因素外部程序一般来说

    • 如前所述,成功与失败应该不是从外部程序调用中是否存在 stderr 输出来推断。

    • 相反,按照(广泛观察的)惯例,外部程序通过其过程发出成功与失败的信号退出代码0 成功,任何非零失败的价值。

    • PowerShell 在其automatic $LASTEXITCODE variable 中反映了最近执行的外部程序的退出代码。

    因此,至少在 PowerShell (Core) 7.3 之前,您需要在每次外部程序调用后检查 $LASTEXITCODE -ne 0为了检测故障(在PowerShell(核心)7.2+,您也可以使用-not $? 立即地通话后(以及&&||pipeline-chain operators),但在Windows PowerShell由于上面提到的2> 重定向错误,它不能可靠地工作)。

    这很麻烦,未来的 PowerShell(核心)版本可能会使这更容易 - 请参阅下一节。


    未来从 PowerShell (Core) 7.3 开始的注意事项:

    从 v7.3 开始,有一个名为 PSNativeCommandErrorActionPreferenceexperimental feature,它可能成为未来版本的官方功能:

    • 如果启用此功能 (Enable-ExperimentalFeature PSNativeCommandErrorActionPreference)关联的 $PSNativeCommandErrorActionPreference preference variable 设置为 $true,任何报告非零退出代码 自动地触发一个电源外壳响应错误(无需显式检查 $LASTEXITCODE -ne 0),然后与 PowerShell 自己的错误处理集成。

    不幸的是,从 v7.3.0 开始,自动触发的 PowerShell 错误是非终止错误而不是语句终止一;后者会更有意义,因为它会允许它选择性地try 声明捕获 - 请参阅GitHub issue #18368

    【讨论】:

      猜你喜欢
      • 2012-11-07
      • 2011-09-19
      • 1970-01-01
      • 2011-05-27
      • 1970-01-01
      • 1970-01-01
      • 2023-04-04
      • 2021-05-24
      • 1970-01-01
      相关资源
      最近更新 更多