PowerShellでExcel・CSV業務処理を自動化する ── 集計・突合・帳票出力の実務レシピ

· · PowerShell, Windows, CSV, Excel, 自動化, 業務効率化, スクリプト, 既存資産活用

「毎月、基幹システムから落としたCSVをExcelで開いて、ピボットで集計して、体裁を整えてメールする」「2つのシステムから出た名簿を突き合わせて、差分を目視で探す」── この種の定型作業の相談をよく受けます。1回あたりは30分でも、毎週・毎月・複数人となると年間では相当な時間が溶けていきますし、手作業のコピペには必ず事故が混ざります。

PowerShellはこの領域と相性のよい道具です。Windows標準で入っており(Windows PowerShell 5.1)、CSVを「オブジェクトの表」として読み込んで、集計・突合・出力までをパイプラインでつなげられます。さらにコミュニティ製のImportExcelモジュールを使えば、Excel本体なしでxlsxの帳票まで作れます。

一方で、この分野には日本語環境特有の地雷があります。文字コードの既定値がWindows PowerShell 5.1とPowerShell 7でまったく違うため、「自分のPCでは動いたのに、他の環境で文字化けした」が頻発するのです。この記事では、中小企業の情シス・業務担当者がCSV・Excel業務をPowerShellで自動化するときの実務レシピを、文字コードの落とし穴から順に整理します。

1. まず結論

  • CSVの読み書きでは、-Encodingを常に明示します。Windows PowerShell 5.1はコマンドレットごとに既定エンコーディングがバラバラで、PowerShell 7は一律BOMなしUTF-8と、両者の既定がまったく違うためです。1
  • 5.1のExport-Csvの既定はASCIIです。-Encodingを付け忘れると、日本語は保存の時点で失われます。また5.1のImport-CsvはBOMのないファイルをUTF-8と解釈するため、Shift_JISのCSVをそのまま読むと文字化けします。1
  • 集計はGroup-Object(グループ化)とMeasure-Object(合計・平均・最大最小)の組み合わせが基本形です。Excelのピボットで毎回やっている集計の多くは、この2つで置き換えられます。23
  • 2つのCSVの突合は、差分の有無だけならCompare-Object、列の引き当て(結合)まで必要ならハッシュテーブルです。Compare-ObjectはSideIndicatorでどちらにだけ存在する行かを示してくれます。4
  • xlsxの読み書きはImportExcelモジュール(コミュニティ製)が第一候補です。Excel本体のインストールは不要で、テーブル化・書式・ピボットテーブルまで作れます。5
  • Excel本体のCOM操作は最終手段です。参照(RCW)の解放漏れでEXCEL.EXEが残留しやすく67、そもそもMicrosoftは無人環境(サービスやスケジュール実行)でのOffice自動化を推奨・サポートしていません。8
  • タスクスケジューラに載せる前に、エンコーディング・パス・実行環境の3点を明示的に固定します。対話実行では動いていたスクリプトが定期実行で壊れる原因の大半はこの3つです。18

2. Import-Csv/Export-Csvの基本 ── 最大の地雷は文字コード

Import-Csv はCSVを「1行=1オブジェクト、1列=1プロパティ」の表として読み込みます。ヘッダー行が列名になり、以降の処理はすべてプロパティ名で書けます。9 Export-Csv はその逆で、オブジェクトの列をCSVに書き出します。10 ここまでは簡単です。問題は文字コードです。

公式ドキュメントに明記されているとおり、Windows PowerShell 5.1の既定エンコーディングはコマンドレットごとに一貫していません1 日本語環境の実務に影響する範囲を表にします。

操作 Windows PowerShell 5.1の既定 PowerShell 7の既定
Export-Csv ASCII(日本語は失われる)1 BOMなしUTF-810
Import-Csv(BOMなしファイル) UTF-8と解釈1 BOMなしUTF-8
Get-Content(BOMなしファイル) ANSI=日本語環境ではShift_JIS1 BOMなしUTF-8
Out-File・リダイレクト(>) UTF-16LE(BOM付き)1 BOMなしUTF-8

つまり5.1では「Get-Contentで読むとShift_JISとして読めたのに、Import-Csvだと化ける」「Export-Csvしたら日本語が全部?になった」がすべて仕様どおりに起きます。PowerShell 7は一律BOMなしUTF-8で一貫していますが1、今度はShift_JISで届く基幹システムのCSVを既定のまま読むと化けるわけです。結論はひとつで、読み書きの両方で -Encoding を明示します。

# 基幹システムが出力するShift_JISのCSVを読む
# Windows PowerShell 5.1: Default = システムのANSIコードページ(日本語環境ではShift_JIS)
$orders = Import-Csv -LiteralPath 'C:\data\orders.csv' -Encoding Default

# PowerShell 7ではコードページ番号で指定できる(932 = Shift_JIS)
# $orders = Import-Csv -LiteralPath 'C:\data\orders.csv' -Encoding 932

# 出力はBOM付きUTF-8にしておくと、ダブルクリックでExcelに開かせても化けにくい
# PowerShell 7: UTF8はBOMなしになるため、BOM付きは utf8BOM と明示する
$orders | Export-Csv -LiteralPath 'C:\data\orders_out.csv' -NoTypeInformation -Encoding utf8BOM
# Windows PowerShell 5.1: utf8BOMという値が存在しない。UTF8を指定すればBOM付きになる
# $orders | Export-Csv -LiteralPath 'C:\data\orders_out.csv' -NoTypeInformation -Encoding UTF8

PowerShell 6.2以降の -Encoding はコードページ番号(932)や登録名でも指定でき、7.4以降は ansi という値も使えます。1 なお -NoTypeInformation は5.1で先頭に付く #TYPE 行を抑止するためのもので、PowerShell 6以降は既定で付かなくなったため指定不要です(付けてもエラーにはなりません)。10 5.1と7の両方で動かすスクリプトでは付けておくのが無難です。

CSVというフォーマット自体の罠(Excelで開くと先頭ゼロが消える、カンマや改行を含む値、インジェクション対策)は「CSVは「ただのテキスト」ではない」で詳しく扱っています。文字コードと改行コードの基礎は「Windowsの文字コードと改行コード」を参照してください。

3. 集計 ── Group-ObjectとMeasure-Objectでピボット相当をつくる

「部署ごとの件数と金額合計」のような集計は、Group-Object でグループ化し、各グループを Measure-Object で合計する、が基本形です。23

# Shift_JISのCSVをPowerShell 7で読むのでコードページ932を明示する
# (7の-Encoding DefaultはUTF-8の意味になり化ける。5.1で動かすならDefaultを指定)
$orders = Import-Csv -LiteralPath 'C:\data\orders.csv' -Encoding 932

# 部署ごとに件数と金額合計を出す。
# Import-Csvの値はすべて文字列なので、[decimal]に変換してから合計するのがポイント
# (Measure-Object -SumのSumはDouble型になるため、金額はdecimalのまま自前で足し込み、
#  桁の大きい合計や小数の精度を落とさない)
$summary = $orders | Group-Object -Property Dept | ForEach-Object {
    $total = [decimal]0
    foreach ($row in $_.Group) { $total += [decimal]$row.Amount }
    [pscustomobject]@{
        Dept  = $_.Name    # グループ化キーの値
        Count = $_.Count   # 件数
        Total = $total     # 金額合計
    }
}

$summary | Sort-Object -Property Total -Descending |
    Export-Csv -LiteralPath 'C:\data\summary.csv' -NoTypeInformation -Encoding UTF8

つまずきやすいのはCSVの値がすべて文字列であることです。Import-Csv が返すのは文字列プロパティの集まりなので9、数値のつもりで Measure-Object -Sum に渡す前に [decimal] へ明示的に変換します。変換を忘れても5.1ではそれなりに動いてしまうことがあり、金額の桁がずれてから気づく事故になりがちです。

Measure-Object-Sum のほか -Average -Maximum -Minimum も同時に取れます。3 また Group-Object -AsHashTable を使うと「キー→そのグループの行の配列」というハッシュテーブルが直接得られ、後述の突合にも応用できます。2 このあたりの単発コマンドの使いどころは「PowerShell実用コマンド集」にまとめています。

4. 突合 ── Compare-Objectとハッシュテーブル結合の使い分け

4.1. 差分の有無だけならCompare-Object

昨日と今日の名簿CSVで「増えた人・消えた人」を出す、という典型的な突合は Compare-Object が最短です。-Property でキー列を指定すると、その列の値だけで比較し、結果のSideIndicatorが =>(差分側にだけある)か <=(基準側にだけある)かで増減が分かります。4

$yesterday = Import-Csv -LiteralPath '.\users_0716.csv' -Encoding UTF8
$today     = Import-Csv -LiteralPath '.\users_0717.csv' -Encoding UTF8

# 社員番号だけで比較する。=> は今日だけにある行(追加)、<= は昨日だけにある行(削除)
Compare-Object -ReferenceObject $yesterday -DifferenceObject $today -Property EmpNo |
    Sort-Object -Property EmpNo |
    Format-Table -Property EmpNo, SideIndicator

注意点は2つです。第一に、-Property を指定すると結果にはその列とSideIndicatorしか残らないため、氏名など他の列も見たい場合は結果のキーで元データを引き直す必要があります。第二に、基準側・差分側のどちらかが $null(0行ではなくnull)だとエラーで止まります。4 空ファイルがあり得る運用では読み込み結果を @() で配列化しておくと安全です。

4.2. 列の引き当て(結合)まで必要ならハッシュテーブル

「明細CSVの社員番号に、マスタCSVから氏名と部署を引き当てる」というSQLのJOIN相当は、マスタ側をキー→行のハッシュテーブルにしてから1行ずつ引くのが定石です。二重ループ(明細×マスタの総当たり)は数千件×数千件で目に見えて遅くなりますが、ハッシュテーブルなら数万件でも実用速度で回ります。

# マスタ側を「社員番号 → 行」のハッシュテーブルにする
# キーが重複していた場合は後の行で上書きされるので、重複があり得るなら事前チェックする
$master = @{}
foreach ($row in (Import-Csv -LiteralPath '.\master.csv' -Encoding UTF8)) {
    $master[$row.EmpNo] = $row
}

# 明細を1行ずつ引き当てる。見つからない行は握りつぶさず、別ファイルに退避する
$unmatched = New-Object System.Collections.Generic.List[object]
$joined = foreach ($row in (Import-Csv -LiteralPath '.\details.csv' -Encoding UTF8)) {
    $hit = $master[$row.EmpNo]
    if ($null -eq $hit) {
        $unmatched.Add($row)
        continue
    }
    [pscustomobject]@{
        EmpNo  = $row.EmpNo
        Name   = $hit.Name
        Dept   = $hit.Dept
        Amount = $row.Amount
    }
}

$joined    | Export-Csv -LiteralPath '.\joined.csv'    -NoTypeInformation -Encoding UTF8
$unmatched | Export-Csv -LiteralPath '.\unmatched.csv' -NoTypeInformation -Encoding UTF8

このレシピの肝は最後の2行です。キーが引けなかった行を黙って捨てない。突合業務の価値は「合わなかったものを人が確認できる」ことにあるので、unmatchedを必ず出力し、件数をログや標準出力に出しておきます。

4.3. 列名のゆらぎとヘッダーの扱い

現場のCSVは「社員番号」「社員No」「emp_no」と列名が揺れがちです。対処は読み込み直後に内部名へ正規化してしまうことに尽きます。以降の処理を内部名だけで書けば、書式が変わっても直すのは正規化の1か所で済みます。

# ヘッダー行がないCSVは -Header で列名を与える(1行目からデータとして読まれる)
# 文字コードは第2章と同じ考え方: Shift_JISなら7では932、5.1ではDefaultを指定する
$rows = Import-Csv -LiteralPath '.\no_header.csv' -Header 'EmpNo', 'Name', 'Dept' -Encoding 932

# 日本語ヘッダーのCSVは、読み込み直後に英字の内部名へ正規化する
$normalized = Import-Csv -LiteralPath '.\jinji.csv' -Encoding 932 |
    Select-Object -Property @{ Name = 'EmpNo'; Expression = { $_.'社員番号' } },
                            @{ Name = 'Name';  Expression = { $_.'氏名' } },
                            @{ Name = 'Dept';  Expression = { $_.'所属部署' } }

-Header はヘッダー行がないファイル用で、指定すると1行目もデータとして読み込まれる点に注意してください。9 またヘッダーに空欄があるとPowerShellが H1 のような仮の列名を自動で振るため9、想定した列名でプロパティが引けないときはまずヘッダー行を疑います。

5. xlsxを扱う ── ImportExcelが第一候補、COMは最終手段

5.1. ImportExcelモジュール ── Excel本体なしでxlsxを読み書きする

集計結果を「CSVではなくExcelファイルで、表に色を付けて」求められるのが日本の職場です。ここで第一候補になるのが、PowerShell Galleryで公開されているコミュニティ製のImportExcelモジュールです。Excel本体のインストール不要でxlsxの読み書きができ、テーブル化・列幅調整・ピボットテーブルまで作れます。5

# 初回のみ。PowerShell Galleryから現在ユーザー向けにインストールする
Install-Module -Name ImportExcel -Scope CurrentUser

# xlsxを読む(Import-Csvと同じ感覚で、シートの表がオブジェクトの配列になる)
$budget = Import-Excel -Path 'C:\data\budget.xlsx' -WorksheetName '予算'

# 第3章の集計結果を、テーブル+列幅自動調整+ピボットテーブル付きのxlsxで出力する
$summary | Export-Excel -Path 'C:\data\monthly-report.xlsx' `
    -WorksheetName '集計' -TableName 'Summary' -AutoSize `
    -IncludePivotTable -PivotRows Dept -PivotData @{ Total = 'Sum' }

コミュニティ製である以上、導入時は社内のソフトウェア導入ルールに沿って確認してください(モジュールの入手元はPowerShell Galleryです5)。それでも「サーバーにExcelをインストールしてCOMで回す」構成に比べれば、ライセンス・安定性・保守のどの面でも筋がよい選択です。帳票生成の方式比較(COM/Open XML/テンプレート)は「Excel帳票出力の作り方」で整理しています。

5.2. Excel COM操作 ── 使うなら解放まで書き切る、無人実行はしない

既存xlsのマクロを蹴りたい、Excelの機能そのもの(再計算、印刷、名前定義の解決など)が必要──そういう場合に限り、Excel本体をCOMで操作します。PowerShellからは New-Object -ComObject で起動できますが、有名な問題がEXCEL.EXEのプロセス残留です。COMオブジェクトへの参照(RCW)が解放されないと、Quit() を呼んでもプロセスが残ります。6 .NET側の対処は Marshal.ReleaseComObject による明示的な解放です。7

# COMは最終手段。「開いたものは必ず閉じ、参照は必ず解放する」をfinallyで保証する
# Excel起動後のCOM呼び出しはすべてtryの中で行う(起動直後の1行で例外が起きても後始末が走るように)
$excel = New-Object -ComObject Excel.Application
$book = $null
try {
    $excel.Visible = $false
    $excel.DisplayAlerts = $false   # 確認ダイアログで止まらないようにする
    $book  = $excel.Workbooks.Open('C:\data\template.xlsx')
    $sheet = $book.Worksheets.Item(1)
    $sheet.Range('B2').Value2 = 12345
    $book.SaveAs('C:\data\output.xlsx')
    $book.Close($false)
}
finally {
    # Quitが失敗しても(Excelが応答なしなど)解放とGCは必ず実行する
    try {
        $excel.Quit()
    }
    finally {
        # 触ったCOMオブジェクトはRCWを明示解放しないとEXCEL.EXEが残留しやすい
        if ($sheet) { [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($sheet) }
        if ($book)  { [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($book) }
        [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($excel)
        [GC]::Collect()
        [GC]::WaitForPendingFinalizers()
    }
}

厄介なのは、$excel.Workbooks.Open(...) のようにドットをつなぐだけで中間オブジェクト(この例ではWorkbooksコレクション)への参照が生まれ、それも解放対象になることです。上のコードでも厳密にはWorkbooksの参照が残っており、確実を期すなら中間オブジェクトも変数に受けて解放します。この「参照管理を書き切る難しさ」自体が、COMを最終手段と位置づける理由です。仕組みの詳細と置き換え判断は「C#のExcel操作でEXCEL.EXEが残る問題」で、PowerShellからのCOM/.NET呼び出し全般は同時公開の「PowerShellからCOMと.NETを呼び出す実践」で扱っています。

そしてもうひとつ決定的な制約があります。Microsoftは、無人・非対話のクライアント(サービス、スケジュール実行など)からのOffice自動化を推奨せず、サポートもしていません。Officeは対話ユーザーがいる前提で設計されており、無人環境では不安定な動作やデッドロックが起こり得ると公式に明記されています。8 SSISのドキュメントでも、無人実行環境ではExcel接続を使わずCSVやOpen XML系の方式に置き換えることが推奨されています。11 「毎晩タスクスケジューラでExcelを開いて帳票を作る」構成は、動いているように見えても砂上の楼閣です。定期実行したい処理はImportExcelやOpen XML系に寄せてください。

6. タスクスケジューラで定期実行する前のチェックリスト

手元で動いたスクリプトをそのままタスクスケジューラに載せると、だいたい次のどれかで壊れます。

  • 文字コード: 対話実行とスケジュール実行で挙動は変わりませんが、「たまたま手元の7で動いていた」スクリプトが、タスク側の起動コマンドが powershell.exe(=5.1)だったために既定エンコーディングが変わって化ける、はよくある事故です。第2章のとおり読み書き両方で -Encoding を明示していれば、どちらで起動されても結果は同じになります。1
  • パス: カレントディレクトリに依存した相対パスは使わず、絶対パスか $PSScriptRoot 基準で書きます。ネットワークドライブ(Z:など)はスケジュール実行のセッションでは見えないため、UNCパスにします。
  • 実行環境: どのPowerShellで動かすのか(powershell.exeかpwsh.exeか)を起動コマンドで明示します。5.1と7の違いと使い分けは同時公開の「Windows PowerShell 5.1とPowerShell 7の違い」を参照してください。
  • Excel COMを含む処理は載せない: 前章のとおり無人実行は非サポートです。8

タスクスケジューラ実行時のログ・証跡の残し方は「PowerShellスクリプト応用 ── ログ調査・アーカイブ・レポート化を安全に自動化する」で詳しく書いています。

7. 実務の定石(判断表)

論点 選択肢 判断の目安
CSVの文字コード 既定に任せる / -Encoding明示 常に明示。5.1と7で既定が違うため「環境が変わると化ける」を構造的に防ぐ1
集計 Excelで手作業 / Group-Object+Measure-Object 毎週・毎月繰り返すならスクリプト化。手順がコードとして残り再現可能になる23
2つのCSVの突合 Compare-Object / ハッシュテーブル結合 差分の有無だけならCompare-Object。他の列を引き当てるならハッシュテーブル。不一致行は必ず別出力4
xlsx出力 CSVで済ます / ImportExcel / COM 書式・ピボットが要るならImportExcel(Excel本体不要)。COMはマクロ実行などExcel機能そのものが必要な場合のみ5
Excel COMの実行形態 タスクスケジューラで無人実行 / 手動・対話実行のみ 無人でのOffice自動化は非サポート。無人化したい処理はExcel本体不要の方式へ寄せる8
定期実行 手元でその都度実行 / タスクスケジューラ -Encoding・絶対パス・起動するPowerShellの3点を明示してからタスク化する

8. まとめ

  • CSV自動化の最大の地雷は文字コードです。5.1は既定がコマンドレットごとにバラバラ(Export-CsvはASCII)、7は一律BOMなしUTF-8。読み書きの両方で-Encodingを明示すれば環境差を消せます。
  • 集計はGroup-Object+Measure-Objectが基本形。CSVの値は全部文字列なので、数値変換してから集計します。
  • 突合は、差分の有無だけならCompare-Object、結合が要るならハッシュテーブル。引き当てられなかった行は必ず別ファイルに出して人が確認できるようにします。
  • 列名のゆらぎは読み込み直後の正規化で吸収し、以降は内部名だけで処理を書きます。
  • xlsxはImportExcelモジュールでExcel本体なしに読み書きできます。COMは解放処理まで書き切れる場合の最終手段で、無人実行には使いません。
  • タスクスケジューラに載せる前に、エンコーディング・パス・起動するPowerShellを明示的に固定してください。

関連記事

関連する相談領域

合同会社小村ソフトでは、CSV・Excelを介した定型業務の自動化スクリプト作成、Excel COM依存の帳票処理からの脱却(ImportExcel/Open XMLへの置き換え)、「特定の環境でだけ文字化けする」「EXCEL.EXEが残る」といった不具合の調査を扱っています。

参考リンク

  1. Microsoft Learn, about_Character_Encoding. Windows PowerShell 5.1の既定エンコーディングがコマンドレットごとに一貫しないこと(Export-CsvはASCII、Set-Content/Get-ContentはANSIのDefault、Out-FileとリダイレクトはUTF-16LE、BOMなしファイルのImport-CsvはUTF-8解釈)、PowerShell 6以降が一律BOMなしUTF-8を既定とすること、6.2以降でコードページ番号・登録名による-Encoding指定が可能なこと、7.4のansi値について。  2 3 4 5 6 7 8 9 10 11 12

  2. Microsoft Learn, Group-Object. Group-Objectが指定プロパティの値でオブジェクトをグループ化し、グループごとの件数と要素を返すこと、-AsHashTableでキー→グループのハッシュテーブルを得られることについて。  2 3 4

  3. Microsoft Learn, Measure-Object. Measure-Objectで件数のほかSum・Average・Maximum・Minimum(および標準偏差)を計算できることについて。  2 3 4

  4. Microsoft Learn, Compare-Object. Compare-Objectが2つのオブジェクト集合を比較し、SideIndicator(<= / => / ==)でどちら側にだけ存在するかを示すこと、-Propertyで指定した列だけを比較できること、参照側・差分側がnullの場合に終了エラーになることについて。  2 3 4

  5. Microsoft Learn, An active Excel process continues to run after using a VBA macro to programmatically quit Excel. ブックを閉じQuitを呼び参照をクリアしても、Excelまたはそのメンバーへの参照がグローバルに保持されているとEXCEL.EXEプロセスが残留し続けることについて。  2

  6. Microsoft Learn, Marshal.ReleaseComObject(Object) Method. ReleaseComObjectがCOMオブジェクトに関連付くRCW(ランタイム呼び出し可能ラッパー)の参照カウントを減らし、COMオブジェクトの寿命を明示的に制御するために使うこと、解放済みオブジェクトへのアクセスが例外になるため使い方に注意が必要なことについて。  2

  7. Microsoft Learn, Considerations for unattended automation of Office in the Microsoft 365 for unattended RPA environment. Microsoftが無人・非対話のクライアント(ASP、DCOM、NTサービス等)からのOfficeアプリケーション自動化を推奨せずサポートもしていないこと、無人環境でOfficeが不安定な動作やデッドロックを起こし得ること、Open XML等の代替手段が推奨されることについて。  2 3 4 5

  8. Microsoft Learn, Import-Csv. Import-CsvがCSVから表形式のカスタムオブジェクトを作ること、1行目がヘッダーとして解釈されること、-Headerでヘッダーなしファイルに列名を与えられること、ヘッダーの空欄にはHから始まる仮の列名が振られること、値が文字列として読み込まれることについて。  2 3 4

  9. Microsoft Learn, Export-Csv. Export-Csvがオブジェクトの各プロパティをCSVの列として書き出すこと、PowerShell 7での既定エンコーディングがUTF8NoBOMであること、PowerShell 6.0以降は#TYPE行が既定で出力されずNoTypeInformationが暗黙になることについて。  2 3

  10. Microsoft Learn, Import data from Excel or export data to Excel with SQL Server Integration Services (SSIS). 無人・非対話環境でのExcelコンポーネント利用がサポートされないこと、本番の自動処理ではフラットファイル(CSV)やOpen XMLベースの方式への置き換えが推奨されることについて。 

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

PowerShellでCSVを読み書きすると文字化けするのはなぜですか?
Windows PowerShell 5.1とPowerShell 7で既定の文字エンコーディングが違うためです。5.1はコマンドレットごとに既定がバラバラで、Export-CsvはASCII(日本語が失われる)、BOMなしファイルのImport-CsvはUTF-8解釈、Get-ContentはANSI(日本語環境ではShift_JIS)です。7は一律BOMなしUTF-8が既定です。読み書きの両方で-Encodingを必ず明示するのが唯一の安全策です。
2つのCSVを突合(差分チェック)するにはどうすればよいですか?
「差分の有無」を見るだけならCompare-Objectに-Propertyでキー列を指定するのが手軽です。SideIndicatorで増えた行(=>)と消えた行(<=)が分かります。もう一方のCSVから名前や部署などの列を引き当てて結合したい場合は、マスタ側をキー→行のハッシュテーブルにしてから1行ずつ引くのが定石で、数万件規模でも高速に処理できます。キーが見つからない行は握りつぶさず、別ファイルに出力して人が確認できるようにします。
PowerShellでExcelファイル(xlsx)を作るのにExcel本体は必要ですか?
必要ありません。コミュニティ製のImportExcelモジュールを使えば、Excelをインストールしていないマシンでもxlsxの読み書き、テーブル化、書式設定、ピボットテーブル作成までできます。PowerShell GalleryからInstall-Moduleで導入します。Excel本体をCOMで操作する方法は、マクロの実行など「Excelそのものの機能」が必要な場合の最終手段と位置づけるのが安全です。
PowerShellからExcelをCOM操作するとEXCEL.EXEが残るのはなぜですか?
COMオブジェクトへの参照(RCW)が解放されないままだと、Quitを呼んでもExcelのプロセスが終了しないためです。ワークブックやセル範囲を触るたびに中間オブジェクトへの参照が増えるので、使い終わったらMarshal.ReleaseComObjectで明示的に解放し、GC.Collectで回収を促します。またMicrosoftはタスクスケジューラなど無人環境でのOffice自動化を推奨・サポートしていないため、定期実行したい処理はImportExcelなどExcel本体不要の方式に寄せるべきです。
CSVの集計はExcelのピボットテーブルとPowerShellのどちらでやるべきですか?
1回きりの分析ならExcelで十分です。毎週・毎月同じ手順を繰り返すなら、Group-ObjectとMeasure-Objectでスクリプト化する価値があります。手順が文書ではなくコードとして残るため、担当者が変わっても同じ結果を再現でき、タスクスケジューラでの定期実行にもつなげられます。集計結果をImportExcelでxlsxに出力すれば、受け取る側はいつものExcelファイルとして扱えます。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る