タイトルの通り、業務でExcel内の文字列置換をしたいことがあったので、PowerShellでツールを作ってみました。
この手のツールは探せばいくらでも出てきますが、制限のある環境下においてはファイルのダウンロードができなかったりしますよね。なので、コードで残しておこうと思います。これならダウンロードしなくてもツールが作れるね!やったね!
なお、PowerShellはWindowsでしか動かないので、Macユーザの方は利用できません。さーせん。
目次
実現したこと
以下が、今回実現したことになります。
- Excel内のテキスト(セル、図形)の特定の文字列を置換
- 指定したディレクトリ配下を再帰的に処理する
- 処理結果をログファイルに出力する
これらの動作については、私の環境では軽く確認し正常動作しているのは確認済みです!
実際のコード
拡張子を「.ps1」にしたファイルに以下を書き込めば完成です。
なお、実行は「右クリック→PowerShellで実行」とかでいけます。
# ユーザーに検索対象と置換対象の文字列を入力してもらう
$searchText = Read-Host "置換したい文字列を入力してください"
$replaceText = Read-Host "置換後の文字列を入力してください"
# 対象のディレクトリ(再帰的に検索)
$targetDirectory = Read-Host "検索を開始するディレクトリのパスを入力してください(例: C:\path\to\directory)"
# ログファイルのパスを指定
$logFile = "$targetDirectory\ExcelReplaceLog.txt"
# 既存のログファイルがあれば削除(上書き)する
if (Test-Path $logFile) {
Remove-Item $logFile
}
# ExcelアプリケーションのCOMオブジェクトを作成
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false
$excel.DisplayAlerts = $false
# 対象ファイルが存在するか
$target = $false
# ログに開始時刻を記録
"--- 置換処理開始: $(Get-Date) ---" | Out-File -FilePath $logFile -Append
# 再帰的に対象ディレクトリ内のすべてのExcelファイルを取得し処理
Get-ChildItem -Path $targetDirectory -Recurse -Filter "*.xlsx" | ForEach-Object {
$file = $_.FullName
Write-Host "Processing: $file"
"処理中のファイル: $file" | Out-File -FilePath $logFile -Append
# ワークブックを開く
$workbook = $excel.Workbooks.Open($file)
$replaced = $false
$target = $true
# 各ワークシート内のセルと図形を検索し、置換
foreach ($sheet in $workbook.Sheets) {
# セル内の文字列置換
$cells = $sheet.UsedRange
if ($cells.Find($searchText)) {
$cells.Replace($searchText, $replaceText)
$replaced = $true
" - シート: $($sheet.Name) - セル内の文字列「$searchText」を「$replaceText」に置換しました" | Out-File -FilePath $logFile -Append
}
# 図形内の文字列置換
foreach ($shape in $sheet.Shapes) {
if ($shape.TextFrame2.HasText) {
$text = $shape.TextFrame2.TextRange.Text
if ($text -match [regex]::Escape($searchText)) {
$shape.TextFrame2.TextRange.Text = $text -replace [regex]::Escape($searchText), $replaceText
$replaced = $true
" - シート: $($sheet.Name) - 図形内の文字列「$searchText」を「$replaceText」に置換しました" | Out-File -FilePath $logFile -Append
}
}
}
}
# 上書き保存して閉じる
$workbook.Save()
$workbook.Close()
if (-not $replaced) {
" - 文字列「$searchText」が見つかりませんでした" | Out-File -FilePath $logFile -Append
}
}
# Excelアプリケーションを終了
$excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
# ログに対象ファイルがなかった旨を記録
if (-not $target) {
" - Excelファイルが見つかりませんでした" | Out-File -FilePath $logFile -Append
}
# ログに終了時刻を記録
"--- 置換処理終了: $(Get-Date) ---" | Out-File -FilePath $logFile -Append
Write-Host "置換が完了しました。ログファイルは $logFile に保存されています。"
pause
最後に
プロジェクト内の用語統一って面倒くさいよね。プロジェクト特有な固有名詞ならまだいいんだけど、そうじゃない単語を指定するのはナンセンスや!もちろん放送禁止用語とかはナシだぞ!