Freigeben über


【PowerShell】「ブロックを解除」するためのメソッドを追加してみる

前回の投稿では、CodeProject で公開されているライブラリを使用して、一括でブロックを解除する方法について紹介しました。

【PowerShell】一括で「ブロックを解除」する ~ Windows PowerShell 編 その1

頻繁に使用するかどうかははなはだ疑問なのですが、ついでなので「ブロックを解除」するためのメソッドを追加しちゃいましょう。

メソッドを追加するとはどういうことか?例えば、以下のような感じです。

PS C:\> $File = Get-Item .\IdentityModel.WP7.dll
PS C:\> $File.DeleteAlternateDataStream

標準では Get-Item で作成した $File には、DeleteAlternateDataStream というメソッドは用意されていません。それを作ってしまおうということです。

なんか、とてつもないことを言っているように感じるかもしれませんが、PowerShell では、既存の Types.ps1xml ファイルを編集したり、新しい Types.ps1xml ファイルを作成することで、メソッドやプロパティを追加することができます。もちろん、内部の処理はスクリプトで書くことができるので、Visual Studio を使って云々..なんて必要もありません。

参考サイトはたくさんありますが、いちおうスタンダードなものは以下でしょうかね。

about_Types.ps1xml

では早速着手してみましょう。

1.メソッドを追加するクラスを特定する

はじめに、どのクラスにメソッドやプロパティを追加するかを決めておく必要があります。

今回は、 $File = Get-Item .\IdentityModel.WP7.dll で取得した $File に対してメソッド等を追加しようとしています。

では、$File のクラスはどうやってを調べるのかといえば、以下のようにして調べることができます。

PS C:\> $File.GetType().FullName System.IO.FileInfo

もし、Get-Item で取得したオブジェクトがレジストリキーであれば、クラスは以下のように Microsoft.Win32.RegistryKey となります。

PS C:\> $REG = Get-Item hklm:\software\microsoft PS C:\> $REG.GetType().FullName Microsoft.Win32.RegistryKey

2.メソッドの設計

まずは、どんなメソッドを実装するかを決めておきます。今回は、以下のメソッドだけを追加しましょう。

  • UnBlock
    代替データストリームから Zone.Identifier を決め打ちで削除する(ブロックを解除する)。引数はありません。

3. .ps1xml ファイルを作成する

メソッドおよびプロパティの定義は、.ps1xml ファイルを新しく作成して、その中に定義します。

今回は、ファイル名を adsinfo.ps1xml としましょう。

まずはメモ帳で adsinfo.ps1xml を新規に作成し、以下の内容をコピペしてください。

<?xml version="1.0" encoding="utf-8" ?> <Types> <Type> <Name>System.IO.FileInfo</Name> <Members> <ScriptMethod> <Name>UnBlock</Name> <Script> [System.Reflection.Assembly]::LoadFile("c:\tmp\Trinet.Core.IO.Ntfs.dll") $File = Get-Item( $this.FullName ) $ADSName = "Zone.Identifier" [Trinet.Core.IO.Ntfs.FileSystem]::DeleteAlternateDataStream( $File, $ADSName ) </Script> </ScriptMethod> </Members> </Type> </Types>

作成したファイルは適当な場所に保存しておいてもよいのですが、$pshome に保存しておくことをお勧めします。

あえて解説するまでもないですが、念のために書いておきます。

<Name>System.IO.FileInfo</Name> はメソッドを実装するクラス(オブジェクトの型)です。指定するクラスを間違えると意味がないので注意しましょう。

<Name>UnBlock</Name> が実際に実装するメソッドの名前です。

<Script> ~ </Script> の間に、処理内容を PowerShell で記述します。 見ていただければわかる通り、何も変わった書き方はありません。1点だけ注意していただきたいのは、取得したファイルオブジェクトは $this として表現されている点です。ここでは、ファイルオブジェクトの FullName プロパティを使用して、あらためて $FS オブジェクトを作成しています。

なお、[System.Reflection.Assembly]::LoadFile("c:\tmp\Trinet.Core.IO.Ntfs.dll") については以下の BLOG エントリを参照してください。このライブラリを用意して読み込まないと、このスクリプトは動きません。ライブラリの保存先はどこでもOKです。今回は c:\tmp に保存しています。

【PowerShell】一括で「ブロックを解除」する ~ Windows PowerShell 編 その1

4. 作成した ps1xml ファイルを読み込む

作成した adsinfo.ps1xml ファイルを読み込むには、update-typedata コマンドを使用します。

PS C:\> update-typedata $pshome\adsinfo.ps1xml

今回はファイルを $pshome(C:\Windows\System32\WindowsPowerShell\v1.0)に保存していますが、特に決まりはありません。管理上便利な場所に保存して、紛失しないようにしましょう。

なお、ファイルの読み込みは、PowerShell コンソールごとに行う必要があります。そのため、一度コンソールを閉じてしまうと定義は消えてしまいます。

定義を永続化するには、$PROFILE(Microsoft.PowerShell_profile.ps1)に上記コマンドを記述しておきます。

5. 動作確認

インターネットからダウンロードしたDLLファイル等を用意して、Get-Item で取得してください。

さらに、 Get-Member でメソッドに UnBlock が追加されていることを確認しましょう。

PS C:\tmp> $File = Get-Item .\IdentityModel.WP7.dll PS C:\tmp> $File |Get-Member

   TypeName: System.IO.FileInfo

Name MemberType Definition ---- ---------- ---------- Mode CodeProperty System.String Mode{get=Mode;} AppendText Method System.IO.StreamWriter AppendText() CopyTo Method System.IO.FileInfo CopyTo(string de... Create Method System.IO.FileStream Create() ・ ・ ・ Length Property System.Int64 Length {get;} Name Property System.String Name {get;} UnBlock ScriptMethod System.Object UnBlock(); BaseName ScriptProperty System.Object BaseName {get=if ($th... VersionInfo ScriptProperty System.Object VersionInfo {get=[Sys...

実際に UnBlock を実行するには、以下のように入力するだけです。

PS C:\tmp> $File.UnBlock()

GAC Version Location --- ------- -------- False v2.0.50727 c:\tmp\Trinet.Core.IO.Ntfs.dll True

Zone.Identifier が削除されると、True と表示されます。

同じように、代替データストリームの一覧を表示するメソッドや、指定した代替データストリームを削除するメソッドなども追加できます。

今回は代替データストリームを削除するためのメソッドを実装してみましたが、業務特有の処理をメソッド化しておくと、業務の処理を効率化したり標準化することができて便利ですね。

他に、スクリプトコマンドレットを作成する...なんていう方法もあるのですが、個人的にはこちらのほうが好みです。

Windows PowerShell: スクリプトでコマンドレットを記述する