PowerShell检测IIS应用.NET版本时的反射程序集加载错误排查
问题分析与修复方案
咱们先拆解你遇到的两个错误,然后给出修复后的PowerShell脚本:
错误1:FileLoadException(程序集重复加载)
原因
ReflectionOnlyLoadFrom会把程序集加载到当前PowerShell的AppDomain中,一旦某个程序集(比如WebGrease.dll)从某个路径加载过,后续再从其他路径加载同名/同标识的程序集时,.NET就会抛出这个错误——因为同一个AppDomain不允许从不同位置加载相同的程序集。
错误2:BadImageFormatException(非.NET程序集加载失败)
原因
epengine.dll是原生Windows DLL(不是.NET程序集),它没有.NET程序集必需的清单结构,所以ReflectionOnlyLoadFrom无法识别它,自然会报错。
修复后的脚本
我调整了脚本逻辑,用更安全的方式获取.NET版本,同时避免上述两个错误:
$Apps = Get-WebApplication foreach($App in $Apps) { $binLocation = Join-Path -Path $App.physicalPath -ChildPath "bin" if (-not (Test-Path -Path $binLocation)) { Write-Host "No bin folder found for app: $($App.Path)" continue } # 获取bin目录下所有dll文件 $dlls = Get-ChildItem -Path $binLocation -Filter "*.dll" -File # 存储唯一的.NET运行时版本 $runtimeVersions = New-Object System.Collections.Generic.HashSet[String] foreach($dll in $dlls) { try { # 仅读取程序集元数据,不加载到AppDomain,避免重复加载冲突 $assemblyName = [System.Reflection.AssemblyName]::GetAssemblyName($dll.FullName) # 获取CLR运行时版本(比如v4.0.30319) $runtimeVersion = $assemblyName.ImageRuntimeVersion if ($runtimeVersion) { $runtimeVersions.Add($runtimeVersion) | Out-Null } } catch [System.BadImageFormatException] { # 跳过非.NET原生DLL,可根据需要取消注释开启日志 # Write-Host "Skipping non-.NET DLL: $($dll.FullName)" continue } catch { # 捕获其他意外错误 Write-Warning "Error processing $($dll.FullName): $_" continue } } # 输出结果 Write-Host "`n=== Web Application: $($App.Path) ===" Write-Host "Physical Path: $($App.physicalPath)" if ($runtimeVersions.Count -gt 0) { Write-Host "Used .NET Runtime Versions:" $runtimeVersions | ForEach-Object { Write-Host " - $_" } } else { Write-Host "No .NET DLLs found or no valid runtime versions detected." } }
关键改进点
- 用
AssemblyName::GetAssemblyName()替代ReflectionOnlyLoadFrom:
这个方法只读取DLL文件的元数据,不会将程序集加载到当前AppDomain,彻底解决了重复加载的冲突问题,性能也更优。 - 异常捕获处理:
- 捕获
BadImageFormatException,自动跳过非.NET原生DLL; - 添加通用异常捕获,避免单个DLL的错误导致整个脚本中断。
- 捕获
- 路径优化:
用Join-Path处理路径拼接,避免手动拼接时的格式错误;新增Test-Path检查bin目录是否存在,减少无效操作。
内容的提问来源于stack exchange,提问作者Tourius
相关产品推荐
相关产品推荐

