PowerShellスクリプトを書いていて、こんなことで困ったことはありませんか?
- 「今この変数にはなにが入っているの?」
- 「この条件分岐に入っているかな?」
- 「スクリプトがどこで止まっているの?」
- 「なぜ期待した結果にならないの?」
そんなときに便利なのが、Write-Debugコマンドです。
Write-Debugは、スクリプトの中で任意のタイミングでデバッグ用メッセージを出力するためのコマンドです。
これをつかえば、開発中にコードの流れを把握したり、トラブルシューティングがぐっと楽になります。
この記事では、Write-Debugの基本的なつかい方から実践的な活用方法まで、初心者向けに説明します。
Write-Debugってなに?
説明
Write-Debugは、PowerShellのスクリプトや関数の中で、デバッグメッセージを出力するためのコマンドレットです。
普通のWrite-Outputとちがって、普段は表示されません。
-Debug
スイッチが有効なときだけ表示される「隠れたメッセージ」のようなものです。
Write-Debugの特徴
- 開発者専用:普段は見えない、開発時だけのメッセージ
- 条件付き表示:必要なときだけ表示できる
- デバッグ専用:本番運用時は影響しない
- 詳細な状況把握:変数の値や処理の流れを確認できる
基本的な書き方
Write-Debug "ここにデバッグメッセージを書く"
ただし、これだけでは表示されません。表示するには特別な設定が必要です。
Write-Debugを表示する方法
方法1:関数で-Debugスイッチをつかう
ステップ1:関数を作成
function Test-Debug {
[CmdletBinding()] # この行が重要
param()
Write-Debug "デバッグメッセージです"
Write-Output "通常の出力です"
}
ステップ2:-Debugスイッチで実行
Test-Debug -Debug
実行結果
DEBUG: デバッグメッセージです
通常の出力です
ステップ3:普通に実行した場合
Test-Debug
実行結果
通常の出力です
デバッグメッセージは表示されません。
方法2:$DebugPreferenceをつかう
# デバッグメッセージを常に表示するように設定
$DebugPreference = "Continue"
Write-Debug "これは常に表示されます"
Write-Output "通常の出力"
# 設定を元に戻す
$DebugPreference = "SilentlyContinue"
実行結果
DEBUG: これは常に表示されます
通常の出力
$DebugPreferenceの値
設定値 | 説明 |
---|---|
SilentlyContinue | 表示しない(デフォルト) |
Continue | 表示して処理を続行 |
Inquire | 表示して続行するか確認 |
Stop | 表示してエラーで停止 |
実践的なWrite-Debugの活用例
例1:変数の値を確認する
説明
スクリプトの実行中に、変数にどんな値が入っているかを確認したい場合の例です。
スクリプト
function Calculate-Tax {
[CmdletBinding()]
param(
[int]$Price,
[double]$TaxRate = 0.1
)
Write-Debug "入力された価格: $Price"
Write-Debug "税率: $TaxRate"
$tax = $Price * $TaxRate
Write-Debug "計算された税額: $tax"
$total = $Price + $tax
Write-Debug "合計金額: $total"
return $total
}
# 使用例
$result = Calculate-Tax -Price 1000 -TaxRate 0.08 -Debug
Write-Output "最終結果: $result"
実行結果
DEBUG: 入力された価格: 1000
DEBUG: 税率: 0.08
DEBUG: 計算された税額: 80
DEBUG: 合計金額: 1080
最終結果: 1080
例2:条件分岐の流れを確認する
説明
if文やswitch文で、どの条件に合致したかを確認したい場合の例です。
スクリプト
function Check-Grade {
[CmdletBinding()]
param(
[int]$Score
)
Write-Debug "=== 成績判定開始 ==="
Write-Debug "入力されたスコア: $Score"
if ($Score -ge 90) {
Write-Debug "90点以上の条件に合致"
$grade = "A"
} elseif ($Score -ge 80) {
Write-Debug "80-89点の条件に合致"
$grade = "B"
} elseif ($Score -ge 70) {
Write-Debug "70-79点の条件に合致"
$grade = "C"
} elseif ($Score -ge 60) {
Write-Debug "60-69点の条件に合致"
$grade = "D"
} else {
Write-Debug "60点未満の条件に合致"
$grade = "F"
}
Write-Debug "決定された成績: $grade"
Write-Debug "=== 成績判定終了 ==="
return $grade
}
# 使用例
$grades = @(95, 82, 75, 58)
foreach ($score in $grades) {
$result = Check-Grade -Score $score -Debug
Write-Output "スコア $score → 成績 $result"
Write-Output "---"
}
例3:ループ処理の進行状況を確認する
説明
繰り返し処理で、現在何回目の処理をしているかや、各回の処理内容を確認したい場合の例です。
スクリプト
function Process-Files {
[CmdletBinding()]
param(
[string[]]$FileNames
)
Write-Debug "=== ファイル処理開始 ==="
Write-Debug "処理対象ファイル数: $($FileNames.Count)"
$processed = 0
foreach ($fileName in $FileNames) {
$processed++
Write-Debug "[$processed/$($FileNames.Count)] 処理中: $fileName"
# ファイル存在チェック(例)
if (Test-Path $fileName) {
Write-Debug " ✓ ファイルが存在します"
# 実際の処理をここに書く
Write-Debug " → 処理完了"
} else {
Write-Debug " ✗ ファイルが見つかりません"
}
}
Write-Debug "=== ファイル処理終了 ==="
Write-Output "処理完了: $processed ファイル"
}
# 使用例
$files = @("test1.txt", "test2.txt", "test3.txt")
Process-Files -FileNames $files -Debug
例4:関数の開始と終了を記録する
説明
複雑なスクリプトで、どの関数がいつ呼ばれて、いつ終了したかを追跡したい場合の例です。
スクリプト
function Get-UserInfo {
[CmdletBinding()]
param(
[string]$UserName
)
Write-Debug ">>> Get-UserInfo開始 ($(Get-Date -Format 'HH:mm:ss'))"
Write-Debug "対象ユーザー: $UserName"
# 仮のユーザー情報取得処理
Start-Sleep -Seconds 1 # 処理時間のシミュレーション
$userInfo = @{
Name = $UserName
Department = "IT部"
Role = "エンジニア"
}
Write-Debug "取得した情報: $($userInfo | ConvertTo-Json -Compress)"
Write-Debug "<<< Get-UserInfo終了 ($(Get-Date -Format 'HH:mm:ss'))"
return $userInfo
}
function Generate-Report {
[CmdletBinding()]
param(
[string[]]$UserNames
)
Write-Debug ">>> Generate-Report開始 ($(Get-Date -Format 'HH:mm:ss'))"
$report = @()
foreach ($user in $UserNames) {
Write-Debug "ユーザー情報取得中: $user"
$info = Get-UserInfo -UserName $user -Debug
$report += $info
}
Write-Debug "レポート生成完了: $($report.Count) 件"
Write-Debug "<<< Generate-Report終了 ($(Get-Date -Format 'HH:mm:ss'))"
return $report
}
# 使用例
$users = @("田中", "佐藤", "山田")
$result = Generate-Report -UserNames $users -Debug
Write-Debugと他の出力コマンドのちがい
比較表
コマンド | 表示される条件 | 主な用途 | 色 |
---|---|---|---|
Write-Output | いつも表示 | 通常の結果出力 | 白 |
Write-Host | いつも表示 | ユーザー向けメッセージ | 指定可能 |
Write-Warning | いつも表示 | 警告メッセージ | 黄 |
Write-Error | いつも表示 | エラーメッセージ | 赤 |
Write-Verbose | -Verbose 時のみ | 詳細な処理情報 | 青 |
Write-Debug | -Debug 時のみ | デバッグ情報 | 白(DEBUG:付き) |
使い分けの例
function Demo-OutputCommands {
[CmdletBinding()]
param(
[string]$UserName
)
Write-Output "これは結果です: $UserName" # 常に表示(結果)
Write-Host "処理を開始します..." -ForegroundColor Green # 常に表示(進捗)
Write-Warning "注意: テスト環境です" # 常に表示(警告)
Write-Verbose "詳細: ユーザー検証中..." # -Verbose時のみ
Write-Debug "デバッグ: 変数チェック完了" # -Debug時のみ
if (-not $UserName) {
Write-Error "ユーザー名が指定されていません" # エラー時のみ
return
}
}
# 実行例
Demo-OutputCommands -UserName "テストユーザー" # 基本出力のみ
Demo-OutputCommands -UserName "テストユーザー" -Verbose # 詳細情報も表示
Demo-OutputCommands -UserName "テストユーザー" -Debug # デバッグ情報も表示
Demo-OutputCommands -UserName "テストユーザー" -Verbose -Debug # すべて表示
スクリプトファイルでのWrite-Debug
スクリプトファイルの例
ファイル名:debug-sample.ps1
[CmdletBinding()]
param(
[string]$InputFile,
[string]$OutputFile
)
Write-Debug "=== スクリプト開始 ==="
Write-Debug "入力ファイル: $InputFile"
Write-Debug "出力ファイル: $OutputFile"
# 入力ファイルの存在確認
if (-not (Test-Path $InputFile)) {
Write-Debug "エラー: 入力ファイルが見つかりません"
Write-Error "ファイルが見つかりません: $InputFile"
exit 1
}
Write-Debug "入力ファイルが確認されました"
# ファイル処理(例)
$content = Get-Content $InputFile
Write-Debug "読み込み行数: $($content.Count)"
# 何らかの処理
$processedContent = $content | ForEach-Object {
Write-Debug "処理中の行: $_"
$_.ToUpper() # 大文字に変換
}
# 出力
$processedContent | Out-File $OutputFile
Write-Debug "出力完了: $OutputFile"
Write-Debug "=== スクリプト終了 ==="
実行方法
# 通常実行(デバッグメッセージなし)
.\debug-sample.ps1 -InputFile "input.txt" -OutputFile "output.txt"
# デバッグモードで実行
.\debug-sample.ps1 -InputFile "input.txt" -OutputFile "output.txt" -Debug
デバッグのベストプラクティス
1. 適切な粒度でメッセージを出力
良い例
Write-Debug "=== 関数開始: Calculate-Discount ==="
Write-Debug "入力パラメータ: Price=$Price, Rate=$Rate"
Write-Debug "計算結果: Discount=$discount"
Write-Debug "=== 関数終了: Calculate-Discount ==="
悪い例(出力しすぎ)
Write-Debug "変数aに1を代入"
Write-Debug "変数bに2を代入"
Write-Debug "a + b を計算"
Write-Debug "結果は3"
2. 構造化されたメッセージ
function Format-DebugMessage {
param(
[string]$Level,
[string]$Function,
[string]$Message
)
$timestamp = Get-Date -Format "HH:mm:ss.fff"
Write-Debug "[$timestamp] [$Level] [$Function] $Message"
}
function Sample-Function {
[CmdletBinding()]
param()
Format-DebugMessage -Level "INFO" -Function "Sample-Function" -Message "処理開始"
Format-DebugMessage -Level "DATA" -Function "Sample-Function" -Message "データ取得完了"
Format-DebugMessage -Level "INFO" -Function "Sample-Function" -Message "処理終了"
}
3. 条件付きデバッグ
function Advanced-Debug {
[CmdletBinding()]
param(
[switch]$DetailedDebug
)
Write-Debug "基本的なデバッグ情報"
if ($DetailedDebug) {
Write-Debug "詳細なデバッグ情報"
Write-Debug "メモリ使用量: $((Get-Process -Id $PID).WorkingSet64 / 1MB) MB"
Write-Debug "実行時間: $(Get-Date)"
}
}
トラブルシューティング
よくある問題と解決方法
問題1:Write-Debugが表示されない
原因:[CmdletBinding()]
が抜けている
# ❌ 悪い例
function Test {
Write-Debug "表示されません"
}
# ✅ 良い例
function Test {
[CmdletBinding()]
param()
Write-Debug "表示されます"
}
問題2:スクリプトで-Debugが効かない
原因:スクリプトの先頭に[CmdletBinding()]
がない
# ❌ 悪い例
param($Name)
Write-Debug "Hello $Name"
# ✅ 良い例
[CmdletBinding()]
param($Name)
Write-Debug "Hello $Name"
問題3:デバッグメッセージが多すぎる
解決:条件分岐やレベル分けを活用
$DebugLevel = "Basic" # "Basic", "Detailed", "Verbose"
if ($DebugLevel -eq "Detailed" -or $DebugLevel -eq "Verbose") {
Write-Debug "詳細なデバッグ情報"
}
if ($DebugLevel -eq "Verbose") {
Write-Debug "さらに詳しい情報"
}
まとめ
Write-Debugの重要ポイント
- 条件付き表示:
-Debug
スイッチまたは$DebugPreference
で制御 - 開発専用:本番運用時は表示されないので安全
- 詳細な追跡:変数の値、処理の流れ、タイミングを確認
- 適切な粒度:必要な情報だけを出力
使い分けガイド
目的 | 使用するコマンド |
---|---|
最終的な結果を出力 | Write-Output |
ユーザーへの状況報告 | Write-Host |
詳細な処理情報 | Write-Verbose |
開発時のデバッグ | Write-Debug |
警告メッセージ | Write-Warning |
エラーメッセージ | Write-Error |
学習のステップ
- 基本的な使い方:Write-Debugと[CmdletBinding()]を覚える
- 表示制御:-Debugスイッチと$DebugPreferenceをマスター
- 実践活用:変数確認、条件分岐、ループで使ってみる
- 高度な技術:構造化メッセージ、条件付きデバッグを試す
コメント