PowerShell v3 以降のそれぞれのバージョン毎のスクリプティングを中心とした新機能のうち、私の独断で選んだ主な機能を列挙しました。
(PowerShell の本来の役割のはずの) コンピュータ管理機能などはばっさり省いています。
ハッシュテーブル を、 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]
属性ををつけることで、 ハッシュテーブル の代わりに 順序付けされたディクショナリ ([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.
# 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 変数が展開されない
$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 プロパティ が使用できないという、意図のよくわからない制限がある。
#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 的な何か
- バックグラウンドジョブ
など
インスタンスメソッド:
$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 -RunAsAdministrator
Get-FileHash
など
- DSC
- Configuration as Code 的な何か
など
#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# のクラスの機能に近い。
#Requires -Version 5
using namespace System.Collections.Generic;
New-Object List[int];
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 や 「プログラムと機能」 を透過的に扱うためのもの
- 管理機能いっぱい
など
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 強化
- モジュールバージョンの指定
- パイプライン速度の向上
Windows, Linux, OS X のクロスプラットフォーム でリリースされている。 https://github.com/PowerShell/PowerShell
.NET Core 上に構築されているため、 使用できる .NET の機能も .NET Core のものになるので注意。
この内容を PowerShell バージョンごとのスクリプティング機能の新機能概略 | Aqua Ware つぶやきブログ の記事にしました。