PowerShell中Add-Type加载程序集仅第二次运行脚本才生效问题
问题原因
PowerShell执行脚本前会先完成全脚本的语法解析,其中对[System.IO.Compression.ZipArchiveMode]、[System.IO.Compression.ZipArchive]这类强类型引用的校验,发生在Add-Type代码行实际执行之前。首次运行时程序集还未被加载,语法校验阶段就会抛出类型找不到的错误;第一次运行失败后,Add-Type其实已经完成了程序集加载,程序集被缓存在当前PowerShell会话中,第二次执行时语法校验阶段就能找到对应类型,所以可以正常运行。
另外还有一个隐藏问题:你只加载了System.IO.Compression.FileSystem程序集,而ZipArchive、ZipArchiveMode等基础类型定义在System.IO.Compression程序集中,部分.NET环境下加载前者不会自动关联加载后者,也会加剧这个问题。
解决方法
可以任选以下一种方案修复:
方案1:改用解析前加载的程序集声明
在脚本最开头添加#Requires指令,该指令会在脚本语法解析阶段就完成程序集加载,早于类型校验步骤:
#Requires -Assembly System.IO.Compression #Requires -Assembly System.IO.Compression.FileSystem # 后续原有代码保持不变
方案2:移除强类型声明
去掉变量前的强类型标注,避免解析阶段的类型校验,运行到对应代码行时Add-Type已经完成加载,就能正常识别类型:
把原来的
[System.IO.Compression.ZipArchive] $arch = [System.IO.Compression.ZipFile]::Open("$pathforfile",[System.IO.Compression.ZipArchiveMode]::Update)
改成
$arch = [System.IO.Compression.ZipFile]::Open("$pathforfile",[System.IO.Compression.ZipArchiveMode]::Update)
方案3:使用PowerShell原生压缩cmdlet
PowerShell 5.1及以上版本自带Compress-Archivecmdlet,无需手动加载程序集,代码更简洁,也不会出现加载顺序问题,优化后的代码如下:
$Date = (Get-Date).AddMonths(-6) $path = "xxxx" $dateforfile = $Date.ToString("yyyyMM") $pathforfile = Join-Path $path "XML-$dateforfile.zip" # 单次查询获取符合条件的XML文件 $items = Get-ChildItem -Path $path -Filter "*.xml" -File | Where-Object { $_.LastWriteTime -le $Date } if ($items.Count -gt 0) { # 直接打包文件 $items | Compress-Archive -DestinationPath $pathforfile -Update # 删除源文件 $items | Remove-Item -Force }
内容的提问来源于stack exchange,提问作者Maiko
相关产品推荐
相关产品推荐

