同事在 Windows 10 高高興興寫了壓縮檔案的 PowerShell 小工具,丟上伺服器執行時踢到鐵板。

PowerShell 有個 Compress-Archive Cmdlet 可壓縮 ZIP 檔,甚至能串接 PowerShell 輸出管線,例如:Get-ChildItem -Path C:\Reference\Afile.txt, C:\Reference\Images\Bfile.txt | Compress-Archive -DestinationPath C:\Archives\PipelineFiles.zip,寫起來道地又方便。但有個問題 - Compress-Archive 要 PowerShell 5.0+ 才能用,Windows Server 2012R2 內建的 PowerShell 版本還是 4.0,登楞!

這次遇到的狀況也偏野外求生,希望做到不安裝或升級軟體、不部署工具程式,就地取材靠 Notepad 就完成任務。

PowerShell 寫了一陣子,現在的我已能淡定面對這類狀況,舉凡 PowerShell 做不到的事,交給 .NET 就對了。C# 既出,誰與爭鋒?

.NET 4.5 起加入 System.IO.Compression 命名空間工具組,其中 ZipFile.CreateFromDirectory() 能直接將整個資料夾壓成 ZIP,最接近我們的需求。所以,原本的 Compress-Archive 指令:

Compress-Archive -Path .\source\*.* -DestinationPath .\src-cmdlet.zip -CompressionLevel Optimal

可簡單改寫成:

Add-Type -AssemblyName System.IO.Compression
[System.IO.Compression.ZipFile]::CreateFromDirectory(".\source", ".\src-dotnet.zip", [System.IO.Compression.CompressionLevel]::Optimal, $true)

沒流什麼汗就解決囉。

不過,測試過程發現 Compress-Archive 有個缺點,CreateFromDirectory() 有個 bool includeBaseDirectory 參數能決定 ZIP 中的檔案要不要包含基底目錄(本例為 source,可參考下圖的差異),但 Compress-Archive 沒得選擇,source 底下的清單直接出現在 ZIP 根目錄:

查了一下,這是已知問題,大家常用的解法是先建個暫存目錄把 source 放進去,改壓縮暫存目錄以模擬 source 層,之後再清掉暫存目錄,說來挺鳥的,但也是種解法啦。如果是我,會選擇改用 .NET ZipFile.CreateFromDirectory() 較省事。

Example of creating ZIP file from directory with PowerShell 4.


Comments

Be the first to post a comment

Post a comment


35 + 19 =