しばたテックブログ

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

PowerShell Core 6.1のPowerShell Remotingにおける改善点について

本エントリではPowerShell Core 6.1のPowerShell Remotingにおける改善点について解説します。

docs.microsoft.com

元ネタは上記のDocsで、現在こちらに対するまとめを作成しているのですが、PowerShell Remotingについては少しボリュームが増えたので本エントリで先出しします。

コンテナ向けPowerShell Directの改善

PowerShell Direct

PowerShell DirectはWindows10/Windows Server 2016以降で利用でき、ホストから仮想マシンおよびコンテナへネットワークを介さず直接接続する機能になります。

利用可能なホストOSではリモート操作系のコマンドレットに-VMName-VMId-VMGuid-ContainerIdのパラメーターが付いており、これらのパラメーターを指定することで直接ゲストに接続します。

# VM向けPowerShell Directの例
Invoke-Command -VMName TestVM -ScriptBlock { $PSVersionTable } -Credential $cred

# コンテナ向けPowerShell Directの例
Invoke-Command -ContainerId 78438d708b648217899f600c3a0ac72b36814714a8a19d2f4bc03fbb08936519 -ScriptBlock { $PSVersionTable }

仕組みとしては、対VMの場合はHyper-V Socketを使った通信を行い、対コンテナの場合はHost Compute Service(HCS)のAPI(例えばHcsCreateProcessなど)を使ってコンテナ内部のPowerShellを起動したプロセス間通信を行っています。

PowerShell Core 6.1での改善

ここまでをふまえてPowerShell Core 6.1での改善点について説明します。

PowerShell Core 6.0までは対コンテナ向けのPowerShell Directで起動するPowerShellのプロセスはpowershell.exeで決め打ちされていました。
対してPowerShell Core 6.1では、最初にpwsh.exeの起動を試みpwsh.exeが無ければpowershell.exeを起動する様に改善されています。

例としてWindows Server 2019*1で以下のコマンドを試してみます。
予めdockerをインストールし、PowerShell Core 6.1をインストール済みのWindows Server Containerが起動された状態です。*2

# 起動しているコンテナの確認
docker ps

# コンテナIDの取得
# ※起動しているコンテナが1つだけの前提
$containerId = (docker inspect $(docker ps -q) | ConvertFrom-Json).Id

# PowerShell Directによるリモートコマンド実行
Invoke-Command -ContainerId $containerId -ScriptBlock { $PSVersionTable.PSVersion } 

Windows PowerShellからこのコマンドを実行すると、結果のバージョンが5.1とWindows PowerShell(powershell.exe)が実行されていることが分かります。

f:id:stknohg:20181013233855p:plain

対してPowerShell Core 6.1から実行すると、結果のバージョンが6.1.0とPowerShell Core(pwsh.exe)が起動され改善されていることがわかります。

f:id:stknohg:20181013233916p:plain

ちなみに、対VMのPowerShell Directはこれまで通りデフォルト指定ではWindows PowerShellとの通信になり、PowerShell Coreと通信する場合は-ConfigurationNameパラメーターを明示してやる必要があります。
こちらについては次項で説明します。

余談1

PowerShell Core 6.1のリリースバージョンではコンテナ接続に関するバグ(#5794)があるため、この機能を試すには最新のmasterから自分でビルドする必要があります。
おそらく次のリリース(PowerShell Core 6.1.1)に取り込まれると思いますので、ビルド環境のない方はそれまでお待ちください。

【2019.04.23追記】

#5794の修正はPowerShell Core 6.2.0で反映されました。

【追記ここまで】

余談2

当初この点についてドキュメントの内容に疑念があったためIssueを上げたところ回答と改善をしてもらえました。

github.com

あまりいないとは思いますが改善前のドキュメントを見ている人向けの補足です。

PowerShell Remotingのエンドポイントがプレビュー版と分離されました

PowerShell Remotingのエンドポイント

普段意識することは少ないでしょうがPowerShell Remotingでは接続対象となるホストに接続先(エンドポイント)が存在します。

このエンドポイントはGet-PSSessionConfigurationコマンドレットで確認でき、例えばWindows PowerShellにおいては下図の様に4つのエンドポイントがあることが分かります。*3

# 要管理者権限
# 接続される側のホストで実行する
Get-PSSessionConfiguration

f:id:stknohg:20181013234030p:plain

で、PowerShell CoreにおいてPowerShell Remotingを有効にした際のエンドポイントがどうなるかというと、バージョンによって何度か変遷しており、PowerShell Core 6.1では以下の2つのエンドポイントが作成されます。

  • PowerShell.6 : メジャーバージョンのみのエンドポイント
  • PowerShell.6.x.y : バージョンを厳密に指定したエンドポイント

Get-PSSessionConfigurationで確認するとこんな感じです。

# 要管理者権限
# PowerShell Coreインストール時にPowerShell Remotingを有効にしてない場合に実行
Enable-PSRemoting

# 接続される側のホストで実行する
Get-PSSessionConfiguration

f:id:stknohg:20181013234055p:plain

また、今後PowerShell Core 6.2に向けたプレビュー版でPowerShell Remotingを有効にした場合はプレビューバージョン向けの2つのエンドポイントが追加される予定となっています。

  • PowerShell.6-preview : メジャーバージョンのみのエンドポイント
  • PowerShell.6.x-preview.y : バージョンを厳密に指定したエンドポイント
Name          : PowerShell.6-preview
PSVersion     : 6.2
StartupScript :
RunAsUser     :
Permission    : NT AUTHORITY\INTERACTIVE AccessAllowed, BUILTIN\Administrators AccessAllowed, BUILTIN\Remote Management Users AccessAllowed

Name          : PowerShell.6.2-preview.1
PSVersion     : 6.2
StartupScript :
RunAsUser     :
Permission    : NT AUTHORITY\INTERACTIVE AccessAllowed, BUILTIN\Administrators AccessAllowed, BUILTIN\Remote Management Users AccessAllowed

これにより安定版とプレビュー版のエンドポイントを分けて利用できるというのが今回の改善点になります。

接続する側の設定について

補足として接続する側について触れておきます。

接続する側はデフォルトでMicrosoft.Powershellというエンドポイントが設定されており、これはWindows PowerShell/PowerShell Coreどちらでも変わりません。
このためPowerShell CoreからEnter-PSSessionなどのコマンドレットを使ってリモート接続してもデフォルトではWindows PowerShellが利用されます。

PowerShell Coreに対してPowerShell Remotingで接続する場合は-ConfigurationNameパラメーターを使って接続するエンドポイントを明示してやる必要があります。

たとえばInvoke-Commandであれば以下の様にしてやります。

# リモートのPowerShell Core 6に接続する場合はエンドポイントを明示する
$cred = Get-Credential
Invoke-Command -ConputerName [Server Name] -Credential $cred -ScriptBlock { $PSVersionTable.PSVersion } -ConfigurationName 'PowerShell.6'

# VM向けPowerShell Directでも同様
Invoke-Command -VMName [VM Name] -Credential $cred -ScriptBlock { $PSVersionTable.PSVersion } -ConfigurationName 'PowerShell.6'

f:id:stknohg:20181013234124p:plain

f:id:stknohg:20181013234136p:plain

PowerShell Remoting over SSHでuser@host:port形式の接続が可能になりました

ssh.exeといったSSHクライアントで使われるuser@host:port形式の接続がコマンドレットでもサポートされました。
PowerShell Remoting over SSHでは-HostNameパラメーターを使用して接続先を決めますが、ここに上記の形式を指定できます。

# Docsの例をそのまま引用
Enter-PSSession -HostName fooUser@ssh.contoso.com:2222

*1:PowerShell Directを利用するにはHyper-Vモジュールが利用可能である必要があり、このためこの改善を確認するためのホストOSはWindows 10 October 2018 Update(1809)かWindows Server 2019でなければなりません

*2:環境構築の手順は端折ります。

*3:正確にはSession Configurationとエンドポイントは別なのでしょうが、本エントリではわかりやすさのために同一視します