You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell WinForms未处理异常捕获:弹窗消失但脚本终止

解决PowerShell WinForms未处理异常导致脚本终止的问题

兄弟,我懂你现在的困扰——好不容易把讨厌的异常弹窗弄没了,结果脚本直接躺平终止了,这完全不是想要的效果对吧?问题出在WinForms的UI线程异常不被PowerShell默认的try/catch捕获,而且你的空catch块相当于把异常吞了但没做任何补救,脚本自然就停了。下面给你一步步解决:

核心问题原因

PowerShell的try/catch只能捕获当前主线程的终止错误,但WinForms的控件事件(比如按钮点击)是在独立的UI线程上执行的,这些线程里的异常根本进不到你外层的try/catch里。你之前的空catch只是碰巧处理了主线程加载WinForms时的错误,但UI事件里的异常还是会直接终止脚本。

解决步骤

1. 注册WinForms全局异常处理事件

我们需要给Application.ThreadException事件添加处理逻辑,这样所有UI线程的未处理异常都会被捕获,既不会弹系统错误框,也不会终止脚本。

2. 设置异常处理模式

通过SetUnhandledExceptionMode告诉WinForms:所有未处理异常都交给我们的自定义逻辑处理,不要用系统默认的弹窗。

3. 优化异常处理逻辑

不要用空的catch块,至少要记录异常信息,方便排查问题;同时确保UI事件里的代码不会因为异常导致脚本崩溃。

修改后的完整代码

Function Get-Choice{
    # 先设置WinForms全局异常处理
    [System.Windows.Forms.Application]::SetUnhandledExceptionMode([System.Windows.Forms.UnhandledExceptionMode]::CatchException)
    $null = [System.Windows.Forms.Application]::add_ThreadException({
        param($sender, $e)
        # 这里可以自定义异常处理,比如记录到日志或者提示用户
        Write-Host "捕获到UI线程异常: $($e.Exception.Message)" -ForegroundColor Red
        # 如果需要弹窗提示也可以加:[System.Windows.Forms.MessageBox]::Show("出错了: $($e.Exception.Message)", "错误", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    })

    Try{
        $ErrorActionPreference = 'Stop'
        [void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
        [void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
        $Form3 = New-Object System.Windows.Forms.Form
        $Form3.Text = "Please Make A Choice From Below"
        $Form3.ClientSize = New-Object System.Drawing.Size(390, 160)
        $form3.topmost = $true
        $Text = New-Object System.Windows.Forms.Label
        $Text.Location = New-Object System.Drawing.Point(15, 15)
        $Text.Size = New-Object System.Drawing.Size(300, 80)
        $Text.Text = "What would you like to do today? `n`n 1. Find the Permissions of a folder `n 2. Find Who Has Access to a Folder `n 3. Find out what shares are on a server`n 4. Select a csv that contains a list of shares"
        $Form3.Controls.Add($Text)

        # 修正按钮点击事件的写法:先关闭窗体再调用目标函数
        Function Button1 {
            $Button1 = New-Object System.Windows.Forms.Button
            $Button1.Location = New-Object System.Drawing.Point(15, 100)
            $Button1.Size = New-Object System.Drawing.Size(125, 25)
            $Button1.Text = "1. Folder Permissions"
            $Button1.add_Click({
                $Form3.Close()
                Folder
            })
            $Form3.Controls.Add($Button1)
        }
        Function Button2 {
            $Button2 = New-Object System.Windows.Forms.Button
            $Button2.Location = New-Object System.Drawing.Point(145, 100)
            $Button2.Size = New-Object System.Drawing.Size(100, 25)
            $Button2.Text = "2. Folder Access"
            $Button2.add_Click({
                $Form3.Close()
                Members
            })
            $Form3.Controls.Add($Button2)
        }
        Function Button3 {
            $Button3 = New-Object System.Windows.Forms.Button
            $Button3.Location = New-Object System.Drawing.Point(250, 100)
            $Button3.Size = New-Object System.Drawing.Size(130, 25)
            $Button3.Text = "3. Shares on a Server"
            $Button3.add_Click({
                $Form3.Close()
                Shares
            })
            $Form3.Controls.Add($Button3)
        }
        Function Button4 {
            $Button4 = New-Object System.Windows.Forms.Button
            $Button4.Location = New-Object System.Drawing.Point(145, 128)
            $Button4.Size = New-Object System.Drawing.Size(100, 25)
            $Button4.Text = "4. Auto Shares"
            $Button4.add_Click({
                $Form3.Close()
                Auto
            })
            $Form3.Controls.Add($Button4)
        }
        Button1
        Button2
        Button3
        Button4
        [void]$Form3.showdialog()
    } Catch[System.Exception]{
        # 处理主线程的异常,比如加载WinForms失败
        Write-Host "主线程捕获异常: $($_.Exception.Message)" -ForegroundColor Red
    }
}

# 模拟你可能定义的目标函数(测试用)
Function Folder { throw "测试Folder函数异常" }
Function Members { throw "测试Members函数异常" }
Function Shares { throw "测试Shares函数异常" }
Function Auto { throw "测试Auto函数异常" }

Get-Choice

关键说明

  • Application.ThreadException事件处理程序会捕获所有UI控件事件里的异常,你可以在里面加日志记录、用户提示等逻辑。
  • SetUnhandledExceptionMode确保系统不会弹出默认的错误对话框。
  • 我修正了你按钮点击事件的写法:原来的Folder $Form3.Close()会把Close()的返回值(布尔值)传给Folder函数,这大概率不是你想要的,改成先关闭窗体再调用函数。
  • 现在即使按钮点击后的函数抛出异常,脚本也不会终止,只会在控制台输出错误信息,你可以根据需求调整异常处理逻辑。

内容的提问来源于stack exchange,提问作者bob500000

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:48:12