2014/04/26

小ネタですが。

まず、ダイナミックパラメータについてはぎたぱそ先生の記事を参照してください。要は、その名の通り動的に定義されるパラメータのことです。

ダイナミックパラメータは他の(静的な)パラメータの指定状態によってリアルタイムに定義されます。ValidateSet(値の候補リスト)だけではなく、パラメータの有無、パラメータ値の型やパラメータ名ですら変わり得ます。

一方、Get-Commandコマンドレットを使うとコマンドのパラメータや構文等の情報を取得する事ができます。しかし、ダイナミックパラメータは前述のような特性があるため、パラメータの有無、パラメータ名、パラメータ値の型が一意に定まりません。

この問題を解決するため、Get-Commandコマンドレットには-ArgumentListパラメータが用意されています。指定コマンドに与えるパラメータ値を-ArgumentListパラメータに指定すると、指定コマンド実行時にそのパラメータ値を指定した場合に定義されるダイナミックパラメータに関する情報が、出力結果に含まれるようになります。

例を挙げましょう。Get-Contentコマンドレットの-Pathパラメータは「位置パラメータ」、つまりパラメータ名を省略できるパラメータであり、パラメータ名なしで指定された一つめの値がバインドされます。つまり、 Get-Content C:\ とするとC:\(FileSystemプロバイダのパス)が-Pathパラメータにバインドされるわけです。(Get-Content -Path C:\ と同じ意味となる)

ところでGet-Contentコマンドレットは、FileSystemプロバイダでのみ有効となる-Encodingというダイナミックパラメータを持っています。「FileSystemプロバイダでのみ」というのはつまり、「カレントディレクトリがFileSystemプロバイダのパスであるか、-PathパラメータにFileSystemプロバイダのパスが指定されたとき」ということになります。

すなわち、 カレントディレクトリがC:\であったり、Get-Content C:\ と入力した瞬間、-Encodingダイナミックパラメータが定義されて利用できるようになります。

ではGet-CommandコマンドレットでGet-Contentコマンドレットの-Encodingダイナミックパラメータの情報を得るにはどうすればよいか。答えは、このダイナミックパラメータが定義されるトリガーとなるパラメータ値である「C:\」を-ArgumentListパラメータに指定してやればいいわけです。つまり 例えば

Get-Command -Name Get-Content -ArgumentList C:\ -Syntax

としてやると、Get-Contentコマンドレットの構文が

Get-Content [-Path] <string[]> [-ReadCount <long>] [-TotalCount <long>] [-Tail <int>] [-Filter <string>] [-Include <string[]>] [-Exclude <string[]>] [-Force] [-Credential <pscredential>] [-UseTransaction] [-Delimiter <string>] [-Wait] [-Raw] [-Encoding <FileSystemCmdletProviderEncoding>] [-Stream <string>] [<CommonParameters>]

のように表示され(※注:一部抜粋)、Get-Content C:\を実行するときに定義される-Encodingダイナミックパラメータも含まれていることがわかります。仮にHKLM:\等のFileSystemプロバイダ以外のパスを-ArgumentListに指定すると、

Get-Content [-Path] <string[]>[-ReadCount <long>] [-TotalCount <long>] [-Tail <int>] [-Filter <string>] [-Include <string[]>] [-Exclude <string[]>] [-Force] [-Credential <pscredential>] [-UseTransaction] [<commonparameters>]

のように表示され、ダイナミックパラメータが表示されないことが分かるかと思います。

さて、-ArgumentListは配列指定もでき、複数パラメータ値を指定した時の構文を調べることもできます。しかし位置パラメータ以外の場合、つまりダイナミックパラメータ定義のトリガーとなるパラメータにパラメータ名を指定する必要があるコマンドの場合はどうやら無理のようです。

以下はおまけです。ダイナミックパラメータのリストを表示します。-ArgumentListは指定してないので、カレントディレクトリのプロバイダの種類でのみ結果が変わります。

$cmds = Get-Command -CommandType Cmdlet,Function
foreach($cmd in $cmds)
{
    $params = $cmd.Parameters
    $dynamicParamNames = @()
    if($null -ne $params)
    {
        $dynamicParamNames = @($params.Values|?{$_.IsDynamic}|%{$_.Name})
    }
    
    if($dynamicParamNames.Length -ne 0)
    {
        foreach($dynamicParamName in $dynamicParamNames)
        {
            [pscustomobject]@{
                Cmdlet=$cmd
                Module=$cmd.ModuleName
                Parameter=$dynamicParamName
            }
        }
    }
}

まあ本題とあんまり関係なくなってしまったんですが、せっかく作ったのでということで。こういうのを見ると、PowerShellはコマンドもオブジェクトなんだ、ということが分かると思います。

2010/02/22

PowerShell 2.0では標準コマンドレットの数が1.0の129個から236個へと、107個増えています。また、既存のコマンドレットの一部にパラメータが増えています。そこで、2.0で新しく加わったコマンドレットと、新しく追加されたパラメータを列挙するスクリプトを作ってみました。

まず、1.0がインストールされている環境で、コマンドレットのリストをXMLに書き出します。次のコマンドを実行してください。

 get-command -type cmdlet|export-clixml cmdlets1.xml -depth 3

同様に、2.0の環境でも実行してください。

 get-command -type cmdlet|export-clixml cmdlets2.xml -depth 3

出来上がった二つのxmlファイルをカレントディレクトリに置いて、次のスクリプトを実行すると、新しく追加されたコマンドレットとパラメータが列挙されます。(必要なら適宜リダイレクトするなどしてファイルに落とし込んでください)

function Get-CmdletHash
{
    param([string]$path)
    $cmdlets = Import-Clixml $path
    $cmdletsHash = @{}
    $cmdlets|
        %{
            $parameters = @()
            $_.ParameterSets|
                %{
                    $_.Parameters|
                        %{
                            $parameters += $_.Name
                        }
                }
            $parameters = $parameters|Sort-Object|Get-Unique|?{"WarningAction","WarningVariable" -notcontains $_}
            $cmdletsHash.Add($_.Name,$parameters)
        }
    return $cmdletsHash
}

$ver1 = Get-CmdletHash cmdlets1.xml
$ver2 = Get-CmdletHash cmdlets2.xml

$ver2.Keys|
    %{
        if($ver1.ContainsKey($_))
        {
            $result = Compare-Object $ver1[$_] $ver2[$_]
            if($result)
            {
                "[Update] $_"  
                $result | Format-Table
            }
        }
        else
        {
            "[New] $_  `r`n" 
        }
    }

出力結果を置いておきます。こちら

このスクリプトではGet-CommandコマンドレットがSystem.Management.Automation.CmdletInfoというコマンドレットの情報を格納したオブジェクトを返すことを利用し、Export-Clixmlコマンドレットでシリアライズ化してXMLファイルに落とし込むことにより異なるバージョンのPowerShell同士を比較しています。ここで-depthパラメータを3にしているのは、パラメータ情報を格納するParametersプロパティがルートから3階層下にあるためです。(デフォルトは2階層下までを出力。PS2.0ではCmdletInfoにParametersプロパティというのがあって2階層でたどれるのですが1.0にこのプロパティはないのでParameterSetsプロパティからたどる必要があります)

また、WarningActionとWarningVariableという共通パラメータが増えているので、これらはすべてのコマンドレットに共通して追加されているパラメータなので除外しておきます。

あとはパラメータをコマンドレットごとに配列化して、Compare-Objectで比較しています。新しく追加されたコマンドレットは[New]のマークをつけ、既存のコマンドレットでパラメータに変化があるものは[Update]をつけて追加されたパラメータを列挙するようにしています。

かなりたくさんのコマンドレットでパラメータが増えたことが分かりますね。また、Get-CommandコマンドレットのPSSnapinパラメータが廃止され、Moduleパラメータに変更されたことなどが分かったりします。

1.0ユーザーだった方にお勧めのスクリプトです。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2010/02/22/186334.aspx


Copyright © 2005-2018 Daisuke Mutaguchi All rights reserved
mailto: mutaguchi at roy.hi-ho.ne.jp
プライバシーポリシー

Books

Twitter