しばたテックブログ

気分で書いている技術ブログです。

PowerShell Core 6.0 新機能まとめ

基本的には公式ドキュメントの内容をベースに説明が不足している個所を補足してまとめています。
正確な情報が必要な場合は英語版の公式ドキュメントをあたってください。

公式ドキュメント

本エントリを書き始めたときは日本語版はなかったのですが最近できた様です。
ただ、明らかに機械翻訳で日本語が怪しい個所がちらほらあるのでできるだけ英語版を見る方が良いでしょう。

新機能一覧

ここから本題に入ります。
構成は公式ドキュメントとできるだけ近くしましたが微妙に変えています。
また、前回説明している部分に関しては端折っています。

ログ

PowerShell内部のイベント発行システムがETWだけでなく、Linuxではsyslogを、macOSではunified logging systemを使う様になりました。

あくまで内部のログ出力が変わっただけでありGet-EventLogなどのコマンドレットがLinuxやmacOSで使える様になったわけではないのでご注意ください。

ファイルシステム

WindowsだけでなくLinuxやmacOSをサポートしたことにより、ファイルシステムに関する制約や挙動に以下の変更が加えられています。

  • パスセパレーターは/\の両方使えます。(これはWindows PowerShellでもサポートされていますが...)
  • LinuxやmacOSにおいてはXDG Base Directoryの仕様に従う様になっています。
    • CurrentUser*なプロファイルは ~/.config/powershell/ 配下に配置されます。
    • PSReadilneのヒストリーは ~/.local/share/powershell/PSReadline/ConsoleHost_history.txt に配置されます。
    • ユーザーモジュールは ~/.local/share/powershell/Modules に配置されます
  • LinuxやmacOSではWindowsで禁止さえれている文字列(:,など)を含むファイルやディレクトリ名がサポートされます。
  • ファイル操作系のCmdletで-LiteralPathが指定された場合はワイルドカード文字(*など)の展開が抑制されます。
  • Get-ChildItemの挙動がよりUnixのls -R、コマンドプロンプトのdir /Sに近くなりました。
    新しいGet-ChildItemはデフォルトでシンボリックリンクのリンク先を再帰検索しない様になっています。

  • PowerShell Coreでは260文字を超えるパスを使用できるようになっています。(#3960)

大文字と小文字の区別

言語としてのPowerShellは基本的に大文字・小文字を区別しませんが、クロスプラットフォーム化したことによりLinuxやmacOSにおいてはいくかのケースで大文字・小文字が区別されます。

  • パス指定
# Windows : 大文字・小文字は区別されない
PS C:\> Test-Path C:\
True
PS C:\> Test-Path c:\
True

# Linux/Mac : 大文字・小文字は区別される
PS /> Test-Path /var/
True
PS /> Test-Path /Var/
False
  • 環境変数
# Windows : 大文字・小文字は区別されない
PS C:\> $env:HOMEDRIVE
C:
PS C:\> $env:HomeDrive
C:

# Linux/Mac : 大文字・小文字は区別される
PS /> $env:HOME
/home/vagrant
PS /> $env:Home

サイドバイサイドインストールのサポート

PowerShell CoreはポータブルなZipファイルのパッケージを持っており、各バージョンをサイドバイサイドでインストールすることが可能です。

WindowsでMSIインストーラーを使用してインストールした場合は過去バージョンのPowerShell Coreは削除されるインプレースアップデートとなります。

プログラム名の変更

PowerShell Coreのプログラム名がpowershell(.exe)からpwsh(.exe)に変更されました。

細かい話はこちらのエントリをご覧ください。

SSHベースのPowerShellリモート処理

PowerShell Core 6.0から通信の下回りにSSHを使用するリモート接続であるPowerShell Remoting over SSHが導入されました。

細かい話はこちらのエントリをご覧ください。

ちなみに、LinuxやmacOSに対して従来のPSRPによるリモート接続も可能です。

既定のエンコーディングに関して

PowerShell Core 6.0からファイル主力に関わるエンコーディングが見直され、BOMなしUTF-8がデフォルトエンコーディングになりました。

細かい話はこちらのエントリをご覧ください。

&によるバックグラウンドジョブ実行

PowerShell Core 6.0からパイプラインの最後にアンパサンド(&)を付けることでジョブを起動することができる様になりました。

細かい話はこちらのエントリをご覧ください。

Dockerサポート

PowerShell CoreはDocker上でも動作させることが可能です。

Docker Hubに公式なもの・非公式なもの合わせてイメージが公開されており、以下に一例を挙げておきます。

またGitHub上で各種OS用のDcokerfileも公開されています。

セマンティックバージョニング

PowerShell Core 6.0からセマンティックバージョニング 2.0と互換のあるバージョン番号が付く様になりました。
$PSVersionTable.PSVersionの型が従来のSystem.Versionから新しいSystem.Management.Automation.SemanticVersionに変更されています。

# PowerShell 5.1まで
PS C:\> ($PSVersionTable.PSVersion).GetType().FullName
System.Version

# PowerShell 6.0
PS C:\> ($PSVersionTable.PSVersion).GetType().FullName
System.Management.Automation.SemanticVersion

ただし、運用としては厳密にセマンティックバージョニングを適用する気は無く、半年ごとのリリースでマイナーバージョンを上げるものとなっています。 (次のリリースはPowerShell Core 6.1になる予定ですがこれには確実に破壊的変更も含まれるでしょう。この場合セマンティックバージョニングを厳密に適用するならPowerShell Core 7.0にしなければなりません。)
あくまでもバージョニングの体系を互換させるのと、アルファ、ベータリリースに対応するためだけに導入した感じです。

言語機能の更新

Unicode文字のエスケープ (#3958)

発端は#2751のIssueで、新しくUnicode文字をエスケープするための構文が追加されました。

`u{CodePoint}の形式でエスケープすることが可能です。

Write-Host "`u{1F363}  `u{1F37A}"

f:id:stknohg:20180209162834p:plain

(通常のコンソールでは絵文字を表示できないためHyperを使っています)

エスケープキャラクター `e のサポート

ESCをエスケープするために`eがサポートされました。

ConvertTo-Jsonの更新 (#4318)

ConvertTo-Jsonコマンドレットに-EnumsAsStringパラメーターが追加され、列挙型を文字列に変換する機能が追加されました。

# PowerShell 5.1 まで
PS C:\> [System.Management.Automation.ActionPreference]::Ignore | ConvertTo-Json
4

# PowerShell Core 6.0 から
PS C:\> [System.Management.Automation.ActionPreference]::Ignore | ConvertTo-Json -EnumsAsString
"Ignore"

範囲演算子がChar型をサポートする様になりました (#5026)

範囲演算子(..演算子)が拡張され、Int型だけでなくChar型も扱える様になりました。

細かい話はこちらのエントリをご覧ください。

読み取り専用であるべき変数が上書きされてしまう問題が修正されました

おそらく#2400の修正を指していると思われます。

[datetime]$HOME=1

の様な本来であれば上書きされてはいけない変数($HOME)が上書きされない様に変更されています。
(従来のWindows PowerShellでは上記コードで$HOME変数の内容が更新されてしまう。)

ドットソース演算子で読み込んだScript Cmdletの自動変数のスコープが修正されました (#4709)

もとのIssueは#4688

pwsh(.exe) -Fileパラメーターおよび、.演算子からソースを読み込みScript Cmdletを呼び出した際の自動変数(元のIssueでは$PSScriptRoot)が正しく設定されない不具合が修正されています。

-split演算子に'Singleline, Multiline'オプションを同時に指定した際の挙動が改善されました (#4721)

PowerShell 5.1までは-split演算子のオプションにSingleline, Multilineを同時に指定するとパラメーターエラーとなりましたが、PowerShell 6.0ではこの制約が取り除かれました。

もともと内部で使わているC#のRegExクラスではSplitOptions.SinglelineSplitOptions.Multilineが併用可能であり、この制約を取り除いても挙動に問題はないと判断された様です。

PowerShellエンジンの更新

$PSVersionTable でサポートするプロパティが増えました

$PSVersionTableに以下のプロパティが増えました。

  • PSEdition : PowerShellのエディション
  • GitCommitId : ソースのコミットID
  • OS : 実行OS情報
  • Platform : プラットフォーム名

$PSVersionTable から BuildVersion プロパティが削除されました

このBuildVersionプロパティはWindowsのビルドと強く結びついているため廃止され、代わりにGitCommitIdプロパティが導入されています。

$PSVersionTable から ClrVersion プロパティが削除されました

PowerShell Coreの基盤である.NET Coreではこのプロパティの値が意味を成さなくなったため廃止されました。

OSを識別するための自動変数が追加されました

OSを識別するために以下の自動変数が追加されました。

  • $IsWindows : Windowsの場合$True。
  • $IsMacOS : macOSの場合$True。
  • $IsLinux : Linuxの場合$True。

割とそのままですが、内部的には.NET CoreのSystem.Runtime.InteropServices.RuntimeInformationクラスの機能が使われており、

# $IsWindows
[System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform([System.Runtime.InteropServices.OSPlatform]::Windows)

# $IsMacOS
[System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform([System.Runtime.InteropServices.OSPlatform]::OSX)

# $IsLinux
[System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform([System.Runtime.InteropServices.OSPlatform]::Linux)

といったコードと等価になります。

PowerShell起動時のバナーにGitCommitIdが追加されました

こちらは割とそのままで、pwsh(.exe)起動時のバナーにGitCommitId(v6.0.1の部分)が表示される様になりいちいち$PSVersionTableの内容を参照しないでもバージョン確認ができる様に改善されています。

f:id:stknohg:20180209162906p:plain

$PSHOMEディレクトリにJSONの設定ファイルが追加されました

$PSHOMEディレクトリにpowershell.config.jsonというJSONの設定ファイルが配置されPowerShell起動時の設定を記述することが出来る様になりました。

今のところWindowsのみ配置されており、初期状態では、

{"Microsoft.PowerShell:ExecutionPolicy":"RemoteSigned"}

とExecutionPolicyの既定値が設定されています。

そのほかのパラメーターについては順次ドキュメント化されていく(#5885)様ですが、まだまとまった資料はありません。

とりあえず現状ログ出力にかかわるパラメーターに関する記述だけ見つけました。

  • LogIdentity
  • LogChannels
  • LogLevel
  • LogKeywords

といった設定項目がある様です。

Windows EXEの実行中はパイプラインをブロックしません

こちらはどのIssueに対する改善か名言されていないのですが、Windowsに限らずネイティブコマンドをパイプラインする際に処理がブロックされる、レスポンスが悪いといった問題がいくつかあり、それに対する改善がPowerShell Core 6.0でされています。

COMコレクションの列挙が有効になりました (#4553)

元になるIssue(#3775)およびPull Request(#4553)を読む限りでは新機能ではなく互換性の保証の様に見受けられます。

現状の.NET CoreではCOMオブジェクトの列挙がサポートされていないためPowerShellで独自に実装してPowerShell 5.1との互換を取ったものの様です。

Windows PowerShellとの後方互換性について

以前ロードマップを公開した時にも述べましたが、PowerShell CoreにはWindows PowerShellとの互換性を持ちWindows PowerShellを置き換えていきたい展望があります。(現状は多くの互換性が切り捨てられています)

互換性保持の一つとしてWindows PowerShellのモジュールをPowerShell Coreから利用するためにWindowsPSModulePathというモジュールが用意されています。

このモジュールにはAdd-WindowsPSModulePathコマンドが用意されており、これを実行するとPowerShell CoreのPSModulePath環境変数にWindows PowerShellのモジュールパスを追加し、PowerShell CoreからWindows PowerShellのモジュールを参照・実行可能になります。

Install-Module WindowsPSModulePath -Force
Add-WindowsPSModulePath

ただし、現状ではあくまでもパスを追加しているだけですので、実行されるモジュール側に互換性がなければ実行時エラーとなりますのでご注意ください。

コマンドレットの更新

ここから各種コマンドレットの更新情報について触れていきます。

新しいコマンドレット

新しく以下のコマンドレットが導入されました。
細かい説明は不要でしょう。

  • Get-Uptime
  • Remove-Alias
  • Remove-Service

Webコマンドレット

PowerShell Core 6.0では基盤が.NET Coreになったこともあり、Web Cmdletsの基盤がWebRequestクラスからHttpClientクラスに代わっており、中身は完全に作り替えられています。
これに伴いHTTP/HTTPSアクセスに係る古い仕様を取り除き新しい仕組みに対応できる様に修正されています。

これらの修正についてほとんどテキサスのMVPであるMark Krausさんが直しており、正直公式ドキュメントより彼のブログ等を見た方が良いでしょう。

JSONコマンドレット

JSON関連のコマンドレットはPowerShell Coreで内部的にJson.NETを使用する様に変更されています。
PowerShell Core 6.0ではこの変更に起因する修正や新機能の導入がされています。
また、ドキュメント化されていない部分で細かな挙動にWindows PowerShellとの差異が発生している様です。

ConvertFrom-Jsonに戻り値をHashTableにして返す-AsHashtableパラメーターが追加されました (#5043)

通常 ConvertFrom-JsonPSCustomObjectを返しますが、-AsHashtableパラメーターを指定した場合はHashTableを返します。

# 通常は PSCustomObjectを返す
PS C:\> '{"a" :', '"x"}' | ConvertFrom-Json | Get-Member

   TypeName: System.Management.Automation.PSCustomObject

   (後略)

# -AsHashtableをつけるとHashtableを返す
PS C:\> '{"a" :', '"x"}' | ConvertFrom-Json -AsHashtable | Get-Member

   TypeName: System.Collections.Hashtable

   (後略)

ConvertTo-Jsonの出力フォーマットが改善されました (#2787)

PowerShell Core 6.0で出力されるJSONはWindows PowerShellよりコンパクトになっています。
基本的には4タブから2タブになったのとクローズブレース(}など)の付き方が変更されています。

# PowerShell 5.1まで
PS C:\> [ordered]@{'one' = 1; 'two' = @{'value' = 2}} | ConvertTo-Json
{
    "one":  1,
    "two":  {
                "value":  2
            }
}

# PowerShell Core 6.0
PS C:\> [ordered]@{'one' = 1; 'two' = @{'value' = 2}} | ConvertTo-Json
{
  "one": 1,
  "two": {
    "value": 2
  }
}

ConvertTo-JsonNewtonsoft.Json.Linq.JObject型のオブジェクトのシリアル化がサポートされました (#5141)

Json.NET対応の一環での機能改善の様です。

複数行にかかわるデータに対するConvertFrom-Jsonの挙動が改善されました (#3823)

元のIssueを見てもいまいち理解しきれない部分があったのですが、

Get-Content .\sample.json | ConvertFrom-Json

の様な場合でGet-Contentの結果であるstring[]の入力を正しく解釈できないことがありそれを改善した様です。

System.Arrayに定義されていたCountエイリアスプロパティが削除され、JSONの配列を扱うケースで不要なCountプロパティが付かない様に改善されました (#3231)

例えば

(1,,"2") | ConvertTo-Json

といった例の場合、Windows PowerShellでは

# PowerShell 5.1まで
PS C:\> (1,,"2") | ConvertTo-Json
[
    1,
    {
        "value":  [
                      "2"
                  ],
        "Count":  1
    }
]

と配列のCountプロパティが出力されてしまいますが、PowerShell Core 6.0からは

# PowerShell Core 6.0
PS C:\> (1,,"2") | ConvertTo-Json
[
  1,
  [
    "2"
  ]
]

の様にCountプロパティは付かない様に改善されています。

CSVコマンドレット

Import-CsvConvertFrom-CsvPSTypeNameのサポートが追加されました (#5389)

これはExport-CsvConvertTo-CSVで付与されるPSTypName(#TYPE [型名]の部分)がImport-CsvConvertFrom-Csvで正しく反映されかった点の改善となります。

Import-Csvの行区切りにCRLFだけでなくCRLFが使える様になりました (#5363)

クロスプラットフォーム化対応での改善です。

Export-CsvConvertTo-Csv-NoTypeInformationを既定値に変更しました (#5164)

こちらは発端となったIssue(#5131)を見ればわかりますが、CSV出力する際にPSTypeNameのヘッダが出力されるのが煩わしいという声が多かったため改善されました。

サービスのコマンドレット

Get-Serviceなどの戻り値であるServiceControllerクラスのプロパティにUserNameDescriptionDelayedAutoStartBinaryPathNameStartupTypeが追加されました (#4907)

UserVoiceのこちらの要望に対する対応として機能追加されました。
ただしWindows PowerShellにバックポートされる見込みは低いでしょう...

Set-Serviceに資格情報を設定するための-Credentialパラメーターが追加されました (#4844)

New-Serviceには-CredentialパラメーターがあるのにSet-Serviceにはなかったことに対する改善です。

その他のコマンドレット

結構大きな変更もあるのですが本エントリでは公式ドキュメントの内容を軽く補足する程度にとどめておきます。

Get-ChildItemにシンボリックリンクを追跡するための-FollowSymlinkパラメーターが追加されました (#4020)

加えてシンボリックリンクにより一度走査したディレクトリを多重に走査しないかチェックする機能がサポートされています。

Add-Type-LanguageCSharpVersion7が追加されました (#3933)

余談ですが、今後の方針としてAdd-Typeで使える言語からJScriptが削除されC#のバージョン指定も簡素化される予定です。

サポートされないAPIを使っていたためMicrosoft.PowerShell.LocalAccountsモジュールは削除されました (#4302)

「サポートされない」の意味に関して.NET CoreとしてのサポートなのかWindowsのサポートなのかは不明です。

サポートされないAPIを使っていたためMicrosoft.PowerShell.Diagnosticsモジュールの*-Countrコマンドレットは削除されました (#4303)

「サポートされない」の意味に関して.NET CoreとしてのサポートなのかWindowsのサポートなのかは不明です。

Split-Path-Extension-LeafBaseパラメーターが追加されました (#2721)

-Extensionは拡張子を、-LeafBaseは拡張子なしのファイル名を取得するためのスイッチパラメーターです。

PS C:\> Split-Path C:\Temp\sample.txt
C:\Temp
PS C:\> Split-Path C:\Temp\sample.txt -Extension
.txt
PS C:\> Split-Path C:\Temp\sample.txt -LeafBase
sample

Sort-Object-Top-Bottomパラメーターが追加されました

概ね以下のコードと等価になります。

# PowerShell 5.1まで
1,3,2,5,4 | Sort-Object | Select-Object -First 2
1,3,2,5,4 | Sort-Object | Select-Object -Last 2

# PowerShell 6.0より
1,3,2,5,4 | Sort-Object -Top 2
1,3,2,5,4 | Sort-Object -Bottom 2

Get-Processなどの戻り値のSystem.Diagnostics.ProcessクラスにコードプロパティParentが追加され、該当プロセスの親プロセスを取得できる様になりました (#2850)

地味ですが便利な改善だと思います。

# PowerShell Core 6.0 から親プロセスの取得が容易に
PS C:\> (Get-Process -id $PID)

 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
     69    43.47      80.04       2.16    2484   1 pwsh

PS C:\> (Get-Process -id $PID).Parent

 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
    191   110.25     119.97   1,865.97    7500   1 explorer

Get-Processの結果を表示する際のメモリ使用量に関する列がKB単位からMB単位に変更されました

こちらは下図を見てもらうのが手っ取り早いでしょう。

f:id:stknohg:20180209164043p:plain

Out-String-NoNewLineパラメーターが追加されました (#5056)

こちらは割とそのままの改善です。
-NoNewlineをつけた時は改行コードがないことが見て取れます。

PS C:\> 'a' | Out-String | Format-Hex


           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000   61 0D 0A                                         a..


PS C:\> 'a' | Out-String -NoNewline | Format-Hex


           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000   61                                               a

Move-Item-Include-Exclude-Filterパラメーターの挙動が改善されました (#3878)

レジストリに対するRemove-Item*が使える様になりました (#4866)

レジストリのパスには*が使用可能なのですが、PowerShellでは*はワイルドカードとして扱われてしまうためRemove-Itemが正しく動作しないケースがあり、PowerShell Core 6.0でこれが修正されています。

Get-Credential-Titleパラメーターが追加されました

PowerShell Coreで認証ダイアログがCUI化したことによる機能追加になります。

Test-Connection-TimeOutパラメーターが追加されました (#2492)

ただし、Test-Connectionはまだ正式にPowerShell Coreに組み込まれていません...(#5328)

Get-AuthenticodeSignatureコマンドレットでTimeStamperCertificateプロパティが取得できなかったのが改善されました (#4061)

こちらは新機能というよりはベータ版で発生した不具合の改善ぽいです。

Get-Helpから-ShowWindowパラメータが削除されました (#4903)

.NET CoreではGUIサポートがないための変更です。
ただ、今後の方針としてConsole GUIおよびそのためのライブラリの導入を検討(#3957)しているのでいずれ復活するかも...しれません。

Get-Content-Delimiterを指定した際にデリミタ自身が残ってしまう不具合が解消されました (#3706)

こちらは以下の例を見てもらうのが手っ取り早いでしょう。

# PowerShell 5.1まではデリミタ "-" が結果に残ってしまう。
PS C:\> "00-01-02-03-04-05-06" > .\mac.txt
PS C:\> Get-Content .\mac.txt -Delimiter "-"
00-
01-
02-
03-
04-
05-
06

# PowerShell 6.0からこの挙動は改善されます
PS C:\> "00-01-02-03-04-05-06" > .\mac.txt
PS C:\> Get-Content .\mac.txt -Delimiter "-"
00
01
02
03
04
05
06

ConvertTo-HTML-Meta-Charset-Transitionalパラメーターが追加されました (#4184)

Get-ComputerInfoの実行結果にWindowsUBRWindowsVersionプロパティが追加されました

なお、現状Get-ComputerInfoはWindowsでのみ利用可能です。

Get-Verb-Groupパラメーターが追加されました

指定したグループだけを抽出可能になっています。

PS C:\> Get-Verb -Group Other

Verb AliasPrefix Group Description
---- ----------- ----- -----------
Use  u           Other Uses or includes a resource to do something

New-FileCatalogTest-FileCatalog-WhatIf-Confirmパラメーターが動作しなかったのが改善されました (#3074)

内部的にはShouldProcessのサポートが正しく実装されました。

Start-Process-WhatIfパラメーターが追加されました (#4735)

併せて-Confirmパラメーターも増えています。

多くの既存コマンドレットのパラメーターにValidateNotNullOrEmpty属性を追加しています

おそらく#2672の改善を指している様です。

引数なしのcdcd ~として動作する様になりました (#1534)

これはUnixのcdコマンドの挙動に合わせた変更となります。

テレメトリ

現在PowerShell Coreではテレメトリとして以下の情報を収集しています。

  • OSのプラットフォーム($PSVersionTable.OSDescription)
  • PowerShellの正確なバージョン($PSVersionTable.GitCommitId)

これをオプトアウトするには$PSHome\DELETE_ME_TO_DISABLE_CONSOLEHOST_TELEMETRYファイルを削除する必要があります。

ただ、この方式はAppImage版のPowerShell Coreなど$PSHOMEが読み取り専用となっているシステムでは使用できないため、オプトアウトの方法をファイルの削除から環境変数の設定に変更する計画が立てられており、PowerShell Core 6.0.2で採用される見込みです。(#6063)

最後に

とりあえずこんな感じです。
ボリュームがありまとめるのも一苦労でした。