【Bicep】PowerShellからデプロイするときに詰まったポイントまとめ
はじめに
BicepからAzureリソースを構築しようとしました。
az deployment group create コマンドでデプロイするときに、上手くデプロイできない場面が複数あったため共有します。
環境
- Windows 11
 - PowerShell
 - Azure CLI
 
ディレクトリ構成
Iac/
├─ deployments/
│    └─ main.bicep
└─ modules/
└─ vnet.bicep, appservice.bicep, etc...
つまづいたポイント
1. Bash と PowerShell の違い
よく紹介されているコマンド例は Bash 前提だった。
az deployment group create \
-g MyResourceGroup \
-f ./main.bicep \
-p storageAccountName=mystorage namePrefix=demo
これをそのまま PowerShell で実行すると…
- 
\が認識されない(PowerShellでは改行はバッククォート ` ) - 
|がパイプとして解釈されてしまう (NODE|18-lts→ エラー) 
結果 → '-g' はコマンドレットではありません や '18-lts' は内部コマンドではありません のエラー。
2. ディレクトリ移動の二重実行
シンプルなミス。
すでに Iac/deployments にいるのに、さらに cd .\deployments を実行。
→ パスが Iac/deployments/deployments となり「フォルダが存在しない」エラー。
3. PowerShell の引数解釈
Azure CLI では --parameters @file.json が正しい文法ですが、PowerShell では @ が配列リテラルとして解釈されてしまいパースエラー。
# NG
--parameters @.\parameters.dev.json
# OK(ダブルクォートで囲む)
--parameters "@.\parameters.dev.json"
また、PowerShell のハッシュテーブル (@{}) を直接渡すのも不可。
$psParams = @{
  storageAccountName = 'mystorage'
}
az deployment group create --parameters $psParams
# → Unable to parse parameter: System.Collections.Hashtable
解決策
方法1: JSON パラメータファイルを使う
parameters.dev.jsonファイルをdeploymentsに追加し、下記コマンドを実行する
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "storageAccountName": { "value": "mystorage12345" },
    "namePrefix": { "value": "demo" },
    "webAppName": { "value": "demo-web" },
    "appServicePlanSku": { "value": "B1" },
    "linuxFxVersion": { "value": "NODE|18-lts" }
  }
}
コマンド:
az deployment group create `
  --resource-group MyResourceGroup `
  --template-file .\main.bicep `
  --parameters "@.\parameters.dev.json"
なぜ解決するのか?
PowerShell は @ を配列リテラルとして解釈するが、クォートで囲むことで文字列として渡せる。
JSON ファイルは Azure CLI が直接パースするので、PowerShell の解釈が入らず安全。
複数環境(dev/prod)での切り替えも楽になる。
パースとは
パース(parse)とは
文字列などのデータを解析して、意味のある形に変換すること
今回の場合は:
PowerShellはファイルの中身には一切触らず、"@.\parameters.dev.json" という文字列だけをAzureCLI(az)に渡す。渡されたaz側が、そのJSONファイルを開いて自分で解釈するということになる
参考:https://it-infomation.com/parse/
配列リテラルとは
配列リテラルとは
プログラミングで 配列(Array) を直接書き出すための表記方法のことです。
例えば数字のリストを一気に作りたいときに使います。
PowerShell の場合
PowerShell では @() を使うと配列リテラルになります。
# 配列リテラルの例
$numbers = @(1, 2, 3, 4)
$numbers[0]   # => 1
$numbers[1]   # => 2
また、単に @() だけじゃなく、@ で始まる色々なリテラル表記があります。
- 
@()→ 配列リテラル - 
@{}→ ハッシュテーブルリテラル(連想配列) - 
@' ... '@→ ヒアストリング(複数行文字列) 
ここでの詰まりポイント
Azure CLI では「@file.json」と書くと「ファイルを読み込む」という意味。
でも PowerShell では先頭の @ を「配列リテラル」と解釈してしまい、
--parameters @.\parameters.dev.json が 「CLI にファイルを渡す」 ではなく
**「PowerShell の配列式」**として解釈されてエラーになる。
方法2: PowerShell のパースを止める
az --% deployment group create --resource-group MyResourceGroup --template-file .\main.bicep --parameters linuxFxVersion=NODE|18-lts
なぜ解決するのか?
--% を付けると PowerShell がそれ以降を解析せず、そのまま文字列として CLI に渡す。
そのため | もパイプ扱いされず、CLI に素直に NODE|18-lts が渡る。
ただし --% を使うとコマンド補完や変数展開も効かないので、使いどころは限定的。
方法3: 値を変数に入れて渡す
$fx = "NODE|18-lts"
az deployment group create --resource-group MyResourceGroup --template-file .\main.bicep --parameters linuxFxVersion=$fx
なぜ解決するのか?
NODE|18-lts を変数に格納することで、PowerShell が途中の | をコマンド分割せず、変数展開で安全に CLI に渡せる。
CLI には「NODE|18-lts」という単一の文字列が届く。
まとめ
- Bash と PowerShell は行継続や記号解釈が違う
 - 
cdの二重実行でパスが崩れることもある - 
--parameters @file.jsonは ダブルクォート必須 - JSONファイルでパラメータ管理するのが一番安定した
 
おわりに
- PowerShell で Azure CLI を使うと、CLI の文法とシェルの文法が衝突するのが落とし穴でした。
 - 「どのCUI(PowerShell, Bash, Azure Cloud Shell)」を使うかによってコマンドの書き方が変わる点も学びました。
今度、T先輩に「Bicepデプロイはどのシェルを使っていますか?」と聞いてみようと思います。 
Discussion