しばたテックブログ

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

Windows 7にPowerShell 6.0をインストールする - 再び

blog.shibata.tech

の続きです。

前回はPowerShell 6.0アルファ版で試しましたが、今回はGAリリース直前のRC2で試しています。

基本的な手順は前回と変わらないのですが、前提条件が若干変わったため、その点を補足するかたちで本エントリを書きます。

前提条件

Windows 7にPowerShell 6.0をインストールするための前提条件は以下となります。

  1. SP1が適用されていること
  2. Universal C Runtimeがインストールされていること
  3. KB2533623が適用されていること
  4. WMF 4.0 ~ 5.1がインストールされていること

SP1の適用について

前回はSP1の適用について明記されていませんでしたが、現在は公式のインストール手順

To install PowerShell on Windows Full SKU (works on Windows 7 SP1 and later), download either the MSI from AppVeyor for a nightly build, or a released package from our GitHub releases page. The MSI file looks like this - PowerShell-6.0.0..<os-arch>.msi

と Windows 7 SP1以降であることが明記されています。

この点に関しては、前回の時点でSP1未適用のWindows 7はすでにサポート切れであったため単純に記載していなかっただけの様です。

Universal C Runtimeのインストールについて

前回はVisual Studio 2015 の Visual C++ 再頒布可能パッケージのインストールが要求されていましたが、これがUniversal C Runtimeに変更されています。

現在はインストーラーでUniversal C Runtimeが必要かを判断し、必要とされる場合は下図の様に警告が表示されてインストールが中断されます。

f:id:stknohg:20171227174300p:plain

リンク先からZipファイルをダウンロードし、該当する.msuファイルを適用してください。

  • Windows 7 SP1(32Bit版) : Windows6.1-KB3118401-x86.msu
  • Windows 7 SP1(64Bit版) : Windows6.1-KB3118401-x64.msu

なお、Universal C RuntimeのインストールにはSP1が適用されている必要があります。

KB2533623の適用について

.NET Coreの利用に必要な事前条件としてKB2533623の適用が必要です。

こちらは前回から変わっていません。

WMF 4.0 ~ 5.1のインストールについて

前回とは異なりWMF 4.0 ~ 5.1の事前インストールが必要となりました。
こちらのPull Requestにその理由が記載されており、

github.com

On Win7, WMF 4.0 or higher version needs to be installed so that the WinRM can support the side-by-side remoting plugin. So I make the WMF 4.0 a prerequisite too.

とPowerShell Remotingを有効にするために必要になったそうです。

こちらもインストーラーでPowerShell Remoting Plugin(pwrshplugin.dll)のインストールを判断し、WMF 4.0以降がインストールされていないと判断された場合は警告が表示されてインストールが中断されます。

f:id:stknohg:20171227174340p:plain

特に制限が無いのであればWMF 5.1をインストールすれば良いでしょう。
手順は以下のエントリを参考にしてください。

blog.shibata.tech


ちなみに、あまりお勧めできない裏技として、PowerShell 6.0をZipファイルからインストールすればWMF 4.0 ~ 5.1がインストールされていない環境でも動作させることは可能です。
ただし、PowerShell Remotingは使えませんし、予期せぬエラーが起きても自己責任でお願いします。

f:id:stknohg:20171227174419p:plain

(右がZipファイルをダウンロードして動かしたpwsh.exeです。)

WMF 4.0以降をインストールできない事情のある環境で役に立つこともある...やもしれません。

インストール手順

事前条件をクリアしていれば、インストールはMSIインストーラーの指示に従うだけでOKです。

前項で触れた様にZipファイルからインストールしても構いません。

細かい説明はしませんがMSIインストーラーのスクリーンショットだけ貼っておきます。


f:id:stknohg:20171227174447p:plain


f:id:stknohg:20171227174504p:plain


f:id:stknohg:20171227174520p:plain


f:id:stknohg:20171227174532p:plain


f:id:stknohg:20171227174546p:plain


f:id:stknohg:20171227174559p:plain


これで無事PowerShell 6.0を起動することができます。

f:id:stknohg:20171227174622p:plain

PowerShell 6.0からジョブの実行に & が使える様になります

PowerShell 6.0 Beta.2からジョブの実行方法が拡張され、文の最後*1にアンパサンド(&)を付けることでジョブを起動することができる様になりました。

これはBash等のシェルにある機能と同等のものですが、PowerShellには従来からバックグラウンドで別プロセスのPowerShellを起動するジョブの仕組みがあり、&はその糖衣構文な感じで実装されました。

& によるジョブの起動例

簡単な例として

dir &

と実行するとジョブが起動され以下の様な画面になります。

f:id:stknohg:20171224104740p:plain

この記述は概ね

Start-Job -ScriptBlock {dir}

と一致し、その結果については従来どおりReceive-Jobなどで取り扱うことが可能です。

f:id:stknohg:20171224104758p:plain

& によるジョブ起動の詳細

さきほど 概ね一致 と書きましたが実際には幾つかの点が異なります。

ジョブ起動時のロケーション

&でジョブを起動したときは自動で以下のコマンドが挿入され現在のロケーションをジョブに引き渡す様になっています。

Microsoft.PowerShell.Management\Set-Location -LiteralPath $using:pwd ;

Start-Jobでジョブを起動した場合は何も挿入されません。

f:id:stknohg:20171224104823p:plain

変数の自動引き渡し

&でジョブを起動したときは自動で変数にusingスコープが付与され、その値がジョブに引き渡されます。

例として

$message1 = "Hello"
Write-Output $message1 &

を実行するとジョブで実行されるコマンドは

Microsoft.PowerShell.Management\Set-Location -LiteralPath $using:pwd ; Write-Output ${using:message1}

となり、message1変数にusingスコープが付与されていることが確認できます。
ジョブの結果を見てもちゃんとmessage1変数に値が渡されています。

f:id:stknohg:20171224104858p:plain

Start-Jobでジョブを起動する場合、usingスコープは自分で付与しなければなりません。
以下の様にジョブを実行してしまうとmessage2には何も設定されませんので注意が必要です。

$message2 = "World"
Start-Job -ScriptBlock { Write-Output $message2 }

f:id:stknohg:20171224105058p:plain

最後に

とりあえずこんな感じです。

これまでちょっと実行するのが面倒であったジョブの仕組みですが、&の登場によりより手軽にできる様になったと思います。

補足

本エントリはPowerShell Advent Calendar 2017 22日目の代理投稿になります。

*1:文法上正確にはパイプラインの最後になりますが、ここではわかりやすさのために文の最後と表記します

PowerShell 6.0で範囲演算子(..演算子)が拡張される話

とあるPull RequestがきっかけでPowerShell 6.0 RC1から範囲演算子(..演算子)が拡張され、Int型だけでなくChar型も扱える様になりました。

本エントリではその内容について説明します。

範囲演算子でChar型が扱える様になります

もともと範囲演算子(..)は、

1..5

の様に[Int型の数値]..[Int型の数値]の形式をとり、指定した数値間で連続する要素を持つ配列を生成します。

# 1~5を要素にもつ配列が生成される
1..5 => (1,2,3,4,5)

f:id:stknohg:20171221213103p:plain

今回、この指定がChar型を取れる様に拡張され、以下の様な記述が可能になります。

'a'..'e'

この例の場合だとaeを要素にもつ配列が生成されます。

# a~eを要素にもつ配列が生成される
'a'..'e' => ([char]'a', [char]'b', [char]'c', [char]'d', [char]'e')

f:id:stknohg:20171221213133p:plain

ただ、PowerShellにはChar型リテラルを表現する手段はないため、'a''e'の記述は実際にはString型であり内部的にChar型へのキャストが発生しています。

# 内部的にはString型→Char型へのキャストが発生しているイメージ
[char]'a'..[char]'e'

もう少し深入りしてみる

これだけだとなんとなくそんなものかという感じですが、この機能拡張はまだバギーなうえかなり気持ち悪い挙動をします。

PowerShellにおけるChar型と本機能拡張

元のPull Requestを見てわかる様に、この機能拡張はもともと、

'a'..'z'

の様な単純なASCIIの範囲の文字の使用を想定している様です。

ただ、PowerShellは.NET Framework/.NET Core製であり.NETの世界のChar型はUnicode Characterです。

このため、

'あ'..'お'

の様な指定も可能となり、以下の様な結果を返します。

f:id:stknohg:20171221213229p:plain

これはざっくり以下と同義になります。

[int][char]'あ'..[int][char]'お' | % { [char]$_ }

現時点で発生しているバグ

現時点で以下のバグが報告されており、

github.com

'あ'..'お' | % { [int]$_ }

の様な記述がエラーとなってしまいます。

f:id:stknohg:20171221213254p:plain

いまのところ()でくくることで回避可能ですが早急に修正してほしい感じです。

# ()でくくることでバグを回避できる
('あ'..'お') | % { [int]$_ }

また、私も別件で以下のIssueを報告しています。

github.com

現状の出来を見るに、個人的には機能を拡張するには軽率だったんじゃないかと思いますし、今からでもこの拡張は取り下げた方が良いんじゃないかとさえ思えます...

型変換の仕様との演算子の整合性について

個人的な感情はとりあえず置いておいて、今回の拡張によって範囲演算子はInt型およびChar型を受け入れることができる様になりました。

ではInt型とChar型を混在させたときはどうなるかというと次の様になります。

  • [Char型] .. [Int型]の場合はOK
# OK
'a'..100

f:id:stknohg:20171221213537p:plain

  • [Int型] .. [Char型]の場合はNG
# NG
95..'a'

f:id:stknohg:20171221213552p:plain

これはPowerShellの二項演算子が左オペランドの型に合わせようとする原則があるためです。
比較演算子のケースですが過去のこちらのエントリが参考になるでしょう。

blog.shibata.tech

PowerShellではInt型からChar型へのキャストは直接行えるのですが、

# OK
[char]100

Char型からInt型へのキャストについては、記述上String型からInt型へのキャストが必要になり、PowerShellにはString型を直接Intにキャストできないため構文エラーとなります。

# NG : String型 → Int型へ直接キャストはできない
[int]'a'

# OK : Char型からInt型へのキャストなら可
[int][char]'a'

なお、Char型からInt型へのキャストは可能なので、

# OK : String型 → Char型 → Int型へのキャストとなる
95..[char]'a'

の様に記述すれば[Int型] .. [Char型]の場合でもエラーなく実行することができます。

f:id:stknohg:20171221213804p:plain

【2017/12/22】 ちょっと追記

String型からInt型へのキャストについて、

[int]'1'

の様に文字列で数値を表現している場合は可能です。
このため、

# これはPowerShell 6.0以前でも可能
'1'..'5'

# これもPowerShell 6.0以前で可能
95..'97'

の様な記述であればエラーなく可能です。

最後に

とりあえずこんな感じです。

この範囲演算子の拡張は個人的には不要とさえ思っているのですが何かしら役に立つケースもあるかもしれません。