マイクロソフト系技術情報 Wiki」は、「Open棟梁Project」,「OSSコンソーシアム .NET開発基盤部会」によって運営されています。

目次

概要

PowerShell の勘所、 .ps1ファイルと実行ポリシー、param、debugの方法、関数、パイプライン、オブジェクトへプロパティの追加、エラー処理、cmdletの作り方、などのトピック情報を纏めています。

特徴

オブジェクトベースのシェル

以前から、オブジェクトベースのプログラム、スクリプト(perl、WSH)などは存在したが、
PowerShellが唯一のオブジェクト・ベースのシェル(perlに似ている)である。
#OSレイヤから少々遠いためシェルというよりシェルスクリプトという意見もある。

PowerShell コンポーネントのダウンロード

PowerShell の各バージョンは、以下のOSに添付されているか、別途ダウンロードできます。
新しいOSほど、新しいPowerShellに対応します。 また、旧OSでは、新しいPowerShellのサポートがありません。 PowerShellのバージョンに依存しそうな場合は、対象とするOSが何か確認ください。

--Windows PC--PowerShell 1.0PowerShell 2.0PowerShell 3.0PowerShell 4.0
Windows XP SP2PS1n/an/a
Windows XP SP3PS1PS2n/an/a
Windows Vista SP1PS1PS2n/an/a
Windows Vista SP2PS1PS2n/an/a
Windows 7OS添付n/an/a
Windows 7 SP1OS添付PS3PS4
Windows 8OS添付(*1)OS添付PS4
Windows 8.1OS添付(*1)OS添付

(*1) Windows 8/8.1 の PowerShell 2.0 スクリプトは、PowerShell 4.0 の下位互換で実行できます。 PowerShell を -version 2.0 指定で実行する場合は .NET Framework 3.5 をインストールすると有効になります。

--Windows Server--PowerShell 1.0PowerShell 2.0PowerShell 3.0PowerShell 4.0
Windows Server 2003R2PS1n/an/a
Windows Server 2003 SP2PS1PS2n/an/a
Windows Server 2008 SP1OS添付PS2PS3n/a
Windows Server 2008 SP2OS添付PS2PS3n/a
Windows Server 2008R2 SP1OS添付PS3PS4
Windows Server 2012OS添付(*1)OS添付PS4
Windows Server 2012 R2OS添付(*1)OS添付

(*1) Windows Server 2012/2012R2 の PowerShell 2.0 スクリプトは、PowerShell 4.0 の下位互換で実行できます。 PowerShell を -version 2.0 指定で実行する場合は .NET Framework 3.5 をインストールすると有効になります。

PowerShellの勘所

PowerShell の実行方法

スタートメニューからPowerShell コマンドプロンプトを開いても、 コマンドプロンプトから PowerShell.exe を実行しても、 PowerShell を手で逐次実行できます。

.ps1ファイルと実行ポリシー

PowerShell の スクリプトファイルは、 拡張子 .ps1 のテキストファイル です。
ps1スクリプトファイルは、コマンドプロンプトの中で「powershell .\script.ps1」、または、PowerShellコマンドプロンプトの中で「.\script.ps1」の様にして実行できますが、既定では、PowerShell スクリプト そのものについて、実行が抑止されています。

.ps1を実行するには、以下の設定変更または回避方法を検討します。

実行ポリシーを変更

実行ポリシーを変更するには、 Set-ExecutionPolicy? を実行します。

Set-ExecutionPolicy RemoteSigned

RemoteSigned? を指定すると、ローカルコンピュータの.ps1ファイルか、ファイル共有またはダウンロードした署名付きの.ps1ファイルが実行できます。
Set-ExecutionPolicy? の設定は、恒久的に設定されます。
Bypass (=無制限に.ps1を実行可能) に変更してそのまま放置しないように。

用が済んだら、既定値の Restricted に戻しておきます。

Set-ExecutionPolicy Restricted

scope を指定して、設定変更の対象を限定することもできます。

Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

CurrentUser? はこのコマンドを実行したユーザーだけ、設定変更します。

(メンテナンスや運用作業で.ps1を使用する場合は、通常時にどの実行ポリシーにしておくか、検討ください。.ps1ファイルに署名を行い、AllSigned? にしておくか。 あるいは RemoteSigned? にしておくか。 それとも Restricted にしておき、都度実行ポリシーを変更するか。等)

PowerShell -Command - 構文でスクリプトを読み込ませる

PowerShell コマンドプロンプトに手入力して逐次実行するかわりに、 -Command - を使用して、標準入力からコマンドを連続実行することができます。
手打ちと同じなので、 Set-ExecutionPolicy? Restricted のままでも、実行可能です。
実行ポリシーをどうしても変更したくない場合の次善策として、使用できるか検討する意味は有ります。
下の例の様に、 batファイルとecho を組み合わせて、引数を与えることも出来ます。

batファイル : ps_test.bat

@( echo $arg1 = "%~1"
   echo $arg2 = "%~2"
   type ps_test.ps1 ) | powershell -command -

ps1ファイル : ps_test.ps1

function main() {
 $a = ($arg1 + $arg2)
 $b = ([int]$arg1 + [int]$arg2)
 write-output "string : $arg1 + $arg2 = $a"
 write-output "integer : $arg1 + $arg2 = $b"
}

$err=0
$ErrorActionPreference = "stop"
try {
  $log = main
} catch [Exception] {
  $err=1
  $log = $_
}

write-output $log
exit $err

実行例: ps_test 1 2

string : 1 + 2 = 12
integer : 1 + 2 = 3

.ps1 の try/catch の } の下に空行がることに注意。
powershellコマンドを -Command - で読み込ませる場合、手入力と同じように。コードブロックの後に空行が必要です。

これを実行すると、echo の2つが ps_test.ps1 の先頭に挿入されて、 PowerShellコマンドプロンプトに手入力して逐次実行することになります。

標準入力を手入力の代わりに使用してしまうため、スクリプトのなかでキー打鍵待ちのようなことは難しくなります。

PowerShellコマンドプロンプトの中に貼り付ける~

PowerShellコマンドプロンプトの画面に、クリップボードからスクリプトを貼り付けます。
スクリプトは、テキストファイルなどで用意しておき、メモ帳などで開いたら、テキスト全体をクリップボードにコピー。それを、PowerShetll?コマンドプロンプトに貼り付けます。
実行ポリシーを変更しない、上のようなバッチファイルも不可であれば、手動でPowerShellコマンドプロンプトへ貼り付けをするか、PowerShellの使用をあきらめるしかありません。

ps1スクリプトへの引数

ps1ファイルの最初に param(..) を記述することで、引数を定義出来ます。

 param (
   [string]$filename,
   [int]$count = 5
 )

[型] と引数名、 省略時の既定値 も指定できます。
引数名を定義すると 「powersehll .\test.ps1 -filename c:\temp\testt.txt -count 2」の様に -引数名 として使用できます。

下の様に 引数名に 属性を付加することも出来ます。

 param (
   [Parameter(Mandatory=$True)]
   [string]$filename,

   [int]$count = 5
 )

Mandatory を指定すると、必須の引数になり、省略した場合には、PowerShellによって、追加の引数を要求するプロンプトが表示されます。

詳細は、下のページを参照。

または、PowerShellコマンドプロンプト内で、「get-help about_Functions_Advanced_Parameters」を参照してください。

変数

変数は $ で始まる 英数字記号 の名前を使用します。
後述の様に スコープ($global:, $script:) をつけることも出来ます。

下の様に ${ } で囲むと、名前にスペースを含むこともできますが、混乱やスペルミスの元になりやすいので避けましょう。

 PS E:\temp> ${var test 1} = 123
 PS E:\temp> $a = ${var test 1} + "123"
 PS E:\temp> $a
 246
 PS E:\temp>

未初期化の初期状態は $null と同じです。
文脈によっては 0 や "" (空文字列) と解釈されます。

 PS E:\temp> $var001
 PS E:\temp> $var001 -eq 0
 False
 PS E:\temp> $var001 -eq $null
 True
 PS E:\temp> $a1 = $var001 + 2
 PS E:\temp> $a1
 2
 PS E:\temp> $a1 = $var001 + "abc"
 PS E:\temp> $a1
 abc
 PS E:\temp>

上の例では、変数 $var001 は未初期化なので、 $null と同じです。
変数をそのまま出力すると、$null は 何も表示されません。
また、 -eq 比較演算子を使って、 0 や $null と比較すると、$null であることが判断できます。

未初期化変数は、数値を足し算した場合は、0 が、文字列を連結した場合は、"" が、それぞれ仮定されます。

Set-StrictMode? を使用すると、未初期化変数を参照する際にエラーとして検出できます。

 PS E:\temp> Set-StrictMode -Version 1.0
 PS E:\temp> $a1 = $var001 + 2
 変数 '$var001' は、設定されていないために取得できません。
 発生場所 行:1 文字:14
 + $a1 = $var001 <<<<  + 2
     + CategoryInfo          : InvalidOperation: (var001:Token) []、RuntimeExcep
     tion
     + FullyQualifiedErrorId : VariableIsUndefined
 
 PS E:\temp>

変数については、下も参照ください。

Set-StrictMode? については、 「get-help Set-StrictMode?」、 または、下のページを参照ください。

変数のスコープ

PowerShellの変数は、変数を使用する場所がスコープの範囲になります。
functionの中、PowerShellモジュールの中、.ps1スクリプトの中、などがスコープの境界になります。

スクリプト: ps_scope1.ps1

 $global:g1 = "0"
 $script:s1 = "0"
 $v1 = "0"
 
 write-host "before      : g1=$global:g1 s1=$script:s1 v1=$v1 v2=$v2"
 
 function test1 {
   write-host "start test1 : g1=$global:g1 s1=$script:s1 v1=$v1 v2=$v2"
   $global:g1 = "1"
   $script:s1 = "1"
   $v1 = "1"
   $v2 = "1"
   write-host "end test1   : g1=$global:g1 s1=$script:s1 v1=$v1 v2=$v2"
 }
 
 test1
 
 write-host "after       : g1=$global:g1 s1=$script:s1 v1=$v1 v2=$v2"

実行例:

 E:\temp>powershell
 Windows PowerShell
 Copyright (C) 2009 Microsoft Corporation. All rights reserved.
 
 PS E:\temp> Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

 PS E:\temp> .\ps_scope1.ps1
 before      : g1=0 s1=0 v1=0 v2=
 start test1 : g1=0 s1=0 v1=0 v2=
 end test1   : g1=1 s1=1 v1=1 v2=1
 after       : g1=1 s1=1 v1=0 v2=

 PS E:\temp> write-host "g1=$global:g1 s1=$script:s1 v1=$v1 v2=$v2"
 g1=1 s1= v1= v2=

 PS E:\temp>

$v1 は .ps1 の中で最初に設定している値が、 関数test1 の中でも参照できますが、関数test1 の中で設定した値は、関数test1 の外では有効ではありません。
$v2 は .ps1 の中で未定義のため、 関数test1 の中でのみ有効。
$script:s1 $v1 $v2 とも、 .ps1 の中だけで有効なため、 スクリプトを終了した後で write-host しても値は設定されていない。
$global:g1 は スコープがグローバルなので、スクリプトを終了しや後で write-host しても値は設定されたまま。

通常は、.ps1の中でスコープが閉じると考えておき、 .ps1の中から write-output 以外の方法でスクリプト呼び出し元へ返す情報がある場合に、$global: を使用するか検討するのがいいでしょう。
あとは、.ps1 の中に限らず、関数間で共有の変数の場合、$script: を使用すると考えておけばいいでしょう。

変数のスコープは、「get-help about_Scopes」、または、下の情報も参考。

if文

if文は、下の様に -で始まる比較演算子を使います。

 $var1 = sub2 $arg1 $arg2
 if ( ( $var1 -eq 1 ) -or ( $var1 -gt 10 ) ) {
    ...
 }

条件のANDやORは、 それぞれを ( ... )で囲んで -and や -or で結びます。

論理のANDやORによるビット演算は、 -band や -bor の -b で始まる演算子を使います。

 $file = get-item $dirname
 if ( $file.Attributes -band [System.IO.FileAttributes]::Directory ) {
    ...
 }

bit演算結果が0以外の場合は、真 とみなされます。

if文の演算子の詳細は、powershellコマンドプロンプトの中で 「get-help about_Comparison_Operators」を参照してください。

配列

配列は、以下の形式で定義できます。

$array1 = @()
$array2 = @(1,2,3)
$array3 = 1,2,3

( ) で囲まなくても、「,」で並べると、配列になります。
コマンドや関数への引数を「,」で区切った場合も配列になるので、書き間違いに注意。

 $ret1 = sub1 2,3,4    # これは @(2,3,4) の配列で引数1つ
 $ret2 = sub1 2 3 4    # これは 引数3つ
 $ret3 = sub1 2,3 4    # これは @(2,3)の配列1つと 数値4 の 引数2つ

また、配列の添え字は、$変数名[添え字] で参照します。
添え字に 負数 を指定すると、配列の末尾からの添え字を指定できます。

 $var1 = $array2[1]   # 上の $array2 から 2 を取り出す
 $var2 = $array2[-1]  # 上の $array2 から 3 を取り出す

配列について詳しくは、 PowerShellコマンドプロンプトで「get-help about_array」 を参照ください。

PowerShellパイプライン

PowerShellの一番強力な機能が、パイプラインです。

Unix/Linuxのshellコマンドや、Windowsのコマンドプロンプトでも、「|」を使って、コマンドを複数並べてパイプラインが記述できます。
ですが、それらは、標準出力のテキストを次のコマンドの標準入力へ渡す、にすぎません。

PowerShellでは、PowerShellのオブジェクトをパイプで渡すことができます。
そして、ほとんどのPowerShellコマンドがオブジェクトを出力します。
また、オブジェクトには、多くのプロパティを含んでいます。
後処理のために、オブジェクトにプロパティを追加することもできます。
このため、プロパティを判定してフィルタしたり、プロパティを使ってソートできます。
最後に Format-List や Format-Table などのコマンドを使って、一部のプロパティを整形して表示します。

.ps1スクリプト内で定義する関数(function)や、自作のCmdletでも、オブジェクトを返すようにしておくと、再利用しやすくなります。

パイプラインの例は、後述の オブジェクトへメンバー追加 の例を参照ください。

パイプラインの詳細は、PowerShellコマンドプロンプトで「get-help about_pipeline」を参照ください。

オブジェクトへメンバー追加

PowerShellでは、Add-Member を使って、オブジェクトに動的にメンバーを追加できます。
OSや他のライブラリが返したオブジェクトに、情報を追加しながら、PowerShellパイプラインを使って、順次処理する。といったことができます。

function dirinfo {
  param(
   [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
   [object]$dir,

   [boolean]$totalup = $false 
  )

  # 空っぽの配列
  $dirs = @()

  # $dir へ プロパティ追加
  $dir | Add-Member -MemberType NoteProperty -Name TotalFiles -Value 0
  $dir | Add-Member -MemberType NoteProperty -Name TotalSize -Value 0

  foreach ($f in (get-childitem $dir.FullName)) {
    if ( $f.Attributes -band [System.IO.FileAttributes]::Directory ) {
      # サブフォルダの情報
      $ret = dirinfo $f $totalup
      if ( $totalup ) {
        # 末尾の情報を $dir へ加算
        $dir.TotalFiles += $ret[-1].TotalFiles
        $dir.TotalSize += $ret[-1].TotalSize
      }
      $dirs += $ret   # サブフォルダ全体を覚える
    } else {
      $dir.TotalFiles += 1
      $dir.TotalSize += $f.Length
      $dirs += $f
    }
  }
  $dirs += $dir   # $dir自身を末尾に覚える

  # 覚えたものをまとめて返す
  write-output $dirs
}

実行例:

  dirinfo (get-item "c:\program files") | sort-object totalsize -Descending | 
      where { $_.TotalSize -gt 1 } | select-object -first 5 | 
      format-list -Property TotalFiles, TotalSize, Fullname
  (行は折り返して表示しています。実行する際は、1行に入力してください。)

実行例のPowerShellパイプラインでは、以下のことをしています

  1. get-item で C:\Program Files フォルダのオブジェクトを取得して、
  2. dirinfo でサブフォルダのサイズを集計、
  3. sort-obejct で TotalSize? の大きい順に並び替えて、
  4. where で TotalSize? が 1以上のオブジェクトだけ抽出して、
  5. select-object で 最初の 5 個だけ取り出し、
  6. format-list で 特定のプロパティのみ表示。

Add-Member の解説については、下も参照ください。

サブフォルダのファイルサイズを集計する例については、下も参照ください。

リモートコンピューターでコマンド実行 (Workgroup編)

Invoke-Command を使って、リモートでコマンド実行ができます。
ただし、事前に構成を変更しておく必要があります。また、実行する要件によっては追加の構成が必要です。

 解放しすぎる場合は(任意のIPアドレスで..など)、範囲を調整する必要があるか、検討ください。
 リモートから実行の可否を制御するには、ユーザーと権限(後述)、または、ファイルウォール例外("Windows リモート管理 (HTTP 受信)")のスコープ設定で行います。

2. PowerShellリモート処理可能なユーザーと権限の設定

Set-PSSessionConfiguration Microsoft.Powershell -ShowSecurityDescriptorUI

 実行すると権限を設定する画面が表示されるので、リモートから指定するユーザーと権限を追加。
 (Administratorsメンバー以外のユーザーを使用する場合に必要)

リモートコンピューターでコマンド実行 (Workgroup + ダブルホップ編)

上の Workgroup編では、リモートコマンドの中から、他サーバーのリソースにアクセスすると、匿名ユーザーが使用されますが、 下の手順の様に、ダブルホップを使用することで、 -credential で指定するものと同じアカウントで 他サーバーのリソースにアクセスすることができます。

*準備 (上の Workgroup編と共通)

*ダブルホップのための 追加の準備

*ダブルホップを使用した、リモートコマンドの実行

エラー処理

.ps1ファイルの中でエラーが発生すると、既定では、赤文字でエラー表示されて、そのまま次の行が実行されます。
エラーを処理するには、下のいずれか必要です。

try/catch の例は、上の ps_test.ps1 を参照ください。
その他の例、説明は、以下のサイトも参照ください。

PSSnapIn? と module

PowerShell は、 PSSnapin と Module で拡張されます。
Windows の役割を追加すると、役割を管理する Cmdlet が一緒にインストールされます。
また、何らかの製品をインストールした際に、PowerShell Cmdlet が追加でインストールされることもあります。

PowerShellコマンドプロンプトを開いた状態では、それらの追加された Cmdlet はまだ使用できません。
PowerShellコマンドプロンプトの中で、「Add-PSSnapin」あるいは「Import-Module」を使って、読み込みます。

読み込みの際に指定する PSSnapin名、 Module名 は、役割、製品の管理者用ドキュメントを参照してください。

インストールされている module は、 「get-module -listavailable」で確認することができます。

cmdlet の作り方

cmdlet は自分で作成することも出来ます。

PSDrive と プロバイダ

PowerShell の中では、 C: や D: などのドライブの他に、

があり、PowerShell の中では、 cd コマンドを使って カレントドライブを移動したり、 get-childitem AD: の様に、 その他のコマンドで使用することが出来ます。

PowerShellスクリプトの debug

debugは、 debug用print文、 デバッグ用環境、を使ってデバッグできます。

PowerShell ISE は、下の情報を参照ください。

PowerShell ISE でのデバッグ操作の画面例は、下を参照ください。

通常の PowerShellコマンドプロンプトのままでも、Set-PsBreakpoint? 等の debug用のコマンドを使用して、1行ずつステップ実行することも出来ます。

Set-PsBreakpoint? を使ったデバッグ方法は、「about_Debuggers」 および下のページを参照ください。

変数が変更されたときに停止するようにブレークポイントを設定することもできます。手順の例は、下を参照ください。

情報の探し方

その他の情報

#この資料では、PowerShell 3.0 の beta/RC 版をベースにしてるため、 PowerShell 2.0 にはないコマンドも紹介されています。
#ただ、WMIオブジェクトの使い方、リモートや権限などのtipsは、PowerShell 2.0 でも参考になります。


Tags: :Windows, :シェル


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS