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

先の投稿で、一括で「ブロックを解除する」方法についてご紹介しました。

【Management】一括で「ブロックを解除」する ~ streams コマンド編

ただ、この方法だとファイルの代替データストリームを全て削除してしまうので、ちょっと感じ悪いというか...なんか他に影響が出ないかすごく心配だったりします。IT Pro 的には。

※ ちなみに、ファイルのプロパティから「ブロックを解除」すれば、ZoneID のみを削除することができます。ただし、ファイル単位に操作するので超面倒なのですね。

代替データストリームは、Dir /r コマンドで確認することができます。例えば、以下の場合には、4つの代替データストリームが存在していることがわかります。

C:\tmp>dir /r IdentityModel.WP7.dll ドライブ C のボリューム ラベルがありません。 ボリューム シリアル番号は 6E7E-0B00 です

C:\tmp のディレクトリ

24/01/12 20:08 44,032 IdentityModel.WP7.dll 7 IdentityModel.WP7.dll:ads1:$DATA 7 IdentityModel.WP7.dll:ads2:$DATA 7 IdentityModel.WP7.dll:ads3:$DATA 26 IdentityModel.WP7.dll:Zone.Identifier:$DATA 1 個のファイル 44,032 バイト 0 個のディレクトリ 16,348,221,440 バイトの空き領域

dir /r で参照した場合、実際に保存されているデータは $DATA と表現されてます。中身は、代替データストリームごとに notepad で参照することができます。ファイル名の後ろに「:<代替データストリーム名>」を付加していることに注意してください。

(参考)NTFS 代替データストリームに関するメモ - B-) の独り言@Ihara さん

C:\tmp>notepad IdentityModel.WP7.dll :Zone.Identifier

image

前置きが長くなってしまいました。ここからが本題です。Windows PowerShell を使用して Zone.Identifier のみを削除するスクリプトを書いてみたいと思います。そんなに難しくありません!

....と、実は少々高をくくっていました...いやー .NET Framework って代替データストリームへのアクセスに対応していないですねぇ。知らなかった...。完全になめていました。

で、いろいろと当たってみると、CodeProject で提供されている以下のライブラリが使いやすそうだと思いました。

代替データストリームにアクセスするためのライブラリ( Richard Deeming 氏提供)
Accessing alternative data-streams of files on an NTFS volume - CodeProject®

上記をダウンロードし、zip ファイルを解凍したら、bin\Trinet.Core.IO.Ntfs.dll を適当なフォルダ(c:\tmpなど)に保存してください。

なお、この dll ファイルもインターネットからダウンロードしたものなので、手動で「ブロックの解除」を行っておいてください。

PowerShell のコンソールを開き、以下のようにして解凍した DLL ファイルを読み込みます。

PS C:\> [System.Reflection.Assembly]::LoadFile("c:\tmp\Trinet.Core.IO.Ntfs.dll")

ファイルに設定されている代替データストリームの一覧を表示するには、ListAlternateDataStreams メソッドを使用し、以下のように入力します。ここでは、C:\tmp\IdentityModel.WP7.dll ファイルの代替データストリームを参照しています。dir /r で表示したときと同じようなデータが表示されていることがわかりますね。

PS C:\> [Trinet.Core.IO.Ntfs.FileSystem]::ListAlternateDataStreams("C:\tmp\IdentityModel.WP7.dll")

FullPath : C:\tmp\IdentityModel.WP7.dll:ads1:$DATA FilePath : C:\tmp\IdentityModel.WP7.dll Name : ads1 Exists : True Size : 7 StreamType : AlternateDataStream Attributes : None

FullPath : C:\tmp\IdentityModel.WP7.dll:ads2:$DATA FilePath : C:\tmp\IdentityModel.WP7.dll Name : ads2 Exists : True Size : 7 StreamType : AlternateDataStream Attributes : None

FullPath : C:\tmp\IdentityModel.WP7.dll:ads3:$DATA FilePath : C:\tmp\IdentityModel.WP7.dll Name : ads3 Exists : True Size : 7 StreamType : AlternateDataStream Attributes : None

FullPath : C:\tmp\IdentityModel.WP7.dll:Zone.Identifier:$DATA FilePath : C:\tmp\IdentityModel.WP7.dll Name : Zone.Identifier Exists : True Size : 26 StreamType : AlternateDataStream Attributes : None

もちろん PowerShell ですから、以下のようにして代替データストリーム単位に参照することも可能です。

PS C:\> $File = "C:\tmp\IdentityModel.WP7.dll" PS C:\> $ADS = [Trinet.Core.IO.Ntfs.FileSystem]::ListAlternateDataStreams( $File ) PS C:\> $ADS[3]

FullPath : C:\tmp\IdentityModel.WP7.dll:Zone.Identifier:$DATA FilePath : C:\tmp\IdentityModel.WP7.dll Name : Zone.Identifier Exists : True Size : 26 StreamType : AlternateDataStream Attributes : None

Zone.Identifier が存在するかどうかを判断するには、AlternateDataStreamExists を使用して以下のように記述します。

PS C:\> $ADSName = "Zone.Identifier" PS C:\> $File = "C:\tmp\IdentityModel.WP7.dll" PS C:\> [Trinet.Core.IO.Ntfs.FileSystem]::AlternateDataStreamExists( $File, $ADSName )

True

代替データストリームの中から、Zone.Identifier を削除するには DeleteAlternateDataStream を使用します。削除に成功すると、以下のように True が返されます。

PS C:\> $ADSName = "Zone.Identifier" PS C:\> $File = "C:\tmp\IdentityModel.WP7.dll" PS C:\> [Trinet.Core.IO.Ntfs.FileSystem]::DeleteAlternateDataStream( $File, $ADSName )

True

この方法を使用して、指定したフォルダ配下の全てのファイルの Zone.Identifier を削除するには、以下のようなスクリプトを作成して実行すればOKです。

[System.Reflection.Assembly]::LoadFile("c:\tmp\Trinet.Core.IO.Ntfs.dll") $Path = "c:\tmp\test" $ADSName = "Zone.Identifier" $Files = Get-ChildItem -Recurse -Name $Path Foreach ($F in $Files) { [Trinet.Core.IO.Ntfs.FileSystem]::DeleteAlternateDataStream( $Path+"\"+$F, $ADSName ) }

もちろん、削除されるのは Zone.Identifier のみなので、その他の代替データストリームはそのまま残ります。