VBA から PowerShell に移った業務SEが、配列とハッシュテーブルで戸惑う3つの構造差

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

Excelマクロ(VBA)で、業務のちょっとした集計や一括処理を回してきた。そういう業務SE、めっちゃ多いですよね。俺もそうでした。

で、それを PowerShell に移そうとすると、最初の壁が配列とハッシュテーブルDim arr() As String のノリで書くと、まず動かない。あれ、なんで動かへん??ってなるやつ。powershell 配列 ハッシュテーブル で検索してつまずくのは、だいたいここの構造差なんですよね。

先に結論を言っときます。@()(配列)と @{}(ハッシュテーブル)の2つさえ覚えれば、業務スクリプトはだいたい動く。これだけ。

この記事は、前に書いたVBA → C# 翻訳チートシートの PowerShell 版です。VBA で知ってる書き方を、PowerShell に翻訳していく。コードは Docker 上の PowerShell で実機確認済み。Windows PowerShell 5.1 でも 7 でも同じ挙動でした。

目次

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

  • 配列は @() — VBA の Dim arr(2) As String のような固定長宣言は不要。可変長で、追加は $arr += x。インデックスは VBA と同じ 0 始まり。
  • 連想配列は @{} — VBA の Scripting.Dictionary 相当。参照設定なしで @{ "key" = value } と書くだけ。
  • ループは ForEach-Objectforeach — VBA の For Each 相当。PowerShell はパイプライン(|)で流す発想が加わる。

この記事の位置づけ

VBA → C# 翻訳チートシートでは、VBA を C# に移す話を書きました。今回はその別方向。VBA を PowerShell に移す話です。

C# は「がっつりアプリを作る」方向。PowerShell は「Excelマクロでやってた自動化を、もっと手軽に回す」方向です。VBA 勢からすると、実は PowerShell のほうが移りやすかったりする。変わるのは、配列・連想配列・ループの3つの書き方だけなんですよね。

対応マップ — VBA ↔ PowerShell

まず全体像から。VBA でやってたことが PowerShell でどう書けるか、対応表にしました。

VBA の配列宣言・要素追加・連想配列・キー取得・ループを、PowerShell の @() / += / @{} / ForEach-Object の構文に対応させた翻訳早見表

右側の @()@{}ForEach-Object。この3つさえ押さえれば、VBA の自動化はだいたい移せます。順番に見ていきましょう。

構造差1: 配列 — Dim arr() As から @()

VBA の配列は、型と大きさを宣言してから使うのが基本でした。

' VBA: 固定長で宣言してから使う。大きさを変えるなら ReDim
Dim arr(2) As String   ' 0〜2 の3要素
arr(0) = "りんご"
ReDim Preserve arr(3)  ' 大きさを変えるのに ReDim が要る

PowerShell は、この宣言がいりません。ん?型も大きさも書かんでええの?って最初は不安になるけど、@() で囲むだけ。しかも最初から可変長です。

# 配列は @() で作る。可変長・0始まり・宣言不要
$arr = @("りんご", "みかん", "ぶどう")
$arr += "もも"              # 追加は += だけ(ReDim 不要)
Write-Output $arr[0]        # りんご(0始まりは VBA と同じ)
Write-Output $arr.Count     # 4

ReDim Preserve のあの煩わしさから解放されます。インデックスが 0 始まりなのは VBA と一緒なので、ここは戸惑わない。.Count で件数が取れるのも、いい感じに素直です。

構造差2: 連想配列 — Scripting.Dictionary から @{}

VBA で連想配列(キーと値のペア)を使うには、Scripting.Dictionary が定番でした。でもこれ、参照設定(Microsoft Scripting Runtime)を追加しないと使えないのが地味に面倒だった。連想配列1個使うのに参照設定??って、毎回思ってましたよね。

' VBA: 参照設定を追加してから Scripting.Dictionary
Dim d As Object
Set d = CreateObject("Scripting.Dictionary")
d("りんご") = 100

PowerShell は、これが最初から @{} として組み込まれてます。参照設定はいりません。

# ハッシュテーブルは @{} で作る(Scripting.Dictionary 相当・参照設定不要)
$ht = @{ "りんご" = 100; "みかん" = 80 }
$ht["ぶどう"] = 300         # 追加もこれだけ
Write-Output $ht["りんご"]  # 100
Write-Output $ht.Keys.Count # 3

CreateObject も参照設定もなしで、いきなり連想配列が書ける。VBA で Dictionary の参照設定を忘れてエラー、をやらかした人ほど、この手軽さが効きます。

構造差3: ループ — For Each から ForEach-Object

VBA のループは For Each でした。PowerShell でも foreach はそのまま使えるので、ここは移行コストほぼゼロ。

# VBA の For Each 相当。foreach 文はほぼそのまま
foreach ($item in $arr) {
    Write-Output $item
}

ただ、PowerShell にはもう一つの発想がある。パイプラインです。配列を | で次の処理に流して、ForEach-Object で1件ずつ捌く。

# パイプラインで流す。$_ が「今の1件」
@("りんご", "みかん", "ぶどう") | ForEach-Object { Write-Output "果物: $_" }

$_ が「今処理してる1件」を指します。最初は戸惑う。でもこれに慣れると、CSV を読んで→絞り込んで→出力、みたいな処理が1行でつながる。Excelマクロで何十行も書いてたのが、パイプ1本で済んだりするんですよね。こんな感じでスッキリ書けるのが、PowerShell の気持ちいいところ。

ミニマム検証 — VBA脳のまま動く最小スクリプト

理屈だけだと不安ですよね。@()@{} だけで書いた、コピペで動く最小形を置いときます。

# 単価表(ハッシュ)と買い物リスト(配列)で合計を出す
$price = @{ "りんご" = 100; "みかん" = 80; "ぶどう" = 300 }
$cart  = @("りんご", "りんご", "ぶどう")

$total = 0
foreach ($item in $cart) {
    $total += $price[$item]
}
Write-Output "合計: $total 円"   # 合計: 500 円

配列でリストを持って、ハッシュで単価を引いて、foreach で合計する。Excelマクロでやってた集計が、ほぼそのままの発想で書ける。いい感じに VBA の発想が乗るんですよね。@()@{} の2つ、と言った意味がこれです。

俺も最初は VBA の DimReDim の癖が抜けなくて、無駄にエラー出してました。でも @()@{} の2つに割り切ってから、Excelマクロ1本を PowerShell に移すのが一気に早くなった。結局、構文の慣れの問題だったんですよね。

ハマりポイント — VBAの癖のまま書くと詰まる所

俺が実際にやらかした順に3つ。

  • Dim で宣言しようとする: PowerShell に Dim はありません。$arr = @() で即作る。VBA の宣言癖が抜けないと、最初ここで止まる。
  • 要素1個の配列が配列にならない: $x = @("りんご") は配列だけど、$x = "りんご" だと文字列。1件でも @() で囲むのがコツ。
  • ハッシュの順番を期待する: @{} は基本、入れた順番を保証しません。順番が要るなら [ordered]@{} を使う。VBA の Dictionary 感覚だと、ここでハマる。

まとめ

VBA から PowerShell へ。配列とハッシュの構造差は、突き詰めるとこの3つだけです。

  • 配列は @() — 宣言不要・可変長・0始まり。ReDim から解放される
  • 連想配列は @{} — 参照設定不要。Scripting.Dictionary の手軽版
  • ループは foreach か パイプライン ForEach-Object — VBA の発想 + パイプの新発想

逆に言えば、この @()@{} の2つを覚えるだけで、Excelマクロでやってた自動化は PowerShell にどんどん移せる。別世界じゃないんです。VBA でやってきた経験は、ちゃんと地続きで活きます!!

よくある質問

Q1. VBA の ReDim Preserve は PowerShell でどう書きますか?

書く必要がありません。PowerShell の配列は可変長なので、$arr += "新しい値" で追加できます。ただし += は内部で配列を作り直すので、何万件もループで足すなら [System.Collections.ArrayList]List を使うほうが速いです。

Q2. @{} の中身を順番どおりに取り出したいです。

通常のハッシュテーブル @{} はキーの順番を保証しません。順番を保ちたいときは [ordered]@{} と書くと、入れた順番が維持されます。CSV を順番どおり出力したい時などに使います。

Q3. PowerShell で Excel ファイルを直接操作できますか?

できます。ImportExcel モジュールを入れると、Excel を開かずに読み書きできます。VBA のように Excel 上でマクロを動かすのではなく、PowerShell スクリプトから Excel ファイルを処理する形になります。まずは CSV での受け渡しから始めると移行が楽です。

Q4. VBA の経験は PowerShell で無駄になりますか?

なりません。配列・連想配列・ループでデータを捌くという発想は、そのまま使えます。変わるのは構文の書き方だけ。むしろ参照設定や ReDim の煩わしさが減って、VBA でやりたかったことがより素直に書けるようになります。

次に読むべき記事

VBA から PowerShell に移ろうとしてる同業がいたら、この記事ぶん投げてやってください。どんどんシェア待ってるぜ!!

以上!

執筆者

バイブス父さん — 業務 SE 7 年 (SIer 正社員 2 / フリーランス 5)。現職は SEO 直轄部の AI アドバイザー兼 PL、副業で中小 SIer の CTO。SIer の正社員からフリーランスに転じ、複数のエージェント経由で案件を回してきた経験ベースで「業務 SE 視点」の技術 + キャリア記事を書いています。

🐦 X: @hiro_progra0524 (日々の現場メモ更新中)
📝 About Me で経歴詳細を見る


この記事が気に入ったら
いいねしてね!

どんどんシェア待ってるぜ!!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次