PowerShell v3 以降のそれぞれのバージョン毎のスクリプティングを中心とした新機能のうち、私の独断で選んだ主な機能を列挙してみた。
(PowerShell の本来の役割のはずの) コンピュータ管理機能などはばっさり省いている。
意外と、そういう情報まとまっているのを見たことなかったので。。。
v3 から
PSCustomObject の型変換
ハッシュテーブル を、 Key-Value ペアを ノートプロパティ に変換した カスタムオブジェクト に型変換できる。
参考: about_Hash_Tables
# On v2
$t = [PSCustomObject]@{Hoge=1; Fuga=3;};
$t.GetType();
# -> Hashtable
$t.PSObject.Properties | ft
# ->
# Name
# ----
# IsReadOnly
# IsFixedSize
# IsSynchronized
# Keys
# Values
# SyncRoot
# Count
# On v3
#Requires -Version 3
$t = [PSCustomObject]@{Hoge=1; Fuga=3;};
$t.GetType();
# -> PSCustomObject
$t.PSObject.Properties | ft
# ->
# Name
# ----
# Hoge
# Fuga
ordered
ハッシュテーブルリテラル @{}
に [ordered]
属性ををつけることで、 ハッシュテーブル の代わりに 順序付けされたディクショナリ ([System.Collections.Specialized.OrderedDictionary]
) を作成できる。
また、 この順序付けされたディクショナリを [PSCustomObject]
に型変換すると、プロパティ順が維持された状態の カスタムオブジェクト が作成される。
参考: about_Hash_Tables
#Requires -Version 3
$o1 = @{Hoge=0; Fuga=100; Hogera=10000; Piyo=1MB}
$o2 = [ordered]@{Hoge=0; Fuga=100; Hogera=10000; Piyo=1MB}
$o1.GetType()
# -> Hashtable
$o2.GetType()
# -> OrderedDictionary
[PSCustomObject]$o1
# ->
# Hogera Piyo Fuga Hoge
# ------ ---- ---- ----
# 10000 1048576 100 0
[PSCustomObject]$o2
# ->
# Hoge Fuga Hogera Piyo
# ---- ---- ------ ----
# 0 100 10000 1048576
ハッシュテーブルからの任意のオブジェクトの作成
パラメーターを持たないコンストラクター があるクラスに対してのみ、プロパティとプロパティ値のハッシュテーブルからクラスのオブジェクトを作成できる。
オブジェクトのプロパティは、パブリックかつ設定可能である必要がある。
参考: about_Object_Creation
#Requires -Version 3
$p = [System.Diagnostics.Process]::Start(
[System.Diagnostics.ProcessStartInfo]@{
FileName = 'cmd.exe';
Arguments = '/s /c "echo foobar&pause"';
}
);
必要なシチュエーションは限定的と思われるが、 プロパティの設定順が重要な場合は [ordered]
を併用する。
また、 ハッシュテーブルが CaseSensitive であるかどうかにかかわらず、 プロパティ名は IgnoreCase で評価され、 複数のキーがプロパティ名と一致する場合は 複数回プロパティに代入される。
#Requires -Version 3
Add-Type -Language CSharpVersion3 -TypeDefinition @'
public class TestClass {
int _c = 0;
string _pA; private string _pB; private string _pC;
public string PropA { get { return _pA; } set { _pA = value + (_c++).ToString(); } }
public string PropB { get { return _pB; } set { _pB = value + (_c++).ToString(); } }
public string PropC { get { return _pC; } set { _pC = value + (_c++).ToString(); } }
}
'@;
# 各プロパティに格納される順番は順不同
[TestClass]@{PropA='Hoge'; PropB='Fuga'; PropC='Piyo'};
# ->
# PropA PropB PropC
# ----- ----- -----
# Hoge2 Fuga1 Piyo0
# 各プロパティに格納される順番は、ハッシュリテラルに登場した順
[TestClass][ordered]@{PropA='Hoge'; PropB='Fuga'; PropC='Piyo'};
# ->
# PropA PropB PropC
# ----- ----- -----
# Hoge0 Fuga1 Piyo2
# 大文字小文字は無視され、 PropA, PropB, PropC, PropA (上書き) の順番で、各プロパティに設定される
$chash = New-Object System.Collections.Specialized.OrderedDictionary; # CaseSensitive
$chash.PropA='Hoge';
$chash.PropB='Fuga';
$chash.PropC='Piyo';
$chash.propa='FooBar';
[TestClass]$chash;
# ->
# PropA PropB PropC
# ----- ----- -----
# FooBar3 Fuga1 Piyo2
ちなみに、 大文字小文字だけが異なる名前のフィールドやプロパティを含むクラスのオブジェクトは、 そもそも PowerShell で取り扱うことが出来ない。
Add-Type -Language CSharpVersion3 -TypeDefinition @'
public class TestClass2 {
public string PropA { get; set; }
public string PropB { get; set; }
public string PropC { get; set; }
public string propa { get; set; }
}
'@;
New-Object TestClass2;
# -> error: The field or property: "propa" for type: "TestClass2" differs only in letter casing from the field or property: "PropA". The type must be Common Language Specification (CLS) compliant.
Simplified Syntax
# On v2
Get-Process | ? { $_.PM -gt 10MB } | %{ $_.Name }
# On v3
#Requires -Version 3
Get-Process | ? PM -GT 10MB | % Name
ネイティブコマンドエスケープ
#Requires -Version 3
cmd.exe /c echo $home
# -> C:\Users\****
# $home 変数が展開される
cmd.exe --% /c echo $home
# -> $home
# $home 変数が展開されない
Member Enumeration
$array = @("Hoge", "Fuga");
$array.ToUpper();
# On v2 ->
# error
# On v3 ->
# HOGE
# FUGA
$single1, $single2 = "Hoge", 9;
$single1.Length;
$single2.Length;
# On v2 ->
# 4 # String.Length
# $null
# On v3 ->
# 4 # String.Length
# 1 # Arrey でも Enumerable でもなく Length プロパティを持たないものに Length プロパティをつけると、 1 が返される
$single1.Count;
$single2.Count;
# On v2 ->
# $null # String に Count プロパティは存在しない
# $null
# On v3 ->
# 1 # Count プロパティを持たないものに Count プロパティをつけると、 1 が返される
# 1
$single1[0];
$single2[0];
# On v2 ->
# H
# error: System.Int32 のオブジェクトにインデックスを付けることはできません。
# On v3 ->
# H # String 型のインデクサが機能している
# 9 # インデックスを持たないものに [0] 又は [-1] のインデックスをつけると、 オブジェクトそのものが返される
例えば、 Get-ChildItem
などのコマンドレットは、 オブジェクトを 1つ だけ返すか 2つ以上返すかわからず、結果を 変数に入れた際の型が [Object[]]
となるか [System.IO.FileSystemInfo]
となるかわからない。
しかし、この機能を使うと どちらであっても同じように扱うことができる。
#Requires -Version 3
$x = Get-ChildItem; # returns 1 or more objects
for ($i = 0; $i -lt $x.Count; $i++) {
$x[$i];
}
詳しくは、 about_Arrays ヘルプトピックを参照して欲しいところだが、 『0 個または 1 個のオブジェクトを含むコレクションで、Count プロパティと Length プロパティを使用できます。また、1 個のオブジェクトを含む配列にインデックスを付けることもできます。』 と書かれていて説明としては微妙。
https://technet.microsoft.com/ja-jp/library/hh847882.aspx
ただし、 [PSCustomObject]
では この Count プロパティと Length プロパティ が使用できないという、意図のよくわからない制限がある。
Set-StrictMode -Version 3.0 による 配列の境界外へのアクセスチェック
#Requires -Version 3
Set-StrictMode -Version 2.0;
@(1,2,3)[3];
# -> $null
Set-StrictMode -Version 3.0;
@(1,2,3)[3];
# -> error: Index was outside the bounds of the array.
ハッシュテーブル を デシリアライズ した場合の挙動の変更
v2 では ハッシュテーブル をデシリアライズした場合に常に 大文字と小文字を区別する デフォルトの ハッシュテーブル となるが、 v3 では キーに重複がない場合は 大文字と小文字を区別しない ハッシュテーブル となる。
$a1 = @{}; # Key は CurrentCultureIgnoreCase される
$b1 = New-Object hashtable; # Key は CaseSensitive される
$a1['a'] = 1;
$a1['A'] = 2;
$b1['a'] = 1;
$b1['A'] = 2;
$a1;
# ->
# Name Value
# ---- -----
# a 2
[hashtable].GetProperty('EqualityComparer', [System.Reflection.BindingFlags]'Instance, NonPublic').GetValue($a1, $null);
# -> System.CultureAwareComparer
$b1;
# ->
# Name Value
# ---- -----
# A 2
# a 1
[hashtable].GetProperty('EqualityComparer', [System.Reflection.BindingFlags]'Instance, NonPublic').GetValue($b1, $null);
# -> $null
# 一旦シリアライズしてからデシリアライズする
$a1 | Export-Clixml "$env:TEMP\t.xml";
$a2 = Import-Clixml "$env:TEMP\t.xml";
$b1 | Export-Clixml "$env:TEMP\t.xml";
$b2 = Import-Clixml "$env:TEMP\t.xml";
$a2['b'] = 3;
$a2['B'] = 4;
$b2['b'] = 3;
$b2['B'] = 4;
$a2; # v2 では常に CaseSensitive となるのに対して、 v3 では デシリアライズしたキーに重複がなければ CurrentCultureIgnoreCase となる。
# On v2 ->
# Name Value
# ---- -----
# b 3
# B 4
# a 2
#
# On v3 ->
# Name Value
# ---- -----
# a 2
# b 4
[hashtable].GetProperty('EqualityComparer', [System.Reflection.BindingFlags]'Instance, NonPublic').GetValue($a2, $null);
# On v2 ->
# $null
# On v3 ->
# System.CultureAwareComparer
$b2; # デシリアライズしたキーに重複があれば、どちらも CaseSensitive となる。
# ->
# Name Value
# ---- -----
# b 3
# B 4
# a 1
# A 2
[hashtable].GetProperty('EqualityComparer', [System.Reflection.BindingFlags]'Instance, NonPublic').GetValue($b2, $null);
# -> $null
演算子
- 算術演算子
- ビットシフト
-shr
(右シフト) と-shl
(左シフト) の追加
- ビットシフト
- 比較演算子
-in
(-iin
,-cin
),-notin
(-inotin
,-cnotin
) 演算子
コマンドレット
Invoke-RestMethod
Invoke-WebRequest
# Invoke-WebRequest のエイリアスが curl, wget に設定されている。 このため、 curl を呼び出す際などは、 curl.exe と書かないといけない.ConvertFrom-Json
ConvertTo-Json
など
その他
- PS Workflow
- Windows Workflow Foundation 的な何か
- バックグラウンドジョブ
など
v4
Dynamic Method
インスタンスメソッド:
$object = $PWD;
$prop = "Path";
$method = "GetType";
$object.$prop;
# -> C:\Users\****
# # プロパティについては、 v2 の頃から使えていた
$object.$method();
# On v3 ->
# error
# On v4 ->
# IsPublic IsSerial Name BaseType
# -------- -------- ---- --------
# True False PathInfo System.Object
# 以下の様な記述であれば、 v2 の頃から使えていた
$object.$method.Invoke()
# ->
# IsPublic IsSerial Name BaseType
# -------- -------- ---- --------
# True False PathInfo System.Object
スタティックメソッド:
$type = [System.IO.Path];
$prop = "DirectorySeparatorChar";
$method = "ChangeExtension";
$type::$prop;
# -> \
# # プロパティについては、 v2 の頃から使えていた
$type::$method('hoge.xml', 'json');
# On v3 ->
# error
# On v4 ->
# hoge.json
# 以下の様な記述であれば、 v2 の頃から使えていた
$type::$method.Invoke('hoge.xml', 'json');
# -> hoge.json
メソッド構文でのフィルタリング
パイプするより早いらしい
#Requires -Version 4
$data = 1..1MB
$data.Where({$_ % 250000 -eq 0}).ForEach({ "out: $_" });
# -> 4秒
$data | ?{$_ % 250000 -eq 0} | %{ "out: $_" };
# -> 19秒
#Requires での管理者権限必須化
#Requires -RunAsAdministrator
コマンドレット
Get-FileHash
など
その他
- DSC
- Configuration as Code 的な何か
など
v5
クラス
#Requires -Version 5
class MyClass { [int]Piyo([int]$a) { return $a * $this.Fuga * $this.Hoge } $Fuga = 2; Hidden $Hoge; MyClass() { $this.Hoge = 3 } }
$o = New-Object MyClass; # 又は、 [MyClass]::new()
$o.Piyo(5);
# -> 30
$o
# ->
# Fuga
# ----
# 2
メソッドで値を帰す場合は 戻り値型の指定や return 文が必須だったりと、 PowerShell の関数の感覚からするといろいろ変で、 C# のクラスの機能に近い。
using namespace
#Requires -Version 5
using namespace System.Collections.Generic;
New-Object List[int];
Auto-Generated Example-Driven Parsing
Excel 2013 の フラッシュフィル のような、 変更例の法則をみて いい感じに残りの変換をやってくれる機能
#Requires -Version 5
"Lee Holmes", "Steve Lee", "Jeffrey Snover", "Steve Jobs", "Yukihiro Matsumoto" | Convert-String -Example "Bill Gates=Gates, B.", "John Smith=Smith, J."
# ->
# Holmes, L.
# Lee, S.
# Snover, J.
# Jobs, S.
# Matsumoto, Y.
残念ながら、 現在のところ v6 α には含まれてい模様。
コマンドレット
Set-Clipboard
/Get-Clipboard
Get-Clipboard -Format FileDropList
とすると、クリップボード内のファイルの FileInfo が取得できたり、なかなか便利。
Compress-Archive
/Expand-Archive
Format-Hex
New-Guid
など
その他
- DSC 強化
- デバッグ機能の強化
- PackageManagement
- chocolatey や NuGet や PowerShellGet や 「プログラムと機能」 を透過的に扱うためのもの
- 管理機能いっぱい
など
v5.1 から
コア エディション と デスクトップエディション
https://msdn.microsoft.com/ja-jp/powershell/wmf/5.1/scenarios-features
- デスクトップ エディション
- .NET Framework 上に構築されており、Server Core や Windows Desktop などの Windows の完全エディションで実行する PowerShell のバージョンを対象とするスクリプトおよびモジュールとの互換性を提供します。
- コア エディション
- .NET Core 上に構築されており、Nano Server や Windows IoT などの Windows の縮小エディションで実行する PowerShell のバージョンを対象とするスクリプトおよびモジュールとの互換性を提供します。
その他
- DSC 強化
- モジュールバージョンの指定
- パイプライン速度の向上
v6 (アルファリリース)
OSS & クロスプラットフォーム
Windows, Linux, OS X のクロスプラットフォーム でリリースされている。
https://github.com/PowerShell/PowerShell
.NET Core 上に構築されているため、 使用できる .NET の機能も .NET Core のものになるので注意。
とりあえずこんなところだが、随時追記していきたい。
更新履歴
- 2016-09-01
- 追加
- ハッシュテーブルからの任意のオブジェクトの作成
- ハッシュテーブル を デシリアライズ した場合の挙動の変更
- 追記
- Dynamic Method
- 追加