実行したら自己削除するPowerShellスクリプト

実行したら自己削除するPowerShellスクリプト Tips
スポンサーリンク

実行したら自己削除するPowerShellスクリプト

情シスとして働いていると、キッティング時や、ユーザに一度だけ実行させたいスクリプトを用意する、というケースに時々遭遇します。

batファイルやvbsファイルでも実装はできますが、スクリプト内に相対パスないしは絶対パスを抜き出して、自分で削除するメソッドを用意する必要があるため、ソースが汚くなりがちです。

ですが、PowerShellであれば1行書くだけでサクッと解決する方法があるのです。

$MyInvocation.MyCommand.Sourceと$MyInvocation.InvocationName

PowerShellによって自動で生成される特殊な変数、Auto Variables(自動変数)と呼ばれる物があります。

その中に、実行したコマンドの様々な情報を格納する$MyInvocationという変数が用意されています。

C:\Users\syobon\Desktop\test.ps1

Write-Output $env:COMPUTERNAME
$MyInvocation

例えば上記の様なPowerShellを実行した際に、$MyInvocationの中身は以下の通り出力されます。

MyCommand             : test.ps1
BoundParameters       : {}
UnboundArguments      : {}
ScriptLineNumber      : 0
OffsetInLine          : 0
HistoryId             : 3
ScriptName            : 
Line                  : 
PositionMessage       : 
PSScriptRoot          : 
PSCommandPath         : 
InvocationName        : C:\Users\syobon\Desktop\test.ps1
PipelineLength        : 2
PipelinePosition      : 1
ExpectingInput        : False
CommandOrigin         : Internal
DisplayScriptPosition :

今回はこの$MyInvocation内のアイテム、「MyCommand」と「InvocationName」に着目してみます。

$MyInvocation.MyCommandについて見てみる

それではまずは$MyInvocation.MyCommandについて詳しく見てみましょう。

Write-Output $env:COMPUTERNAME
$MyInvocation.MyCommand

先ほど書いたtest.ps1を上記の様に書き直して実行した際の、$MyInvocation.MyCommandの内容は下記の通りになります。

CommandType     Name        Version    Source                                                                                                                                                                      
-----------     ----        -------    ------                                                                                                                                                                      
ExternalScript  test.ps1               C:\Users\syobon\Desktop\test.ps1

こうしてみると、$MyInvocation.MyCommandの中にスクリプトの絶対パスが格納されたSourceアイテムがあることが分かります。

$MyInvocation.InvocationNameにも同じ内容が格納されている。

上記記載の通り、$MyInvocation.InvocationNameにも$MyInvocation.MyCommand.Sourceと同じく、実行したPowerShellスクリプトの絶対パスが記載されています。

なので、下記コマンドのどちらかを実行すれば自己削除機能を実現することができます。

Remove-Item $MyInvocation.InvocationName
Remove-Item $MyInvocation.MyCommand.Source

自己削除用コマンドをスクリプトの頭に持ってきても動く

ちょっとしたトリビアのような物ですが、上記で記載した自己削除用コマンドをPowerShellスクリプトの1行目に書いても、2行目以降の処理が走ります。

これは、PowerShellスクリプト内部のコマンドは、PowerShellプロセスの子として実行される、という特徴のためです。

.batで1行目に自分自身を削除するようにすると・・・?

C:\Users\syobon\Desktop\test.bat

del /Q C:\users\syobon\Desktop\test.bat
ping 8.8.8.8

例えば、上記のようなbatファイルを実行すると下記の様な実行結果が表示されます。

C:\Users\syobon\Desktop\test.bat

C:\Users\syobon\Desktop>del /Q C:\users\syobon\Desktop\test.bat
バッチ ファイルが見つかりません。

.ps1で1行目に自分自身を削除するようにすると・・・?

PowerShellスクリプトで、最初にスクリプト自身を削除して、8.8.8.8へpingを打つスクリプトを書くと以下の通りとなります。

C:\Users\syobon\Desktop\InvocationName.ps1

Remove-Item $MyInvocation.InvocationName
ping 8.8.8.8

C:\Users\syobon\Desktop\MyCommand.ps1

Remove-Item $MyInvocation.MyCommand.Source
ping 8.8.8.8

それぞれを実行すると下記の様な結果が得られます。

PS C:\Users\syobon\Desktop> ls *.ps1   

    ディレクトリ: C:\Users\syobon\Desktop


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2020/01/15      0:45             57 InvocationName.ps1
-a----       2020/01/15      0:45             59 MyCommand.ps1

PS C:\Users\syobon\Desktop> cat .\InvocationName.ps1
Remove-Item $MyInvocation.InvocationName
ping 8.8.8.8
PS C:\Users\syobon\Desktop> cat .\MyCommand.ps1
Remove-Item $MyInvocation.MyCommand.Source
ping 8.8.8.8
PS C:\Users\syobon\Desktop>
PS C:\Users\syobon\Desktop>
PS C:\Users\syobon\Desktop>
PS C:\Users\syobon\Desktop> .\InvocationName.ps1

8.8.8.8 に ping を送信しています 32 バイトのデータ:
8.8.8.8 からの応答: バイト数 =32 時間 =4ms TTL=53
8.8.8.8 からの応答: バイト数 =32 時間 =5ms TTL=53
8.8.8.8 からの応答: バイト数 =32 時間 =7ms TTL=53
8.8.8.8 からの応答: バイト数 =32 時間 =4ms TTL=53

8.8.8.8 の ping 統計:
    パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
    最小 = 4ms、最大 = 7ms、平均 = 5ms
PS C:\Users\syobon\Desktop> .\MyCommand.ps1

8.8.8.8 に ping を送信しています 32 バイトのデータ:
8.8.8.8 からの応答: バイト数 =32 時間 =8ms TTL=53
8.8.8.8 からの応答: バイト数 =32 時間 =4ms TTL=53
8.8.8.8 からの応答: バイト数 =32 時間 =5ms TTL=53
8.8.8.8 からの応答: バイト数 =32 時間 =4ms TTL=53

8.8.8.8 の ping 統計:
    パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
    最小 = 4ms、最大 = 8ms、平均 = 5ms
PS C:\Users\syobon\Desktop> ls *.ps1
PS C:\Users\syobon\Desktop>

ご覧の通り、batファイルでは実行されなかった「ping 8.8.8.8」がどちらも実行されていてかつ、実行後にはInvocationName.ps1、MyCommand.ps1ともに削除されていることが分かります。

まとめ

そろそろ.batや.vbsから.ps1への移行が佳境を迎えている(主にAzure対応で)ので、このTipsが少しでも情シス担当の方の役に立てれば幸いです。

Source: Microsoft | stack overflow

コメント

タイトルとURLをコピーしました