型を検索する PowerShell 関数(親クラス→子クラス)

はじめに

ネット環境無しで PowerShell を弄っているとたまに起こるのが、「引数に何を渡せば良いのかわからない」問題です。

Get-Member コマンドレットなどで各種メンバーの定義は確認できますが、引数の型が抽象的な型になっていて、具体的な型がわからない、という問題です。

例:System.DateTimeToString メソッド

PS >[datetime]::Now.ToString.OverloadDefinitions

string ToString()
string ToString(string format)
string ToString(System.IFormatProvider provider)
string ToString(string format, System.IFormatProvider provider)
string IFormattable.ToString(string format, System.IFormatProvider formatProvider)
string IConvertible.ToString(System.IFormatProvider provider)

System.IFormatProvider って具体的に何……?」という問題です。

型名の先頭にIが付いていることからインターフェイスということはわかりますが、これだけではその先に繋がりません。

Microsoft Docs を見られれば、派生が書いてあるのでそれでOKなのですが……。 IFormatProvider Interface (System) | Microsoft Docs

対策の方針

今使えるすべての型の中から、該当する型の子クラス(やや不正確な表現)を探索する。

System.AppDomain を使えばロード済みアセンブリを取得できるので、さらにそのアセンブリ内の型を列挙すれば、使えるすべての型を取得できる。

Type.IsAssignableFrom(Type) Method (System) | Microsoft Docs を使えば、該当する型の子クラスかどうかも判定できる。

作成した関数

github.com

<#
.SYNOPSIS
Search type from loaded assemblies.
ロード済みアセンブリー内から型を検索します。
.DESCRIPTION
Search type by root type from Loaded assemblies.
ロード済みアセンブリー内から、指定した型及びサブクラスを検索します。
.EXAMPLE
[System.IFormatProvider] | Search-Type
IsPublic IsSerial Name               BaseType     
-------- -------- ----               --------     
True     False    IFormatProvider                 
True     True     CultureInfo        System.Object
True     True     DateTimeFormatInfo System.Object
True     True     NumberFormatInfo   System.Object
.INPUTS
System.Type
.OUTPUTS
System.Type
By default, return all public type in loaded assemblies.
#>
function Search-Type {
    [CmdletBinding()]
    [OutputType([type])]
    param (
        [Parameter(ValueFromPipeline=$true)]
        [type]$RootType = [System.Object]
        ,
        [SupportsWildcards()]
        [string]$Name
        ,
        [SupportsWildcards()]
        [string]$Namespace
        ,
        [SupportsWildcards()]
        [string]$FullName
    )
    begin {
        # Declare foreach variables for IntelliSense.
        [System.Reflection.Assembly]$asm = [type]$t = $null
    }
    process {
        foreach ($asm in [System.AppDomain]::CurrentDomain.GetAssemblies()) {
            foreach ($t in $asm.GetTypes()) {
                # Public only.
                if (-not $t.IsPublic) { continue }

                if (-not $RootType.IsAssignableFrom($t)) { continue }

                # Name check.
                if (-not [string]::IsNullOrEmpty($Name)      -and ($t.Name      -notlike $Name)      ) { continue }
                if (-not [string]::IsNullOrEmpty($Namespace) -and ($t.Namespace -notlike $Namespace) ) { continue }
                if (-not [string]::IsNullOrEmpty($FullName)  -and ($t.FullName  -notlike $FullName)  ) { continue }

                Write-Output -InputObject $t
            }
        }
    }
}

使用例1

前述のSystem.IFormatProviderを探したい場合は以下のようにする。

PS> [System.IFormatProvider] | Search-Type

IsPublic IsSerial Name               BaseType     
-------- -------- ----               --------     
True     False    IFormatProvider                 
True     True     CultureInfo        System.Object
True     True     DateTimeFormatInfo System.Object
True     True     NumberFormatInfo   System.Object

さらに以下のようにすれば、FullNameも分かるのであとはある程度何とかなる。

PS> [System.IFormatProvider] | Search-Type | Select-Object -ExpandProperty FullName

System.IFormatProvider
System.Globalization.CultureInfo
System.Globalization.DateTimeFormatInfo
System.Globalization.NumberFormatInfo

使用例2

どんなコレクションがあるんだっけ…?と発作的に調べてくなったら以下のようにする(ワイルドカード指定のサンプル)。

PS> [System.Collections.IEnumerable] | Search-Type -Namespace System.Collections*

IsPublic IsSerial Name                             BaseType                                                     
-------- -------- ----                             --------                                                     
True     True     CollectionBase                   System.Object                                                
True     True     DictionaryBase                   System.Object                                                
True     True     ReadOnlyCollectionBase           System.Object                                                
True     True     Queue                            System.Object                                                
True     True     ArrayList                        System.Object                                                
True     True     BitArray                         System.Object                                                
True     True     Stack                            System.Object                                                
True     True     Hashtable                        System.Object                                                
True     False    ICollection                                                                                   
True     False    IDictionary                                                                                   
True     False    IEnumerable                                                                                   
True     False    IList                                         
...