動くコード図鑑技術記事現場の渡り方キャリア論すべての記事About
技術記事

PowerShell のハッシュテーブル / PSCustomObject / スプラッティングの使い分け

バイブス父さん
現役の業務SE
2026年9月15日12 min read広告 (PR) を含む場合があります
PowerShell のハッシュテーブル / PSCustomObject / スプラッティングの使い分け

みなさんこんにちは!ヒロポンです!

PowerShell でちょっとした自動化を書いてると、「設定をまとめて持ち回りたい」「関数に渡す引数が多すぎてつらい」って場面、来ますよね??

そこで顔を出すのが ハッシュテーブル @{}PSCustomObject、それに スプラッティング。全部 @{...} っぽい見た目で、どれをどう使うのか正直こんがらがる。

俺も最初、全部ハッシュテーブルで押し切ろうとして、CSV 出力でぐちゃぐちゃにした。

今回は PowerShell のハッシュテーブルPSCustomObject、それにスプラッティングがそれぞれ何のための入れ物なのかを、1人で運用を回す自動化の目線で順番に積んでいきます。役割の違いが腑に落ちると、取り回しが一気に楽になる。

忙しい人向けに最初にまとめ

  • ハッシュテーブル @{} … キーと値をひくための入れ物。ただし順序は保証されない[ordered]@{} で順序付き)
  • PSCustomObject … プロパティを持つオブジェクト。記述順を保持し、Export-Csv や表出力に向く
  • スプラッティング … コマンドの引数をハッシュテーブルにまとめて、$ ではなく @ を付けて渡す書き方
  • 一番ハマるのは「ハッシュテーブルをそのまま Export-Csv に流して崩れる」やつ。表・CSV にするなら PSCustomObject

以下、それぞれ実際に動かしながら見ていきます。

そもそも、この3つは何のための入れ物か

まず全体像。似て見えるけど、狙ってる用途がまるで違います

  • ハッシュテーブルは「$設定['ServerName'] みたいに、キーで値をひきたい」時の入れ物
  • PSCustomObject は「1件のデータを、名前付きのプロパティを持つオブジェクトとして扱いたい」時の入れ物
  • スプラッティングは入れ物というより「引数の渡し方」で、中身はハッシュテーブル

この住み分けを外すと、「ハッシュテーブルで CSV を出そうとして崩れる」みたいな事故になる。逆に頭に入ってれば、設定はハッシュテーブル、出力は PSCustomObject、コマンド呼び出しはスプラッティング、と迷わず手が動きます。

ここまでで分かったこと: 3つは用途が別。「ひく」ハッシュテーブル、「出す」PSCustomObject、「渡す」スプラッティング。

ハッシュテーブル @{} — キーと値の入れ物

一番基本の入れ物です。@{ キー = 値 } で作って、キーで値をひく。

$config = @{
    ServerName = "SV-BATCH01"
    Port       = 1433
    Retry      = 3
}

# キーで値をひく (両方同じ)
$config["ServerName"]
$config.ServerName

# 後から足す
$config["Timeout"] = 30

こんな感じで、設定値やパラメータを名前でまとめて持てる。ちょうどいい入れ物です。

で、ここで業務でよくハマる1つ目。ハッシュテーブルは キーの順序が保証されません。書いた順に並ぶとは限らない。

$config = @{ A = 1; B = 2; C = 3 }
$config   # A, B, C の順で出るとは限らない

「設定を書いた順に表示したい」「順番が意味を持つ」時は、[ordered] を付けます。

$config = [ordered]@{ A = 1; B = 2; C = 3 }
$config   # A, B, C の順が保たれる

[ordered]@{} は中身が OrderedDictionary になって、記述順が保たれる。地味だけど、出力の見た目が絡む時にじわっと効いてきます。

ここまでで分かったこと: ハッシュテーブルはキーで値をひく入れ物。既定は順序保証なし、順番が要るなら [ordered]

PSCustomObject — プロパティを持つオブジェクト

次。PSCustomObject は、ハッシュテーブルにそっくりな書き方なのに、できあがるものが別物です。

$row = [PSCustomObject]@{
    Name   = "田中"
    Dept   = "経理"
    Active = $true
}

$row.Name    # プロパティとしてアクセス
$row         # Name / Dept / Active を持つ「オブジェクト」として表示される

見た目は [PSCustomObject] を頭に足しただけ。でもこれは「キーと値の入れ物」じゃなく、Name・Dept・Active というプロパティを持つ1件のオブジェクトになる。

しかも PSCustomObject は、記述した順にプロパティが並ぶ。ハッシュテーブルと違って順序を気にしなくていい。

何がうれしいか。パイプラインに流した時です。オブジェクトだから、Format-Table でも Export-Csv でも、プロパティがそのまま列になる!!

$people = @(
    [PSCustomObject]@{ Name = "田中"; Dept = "経理" }
    [PSCustomObject]@{ Name = "佐藤"; Dept = "総務" }
)
$people | Format-Table
$people | Export-Csv -Path "people.csv" -NoTypeInformation -Encoding UTF8

こんな感じで、1件=1オブジェクトを並べて表や CSV にできる。1人運用の自動化だと、AD ユーザーの棚卸し結果とかログの集計結果を CSV に吐く場面が多い。出力するデータは PSCustomObject で作る、が定石です。

ここまでで分かったこと: PSCustomObject はプロパティを持つオブジェクト。記述順を保ち、表・CSV 出力に向く。

ハッシュテーブルと PSCustomObject の使い分け(CSV でハマる)

ここが業務でハマる2つ目。そして一番多い事故です。

「ハッシュテーブルもキーと値だし、そのまま CSV にできるだろ」と思って、こう書く。

$row = @{ Name = "田中"; Dept = "経理" }
$row | Export-Csv -Path "ng.csv" -NoTypeInformation

これ、バージョンによって壊れ方が違う。ただ、どっちにしても期待どおりにはならない。

  • Windows PowerShell 5.1.NET Framework 世代の現場に多い powershell.exe)だと、NameDept が列になるんじゃなく、ハッシュテーブル自体の情報CountKeys など)が列になって完全に崩れる
  • PowerShell 7 では改善されてキーは列になる。ところが今度は列の順序が保証されない。下の実測でも、書いた順は Name, Dept なのに CSV は Dept, Name と逆順で出ています

実行結果(PowerShell 7 での実測):

PowerShell 7 でハッシュテーブルと PSCustomObject を Export-Csv した実測 — ハッシュテーブルは Dept,Name と逆順で列が出て順序が崩れ、PSCustomObject は Name,Dept と書いた順を保つ

どっちのバージョンでも、出力するデータは PSCustomObject で作るのが安全。記述した順のまま列が並びます。

Export-Csv 用のデータをハッシュテーブルから PSCustomObject に変える差分

覚え方はシンプル。「ひくだけならハッシュテーブル、出すなら PSCustomObject」。これだけ。

ここまでで分かったこと: ハッシュテーブルは CSV/表出力に向かない。出力するデータは PSCustomObject にする。

スプラッティング @params — 引数をまとめて渡す

最後。スプラッティングは、これまでの2つと毛色が違って、「コマンドへの引数の渡し方」です。中身はハッシュテーブルなんだけど、使い方が別。

引数の多いコマンドって、1行が横にどんどん伸びて読みにくい。

# 引数が多くて横に伸びる
Copy-Item -Path "C:\src\data.txt" -Destination "D:\backup\data.txt" -Force -Verbose

これを、引数をハッシュテーブルにまとめて、@ を付けて渡す。

$params = @{
    Path        = "C:\src\data.txt"
    Destination = "D:\backup\data.txt"
    Force       = $true
    Verbose     = $true
}
Copy-Item @params

こんな感じで、横に伸びてた引数がすっきり縦にまとまる。

肝は、渡す時に $params じゃなく @params と書くこと。@ を付けると「このハッシュテーブルのキーを、そのまま名前付き引数として展開してね」の意味になる。ここが業務でハマる3つ目$ のままだと「ハッシュテーブルそのものを1個の引数として渡す」ことになって動きません。ん?なんでエラー??ってなるやつなので、$@ かは最初に確認するクセをつけてください。

スプラッティングのいいところは、引数を条件で組み立てられることです。

$params = @{ Path = $src; Destination = $dst }
if ($force) { $params["Force"] = $true }   # 条件次第で引数を足す
Copy-Item @params

if-Force を付けたり外したり、を分岐だらけにせず書ける。1人運用のスクリプトだと、この組み立てやすさがかなり効く。

ここまでで分かったこと: スプラッティングは引数の渡し方。中身はハッシュテーブル、渡す時は @ を付ける。条件で引数を組み立てられる。

3つの使い分け早見

ここまでを一枚で。

ハッシュテーブル / PSCustomObject / スプラッティングの用途・順序・CSV出力・作り方・渡し方の比較表

判断に迷ったら、この順で辿ると早いです。

用途からハッシュテーブル・PSCustomObject・スプラッティングのどれを選ぶかの判断フロー

俺の現場ではこう使い分けてる

1人で AD の運用を回してた頃、ユーザーの棚卸しスクリプトで全部ハッシュテーブルに詰めて、最後に Export-Csv したら列が崩れて呆然とした。あれ、実際にやりました。半日は無駄にした記憶がある。

そこから使い分けをはっきりさせて、今はこう固定してます。

  • 設定・接続情報 → ハッシュテーブル($config['ServerName'] でひく)
  • 出力する1件のデータ → PSCustomObject(そのまま Export-Csv / Format-Table
  • コマンド呼び出し → スプラッティング(引数を組み立てて @params


この記事のコードと手順は ぜんぶ動作検証済み。 安心して現場で試してくれ。
バイブス父さん

現役の業務SE。C# / SQL Server 保守の現場から、コードも人もキャリアも全部書く。 実体験ベース。

運営者について