緒言
Effective Windows PowerShell: The Free eBook は PowerShell 2.0 までをあつかっていますが、いまでもおそわることはおおくあるとおもいます。公式のドキュメントではきづかなかったことがたくさんかかれています。
その Effective Windows PowerShell.pdf
の Item 3: Know What Objects Are Flowing Down the Pipeline1 に
PowerShell
filter Get-TypeName {if ($_ -eq $null) {''} else {$_.GetType().Fullname }}
は `$profile` にいれておきたいくらい便利とあります。ただし、
> ```
PS> @() | Get-TypeName
とするとなにも出力されません。配列はパイプにおくられるときに要素に展開されますが、ここで @()
の要素はからなのでパイプにはなにもおくられないということでしょう。
The PowerShell Community Extensions (PSCX) の Get-TypeName
をつかうと、このようなばあいに警告を表示してくれるとのことです。
しかし、さしあたり Get-TypeName
のみがほしいのと、これを PS の function
で実装できないかしらとおもったのでした2。
移植
PSCX の Get-TypeName
の C♯ の ソース コード を PS におきかえただけです。
function Get-TypeName {
[CmdletBinding()]
[OutputType([String], [PSObject])]
param(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[AllowNull()]
[PSObject]$InputObject,
[Parameter(Mandatory=$false)]
[Switch]$FullName,
[Parameter(Mandatory=$false)]
[Switch]$PassThru
)
begin {
$_processedAnyInput = $false
}
process {
if ($null -eq $InputObject) {
Write-Host -Object '<null>'
} else {
$name = if ($FullName) {
$InputObject.GetType().FullName
} else {
$InputObject.GetType().Name
}
if ($PassThru) {
Write-Host -Object $name
Write-Output -InputObject $InputObject
} else {
Write-Output -InputObject $name
}
}
$_processedAnyInput = $true
}
end {
if (-not $_processedAnyInput) {
Write-Warning -Message (
'Get-TypeName did not receive any input. The input may be an empty ' +
'collection. You can either prepend the collection expression with ' +
'the comma operator e.g. ",$collection | gtn" or you can pass the ' +
'variable or expression to Get-TypeName as an argument e.g. ' +
'"gtn $collection".'
)
}
}
}
Set-Alias gtn Get-TypeName -Description "PSCX alias"
なお、オリジナルのコードできになるのは
C#
string name = InputObject.TypeNames[0];
if (!FullName)
{
if (name.Contains("`"))
{
string nonGenericPart = name.Split('[')[0];
int ndx = nonGenericPart.LastIndexOf('.');
if ((ndx >= 0) && (ndx < (nonGenericPart.Length - 1)))
{
name = nonGenericPart.Substring(ndx + 1);
}
}
else
{
// ...
}
}
ですが、この部分は、たとえば
PS> ([System.Collections.Generic.List[int]]::new()).GetType().FullName
System.Collections.Generic.List1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] PS> ([System.Collections.Generic.List[int]]::new()).GetType().Name List
1
というふうになるので、 `GetType().Name` でまきとれているとおもいます。
# 2020/07/22 追記
```powershell
process {
if ($InputObject -eq $null) {
# ...
としていましたが、 Everything you wanted to know about arrays | $null or empty にしたがい
process {
if ($null -eq $InputObject) {
# ...
に修正しました。
ただ、当該記事で
$array = @('one',$null,'three')
if ( $array -eq $null)
{
'I think Array is $null, but I would be wrong'
}
はバージョン 5.1.19041.1 では著者の意図どおりにはなりませんでした。たしかに、
```console
PS> Get-Member -InputObject ($array -eq $null)
TypeName: System.Object[]
...
となるので、 $array -eq $null
が $null
が要素の要素数 1 の配列つまり $true
相当と評価されてしかるべきとおもいますが…。
-
もとになったブログは Effective PowerShell Item 6: Know What Objects Are Flowing Down the Pipe ↩
-
PS 2.0 まででは不可能だったのかもしれません。 ↩