しばたテックブログ

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

WMF 5.1の新機能をざっくり説明する - 2. バグ修正 編

前回の続きです。

今回の対象範囲

今回は、

WMF 5.1 のバグ修正

についてわかる範囲で補足を入れていく感じにします。

モジュールの自動検出の完全な受け入れ

TODO : もう少し調べる

MSDNを読んでもいまいちなんのためのバグ修正なのかわかりませんでした...

モジュールの自動検出順が、

  • PowerShell 3.0 ~ 5.0 : $PSHome\Modules$env:PSModulePath の順
  • PowerShell 5.1 ~ : $env:PSModulePath のみ

になったということでしょうか?

また、

これにより、PowerShell によって提供されるコマンド (Get-ChildItem など) を定義するユーザー作成のモジュールを、自動的に読み込み、組み込みコマンドを正しくオーバーライドできます。

との事なのでPowerShell標準のコマンドレットをカスタマイズしやすくするための改善の様です。

ファイルのリダイレクトの非ハードコード化

こちらはわかりやすく、かつ結構な人が望んでいた改善ではないでしょうか。

これまでのPowerShellでは>(>>)演算子を使ってファイルリダイレクトした場合のエンコーディングUnicode固定でした。

これは、>(>>)演算子は内部的にOut-Fileコマンドレットに置き換えられるのですが、その際の引数に-Endoding Unicodeがハードコーディングされていたために起きていました。
PowerShell 5.0だとSystem.Management.Automation.FileRedirectionクラスがOut-Fileコマンドレットへの置き換えをになっている様で、ILSpyで中身を見ると、

// WMF 5.0 (Windows 10)
internal Pipe GetRedirectionPipe(ExecutionContext context, PipelineProcessor parentPipelineProcessor)
{

    // ・・・(中略)・・・

    CommandProcessorBase commandProcessorBase = context.CreateCommand("out-file", false);
    CommandParameterInternal parameter = CommandParameterInternal.CreateParameterWithArgument(PositionUtilities.EmptyExtent, "Encoding", "-Encoding:", PositionUtilities.EmptyExtent, "Unicode", false, false);
    commandProcessorBase.AddParameter(parameter);
    if (this.Appending)
    {
        parameter = CommandParameterInternal.CreateParameterWithArgument(PositionUtilities.EmptyExtent, "Append", "-Append:", PositionUtilities.EmptyExtent, true, false, false);
        commandProcessorBase.AddParameter(parameter);
    }
    parameter = CommandParameterInternal.CreateParameterWithArgument(PositionUtilities.EmptyExtent, "Filepath", "-Filepath:", PositionUtilities.EmptyExtent, this.File, false, false);
    commandProcessorBase.AddParameter(parameter);
    this.PipelineProcessor = new PipelineProcessor();
    this.PipelineProcessor.Add(commandProcessorBase);
    
    // ・・・(後略)・・・
}

な感じで-Endodingパラメーターがハードコードされています。

そして、WMF 5.1ではこの-Endoding Unicodeのハードコードが取り除かれました。
System.Management.Automation.FileRedirectionクラスを見ると、

// WMF 5.1 (Windows 10 Insider Preview)
internal Pipe GetRedirectionPipe(ExecutionContext context, PipelineProcessor parentPipelineProcessor)
{

    // ・・・(中略)・・・
        
    CommandProcessorBase commandProcessorBase = context.CreateCommand("out-file", false);
    CommandParameterInternal parameter = CommandParameterInternal.CreateParameterWithArgument(PositionUtilities.EmptyExtent, "Filepath", "-Filepath:", PositionUtilities.EmptyExtent, this.File, false, false);
    commandProcessorBase.AddParameter(parameter);
    if (this.Appending)
    {
        parameter = CommandParameterInternal.CreateParameterWithArgument(PositionUtilities.EmptyExtent, "Append", "-Append:", PositionUtilities.EmptyExtent, true, false, false);
        commandProcessorBase.AddParameter(parameter);
    }
    this.PipelineProcessor = new PipelineProcessor();
    this.PipelineProcessor.Add(commandProcessorBase);
    
    // ・・・(後略)・・・
}

と、

CommandParameterInternal parameter = CommandParameterInternal.CreateParameterWithArgument(PositionUtilities.EmptyExtent, "Encoding", "-Encoding:", PositionUtilities.EmptyExtent, "Unicode", false, false);

の行が消えているのが確認できます。

この修正により、WMF 5.1からは$PSDefaultParameterValues変数を以下の様に設定することで、>(>>)演算子を使ったリダイレクトのエンコーディングを変えることができます。

$PSDefaultParameterValues["Out-File:Encoding"] = "Ascii"

なお、$PSDefaultParameterValues自体はPowerShell 3.0から導入された、コマンドレットを呼ぶ際の引数のデフォルト値を制御するための機能になります。

$PSDefaultParameterValues["[コマンドレット名]:[パラメーター名]"] = [デフォルト値]の形式でコマンドレットのデフォルト値を制御することができます。
詳細はabout_Parameters_Default_Valuesを参照してください。

メンバーへのアクセスでのバグ再発の修正

こちらはMSDNの説明の通りでしょう。

WMF 5.0 で新しく発生したバグにより、System.Reflection.RuntimeType のメンバーにアクセスできませんでした ([int].ImplementedInterfaces など)。 WMF5.1 ではこのバグが修正されています。

[int].ImplementedInterfacesで試してみると、以下の様にWMF 5.0では値をとれなかったのがWMF 5.1では正しくとれる様に改善されます。

# WMF 5.0
PS C:\> [int].ImplementedInterfaces
PS C:\>

# WMF 5.1
PS C:\> [int].ImplementedInterfaces

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    IComparable
True     False    IFormattable
True     False    IConvertible
True     False    IComparable`1
True     False    IEquatable`1

ただ、この改善がどれくらいの人にとってうれしいのかはよくわかりません...

COM オブジェクトでのいくつかの問題の修正

こちらもMSDNの説明の通り、とくに触れることは無いでしょう。

WMF 5.0 では、COM オブジェクト上のメソッドを呼び出して COM オブジェクトのプロパティにアクセスする新しい COM バインダーが導入されました。
この新しいバインダーによりパフォーマンスが大幅に向上しましたが、バグもいくつか含まれていました。
WMF5.1 ではそれが修正されました。

例として出されているコードは、WMF 5.0、5.1で実行すると以下の様になります。  

# WMF 5.0
PS C:\> $obj = new-object -com wscript.shell
PS C:\> $obj.SendKeys([char]173)
PS C:\> 173

# WMF 5.1
PS C:\> $obj = new-object -com wscript.shell
PS C:\> $obj.SendKeys([char]173)
PS C:\> -

ちなみにWMF 5.0でこの例を正しく動かすには以下の様に明示的に[string]にキャストする必要があります。

# WMF 5.0
PS C:\> $obj = new-object -com wscript.shell
PS C:\> $obj.SendKeys([string][char]173)
PS C:\> -

[ordered] がクラス内で許可されなかった

WMF 5.1ではクラス内で[ordered]が使える様になりました。

WMF5 では、クラスで使用されるリテラル形を検証するクラスが導入されました。
[ordered] はリテラル形のように見えますが、真の .Net 型ではありません。
WMF5 は、クラスの内の [ordered] で誤ってエラーを報告しました。

について、[ordered]PowerShell言語仕様書にも、

4.3.9 The ordered type
Type ordered is a pseudo type used only for conversions.

とあり、型変換のためだけに使う疑似型であることが明記されています。

WMF 5.0では[ordered]という特例に対する考慮が漏れていた(もしくは後回しにした)といった感じでしょうか。

複数のバージョンがあるトピックについてのヘルプが機能しない

TODO : もう少し調べる

こちらについては検証環境を作ることができず検証ができませんでした...

とりあえずWMF 5.1では、

WMF 5.1 では、最新バージョンのトピックのヘルプを返すことでこれが解決されています。

だけ押さえておけば良いと思います。

リンク

他の回のリンクはこちら。
その1その3その4