[PowerShell]自動変数(予約語)のデータ型を調べてみた
概要
PowerShellの予約語のようなものである自動変数を使用する際、
正しくデータ型を理解しておく必要があります。
私は、PowerShellのスクリプトを作成し自動変数を使用する度にコマンドでデータ型をチェックしていました。
いっその事、事前にすべての自動変数のデータ型を調べて一覧化してしまおうというのが、この記事の趣旨となります。
この記事のターゲット
- PowerShellユーザーの方
- 自動変数のデータ型を確認したい方
環境
PS C:\WINDOWS\system32> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.19041.3031
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.19041.3031
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
PS C:\WINDOWS\system32>
なお、一部の自動変数はPowerShell Coreを導入しチェックする必要があった為、
ZIP版をローカルにダウンロードして検証しました。
念のため、PowerShell Coreのバージョンを記載しておきます。
PS D:\Downloads\PowerShell-7.3.6-win-x64> $PSVersionTable
Name Value
---- -----
PSVersion 7.3.6
PSEdition Core
GitCommitId 7.3.6
OS Microsoft Windows 10.0.19045
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
PS D:\Downloads\PowerShell-7.3.6-win-x64>
調査方法
自動変数名.GetType().FullName
によりデータ型を調べました。
実際に、$PSVersionTable
のデータ型を調べた際のコマンドは、下記の通りです。
$PSVersionTable.GetType().FullName
PS C:\WINDOWS\system32> $PSVersionTable.GetType().FullName
System.Collections.Hashtable
PS C:\WINDOWS\system32>
知っておくと便利な情報:「Get-Member」コマンドでプロパティを調べる < クリックで折りたたみが開く >
パイプラインでコマンドを渡してGet-Member
コマンドを実行すると、
使用できるプロパティの一覧が表示できる。
$PSVersionTable | Get-Member
PS C:\WINDOWS\system32> $PSVersionTable | Get-Member
TypeName: System.Collections.Hashtable
Name MemberType Definition
---- ---------- ----------
Add Method void Add(System.Object key, System.Object value), void IDictionary.Add(Syste...
Clear Method void Clear(), void IDictionary.Clear()
Clone Method System.Object Clone(), System.Object ICloneable.Clone()
Contains Method bool Contains(System.Object key), bool IDictionary.Contains(System.Object key)
ContainsKey Method bool ContainsKey(System.Object key)
ContainsValue Method bool ContainsValue(System.Object value)
CopyTo Method void CopyTo(array array, int arrayIndex), void ICollection.CopyTo(array arra...
Equals Method bool Equals(System.Object obj)
GetEnumerator Method System.Collections.IDictionaryEnumerator GetEnumerator(), System.Collections...
GetHashCode Method int GetHashCode()
GetObjectData Method void GetObjectData(System.Runtime.Serialization.SerializationInfo info, Syst...
GetType Method type GetType()
OnDeserialization Method void OnDeserialization(System.Object sender), void IDeserializationCallback....
Remove Method void Remove(System.Object key), void IDictionary.Remove(System.Object key)
ToString Method string ToString()
Item ParameterizedProperty System.Object Item(System.Object key) {get;set;}
Count Property int Count {get;}
IsFixedSize Property bool IsFixedSize {get;}
IsReadOnly Property bool IsReadOnly {get;}
IsSynchronized Property bool IsSynchronized {get;}
Keys Property System.Collections.ICollection Keys {get;}
SyncRoot Property System.Object SyncRoot {get;}
Values Property System.Collections.ICollection Values {get;}
PS C:\WINDOWS\system32>
参考情報:調査方法
調査結果
コマンド結果でnull
によりエラーとなったものに対しては、「エラー(nullだった)」と表記。
初期値がnull
の自動変数は値が入る条件(たとえば、$_
ではForEach内で値がセット)がある為、
PowerShellの起動直後ではnull
になっているものと思われます。
現時点で理由がわかるものに関しては、その理由を注釈として記載しています。
PS C:\WINDOWS\system32> $_.GetType().FullName
null 値の式ではメソッドを呼び出せません。
発生場所 行:1 文字:1
+ $_.GetType().FullName
+ ~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) []、RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
PS C:\WINDOWS\system32>
自動変数名 | データ型 |
---|---|
$$ |
System.String |
$? |
System.Boolean |
$^ |
System.String |
$_($PSItem) * パイプラインで渡ってくるオブジェクトにより変化 |
Get-Process | ForEach-Object -Process { Write-Host $_.GetType().FullName } の場合だと System.Diagnostics.Process 。 * 初期起動時に確認するとエラー(nullだった) |
$args |
System.Object[] |
$ConsoleFileName |
System.String |
$EnabledExperimentalFeatures * PowerShell Core 導入で使用可能 |
System.Management.Automation.Internal.ReadOnlyBag`1[[System.String, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]] * Windows標準のPowerShellだとエラー(nullだった) |
$Error |
System.Collections.ArrayList |
$ErrorActionPreference |
System.Management.Automation.ActionPreference |
$Event |
実行環境により変化 * 参考:調査時のエビデンス * 初期起動時に確認するとエラー(nullだった) |
$EventArgs |
実行環境により変化 * 参考:調査時のエビデンス * 初期起動時に確認するとエラー(nullだった) |
$EventSubscriber |
実行環境により変化 * 参考:調査時のエビデンス * 初期起動時に確認するとエラー(nullだった) |
$ExecutionContext |
System.Management.Automation.EngineIntrinsics |
$false |
System.Boolean |
$foreach |
System.Array+SZArrayEnumerator * 参考:調査時のエビデンス * 初期起動時に確認するとエラー(nullだった) |
$HOME |
System.String |
$Host |
System.Management.Automation.Internal.Host.InternalHost |
$input |
System.Collections.ArrayList+ArrayListEnumeratorSimple |
$IsCoreCLR * PowerShell Core 導入で使用可能 |
System.Boolean * Windows標準のPowerShellだとエラー(nullだった) |
$IsLinux * PowerShell Core 導入で使用可能 |
System.Boolean * Windows標準のPowerShellだとエラー(nullだった) |
$IsMacOS * PowerShell Core 導入で使用可能 |
System.Boolean * Windows標準のPowerShellだとエラー(nullだった) |
$IsWindows * PowerShell Core 導入で使用可能 |
System.Boolean * Windows標準のPowerShellだとエラー(nullだった) |
$OutputEncoding |
System.Text.ASCIIEncoding |
$Matches |
System.Collections.Hashtable * 参考:調査時のエビデンス * 初期起動時に確認するとエラー(nullだった) |
$MyInvocation |
System.Management.Automation.InvocationInfo |
$NestedPromptLevel |
System.Int32 |
$null |
エラー(nullのため) |
$PID |
System.Int32 |
$profile |
System.String |
$PSBoundParameters |
System.Management.Automation.PSBoundParametersDictionary |
$PSCmdlet |
System.Management.Automation.PSScriptCmdlet * 参考:調査時のエビデンス * 初期起動時に確認するとエラー(nullだった) |
$PSCommandPath |
System.String |
$PSCulture |
System.String |
$PSDebugContext |
System.Management.Automation.PSDebugContext * 参考:調査時のエビデンス * 初期起動時に確認するとエラー(nullだった) |
$PSEdition |
System.String |
$PSHOME |
System.String |
$PSScriptRoot |
System.String |
$PSSenderInfo |
System.Management.Automation.Remoting.PSSenderInfo * 参考:調査時のエビデンス * 初期起動時に確認するとエラー(nullだった) |
$PSUICulture |
System.String |
$PSVersionTable |
System.Collections.Hashtable |
$PWD |
System.Management.Automation.PathInfo |
$Sender |
実行環境により変化 * 参考:調査時のエビデンス * 初期起動時に確認するとエラー(nullだった) |
$ShellId |
System.String |
$StackTrace |
System.String |
$switch |
System.Array+SZArrayEnumerator * 参考:調査時のエビデンス * 初期起動時に確認するとエラー(nullだった) |
$this |
実行環境により変化 * 参考:調査時のエビデンス * 初期起動時に確認するとエラー(nullだった) |
$true |
System.Boolean |
調査時のエビデンス
$Event と $Sender 、 $this のデータ型をチェック < クリックで折りたたみが開く >
処理内容によって変化する。下記のサンプルコードでは、
- $Eventが
[System.Windows.Forms.MouseEventArgs
] - $Senderが
[System.Windows.Forms.Button
] - $thisが
[System.Windows.Forms.Button
]
[Void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$form = New-Object Windows.Forms.Form
$button = New-Object Windows.Forms.Button
$button.Text = "テストのボタン"
$button.Dock = "Fill"
$button_click =
{
($Sender, $Event) = $this, $_
Write-Host ' ----- '
Write-Host 'Event : '$Event.GetType().FullName
Write-Host 'Sender: '$Sender.GetType().FullName
Write-Host 'this : '$this.GetType().FullName
Write-Host ' ----- '
}
$button.add_Click($button_click)
$form.Controls.Add($button)
$form.ShowDialog()
上記は実行後、ボタンを押すとデータ型を確認可能。
$EventArgs のデータ型をチェック < クリックで折りたたみが開く >
処理内容によって変化する。下記のサンプルコードでは、
- $EventArgsが
[System.IO.FileSystemEventArgs
]
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "C:\"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true
$watcher.Site
$arrary = @()
$watcher.Filter = ""
Register-ObjectEvent $watcher "Created" -Action {
Write-Host $EventArgs.GetType().FullName
exit
}
上記を実行するとデータ型がチェックできる。
$Event と $EventSubscriber 、 $Sender のデータ型をチェック < クリックで折りたたみが開く >
処理内容によって変化する。下記のサンプルコードでは、
- $Eventが
[System.Management.Automation.PSEventArgs
] - $EventSubscriberが
[System.Management.Automation.PSEventSubscriber
] - $Senderが
[System.IO.FileSystemWatcher
]
$wait= New-Object System.IO.FileSystemWatcher
$wait.NotifyFilter= [IO.NotifyFilters]::LastWrite
$wait.Path= "D:\Downloads"
$wait.Filter= "*.txt”
#バックグランドで稼働
Register-ObjectEvent -InputObject $wait -SourceIdentifier "mml_wch” -EventName "Changed” -Action{
if($i -eq $null){ # 初期化
[int]$i= 0
}
$t= $Event.TimeGenerated # 見やすくするため
$f= $Event.SourceEventArgs
[string]$lated_time= $t.ToString(‘yy/MM/dd HH:mm:ss.f’)
if($lated_time -ne $chk_time){ # 出力
Write-Host ("`r`n”+ ‘no. ‘+ $i)
$i++
write-host ("change type: "+ $f.ChangeType)
write-host ("full path: "+ $f.FullPath)
write-host ("name: "+ $f.Name)
write-host ("time: "+ $lated_time)
write-host ("-----")
write-host (‘$Event : ‘+ $Event.GetType().FullName)
write-host (‘$EventSubscriber : ‘+ $EventSubscriber.GetType().FullName)
write-host (‘$Sender : ‘+ $Sender.GetType().FullName)
# write-host (‘$SourceEventArgs : ‘+ $SourceEventArgs.GetType().FullName)
# write-host (‘$SourceArgs : ‘+ $SourceArgs.GetType().FullName)
write-host (‘$Event.SourceArgs : ‘+ $Event.SourceArgs.GetType().FullName)
write-host (‘$Event.SourceEventArgs : ‘+ $Event.SourceEventArgs.GetType().FullName)
write-host ("-----")
[string]$chk_time= $lated_time
}
}
上記を実行すると「D:¥Downloads配下」のテキストファイルを監視する常駐プロセスが起動する。
PS C:\WINDOWS\system32>
no. 0
change type: Changed
full path: D:\Downloads\20230823_memo.txt
name: 20230823_memo.txt
time: 23/08/23 15:48:13.2
-----
$Event : System.Management.Automation.PSEventArgs
$EventSubscriber : System.Management.Automation.PSEventSubscriber
$Sender : System.IO.FileSystemWatcher
$Event.SourceArgs : System.Object[]
$Event.SourceEventArgs : System.IO.FileSystemEventArgs
-----
PS C:\WINDOWS\system32>
# 監視終了
Unregister-Event -SourceIdentifier "mml_wch"
$foreach のデータ型をチェック < クリックで折りたたみが開く >
- $foreachが
[System.Array+SZArrayEnumerator
]
foreach($item in $array) {
write-host "foreach: $($foreach.GetType().FullName)"
write-host "item : $($item.GetType().FullName)"
break
}
PS C:\WINDOWS\system32> foreach($item in $array) {
>> write-host "foreach: $($foreach.GetType().FullName)"
>> write-host "item : $($item.GetType().FullName)"
>> break
>> }
foreach: System.Array+SZArrayEnumerator
item : System.Int32
PS C:\WINDOWS\system32>
$Matches のデータ型をチェック < クリックで折りたたみが開く >
- $Matchesが
[System.Collections.Hashtable
]
# マッチした場合
PS C:\WINDOWS\system32> "abc" -match "abc"
True
PS C:\WINDOWS\system32>
PS C:\WINDOWS\system32> $Matches
Name Value
---- -----
0 abc
PS C:\WINDOWS\system32>
PS C:\WINDOWS\system32> $Matches.Gettype().Fullname
System.Collections.Hashtable
PS C:\WINDOWS\system32>
# マッチしない場合
PS C:\WINDOWS\system32> "abc" -match "123"
False
PS C:\WINDOWS\system32>
PS C:\WINDOWS\system32> $Matches
Name Value
---- -----
0 abc
PS C:\WINDOWS\system32>
PS C:\WINDOWS\system32> $Matches.Gettype().Fullname
System.Collections.Hashtable
PS C:\WINDOWS\system32>
$PSCmdlet のデータ型をチェック < クリックで折りたたみが開く >
- $PSCmdletが
[System.Management.Automation.PSScriptCmdlet
]
function typeof-psCmdlet {
[cmdletBinding()] param()
echo "type of `$psCmdlet is $($psCmdlet.GetType().FullName)"
}
PS C:\WINDOWS\system32> function typeof-psCmdlet {
>> [cmdletBinding()] param()
>>
>> echo "type of `$psCmdlet is $($psCmdlet.GetType().FullName)"
>> }
>>
>> typeof-psCmdlet
type of $psCmdlet is System.Management.Automation.PSScriptCmdlet
PS C:\WINDOWS\system32>
$PSDebugContext のデータ型をチェック < クリックで折りたたみが開く >
- $PSDebugContextが
[]System.Management.Automation.PSDebugContext
]
$PSDebugContext.GetType().FullName # ← この行をブレークポイントに設定しデバッグ実行
Write-Host $PSDebugContext.GetType().FullName # ← デバッグや通常の実行ではnullエラー(*)となってしまう。
# ブレークポイントでデバッグ停止中に同じコマンドを叩くと確認できた
# * nullエラー:「null 値の式ではメソッドを呼び出せません。」
調査時に当初は下記のコードを使ってデバッグしていない通常起動の時は、"Is Null"。
デバッグ中の時は、"Is not Null" + $PSDebugContext
のデータ型を表示。という想定でいたが、
期待通りに動作しなく、どちらのパターンでもTrue系となった。
原因は不明だが、おそらく$PSDebugContext
がデバッグのブレーク中でないと、データが参照できないのだと思われる。
if ($null -eq $PSDebugContext) {
Write-Host "Is Null"
} else {
Write-Host "Is not Null"
Write-Host $PSDebugContext.GetType().FullName
}
$PSSenderInfo のデータ型をチェック < クリックで折りたたみが開く >
- $PSSenderInfoが
[System.Management.Automation.Remoting.PSSenderInfo
]
PS C:\WINDOWS\system32> Enter-PSSession -ComputerName 192.168.XXX.XXX -Credential "UserName"
[192.168.XXX.XXX]: PS D:\ドキュメント>
[192.168.XXX.XXX]: PS D:\ドキュメント> $PSSenderInfo
UserInfo : System.Management.Automation.Remoting.PSPrincipal
ClientTimeZone : System.CurrentSystemTimeZone
ConnectionString : http://192.168.XXX.XXX:5985/wsman?PSVersion=5.1.19041.3031
ApplicationArguments : {PSVersionTable}
ConfigurationName : Microsoft.PowerShell
ConnectedUser : ComputerName\UserName
RunAsUser : ComputerName\UserName
[192.168.XXX.XXX]: PS D:\ドキュメント>
[192.168.XXX.XXX]: PS D:\ドキュメント> $PSSenderInfo.GetType().FullName
System.Management.Automation.Remoting.PSSenderInfo
[192.168.XXX.XXX]: PS D:\ドキュメント>
[192.168.XXX.XXX]: PS D:\ドキュメント> exit
PS C:\WINDOWS\system32>
- 参考情報:PSSessionの設定方法
https://zenn.dev/haretokidoki/articles/fd1eeb92fa4095
$switch のデータ型をチェック < クリックで折りたたみが開く >
- $foreachが
[System.Array+SZArrayEnumerator
]
switch (2) {
1 {"One."}
2 {$switch.GetType().FullName}
3 {"Three."}
default {"Not matched."}
}
PS C:\WINDOWS\system32> switch (2) {
>> 1 {"One."}
>> 2 {$switch.GetType().FullName}
>> 3 {"Three."}
>> default {"Not matched."}
>> }
System.Array+SZArrayEnumerator
PS C:\WINDOWS\system32>
参考情報:本記事を作成するにあたり参考にした情報
関連記事
Discussion