インフラエンジニアの羅針盤

インフラエンジニア1〜3年目のための技術ガイド

WindowsServer 2025 総合ガイド 第04回

公開更新

WindowsServer 2025 総合ガイド 第04回
PowerShellスクリプティング基礎 ― 自動化への第一歩

第3回では、PowerShellを使ったファイル・フォルダ操作、ディスク管理、ローカルユーザーとグループの管理を学びました。第4回となる今回は、PowerShellスクリプティングの基礎を学びます。変数、データ型、条件分岐、ループ処理、関数の定義、そしてエラーハンドリングまで、自動化スクリプトを作成するために必要な知識を習得しましょう。

目次
  1. 4.1 この記事で学ぶこと
  2. 4.2 前提条件
  3. 4.3 変数の基礎
    1. 4.3.1 変数の宣言と代入
    2. 4.3.2 データ型
    3. 4.3.3 型の確認と変換
    4. 4.3.4 特殊変数
  4. 4.4 文字列操作
    1. 4.4.1 文字列の結合
    2. 4.4.2 変数展開(ダブルクォート vs シングルクォート)
    3. 4.4.3 ヒアストリング(複数行文字列)
    4. 4.4.4 文字列メソッド
  5. 4.5 配列とハッシュテーブル
    1. 4.5.1 配列の作成とアクセス
    2. 4.5.2 ハッシュテーブルの作成とアクセス
  6. 4.6 条件分岐
    1. 4.6.1 比較演算子
    2. 4.6.2 論理演算子
    3. 4.6.3 if文
    4. 4.6.4 switch文
    5. 4.6.5 三項演算子(PowerShell 7以降)
  7. 4.7 ループ処理
    1. 4.7.1 foreach文
    2. 4.7.2 for文
    3. 4.7.3 while文とdo-while文
    4. 4.7.4 ForEach-Objectコマンドレット
    5. 4.7.5 ループ制御(break、continue)
  8. 4.8 関数の定義
    1. 4.8.1 関数の基本構文
    2. 4.8.2 戻り値(return)
    3. 4.8.3 パラメータの詳細設定
    4. 4.8.4 スコープの概念
  9. 4.9 スクリプトファイルの作成
    1. 4.9.1 .ps1ファイルの作成
    2. 4.9.2 スクリプトの実行方法
    3. 4.9.3 コメントの書き方
    4. 4.9.4 実践的なスクリプト例
  10. 4.10 エラーハンドリング基礎
    1. 4.10.1 エラーの種類
    2. 4.10.2 -ErrorActionパラメータ
    3. 4.10.3 try-catch-finally構文
    4. 4.10.4 $Error変数
    5. 4.10.5 実践的なエラーハンドリング例
  11. 4.11 まとめ
  12. 4.12 次回予告
  13. 4.13 参考リンク

4.1 この記事で学ぶこと

  • 変数とデータ型を理解し、使用できる
  • 条件分岐とループ処理を記述できる
  • 関数を定義し、スクリプトファイルを作成できる

4.2 前提条件

  • 第3回完了(PowerShellの基本操作が可能)
  • Windows Server 2025にリモートデスクトップ接続できる状態
  • PowerShell 7.4を管理者として起動できる状態

4.3 変数の基礎

プログラミングにおいて「変数」は、データを一時的に保存しておく箱のようなものです。PowerShellでは、変数を使うことで、コマンドの実行結果を保存したり、繰り返し使う値を管理したりできます。

4.3.1 変数の宣言と代入

PowerShellでは、変数名の前に $(ドル記号)を付けて変数を定義します。

[実行環境: PowerShell 7.4 (管理者)]

# 変数に値を代入
$message = "Hello, PowerShell!"
$number = 42
$isEnabled = $true

# 変数の値を表示
$message
$number
$isEnabled

実行結果の例:

Hello, PowerShell!
42
True

変数名の命名規則

変数名には以下のルールがあります。

  • 英数字とアンダースコア(_)が使用可能
  • 大文字小文字を区別しない($Name$name は同じ変数)
  • 数字で始めることはできない
  • スペースや特殊文字は使用できない(ただし ${変数名} の形式なら可能)

可読性のために、以下のような命名規則を推奨します。

スタイル 説明
キャメルケース $userName 最初の単語は小文字、以降の単語は大文字で始める
パスカルケース $UserName すべての単語を大文字で始める

本シリーズでは、ローカル変数にはキャメルケース、グローバル変数やパラメータにはパスカルケースを使用します。

4.3.2 データ型

PowerShellは動的型付け言語であり、変数に代入した値によって自動的にデータ型が決まります。主要なデータ型を紹介します。

データ型 .NET型名 説明
文字列 [String] "Hello" テキストデータ
整数 [Int32] 42 32ビット整数(約±21億)
長整数 [Int64] 9999999999 64ビット整数
小数 [Double] 3.14 倍精度浮動小数点数
真偽値 [Boolean] $true, $false 真または偽
配列 [Array] @(1, 2, 3) 複数の値を格納
ハッシュテーブル [Hashtable] @{Key = "Value"} キーと値のペア

4.3.3 型の確認と変換

GetType()メソッド

変数のデータ型を確認するには、GetType()メソッドを使用します。

[実行環境: PowerShell 7.4 (管理者)]

# 各変数の型を確認
$text = "Hello"
$num = 100
$decimal = 3.14
$flag = $true

$text.GetType().Name
$num.GetType().Name
$decimal.GetType().Name
$flag.GetType().Name

実行結果の例:

String
Int32
Double
Boolean

型のキャスト(変換)

明示的に型を指定するには、型名を角括弧で囲んで変数の前に置きます。

# 文字列を整数に変換
[int]$stringToInt = "123"
$stringToInt.GetType().Name  # Int32

# 整数を文字列に変換
[string]$intToString = 456
$intToString.GetType().Name  # String

# 小数を整数に変換(小数点以下は切り捨て)
[int]$doubleToInt = 3.7
$doubleToInt  # 4(四捨五入される)

注意:変換できない値をキャストしようとするとエラーになります。例えば、[int]"abc" はエラーになります。

4.3.4 特殊変数

PowerShellには、システムが自動的に設定する特殊な変数があります。

変数 説明
$null 値が存在しないことを表す
$true 真偽値の「真」
$false 真偽値の「偽」
$_ パイプラインの現在のオブジェクト
$PSVersionTable PowerShellのバージョン情報
$HOME ユーザーのホームディレクトリ
$PWD 現在の作業ディレクトリ
$Error 直近のエラー情報を格納する配列

[実行環境: PowerShell 7.4 (管理者)]

# 特殊変数の例
$PSVersionTable.PSVersion  # PowerShellのバージョン
$HOME                       # ホームディレクトリ
$PWD                        # 現在のディレクトリ

実行結果の例:

Major  Minor  Patch  PreReleaseLabel BuildLabel
-----  -----  -----  --------------- ----------
7      4      7

C:\Users\Administrator
C:\Users\Administrator

4.4 文字列操作

サーバー管理では、ログメッセージの生成、設定ファイルの編集、レポートの作成など、文字列を扱う場面が多くあります。PowerShellでの文字列操作を学びましょう。

4.4.1 文字列の結合

文字列を結合するにはいくつかの方法があります。

[実行環境: PowerShell 7.4 (管理者)]

# 方法1: + 演算子
$firstName = "Taro"
$lastName = "Yamada"
$fullName = $firstName + " " + $lastName
$fullName  # Taro Yamada

# 方法2: -join 演算子
$parts = @("2025", "01", "20")
$date = $parts -join "-"
$date  # 2025-01-20

# 方法3: -f 演算子(フォーマット文字列)
$name = "Server01"
$status = "Running"
$message = "サーバー {0} の状態: {1}" -f $name, $status
$message  # サーバー Server01 の状態: Running

4.4.2 変数展開(ダブルクォート vs シングルクォート)

PowerShellでは、ダブルクォート(")とシングルクォート(')で文字列の扱いが異なります。

[実行環境: PowerShell 7.4 (管理者)]

$serverName = "WS2025-01"

# ダブルクォート:変数が展開される
"サーバー名: $serverName"  # サーバー名: WS2025-01

# シングルクォート:変数が展開されない(リテラル文字列)
'サーバー名: $serverName'  # サーバー名: $serverName

サブ式演算子

ダブルクォート内で複雑な式を展開するには、$()(サブ式演算子)を使用します。

# プロパティやメソッドを展開する場合
$service = Get-Service -Name W32Time
"サービス状態: $($service.Status)"

# 計算結果を展開する場合
$a = 10
$b = 20
"合計: $($a + $b)"  # 合計: 30

4.4.3 ヒアストリング(複数行文字列)

複数行にわたる文字列を定義するには、ヒアストリングを使用します。

[実行環境: PowerShell 7.4 (管理者)]

# 変数展開ありのヒアストリング
$serverName = "WS2025-01"
$multiLine = @"
サーバー情報レポート
====================
サーバー名: $serverName
作成日時: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")
"@

$multiLine

実行結果の例:

サーバー情報レポート
====================
サーバー名: WS2025-01
作成日時: 2025-01-20 10:30:45
# 変数展開なしのヒアストリング(リテラル)
$literal = @'
これは $変数 が展開されません。
$(コマンド) も実行されません。
'@

$literal

注意:ヒアストリングの開始記号(@" または @')の後ろには何も記述できません。また、終了記号("@ または '@)は行頭に置く必要があります。

4.4.4 文字列メソッド

文字列オブジェクトには、便利なメソッドが多数用意されています。

[実行環境: PowerShell 7.4 (管理者)]

$text = "  Hello, Windows Server 2025!  "

# 大文字・小文字変換
$text.ToUpper()  # "  HELLO, WINDOWS SERVER 2025!  "
$text.ToLower()  # "  hello, windows server 2025!  "

# 文字列の検索
$text.Contains("Server")   # True
$text.Contains("Linux")    # False
$text.StartsWith("  Hello") # True
$text.EndsWith("!  ")      # True

# 文字列の置換
$text.Replace("2025", "2026")  # "  Hello, Windows Server 2026!  "

# 空白の除去
$text.Trim()       # "Hello, Windows Server 2025!"(前後の空白を除去)
$text.TrimStart()  # "Hello, Windows Server 2025!  "(前の空白を除去)
$text.TrimEnd()    # "  Hello, Windows Server 2025!"(後の空白を除去)

# 文字列の分割
"apple,banana,cherry".Split(",")  # @("apple", "banana", "cherry")

# 部分文字列の取得
"PowerShell".Substring(0, 5)  # "Power"
"PowerShell".Substring(5)     # "Shell"

4.5 配列とハッシュテーブル

複数のデータをまとめて扱うには、配列やハッシュテーブルを使用します。

4.5.1 配列の作成とアクセス

配列は、複数の値を順序付けて格納するデータ構造です。

[実行環境: PowerShell 7.4 (管理者)]

# 配列の作成方法
$servers = @("Server01", "Server02", "Server03")
$numbers = 1, 2, 3, 4, 5  # @() は省略可能
$empty = @()  # 空の配列

# 配列の要素数
$servers.Count  # 3

# インデックスによるアクセス(0から始まる)
$servers[0]   # Server01(最初の要素)
$servers[1]   # Server02(2番目の要素)
$servers[-1]  # Server03(最後の要素)

# 範囲指定
$servers[0..1]  # @("Server01", "Server02")

配列への要素追加

# 要素の追加
$servers += "Server04"
$servers  # @("Server01", "Server02", "Server03", "Server04")

パフォーマンスの注意:+= 演算子は、実際には新しい配列を作成して全要素をコピーします。大量の要素を追加する場合は、System.Collections.ArrayListSystem.Collections.Generic.List の使用を検討してください。

foreachでの繰り返し処理

# 配列の各要素に対して処理
$servers = @("Server01", "Server02", "Server03")
foreach ($server in $servers) {
    Write-Host "Processing: $server"
}

実行結果の例:

Processing: Server01
Processing: Server02
Processing: Server03

4.5.2 ハッシュテーブルの作成とアクセス

ハッシュテーブルは、キーと値のペアでデータを格納するデータ構造です。設定情報やプロパティの管理に便利です。

[実行環境: PowerShell 7.4 (管理者)]

# ハッシュテーブルの作成
$serverInfo = @{
    Name = "WS2025-01"
    IPAddress = "192.168.1.10"
    Role = "WebServer"
    IsProduction = $true
}

# 値へのアクセス方法
$serverInfo["Name"]       # WS2025-01(ブラケット記法)
$serverInfo.IPAddress     # 192.168.1.10(ドット記法)

# 値の変更
$serverInfo.Role = "AppServer"

# キーと値の追加
$serverInfo["OS"] = "Windows Server 2025"
$serverInfo.Memory = "16GB"

# キーの存在確認
$serverInfo.ContainsKey("Name")  # True
$serverInfo.ContainsKey("CPU")   # False

# すべてのキーと値を取得
$serverInfo.Keys    # すべてのキー
$serverInfo.Values  # すべての値

ハッシュテーブルの表示

# ハッシュテーブルの内容を表示
$serverInfo | Format-Table -AutoSize

実行結果の例:

Name            Value
----            -----
Name            WS2025-01
IPAddress       192.168.1.10
Role            AppServer
IsProduction    True
OS              Windows Server 2025
Memory          16GB

4.6 条件分岐

条件に応じて異なる処理を実行するには、条件分岐を使用します。

4.6.1 比較演算子

PowerShellの比較演算子は、他の言語とは異なる表記を使用します。

演算子 意味
-eq 等しい(equal) 5 -eq 5 → True
-ne 等しくない(not equal) 5 -ne 3 → True
-gt より大きい(greater than) 5 -gt 3 → True
-ge 以上(greater or equal) 5 -ge 5 → True
-lt より小さい(less than) 3 -lt 5 → True
-le 以下(less or equal) 5 -le 5 → True

パターンマッチング演算子

演算子 意味
-like ワイルドカードパターンに一致 "Server01" -like "Server*" → True
-notlike ワイルドカードパターンに一致しない "Server01" -notlike "Web*" → True
-match 正規表現に一致 "Server01" -match "Server\d+" → True
-notmatch 正規表現に一致しない "Server01" -notmatch "^\d+" → True

コレクション演算子

演算子 意味
-contains 配列が値を含む @(1,2,3) -contains 2 → True
-notcontains 配列が値を含まない @(1,2,3) -notcontains 5 → True
-in 値が配列に含まれる 2 -in @(1,2,3) → True
-notin 値が配列に含まれない 5 -notin @(1,2,3) → True

4.6.2 論理演算子

複数の条件を組み合わせるには論理演算子を使用します。

演算子 意味
-and 両方が真 ($a -gt 0) -and ($a -lt 10)
-or どちらかが真 ($a -eq 0) -or ($a -eq 1)
-not / ! 否定 -not $false / !$false

4.6.3 if文

最も基本的な条件分岐は if 文です。

[実行環境: PowerShell 7.4 (管理者)]

# 基本的なif文
$diskUsage = 85

if ($diskUsage -ge 90) {
    Write-Host "警告: ディスク使用率が危険水準です!" -ForegroundColor Red
}
elseif ($diskUsage -ge 80) {
    Write-Host "注意: ディスク使用率が高くなっています。" -ForegroundColor Yellow
}
else {
    Write-Host "正常: ディスク使用率は問題ありません。" -ForegroundColor Green
}

実行結果の例:

注意: ディスク使用率が高くなっています。

実践例:サービス状態のチェック

# サービスの状態をチェックして適切なメッセージを表示
$service = Get-Service -Name "W32Time"

if ($service.Status -eq "Running") {
    Write-Host "$($service.Name) は正常に実行中です。" -ForegroundColor Green
}
elseif ($service.Status -eq "Stopped") {
    Write-Host "$($service.Name) は停止しています。" -ForegroundColor Yellow
}
else {
    Write-Host "$($service.Name) の状態: $($service.Status)" -ForegroundColor Cyan
}

4.6.4 switch文

複数の条件を効率的に処理するには switch 文を使用します。

[実行環境: PowerShell 7.4 (管理者)]

# 基本的なswitch文
$dayOfWeek = (Get-Date).DayOfWeek

switch ($dayOfWeek) {
    "Monday"    { Write-Host "月曜日です。週の始まり!" }
    "Tuesday"   { Write-Host "火曜日です。" }
    "Wednesday" { Write-Host "水曜日です。週の折り返し。" }
    "Thursday"  { Write-Host "木曜日です。" }
    "Friday"    { Write-Host "金曜日です。もうすぐ週末!" }
    "Saturday"  { Write-Host "土曜日です。休日!" }
    "Sunday"    { Write-Host "日曜日です。休日!" }
    default     { Write-Host "不明な曜日です。" }
}

ワイルドカードと正規表現の使用

# -Wildcard オプション
$fileName = "report_2025.xlsx"

switch -Wildcard ($fileName) {
    "*.xlsx" { Write-Host "Excelファイルです。" }
    "*.docx" { Write-Host "Wordファイルです。" }
    "*.pdf"  { Write-Host "PDFファイルです。" }
    default  { Write-Host "その他のファイルです。" }
}

# -Regex オプション
$ipAddress = "192.168.1.100"

switch -Regex ($ipAddress) {
    "^10\."      { Write-Host "クラスAプライベートアドレスです。" }
    "^172\.(1[6-9]|2[0-9]|3[0-1])\." { Write-Host "クラスBプライベートアドレスです。" }
    "^192\.168\." { Write-Host "クラスCプライベートアドレスです。" }
    default      { Write-Host "パブリックアドレスの可能性があります。" }
}

4.6.5 三項演算子(PowerShell 7以降)

PowerShell 7以降では、三項演算子(条件演算子)が使用できます。

[実行環境: PowerShell 7.4 (管理者)]

# 三項演算子: 条件 ? 真の場合 : 偽の場合
$isProduction = $true
$environment = $isProduction ? "本番環境" : "開発環境"
$environment  # 本番環境

# 従来のif文での記述(比較用)
if ($isProduction) {
    $environment = "本番環境"
} else {
    $environment = "開発環境"
}

補足:三項演算子はPowerShell 7以降の機能です。Windows PowerShell 5.1では使用できません。

4.7 ループ処理

同じ処理を繰り返し実行するには、ループ処理を使用します。

4.7.1 foreach文

コレクション(配列など)の各要素に対して処理を行います。

[実行環境: PowerShell 7.4 (管理者)]

# 配列の各要素を処理
$services = @("W32Time", "Spooler", "WinRM")

foreach ($serviceName in $services) {
    $service = Get-Service -Name $serviceName
    Write-Host "$serviceName : $($service.Status)"
}

実行結果の例:

W32Time : Running
Spooler : Running
WinRM : Running

4.7.2 for文

カウンタを使った繰り返し処理に適しています。

[実行環境: PowerShell 7.4 (管理者)]

# 1から5まで繰り返し
for ($i = 1; $i -le 5; $i++) {
    Write-Host "カウント: $i"
}

実行結果の例:

カウント: 1
カウント: 2
カウント: 3
カウント: 4
カウント: 5

配列のインデックスを使ったアクセス

# インデックスを使って配列にアクセス
$servers = @("Server01", "Server02", "Server03")

for ($i = 0; $i -lt $servers.Count; $i++) {
    Write-Host "サーバー $($i + 1): $($servers[$i])"
}

4.7.3 while文とdo-while文

条件が真の間、処理を繰り返します。

[実行環境: PowerShell 7.4 (管理者)]

# while文:条件を先に評価
$count = 1
while ($count -le 3) {
    Write-Host "while: $count"
    $count++
}

# do-while文:処理を先に実行してから条件を評価
$count = 1
do {
    Write-Host "do-while: $count"
    $count++
} while ($count -le 3)

実践例:サービス起動の待機

# サービスが起動するまで待機(最大30秒)
$serviceName = "W32Time"
$maxWait = 30
$waited = 0

while ((Get-Service -Name $serviceName).Status -ne "Running" -and $waited -lt $maxWait) {
    Write-Host "サービスの起動を待機中... ($waited 秒)"
    Start-Sleep -Seconds 1
    $waited++
}

if ((Get-Service -Name $serviceName).Status -eq "Running") {
    Write-Host "サービスが起動しました。"
} else {
    Write-Host "タイムアウト: サービスが起動しませんでした。"
}

4.7.4 ForEach-Objectコマンドレット

パイプラインで使用するループ処理です。

[実行環境: PowerShell 7.4 (管理者)]

# パイプラインでForEach-Objectを使用
Get-Service | Where-Object { $_.Status -eq "Running" } | ForEach-Object {
    Write-Host "実行中: $($_.Name)"
} | Select-Object -First 5

簡略構文

# $_ は現在のオブジェクトを表す
1..5 | ForEach-Object { $_ * 2 }  # 2, 4, 6, 8, 10

並列処理(PowerShell 7以降)

PowerShell 7以降では、-Parallel パラメータで並列処理が可能です。

# 並列処理(大量のデータ処理時に有効)
$servers = @("Server01", "Server02", "Server03", "Server04", "Server05")

$servers | ForEach-Object -Parallel {
    Write-Host "Processing: $_"
    Start-Sleep -Seconds 1  # 何らかの処理をシミュレート
} -ThrottleLimit 3  # 同時実行数を制限

補足:-Parallel はPowerShell 7以降の機能です。並列処理内では、外部の変数に直接アクセスできない点に注意してください($using: スコープ修飾子を使用)。

4.7.5 ループ制御(break、continue)

ループの実行を制御するキーワードです。

[実行環境: PowerShell 7.4 (管理者)]

# break:ループを完全に終了
foreach ($i in 1..10) {
    if ($i -eq 5) {
        Write-Host "5でループを終了"
        break
    }
    Write-Host "数値: $i"
}
# 出力: 1, 2, 3, 4 の後に "5でループを終了"

# continue:現在の反復をスキップして次へ
foreach ($i in 1..5) {
    if ($i -eq 3) {
        continue  # 3をスキップ
    }
    Write-Host "数値: $i"
}
# 出力: 1, 2, 4, 5(3はスキップ)

4.8 関数の定義

繰り返し使用する処理は、関数として定義することで再利用できます。

4.8.1 関数の基本構文

[実行環境: PowerShell 7.4 (管理者)]

# 基本的な関数の定義
function Get-Greeting {
    return "Hello, PowerShell!"
}

# 関数の呼び出し
Get-Greeting  # Hello, PowerShell!

パラメータの定義

# パラメータを持つ関数
function Get-Greeting {
    param (
        [string]$Name
    )
    return "Hello, $Name!"
}

# パラメータを指定して呼び出し
Get-Greeting -Name "Administrator"  # Hello, Administrator!
Get-Greeting "Administrator"         # 位置パラメータでも可

4.8.2 戻り値(return)

PowerShellでは、関数内で出力されたすべての値が戻り値となります。return は明示的に値を返し、関数を終了します。

[実行環境: PowerShell 7.4 (管理者)]

# 戻り値の例
function Get-DiskUsage {
    param (
        [string]$DriveLetter = "C"
    )
    
    $volume = Get-Volume -DriveLetter $DriveLetter
    $usedPercent = [math]::Round((($volume.Size - $volume.SizeRemaining) / $volume.Size) * 100, 1)
    
    return $usedPercent
}

$usage = Get-DiskUsage -DriveLetter "C"
Write-Host "Cドライブ使用率: $usage%"

4.8.3 パラメータの詳細設定

型指定とデフォルト値

[実行環境: PowerShell 7.4 (管理者)]

function Test-ServiceStatus {
    param (
        [string]$ServiceName = "W32Time",  # デフォルト値
        [int]$TimeoutSeconds = 30           # デフォルト値
    )
    
    $service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
    
    if ($null -eq $service) {
        return "サービス '$ServiceName' が見つかりません。"
    }
    
    return "サービス '$ServiceName' の状態: $($service.Status)"
}

# デフォルト値を使用
Test-ServiceStatus

# パラメータを指定
Test-ServiceStatus -ServiceName "Spooler" -TimeoutSeconds 60

必須パラメータ

function New-ServerReport {
    param (
        [Parameter(Mandatory)]  # 必須パラメータ
        [string]$ServerName,
        
        [Parameter(Mandatory)]
        [string]$ReportPath
    )
    
    Write-Host "サーバー: $ServerName のレポートを $ReportPath に作成します。"
}

# 必須パラメータを省略するとプロンプトが表示される
# New-ServerReport

ValidateSet による値の制限

function Set-Environment {
    param (
        [Parameter(Mandatory)]
        [ValidateSet("Development", "Staging", "Production")]
        [string]$Environment
    )
    
    Write-Host "環境を '$Environment' に設定しました。"
}

Set-Environment -Environment "Production"  # OK
# Set-Environment -Environment "Test"      # エラー: 許可されていない値

4.8.4 スコープの概念

変数にはスコープ(有効範囲)があります。

[実行環境: PowerShell 7.4 (管理者)]

# グローバルスコープとローカルスコープ
$globalVar = "グローバル変数"

function Test-Scope {
    $localVar = "ローカル変数"
    
    Write-Host "関数内から見たグローバル変数: $globalVar"
    Write-Host "関数内から見たローカル変数: $localVar"
}

Test-Scope
Write-Host "関数外から見たグローバル変数: $globalVar"
# Write-Host "関数外から見たローカル変数: $localVar"  # エラー: 存在しない

グローバル変数の明示的な指定

# 関数内からグローバル変数を変更
$counter = 0

function Increment-Counter {
    $global:counter++
}

Increment-Counter
Increment-Counter
Write-Host "カウンター: $counter"  # 2

ベストプラクティス:グローバル変数の多用は避け、パラメータと戻り値を使って関数間でデータを受け渡すことを推奨します。

4.9 スクリプトファイルの作成

ここまで学んだ内容を組み合わせて、再利用可能なスクリプトファイルを作成しましょう。

4.9.1 .ps1ファイルの作成

PowerShellスクリプトは .ps1 という拡張子のファイルに保存します。

まず、スクリプトを保存するフォルダを作成します。

[実行環境: PowerShell 7.4 (管理者)]

# スクリプト用フォルダを作成
New-Item -Path C:\Scripts -ItemType Directory -Force

次に、簡単なスクリプトファイルを作成します。

# スクリプトファイルを作成
$scriptContent = @'
# Hello-World.ps1
# 簡単な挨拶スクリプト

param (
    [string]$Name = "World"
)

Write-Host "Hello, $Name!" -ForegroundColor Cyan
Write-Host "現在の日時: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
'@

Set-Content -Path "C:\Scripts\Hello-World.ps1" -Value $scriptContent

4.9.2 スクリプトの実行方法

スクリプトを実行するにはいくつかの方法があります。

[実行環境: PowerShell 7.4 (管理者)]

# 方法1: フルパスで実行
C:\Scripts\Hello-World.ps1

# 方法2: 相対パスで実行(カレントディレクトリがC:\Scriptsの場合)
Set-Location C:\Scripts
.\Hello-World.ps1

# 方法3: パラメータを指定して実行
C:\Scripts\Hello-World.ps1 -Name "Administrator"

実行結果の例:

Hello, Administrator!
現在の日時: 2025-01-20 11:30:45

4.9.3 コメントの書き方

コードを読みやすくするために、適切なコメントを記述しましょう。

# 単一行コメント
# これは単一行のコメントです

<#
複数行コメント
これは複数行に
わたるコメントです
#>

# 関数やスクリプトの説明にはヘルプコメントを使用
<#
.SYNOPSIS
    サービスの状態を確認するスクリプト

.DESCRIPTION
    指定されたサービスの状態を確認し、結果を表示します。

.PARAMETER ServiceName
    確認するサービスの名前

.EXAMPLE
    .\Check-Service.ps1 -ServiceName "W32Time"
    W32Timeサービスの状態を確認します
#>

4.9.4 実践的なスクリプト例

サービス状態レポートを作成するスクリプトを作成しましょう。

[ファイル: C:\Scripts\Get-ServiceReport.ps1]

<#
.SYNOPSIS
    重要なサービスの状態レポートを作成します

.DESCRIPTION
    指定されたサービスの状態を確認し、レポートを出力します。

.PARAMETER Services
    確認するサービス名の配列

.PARAMETER OutputPath
    レポートの出力先パス(省略時は画面に表示)

.EXAMPLE
    .\Get-ServiceReport.ps1
    デフォルトのサービスリストでレポートを表示
#>

param (
    [string[]]$Services = @("W32Time", "Spooler", "WinRM", "EventLog", "Dnscache"),
    [string]$OutputPath
)

# レポートのヘッダー
$report = @()
$report += "=================================="
$report += "サービス状態レポート"
$report += "作成日時: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
$report += "=================================="
$report += ""

# 各サービスの状態を確認
foreach ($serviceName in $Services) {
    $service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
    
    if ($null -eq $service) {
        $report += "[不明] $serviceName - サービスが見つかりません"
    }
    elseif ($service.Status -eq "Running") {
        $report += "[正常] $serviceName - 実行中"
    }
    else {
        $report += "[注意] $serviceName - $($service.Status)"
    }
}

$report += ""
$report += "=================================="

# 出力
if ($OutputPath) {
    $report | Set-Content -Path $OutputPath -Encoding UTF8
    Write-Host "レポートを保存しました: $OutputPath" -ForegroundColor Green
}
else {
    $report | ForEach-Object { Write-Host $_ }
}

このスクリプトを作成して実行します。

[実行環境: PowerShell 7.4 (管理者)]

# スクリプトファイルを作成(上記の内容をコピー)
# 実行
C:\Scripts\Get-ServiceReport.ps1

実行結果の例:

==================================
サービス状態レポート
作成日時: 2025-01-20 11:45:30
==================================

[正常] W32Time - 実行中
[正常] Spooler - 実行中
[正常] WinRM - 実行中
[正常] EventLog - 実行中
[正常] Dnscache - 実行中

==================================

4.10 エラーハンドリング基礎

スクリプトの信頼性を高めるには、エラーを適切に処理することが重要です。

4.10.1 エラーの種類

PowerShellのエラーには2種類あります。

種類 説明
終了エラー(Terminating Error) 処理を中断するエラー コマンドレットの致命的エラー、throw
非終了エラー(Non-Terminating Error) エラーを表示して処理を継続 ファイルが見つからない、アクセス拒否

4.10.2 -ErrorActionパラメータ

コマンドレットのエラー動作を制御するには、-ErrorAction パラメータを使用します。

動作
Continue エラーを表示して処理を継続(デフォルト)
Stop エラーを終了エラーとして処理を中断
SilentlyContinue エラーを表示せずに処理を継続
Ignore エラーを完全に無視($Errorにも記録されない)

[実行環境: PowerShell 7.4 (管理者)]

# エラーを無視して処理を継続
$service = Get-Service -Name "存在しないサービス" -ErrorAction SilentlyContinue

if ($null -eq $service) {
    Write-Host "サービスが見つかりませんでした。"
}

4.10.3 try-catch-finally構文

エラーをキャッチして適切に処理するには、try-catch-finally 構文を使用します。

[実行環境: PowerShell 7.4 (管理者)]

# 基本的なtry-catch
try {
    # エラーが発生する可能性のある処理
    $service = Get-Service -Name "存在しないサービス" -ErrorAction Stop
    Write-Host "サービス状態: $($service.Status)"
}
catch {
    # エラー発生時の処理
    Write-Host "エラーが発生しました: $($_.Exception.Message)" -ForegroundColor Red
}
finally {
    # 必ず実行される処理(省略可能)
    Write-Host "処理を完了しました。"
}

実行結果の例:

エラーが発生しました: Cannot find any service with service name '存在しないサービス'.
処理を完了しました。

特定の例外をキャッチ

# 特定の例外タイプをキャッチ
try {
    $content = Get-Content -Path "C:\存在しないファイル.txt" -ErrorAction Stop
}
catch [System.Management.Automation.ItemNotFoundException] {
    Write-Host "ファイルが見つかりません。" -ForegroundColor Yellow
}
catch [System.UnauthorizedAccessException] {
    Write-Host "アクセスが拒否されました。" -ForegroundColor Red
}
catch {
    Write-Host "予期しないエラー: $($_.Exception.Message)" -ForegroundColor Red
}

4.10.4 $Error変数

$Error は、セッション中に発生したエラーを格納する自動変数です。

[実行環境: PowerShell 7.4 (管理者)]

# 直近のエラーを確認
$Error[0]

# エラーの詳細を確認
$Error[0] | Format-List -Force

# エラーをクリア
$Error.Clear()

4.10.5 実践的なエラーハンドリング例

サービス管理スクリプトにエラーハンドリングを追加します。

[ファイル: C:\Scripts\Check-ServiceStatus.ps1]

<#
.SYNOPSIS
    サービスの状態を確認し、必要に応じて起動します
#>

param (
    [Parameter(Mandatory)]
    [string]$ServiceName
)

function Test-AndStartService {
    param (
        [string]$Name
    )
    
    try {
        # サービスの取得を試行
        $service = Get-Service -Name $Name -ErrorAction Stop
        
        Write-Host "サービス '$Name' を確認しました。" -ForegroundColor Cyan
        Write-Host "現在の状態: $($service.Status)"
        
        # サービスが停止している場合は起動を試行
        if ($service.Status -eq "Stopped") {
            Write-Host "サービスを起動しています..." -ForegroundColor Yellow
            
            try {
                Start-Service -Name $Name -ErrorAction Stop
                Write-Host "サービスを起動しました。" -ForegroundColor Green
            }
            catch {
                Write-Host "サービスの起動に失敗しました: $($_.Exception.Message)" -ForegroundColor Red
                return $false
            }
        }
        
        return $true
    }
    catch [Microsoft.PowerShell.Commands.ServiceCommandException] {
        Write-Host "サービス '$Name' が見つかりません。" -ForegroundColor Red
        return $false
    }
    catch {
        Write-Host "予期しないエラーが発生しました: $($_.Exception.Message)" -ForegroundColor Red
        return $false
    }
}

# メイン処理
$result = Test-AndStartService -Name $ServiceName

if ($result) {
    Write-Host "`n処理が正常に完了しました。" -ForegroundColor Green
}
else {
    Write-Host "`n処理中にエラーが発生しました。" -ForegroundColor Red
    exit 1
}

4.11 まとめ

第4回では、以下の内容を学びました。

  • 変数の基礎
    • $ 記号で変数を定義、GetType() で型を確認
    • 主要なデータ型:String、Int32、Double、Boolean、Array、Hashtable
    • 特殊変数:$null$true$false$_$Error
  • 文字列操作
    • ダブルクォートで変数展開、シングルクォートでリテラル
    • ヒアストリング(@" "@)で複数行文字列
    • 文字列メソッド:ToUpper()Split()Replace()Trim() など
  • 配列とハッシュテーブル
    • 配列:@() で作成、インデックスでアクセス
    • ハッシュテーブル:@{} で作成、キーと値のペア
  • 条件分岐
    • 比較演算子:-eq-ne-gt-lt-like-match
    • if-elseif-else 文、switch
    • 三項演算子(PowerShell 7以降):条件 ? 真 : 偽
  • ループ処理
    • foreach 文:コレクションの反復処理
    • for 文:カウンタベースの繰り返し
    • whiledo-while 文:条件ベースの繰り返し
    • ForEach-Object:パイプラインでの使用、-Parallel で並列処理
    • breakcontinue でループ制御
  • 関数の定義
    • function キーワードと param() ブロック
    • [Parameter(Mandatory)] で必須パラメータ
    • [ValidateSet()] で値を制限
    • スコープ:ローカル変数とグローバル変数
  • スクリプトファイルの作成
    • .ps1 ファイルの作成と実行
    • コメント:#(単一行)、<# #>(複数行)
  • エラーハンドリング
    • 終了エラーと非終了エラー
    • -ErrorAction パラメータ:Stop、SilentlyContinue など
    • try-catch-finally 構文
    • $Error 変数でエラー情報を確認

これらのスクリプティング技術は、今後のサーバー管理の自動化に直接活用できます。

4.12 次回予告

第5回では「Windowsサービスの管理 ― サーバーの心臓部を理解する」と題して、サービスの概念と役割、状態確認・起動・停止の方法、スタートアップの種類の設定、そしてサービス監視スクリプトの作成を学びます。今回学んだスクリプティング技術を活用して、実践的なサービス管理を行いましょう。

4.13 参考リンク

前の記事
次の記事