如何从ADK CAB文件提取oscdimg.exe并实现内存直接提取?
内存中直接提取ADK CAB文件内的oscdimg.exe
当然可以直接在内存中完成CAB文件的提取操作,无需将临时CAB文件写入本地磁盘。下面提供两种实用的PowerShell实现方案:
方案一:使用Microsoft.Deployment.Compression.Cab(推荐,原生内存支持)
这个类来自Windows ADK的部署压缩库,原生支持从内存流中读取CAB并提取文件,无需磁盘中转。
# 下载并内存提取oscdimg.exe工具 $tmp = $env:temp $exePath = Join-Path $tmp "oscdimg.exe" $cabUrl = "https://download.microsoft.com/download/1/f/d/1fd2291e-c0e9-4ae0-beae-fbbe0fe41a5a/adk/Installers/5d984200acbde182fd99cbfbe9bad133.cab" $targetCabFile = "fil720cc132fbb53f3bed2e525eb77bdbc1" if (-not (Test-Path -Path $exePath -PathType Leaf)) { # 加载ADK压缩库(如果未加载) try { Add-Type -AssemblyName Microsoft.Deployment.Compression.Cab -ErrorAction Stop } catch { # 尝试从ADK默认路径加载(如果系统已安装ADK) $adkPath = "${env:ProgramFiles(x86)}\Windows Kits\10\bin\10.0.22621.0\x64\Microsoft.Deployment.Compression.Cab.dll" if (Test-Path $adkPath) { Add-Type -Path $adkPath } else { throw "未找到Microsoft.Deployment.Compression.Cab程序集,请确保已安装Windows 11 ADK或指定正确路径" } } # 直接将CAB下载到字节数组 $cabBytes = Invoke-WebRequest -Uri $cabUrl -UseBasicParsing -ErrorAction Stop | Select-Object -ExpandProperty Content # 将字节数组转为内存流 $memoryStream = New-Object System.IO.MemoryStream($cabBytes) # 打开CAB文件并提取目标文件 $cabFile = [Microsoft.Deployment.Compression.Cab.CabFile]::Open($memoryStream) $targetEntry = $cabFile.Entries | Where-Object { $_.Name -eq $targetCabFile } if ($targetEntry) { # 将提取的文件写入目标路径 $targetEntry.ExtractToFile($exePath, $true) } else { throw "CAB文件中未找到目标文件:$targetCabFile" } # 清理资源 $cabFile.Close() $memoryStream.Dispose() }
方案二:使用System.IO.Packaging(替代方案,无需额外安装ADK)
如果系统未安装ADK,可以利用.NET的System.IO.Packaging类处理CAB文件(CAB本质是一种特殊的Package格式):
# 下载并内存提取oscdimg.exe工具 $tmp = $env:temp $exePath = Join-Path $tmp "oscdimg.exe" $cabUrl = "https://download.microsoft.com/download/1/f/d/1fd2291e-c0e9-4ae0-beae-fbbe0fe41a5a/adk/Installers/5d984200acbde182fd99cbfbe9bad133.cab" $targetCabFile = "fil720cc132fbb53f3bed2e525eb77bdbc1" if (-not (Test-Path -Path $exePath -PathType Leaf)) { # 加载System.IO.Packaging程序集 Add-Type -AssemblyName WindowsBase # 下载CAB到字节数组 $cabBytes = Invoke-WebRequest -Uri $cabUrl -UseBasicParsing -ErrorAction Stop | Select-Object -ExpandProperty Content $memoryStream = New-Object System.IO.MemoryStream($cabBytes) # 打开Package(CAB) $package = [System.IO.Packaging.Package]::Open($memoryStream) $targetPart = $package.GetParts() | Where-Object { $_.Uri.OriginalString -eq "/$targetCabFile" } if ($targetPart) { # 读取文件内容并写入目标路径 $fileStream = New-Object System.IO.FileStream($exePath, [System.IO.FileMode]::Create) $targetPart.GetStream().CopyTo($fileStream) $fileStream.Close() } else { throw "CAB文件中未找到目标文件:$targetCabFile" } # 清理资源 $package.Close() $memoryStream.Dispose() }
关键优势
- 完全避免临时CAB文件写入磁盘,减少IO操作,提升效率
- 规避磁盘残留临时文件的风险
- 代码逻辑更紧凑,无需处理文件重命名、删除等额外步骤
内容的提问来源于stack exchange,提问作者Carsten
相关产品推荐
相关产品推荐

