cv.cm

コーディング · プログラミング言語

PowerShell入門:初心者向けチュートリアル

約13分で読めます

結論

PowerShellは、自動化のためにMicrosoftが提供するクロスプラットフォームのシェル兼スクリプト言語です。コマンド(コマンドレット)はテキストではなく.NETオブジェクトをパイプラインで受け渡すため、テキストを解析しなくてもデータの絞り込み、並べ替え、エクスポートができます。このページでは、PowerShell 7のインストール、スクリプトの実行、コマンドレット、変数、演算子、制御構文、関数、コレクション、エラー処理を扱います。

正規表現テストを開く

PowerShellとは何か、何に使うのか

PowerShellは、.NET上に構築されたMicrosoft製のクロスプラットフォームのシェル兼スクリプト言語です。従来のシェルはコマンド間でプレーンテキストを受け渡しますが、PowerShellはプロパティとメソッドを持つ.NETオブジェクトを受け渡すので、テキストを解析せずにデータを絞り込んだり並べ替えたりできます。

システム管理者やDevOpsエンジニアは、PowerShellをWindowsの自動化、Active Directory・Microsoft 365・Azureの管理、ビルドやデプロイ用スクリプトの作成に使います。エディションは2種類あります。Windowsに組み込まれているWindows PowerShell 5.1と、オープンソースでWindows・Linux・macOSで動作するPowerShell 7以降(コマンド名はpwsh)です。このチュートリアルはPowerShell 7を対象にしています。

PowerShellのインストールとHello, worldの実行

Windowsではwinget install --id Microsoft.PowerShell --source wingetでPowerShell 7をインストールします。macOSとLinuxでは、Homebrewか、Microsoftのインストールガイドに載っているパッケージマネージャーを使ってください。スクリプトは拡張子.ps1のテキストファイルです。

# hello.ps1
Write-Output "Hello, world!"
pwsh ./hello.ps1
# Hello, world!

Windowsでは、実行ポリシーによってスクリプトがブロックされることがあります。Set-ExecutionPolicy -Scope CurrentUser RemoteSignedを実行すると、自分で作ったローカルのスクリプトは実行でき、ダウンロードしたスクリプトには署名が必要なままになります。エディターはPowerShell拡張機能を入れたVisual Studio Codeがおすすめです。

コマンドレットとパイプライン

コマンドはコマンドレットと呼ばれ、Get-Process、Set-Location、New-ItemのようにVerb-Noun(動詞-名詞)の命名規則に従います。ほかのコマンドを調べるときは、Get-Command、Get-Help、Get-Memberの3つが役に立ちます。

Get-Command -Noun Process          # list commands that work with processes
Get-Help Get-ChildItem -Examples   # show usage examples

# five processes using the most memory
Get-Process |
    Sort-Object -Property WorkingSet64 -Descending |
    Select-Object -First 5 -Property Name, Id, WorkingSet64

# files larger than 1 MB in the current folder
Get-ChildItem -File | Where-Object { $_.Length -gt 1MB } |
    ForEach-Object { "{0}  {1:N0} KB" -f $_.Name, ($_.Length / 1KB) }

Get-Date | Get-Member -MemberType Property   # inspect an object

スクリプトブロックの中では、$_(または$PSItem)がパイプラインを流れてきた現在のオブジェクトです。オブジェクトは型を保ったままなので、Sort-Objectは何もしなくても数値を数値として、日付を時系列として並べ替えます。

変数と型

変数は$で始まります。変数にはあらゆる.NETオブジェクトを入れられ、角かっこで型制約を付けることもできます。二重引用符の文字列では変数と$( )式が展開され、単一引用符の文字列はそのままの文字列になります。

$name = "Ada"
[int]$count = 3
$price = 19.99                      # System.Double
$isAdmin = $false
$today = Get-Date

"Hello, $name"                      # Hello, Ada
"Next: $($count + 1)"               # Next: 4
'No $expansion here'                # No $expansion here
$price.GetType().Name               # Double
$today.ToString("yyyy-MM-dd")       # for example 2026-10-31
[int]"42" + 1                       # 43 (explicit conversion)
型例補足
[int]4232ビット整数
[double]3.14浮動小数点数。金額には[decimal]を使います
[string]"text"比較はデフォルトで大文字・小文字を区別しません
[bool]$true, $falseキーワードではなく自動変数です
[datetime]Get-Date完全な.NETのDateTimeオブジェクト
[array], [hashtable]@(1, 2), @{ a = 1 }コレクション。後述します

演算子と制御構文

比較演算子は記号ではなく単語です。-eq、-ne、-gt、-lt、-ge、-le、-like(ワイルドカード)、-match(正規表現)、-containsがあります。文字列の比較は、-ceqのようにc付きの演算子を使わない限り大文字・小文字を区別しません。

$temp = 22
if ($temp -gt 30) {
    "hot"
} elseif ($temp -ge 15) {
    "mild"                           # mild
} else {
    "cold"
}

switch ("report.csv") {
    { $_ -like "*.csv" } { "CSV file" }    # CSV file
    { $_ -like "*.txt" } { "text file" }
    default { "other" }
}

foreach ($n in 1..3) { "n = $n" }          # n = 1, n = 2, n = 3
for ($i = 0; $i -lt 2; $i++) { "i = $i" }  # i = 0, i = 1
$k = 3
while ($k -gt 0) { $k-- }
"Hello" -eq "hello"                        # True

関数とパラメーター

関数はparam()ブロックで、型付きで名前のあるパラメーターを宣言します。[CmdletBinding()]を付けると、-Verboseなど組み込みコマンドレットと同じ共通パラメーターが使えるようになります。キャプチャされなかった出力は、すべて関数の戻り値になります。

function Get-Greeting {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Name,
        [string]$Greeting = "Hello"
    )
    Write-Verbose "Building greeting for $Name"
    "$Greeting, $Name!"
}

Get-Greeting -Name "Ann"                  # Hello, Ann!
Get-Greeting -Name "Bo" -Greeting "Hi"    # Hi, Bo!
Get-Greeting "Cy" -Verbose                # also prints the verbose message

関数はコマンドレットと同じように、引数を空白で区切って呼び出します。例:Get-Greeting -Name Ann。Get-Greeting("Ann", "Hi")と書くと配列が1つの引数として渡されるため、ほかの言語から来た人がよくつまずきます。

配列・ハッシュテーブル・カスタムオブジェクト

配列は@( )またはカンマ区切りのリストで作ります。@{ }と書くハッシュテーブルは、キーと値のペアを保持します。[pscustomobject]はハッシュテーブルをオブジェクトに変換し、Sort-Object、Format-Table、Export-Csvとうまく組み合わせられます。

$langs = @("PowerShell", "Python")
$langs += "Go"                       # creates a new, longer array
$langs.Count                         # 3
$langs[0]                            # PowerShell
$langs -contains "Go"                # True

$ports = @{ http = 80; https = 443 }
$ports["ssh"] = 22
$ports.https                         # 443
$ports.Keys.Count                    # 3

$user = [pscustomobject]@{ Name = "Ann"; Age = 31 }
$user.Name                           # Ann
$people = @(
    [pscustomobject]@{ Name = "Bo"; Age = 25 }
    $user
)
$people | Sort-Object Age | Format-Table

配列に+=で追加すると、そのたびに配列全体がコピーされます。ループが大きい場合は、ループの出力を直接受け取る($result = foreach (...) { ... })か、[System.Collections.Generic.List[object]]を使ってください。

エラー処理

PowerShellのエラーには、実行を止める終了エラーと、メッセージを表示して処理を続ける非終了エラーがあります。try/catch/finallyが捕捉するのは終了エラーだけなので、コマンドレットの失敗を捕捉したいときは-ErrorAction Stopを付けます。

try {
    $content = Get-Content -Path "missing.txt" -ErrorAction Stop
}
catch [System.Management.Automation.ItemNotFoundException] {
    Write-Warning "File not found: $($_.Exception.Message)"
}
catch {
    Write-Error "Unexpected error: $_"
}
finally {
    "cleanup done"
}

$ErrorActionPreference = "Stop"   # make all errors terminating in this script
throw "Something went wrong"      # raise your own terminating error

catchの中では、$_がエラーレコードです。スクリプトの先頭で$ErrorActionPreference = "Stop"を設定するのは、すぐに失敗させるためによく使われる方法です。

小さな完成スクリプト:ディスク使用量レポート

このスクリプトは、フォルダー以下の大きなファイルを一覧にし、拡張子ごとにグループ化して、CSVレポートとして出力します。パラメーター、パイプライン、計算プロパティ、エラー処理をひととおり組み合わせています。

# report.ps1
param(
    [string]$Path = ".",
    [int]$Top = 5
)
$ErrorActionPreference = "Stop"

$files = Get-ChildItem -Path $Path -File -Recurse

"Largest $Top files:"
$files | Sort-Object Length -Descending | Select-Object -First $Top |
    Format-Table Name, @{ Name = "SizeKB"; Expression = { [math]::Round($_.Length / 1KB, 1) } }

$byExt = $files | Group-Object Extension | ForEach-Object {
    [pscustomobject]@{
        Extension = if ($_.Name) { $_.Name } else { "(none)" }
        Files     = $_.Count
        TotalMB   = [math]::Round(($_.Group | Measure-Object Length -Sum).Sum / 1MB, 2)
    }
} | Sort-Object TotalMB -Descending

$byExt | Format-Table
$byExt | Export-Csv -Path "usage.csv" -NoTypeInformation
"Report saved to usage.csv"
pwsh ./report.ps1 -Path ~/Documents -Top 3

次に学ぶこと

  • Microsoft Learnにある「PowerShell 101」とPowerShellのドキュメント。
  • シェル内のGet-Help about_*。たとえばGet-Help about_Operatorsのように使います。先にUpdate-Helpを実行してください。
  • PowerShell Gallery。モジュールの公式リポジトリで、Install-Moduleと組み合わせて使います。
  • PSScriptAnalyzer。推奨されるプラクティスに沿っているかどうかをスクリプトで検査するリンターです。

よくある質問

PowerShellとWindows PowerShellの違いは何ですか?

Windows PowerShell 5.1はWindowsに組み込まれている旧エディションで、.NET Frameworkをベースにしています。PowerShell 7以降はクロスプラットフォームのオープンソース版で、最新の.NETをベースにしており、pwshコマンドで起動します。

PowerShellはコマンドプロンプトと同じものですか?

いいえ。コマンドプロンプト(cmd.exe)はバッチコマンドを実行し、テキストを受け渡します。PowerShellはオブジェクトを受け渡す本格的なスクリプト言語で、ほとんどのコマンドラインプログラムも実行できます。

PowerShellはLinuxやmacOSでも動きますか?

はい。PowerShell 7以降はWindows、Linux、macOSで動作します。ただし、Windows専用のモジュールの一部はWindowsでしか使えません。

.ps1スクリプトが実行できないのはなぜですか?

Windowsの実行ポリシーでブロックされている可能性があります。Set-ExecutionPolicy -Scope CurrentUser RemoteSignedを実行し、スクリプトは./script.ps1のようにパスを付けて起動してください。

PowerShellの$_は何を意味しますか?

$_($PSItemも同じ)は、パイプラインを流れてきた現在のオブジェクトです。Where-ObjectやForEach-Objectなどのスクリプトブロックの中で使い、catchの中では現在のエラーを指します。

コーディング講座の一覧