334 lines
11 KiB
Markdown
334 lines
11 KiB
Markdown
---
|
||
applyTo: '**/*.ps1,**/*.psm1'
|
||
description: 'Microsoftガイドラインに基づくPowerShellコマンドレットとスクリプトのベストプラクティス'
|
||
---
|
||
|
||
# PowerShellコマンドレット開発ガイドライン
|
||
|
||
このガイドは、GitHub Copilotが慣用的で安全で保守可能なスクリプトを生成するのに役立つPowerShell固有の指示を提供します。MicrosoftのPowerShellコマンドレット開発ガイドラインと整合性を保っています。
|
||
|
||
## 命名規則
|
||
|
||
- **動詞-名詞形式:**
|
||
- 承認されたPowerShell動詞を使用する(Get-Verb)
|
||
- 単数形の名詞を使用する
|
||
- 動詞と名詞の両方にPascalCaseを使用する
|
||
- 特殊文字とスペースを避ける
|
||
|
||
- **パラメーター名:**
|
||
- PascalCaseを使用する
|
||
- 明確で説明的な名前を選択する
|
||
- 常に複数でない限り単数形を使用する
|
||
- PowerShell標準名に従う
|
||
|
||
- **変数名:**
|
||
- パブリック変数にはPascalCaseを使用する
|
||
- プライベート変数にはcamelCaseを使用する
|
||
- 省略形を避ける
|
||
- 意味のある名前を使用する
|
||
|
||
- **エイリアスの回避:**
|
||
- 完全なコマンドレット名を使用する
|
||
- スクリプトでエイリアスを使用しない(例:gciの代わりにGet-ChildItemを使用)
|
||
- カスタムエイリアスを文書化する
|
||
- 完全なパラメーター名を使用する
|
||
|
||
### 例
|
||
|
||
```powershell
|
||
function Get-UserProfile {
|
||
[CmdletBinding()]
|
||
param(
|
||
[Parameter(Mandatory)]
|
||
[string]$Username,
|
||
|
||
[Parameter()]
|
||
[ValidateSet('Basic', 'Detailed')]
|
||
[string]$ProfileType = 'Basic'
|
||
)
|
||
|
||
process {
|
||
# ロジックをここに記述
|
||
}
|
||
}
|
||
```
|
||
|
||
## パラメーター設計
|
||
|
||
- **標準パラメーター:**
|
||
- 共通パラメーター名を使用する(`Path`、`Name`、`Force`)
|
||
- 組み込みコマンドレット規約に従う
|
||
- 専門用語にはエイリアスを使用する
|
||
- パラメーターの目的を文書化する
|
||
|
||
- **パラメーター名:**
|
||
- 常に複数でない限り単数形を使用する
|
||
- 明確で説明的な名前を選択する
|
||
- PowerShell規約に従う
|
||
- PascalCase形式を使用する
|
||
|
||
- **型選択:**
|
||
- 一般的な.NET型を使用する
|
||
- 適切な検証を実装する
|
||
- 限定されたオプションにはValidateSetを検討する
|
||
- 可能な場合はタブ補完を有効にする
|
||
|
||
- **スイッチパラメーター:**
|
||
- ブール型フラグには[switch]を使用する
|
||
- $true/$falseパラメーターを避ける
|
||
- 省略時はデフォルトで$falseとする
|
||
- 明確なアクション名を使用する
|
||
|
||
### 例
|
||
|
||
```powershell
|
||
function Set-ResourceConfiguration {
|
||
[CmdletBinding()]
|
||
param(
|
||
[Parameter(Mandatory)]
|
||
[string]$Name,
|
||
|
||
[Parameter()]
|
||
[ValidateSet('Dev', 'Test', 'Prod')]
|
||
[string]$Environment = 'Dev',
|
||
|
||
[Parameter()]
|
||
[switch]$Force,
|
||
|
||
[Parameter()]
|
||
[ValidateNotNullOrEmpty()]
|
||
[string[]]$Tags
|
||
)
|
||
|
||
process {
|
||
# ロジックをここに記述
|
||
}
|
||
}
|
||
```
|
||
|
||
## パイプラインと出力
|
||
|
||
- **パイプライン入力:**
|
||
- 直接オブジェクト入力には`ValueFromPipeline`を使用する
|
||
- プロパティマッピングには`ValueFromPipelineByPropertyName`を使用する
|
||
- パイプライン処理にはBegin/Process/Endブロックを実装する
|
||
- パイプライン入力要件を文書化する
|
||
|
||
- **出力オブジェクト:**
|
||
- フォーマットされたテキストではなくリッチオブジェクトを返す
|
||
- 構造化データにはPSCustomObjectを使用する
|
||
- データ出力にWrite-Hostを避ける
|
||
- 下流コマンドレット処理を有効にする
|
||
|
||
- **パイプラインストリーミング:**
|
||
- 一度に一つのオブジェクトを出力する
|
||
- ストリーミングにはprocessブロックを使用する
|
||
- 大きな配列の収集を避ける
|
||
- 即座の処理を有効にする
|
||
|
||
- **PassThruパターン:**
|
||
- アクションコマンドレットではデフォルトで出力なしとする
|
||
- オブジェクトリターンには`-PassThru`スイッチを実装する
|
||
- `-PassThru`で変更/作成されたオブジェクトを返す
|
||
- ステータス更新にはverbose/warningを使用する
|
||
|
||
### 例
|
||
|
||
```powershell
|
||
function Update-ResourceStatus {
|
||
[CmdletBinding()]
|
||
param(
|
||
[Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
|
||
[string]$Name,
|
||
|
||
[Parameter(Mandatory)]
|
||
[ValidateSet('Active', 'Inactive', 'Maintenance')]
|
||
[string]$Status,
|
||
|
||
[Parameter()]
|
||
[switch]$PassThru
|
||
)
|
||
|
||
begin {
|
||
Write-Verbose "リソースステータス更新プロセスを開始します"
|
||
$timestamp = Get-Date
|
||
}
|
||
|
||
process {
|
||
# 各リソースを個別に処理
|
||
Write-Verbose "リソースを処理中: $Name"
|
||
|
||
$resource = [PSCustomObject]@{
|
||
Name = $Name
|
||
Status = $Status
|
||
LastUpdated = $timestamp
|
||
UpdatedBy = $env:USERNAME
|
||
}
|
||
|
||
# PassThruが指定された場合のみ出力
|
||
if ($PassThru) {
|
||
Write-Output $resource
|
||
}
|
||
}
|
||
|
||
end {
|
||
Write-Verbose "リソースステータス更新プロセスが完了しました"
|
||
}
|
||
}
|
||
```
|
||
|
||
## エラーハンドリングと安全性
|
||
|
||
- **ShouldProcess実装:**
|
||
- `[CmdletBinding(SupportsShouldProcess = $true)]`を使用する
|
||
- 適切な`ConfirmImpact`レベルを設定する
|
||
- システム変更には`$PSCmdlet.ShouldProcess()`を呼び出す
|
||
- 追加確認には`ShouldContinue()`を使用する
|
||
|
||
- **メッセージストリーム:**
|
||
- `-Verbose`での操作詳細には`Write-Verbose`
|
||
- 警告条件には`Write-Warning`
|
||
- 非終了エラーには`Write-Error`
|
||
- 終了エラーには`throw`
|
||
- ユーザーインターフェーステキスト以外では`Write-Host`を避ける
|
||
|
||
- **エラーハンドリングパターン:**
|
||
- エラー管理にはtry/catchブロックを使用する
|
||
- 適切なErrorAction設定を設定する
|
||
- 意味のあるエラーメッセージを返す
|
||
- 必要に応じてErrorVariableを使用する
|
||
- 適切な終了vs非終了エラーハンドリングを含める
|
||
|
||
- **非対話型設計:**
|
||
- パラメーター経由で入力を受け入れる
|
||
- スクリプトで`Read-Host`を避ける
|
||
- 自動化シナリオをサポートする
|
||
- すべての必要な入力を文書化する
|
||
|
||
### 例
|
||
|
||
```powershell
|
||
function Remove-UserAccount {
|
||
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
|
||
param(
|
||
[Parameter(Mandatory, ValueFromPipeline)]
|
||
[ValidateNotNullOrEmpty()]
|
||
[string]$Username,
|
||
|
||
[Parameter()]
|
||
[switch]$Force
|
||
)
|
||
|
||
begin {
|
||
Write-Verbose "ユーザーアカウント削除プロセスを開始します"
|
||
$ErrorActionPreference = 'Stop'
|
||
}
|
||
|
||
process {
|
||
try {
|
||
# 検証
|
||
if (-not (Test-UserExists -Username $Username)) {
|
||
Write-Error "ユーザーアカウント '$Username' が見つかりません"
|
||
return
|
||
}
|
||
|
||
# 確認
|
||
$shouldProcessMessage = "ユーザーアカウント '$Username' を削除"
|
||
if ($Force -or $PSCmdlet.ShouldProcess($Username, $shouldProcessMessage)) {
|
||
Write-Verbose "ユーザーアカウントを削除中: $Username"
|
||
|
||
# メイン操作
|
||
Remove-ADUser -Identity $Username -ErrorAction Stop
|
||
Write-Warning "ユーザーアカウント '$Username' が削除されました"
|
||
}
|
||
}
|
||
catch [Microsoft.ActiveDirectory.Management.ADException] {
|
||
Write-Error "Active Directoryエラー: $_"
|
||
throw
|
||
}
|
||
catch {
|
||
Write-Error "ユーザーアカウント削除の予期しないエラー: $_"
|
||
throw
|
||
}
|
||
}
|
||
|
||
end {
|
||
Write-Verbose "ユーザーアカウント削除プロセスが完了しました"
|
||
}
|
||
}
|
||
```
|
||
|
||
## ドキュメントとスタイル
|
||
|
||
- **コメントベースヘルプ:** パブリック向けの関数またはコマンドレットにはコメントベースヘルプを含める。関数内に`<# ... #>`ヘルプコメントを追加し、少なくとも以下を含める:
|
||
- `.SYNOPSIS` 簡潔な説明
|
||
- `.DESCRIPTION` 詳細な説明
|
||
- `.EXAMPLE` 実用的な使用法のセクション
|
||
- `.PARAMETER` 説明
|
||
- `.OUTPUTS` 返される出力の型
|
||
- `.NOTES` 追加情報
|
||
|
||
- **一貫したフォーマット:**
|
||
- 一貫したPowerShellスタイルに従う
|
||
- 適切なインデント(4スペース推奨)を使用する
|
||
- 文と同じ行に開始中括弧を配置
|
||
- 新しい行に終了中括弧を配置
|
||
- パイプライン演算子の後に改行を使用
|
||
- 関数とパラメーター名にPascalCaseを使用
|
||
- 不要な空白を避ける
|
||
|
||
- **パイプラインサポート:**
|
||
- パイプライン関数にはBegin/Process/Endブロックを実装する
|
||
- 適切な場合はValueFromPipelineを使用する
|
||
- プロパティ名によるパイプライン入力をサポートする
|
||
- フォーマットされたテキストではなく適切なオブジェクトを返す
|
||
|
||
- **エイリアスを避ける:** 完全なコマンドレット名とパラメーターを使用する
|
||
- スクリプトでエイリアスを使用しない(例:gciの代わりにGet-ChildItemを使用);エイリアスは対話型シェル使用では許可される。
|
||
- `?`や`where`の代わりに`Where-Object`を使用
|
||
- `%`の代わりに`ForEach-Object`を使用
|
||
- `ls`や`dir`の代わりに`Get-ChildItem`を使用
|
||
|
||
## 完全な例:エンドツーエンドコマンドレットパターン
|
||
|
||
```powershell
|
||
function New-Resource {
|
||
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
|
||
param(
|
||
[Parameter(Mandatory = $true,
|
||
ValueFromPipeline = $true,
|
||
ValueFromPipelineByPropertyName = $true)]
|
||
[ValidateNotNullOrEmpty()]
|
||
[string]$Name,
|
||
|
||
[Parameter()]
|
||
[ValidateSet('Development', 'Production')]
|
||
[string]$Environment = 'Development'
|
||
)
|
||
|
||
begin {
|
||
Write-Verbose "リソース作成プロセスを開始します"
|
||
}
|
||
|
||
process {
|
||
try {
|
||
if ($PSCmdlet.ShouldProcess($Name, "新しいリソースを作成")) {
|
||
# リソース作成ロジックをここに記述
|
||
Write-Output ([PSCustomObject]@{
|
||
Name = $Name
|
||
Environment = $Environment
|
||
Created = Get-Date
|
||
})
|
||
}
|
||
}
|
||
catch {
|
||
Write-Error "リソース作成に失敗しました: $_"
|
||
}
|
||
}
|
||
|
||
end {
|
||
Write-Verbose "リソース作成プロセスが完了しました"
|
||
}
|
||
}
|
||
```
|