从 Powershell 调用 .exe 时如何防止 "Program has stopped working" 对话框

How to prevent "Program has stopped working" dialog when calling an .exe from Powershell

我正在编写一个 PS 脚本来生成大量 Crystal 报告的 .xml 表示(Windows 7)。在此脚本中,我创建了一个代表所有需要解析的文件的对象,然后遍历它们,对它们逐一调用 .exe。有时,此 .exe 会崩溃。这很好,因为它非常罕见,而且无法处理的报告可以手动标记和审查。问题是我有数以千计的 .rpt 文件要处理,当 .exe 崩溃时,Windows 弹出一个对话框要求调试或继续。

我为解决问题所做的尝试:

不过,我收到了弹出窗口。还有另一个注册表项,它完全禁用 "Program has stopped working" UI,但我不想这样做,因为作为其他应用程序的开发人员,我需要知道什么时候崩溃。我只想排除此脚本或它调用的 exe 显示 UI.

如果我能做到这一点,那么脚本就可以 运行 无人值守。

行为不端的 .exe 是来自此处的最新二进制版本:https://github.com/ajryan/RptToXml,当它在报告文件中遇到空字节时似乎会失败。

这是我的代码:

[xml]$MainConfigFile = Get-Content "settings.config.xml"
[xml]$SSRSConfigFile = Get-Content "ssrs.config.xml"
[xml]$CrystalConfigFile = Get-Content "crystal.config.xml"

# create settings objects from xml objects
$MainSettings = @{
    OutputPath = $MainConfigFile.Settings.OutputPath
    SearchString = $MainConfigFile.Settings.SearchString
    ParseCrystal = $MainConfigFile.Settings.ParseCrystal
    ParseSSRS = $MainConfigFile.Settings.ParseSSRS
}

$CrystalSettings = @{
    InputFolderPath = $CrystalConfigFile.CrystalSettings.InputFolderPath
    ContinueOnError = $CrystalConfigFile.CrystalSettings.ContinueOnError
}

$RsSettings = @{
    ReportServerUri = $SSRSConfigFile.RsSettings.ReportServerUri
    RsVersion = $SSRSConfigFile.RsSettings.RsVersion
}

Clear

Write-Host "Ensure these settings are correct before you proceed:" -ForegroundColor Yellow
Write-Host ""

Write-Host "Main Settings" -ForegroundColor Green
$MainSettings
Write-Host ""

Write-Host "Crystal Settings" -ForegroundColor Green
$CrystalSettings
Write-Host ""

Write-Host "SSRS Settings" -ForegroundColor Green
$RsSettings
Write-Host ""

# user must confirm
[string]$SettingsOK=(Read-Host "[Y] to proceed, [N] to quit:")
if ($SettingsOK -ne "Y") {exit}

Write-Host ""
Write-Host "______________________________________"
Clear

# is the output path syntax valid?
if (!(Test-Path -Path $MainSettings.OutputPath -IsValid)) {
    Write-Host -ForegroundColor Green "Output path syntax is invalid:" $MainSettings.OutputPath
    exit
    } else {
    Write-Host -ForegroundColor Green "Output path syntax is correct:" $MainSettings.OutputPath
    }

# does the output path exist?
if (!(Test-Path -Path $MainSettings.OutputPath)) {
    Write-Host -ForegroundColor Yellow "Output path does not exist:" $MainSettings.OutputPath
    [string]$CreateOutputPathOK=(Read-Host "[Y] to create the directory, [N] to quit.")
        if ($CreateOutputPathOK -ne "Y") {exit} else {New-Item -Path $MainSettings.OutputPath -ItemType Directory}
    } else {
    Write-Host -ForegroundColor Green "Output path already exists:" $MainSettings.OutputPath
}

Write-Host ""
Write-Host "______________________________________"
Clear

# get all .rpt files in the input folder, recursively
$CrystalFiles=Get-ChildItem -Path $CrystalSettings.InputFolderPath -Include "*.rpt" -Recurse

Write-Host ""
# count files first and ask the user if they want to see the output, otherwise proceed
Write-Host -ForegroundColor Yellow $CrystalFiles.Count ".rpt files were found in" $CrystalSettings.InputFolderPath
[string]$ShowFilesOK=(Read-Host "[Enter] to proceed, [Y] to view the list of files in the directory, [N] to quit.")
if ($ShowFilesOK -eq "Y") {
    Clear
    # loop through the collection of files and display the file path of each one
    $CrystalFiles | ForEach-Object -Process {$_.FullName.TrimStart($CrystalSettings.InputFolderPath)}
    Write-Host "______________________________________"
    # user must confirm
    Write-Host ""
    Write-Host -ForegroundColor Yellow "The above .rpt files were found in" $CrystalSettings.InputFolderPath 
} elseif ($ShowFilesOK -eq "N") {exit}

Write-Host ""
[string]$ProcessingOK=(Read-Host "[Y] to proceed with .rpt file processing, [N] to quit:")
if ($ProcessingOK -ne "Y") {exit}

Write-Host ""
Write-Host "______________________________________"
Clear

# create a dir inside the output path to hold this run's output
Write-Host -ForegroundColor Green "Creating folder to hold this run's output..."
$RunDir = (New-Item -Path $MainSettings.OutputPath -Name "$(Get-Date -f yyyy-mm-dd__hh_mm_ss)" -ItemType Directory)
$RunDir.FullName

# use .NET ArrayList because immutable PS arrays are very slow
$Success = New-Object System.Collections.ArrayList
$Failure = New-Object System.Collections.ArrayList

#loop through the collection again, this time processing each file and dumping the output to the output dir
$CrystalFiles | ForEach-Object -ErrorAction SilentlyContinue -Process {
    $RelativePathName = $_.FullName.TrimStart($CrystalSettings.InputFolderPath)
    $XmlFileName = "$RunDir$RelativePathName.xml"

    # force-create the file to ensure the parent folder exists, otherwise RptToXML will crash trying to write the file
    New-Item -Path $XmlFileName -Force
    # then simply delete the empty file
    Remove-Item -Path $XmlFileName

    Write-Host -ForegroundColor Green "Processing file" $RelativePathName
    CMD /c .\RptToXML\RptToXml.exe $_.FullName $RunDir$($_.FullName.TrimStart($CrystalSettings.InputFolderPath)).xml
    if ($LASTEXITCODE -eq 0) {
        Write-Host "Success" $Success.Add($RelativePathName)} else {Write-Host "Failure" $Failure.Add($RelativePathName)}
    }

$Success | Export-CSV "$RunDir\CrystalSuccess.txt"
$Failure | Export-CSV "$RunDir\CrystalFailure.txt"

我讨厌这样做,回答我自己的问题,但我现在找到了解决方法。

循环前:

# Disable WER temporarily
Set-ItemProperty "HKCU:\Software\Microsoft\Windows\Windows Error Reporting" -Name DontShowUI -Value 1

循环后:

# Reset the WER UI reg key
Set-ItemProperty "HKCU:\Software\Microsoft\Windows\Windows Error Reporting" -Name DontShowUI -Value 0

这将通过从另一个脚本调用此脚本得到改进:

  • 获取要修改的键的当前值
  • 改变它们
  • 将returns控制的脚本调用给调用者即使它崩溃了
  • Return 将注册表键恢复为原始值