【PowerShell】Excel内の文字列(セル、図形)を置換し、結果をログ出力する

当ページのリンクには広告が含まれています。

タイトルの通り、業務で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

最後に

プロジェクト内の用語統一って面倒くさいよね。プロジェクト特有な固有名詞ならまだいいんだけど、そうじゃない単語を指定するのはナンセンスや!もちろん放送禁止用語とかはナシだぞ!

やまぐろ
システムエンジニア
SESで業務アプリケーション開発、エンドユーザ向け機能などの開発に携わっている文系(経営学)卒エンジニア。
当サイトでは読書記録を残したり、ガジェットのレビューをしたりしています。
たまにエンジニアっぽい記事を書いたりすることも。
  • URLをコピーしました!
  • URLをコピーしました!
目次