PowerShell 小工具 - XLS 轉 XLSX 批次轉換
| | 9 | |
Excel 2007 起開始推 XLSX 格式取代傳統 XLS,距今快 15 年了,XLS 大軍仍野火燒不盡,春風吹又生。一般使用者不太會知道二者差別,但也不至於刻意選 XLS 檔,現在仍在流傳的 XLS 檔很多是代代相傳,後人開啟更新後按儲存,沒人想過要換格式,就這麼一直活下去;又或者在建新文件時用舊 XLS 當範本,另存新檔時沿用 XLS 格式,老蚌生珠,香火不絕。
使用者通常不在意工作表存 XLS 或 XLSX,反正 Excel 都能開能存。但對系統來說,格式不統一必有額外成本,系統為求單純可限制只吃 XLSX (開檔再另存兩個動作幾秒鐘搞定的舉手之勞,使用者多半樂意配合),一方面也有助早日消滅舊格式,為推動世界前進盡一份心力。(你瞧,這世界不就因 IE 消失變得更美好?)
不過,懶人如我,手工轉存三份 XLS 便超過容忍上限,一個批次轉檔任務催生了「黑暗版 XLS 轉 XLSX 批次轉換工具」。
開發這個 PowerShell 小工具會用到以下知識:
- XLS / XLSX 轉換程式寫法
之前沒找到順手的免費元件或軟體,NPOI 兩種格式都吃但不好搞。我的轉換情境在客戶端前景執行,且一定有裝 Excel,用 PowerShell 操作 Excel 是好主意。 - 使用 PowerShell 批次設定 Excel 保護密碼
PowerShell 控制 Excel 軟體的範例,上回已有實務經驗。 - PowerShell 小技巧 - 路徑參數解析與萬用字元
輸入 XLS 路徑時我想支援萬用字元、一次輸入多筆、用 ~ 代表使用者 Profile 目錄,上回做過功課,知道直接用 Get-Item 就好,用 ValueFromRemainingArguments 屬性接受一到多個參數,感覺更高級。 - PowerSehll 小技巧 - 開關參數與腳本使用說明
工具使用 -Replace 旗標決定原本的 XLS 是否保留,學 ValueFromRemainingArguments 時還一併學到 ValueFromPipelineByPropertyName,這回派上用場。
憑著之前的知識與經驗,輕鬆秒殺:
Param(
[parameter(Mandatory=$true, ValueFromRemainingArguments=$true)]
[string]
$excelPaths,
[parameter(ValueFromPipelineByPropertyName=$true)]
[switch][bool]
$replace
)
$ErrorActionPreference = "STOP"
try
{
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $true # 顯示 UI,方便使用者了解處理進度、輸入密碼等
Get-Item $excelPaths | ForEach-Object {
$path = $_.FullName
Write-Host "開啟 $path..."
try {
$excel.WorkBooks.Open($path) | Out-Null
$savePath = $path.Replace(".xls", ".xlsx")
# xlsx => xlOpenXMLWorkbook = 51
$excel.ActiveWorkbook.SaveAs($savePath, 51)
$excel.ActiveWorkBook.Close()
if ($replace) {
Remove-Item $path
}
}
catch {
Write-Host "發生錯誤 - $path" -ForegroundColor Red
}
}
}
finally
{
$excel.Quit()
}
使用範例:
Convert-Xls2Xlsx.ps1 D:\Foo\*.xls -Replace
Convert-Xls2Xlsx.ps1 D:\Foo\*.xls D:\Bar\*.xls ~\Documents\Work\*.xls
學習程式的過程,隨著知識與經驗積累,程式會愈寫愈輕鬆,這種倒吃甘蔗的爽快與成就感,是 Coding 讓人愈陷愈深無法自拔的原因之一吧!
Example of converting .xls to .xlsx with PowerShell.
Comments
# by A reader far away
In fact, still using old format of XLS may harm businesses. If you have interest, check these BBC news how COVID data got lost due to old XLS format used in British government agency. https://www.bbc.com/news/technology-54423988
# by Jeffrey
to A reader far away, 哈,去年也有讀到這則新聞,謝謝分享精彩實例。
# by mouse
請問有doc 轉成 docx的嗎? 謝謝!!
# by 學習的人
不好意思想請問您,因為是完全新手想問我的作法是用記事本後面改.ps1 但執行後發現出現下面的文字... Cmdlet 新文字文件.ps1 在命令管線位置 1 請提供下列參數的值: excelPaths: 想請問該怎麼做呢? 真的非常謝謝您!!!!
# by Jeffrey
to 學習的人,PowerShell 提示你漏了 excelPaths 這個必要參數,在冒號後方填入 D:\your-path\your-excel.xlsx 按 Enter,或執行時輸入 ".\新文字文件.ps1 D:\your-path\your-excel.xlsx" 直接附上參數都可以。
# by s
大大的程式有些小缺點 只能對有xls的資料夾做轉檔 遇上子資料夾內的xls檔案就無法了,只能一直切換資料夾 有辦法做出小改版嗎?
# by Jeffrey
to s,程式不用改,外面套一層指令,列舉所有子資料夾當成路徑參數傳入就好了,例如: Get-ChildItem -Path D:\XXX -Directory -Recurse | ForEach-Object { & .\Convert-Xls2Xlsx.ps1 "$($_.FullName)\*.xls" }
# by A
Get-ChildItem -Path D:\XXX -Directory -Recurse | ForEach-Object { & .\Convert-Xls2Xlsx.ps1 "$($_.FullName)\*.xls" } 請問這條指令應該加在外面的哪裏,才可以列舉根目錄下所有的子資料夾
# by Jeffrey
to A, 不太懂你的問題。以上指令的原理是 Get-ChildItem -Path D:\XXX -Directory -Recurse 會傳回一個集合,包含 XXX 目錄下的所有子、孫資料夾,串接 ForeEach-Object 跑迴圈,看你要對每個子資料夾進行什麼處理。