はじめに
Excel マクロがブロックされたり、EXE ファイルの実行が SmartScreen によって制限されることがあります。
本記事では、まず、これらの制約の原因となる MoTW(Mark of the Web)と、その実装メカニズムである Zone.Identifier ストリームについて記載します。
その後、C#、PowerShell、コマンドプロンプトでの Zone.Identifier 操作を記載します。
参考情報
テスト環境
ここに記載した情報は、Windows 11 24H2 で動作確認しています。
C#ソースコードは、Visual Studio Community 2022 を利用した下記プロジェクトで生成したモジュールで確認しています。
- Windows Forms - .NET Framework 4.8
- Windows Forms - .NET 8
- WPF - .NET Framework 4.8
- WPF - .NET 8
Visual Studio 2022 - .NET Framework 4.8 は、C# 7.3 が既定です。
このため、サンプルコードは、基本的に C# 7.3 機能範囲で記述しています。
MoTW と Zone.Identifier ストリーム
MoTW
MoTW(Mark of the Web)は、Windows 独自のセキュリティ機能で、インターネット経由で取得したファイルに適用される属性です。
MoTW が付与されたファイルは、特定の条件下で実行が制限されることがあります。
- マクロ付きのOfficeファイル(Excel、Wordなど)は、マクロの実行が制限されます
- スクリプトファイル(.ps1, .vbs, .jsなど)は、 PowerShell スクリプトや VBScript の実行が制限されます
- 実行ファイル(.exe, .dllなど)は、Windows の SmartScreen フィルターによって実行が制限されます
Zone.Identifier ストリーム
MoTW の実装には、Zone.Identifier ストリームと呼ばれる特殊な NTFS 代替データストリーム(ADS:Alternate Data Streams)が使用されます。
Zone.Identifier ストリームには、ファイルの出所に関する情報が記録されます。
[ZoneTransfer]
ZoneId=3
ReferrerUrl=http://example.com
HostUrl=http://download.example.com/file.exe
- ZoneId: ファイルの取得元のセキュリティゾーン
- ReferrerUrl: ダウンロード元の Web ページ URL
- HostUrl: ファイルを取得したサーバーの URL
- HostIpAddress: ダウンロード元の IP アドレス(記録されない場合あり)
ブラウザでダウンロードした場合は、Zone.Identifier が作成されます。
PowerShell の Invoke-WebRequest や curl.exe など、一部のコマンドラインツールでは、Zone.Identifier が作成されません。
ZoneIdの種類:
ZoneId | 意味 | 影響 |
---|---|---|
0 | ローカルコンピュータ | 制限なし |
1 | ローカルイントラネット | 制限なし |
2 | 信頼済みサイト | 制限なし |
3 | インターネット | ブロック、もしくは、警告 |
4 | 制限付きサイト | 基本的にブロック |
Chrome、FireFox は独自のセキュリティモデルに基づいて、ZoneId を決定します。
Edge でダウンロードした場合、Windows「インターネットオプション」セキュリティタブの各ゾーンに設定されているサイトに基づいて、ZoneId を決定します。
上記は、ファイル名を指定して実行で「inetcpl.cpl」を入力して起動できます。
マクロ付き Office ファイルの影響:
- ZoneId=0,1,2 は、マクロの実行が許可されます
- ZoneId=3 は、保護ビューで開かれ、マクロの実行が制限されます
- ZoneId=4 は、基本的にブロックされます
スクリプトファイルの影響:
- ZoneId=0,1,2 は、スクリプト実行が許可されます
- ZoneId=3 は、Windows のセキュリティ機能(SmartScreen、PowerShell 実行ポリシーなど)によってブロック、もしくは、警告が表示されます
- ZoneId=4 は、基本的にブロックされます
実行ファイルの影響:
- ZoneId=0,1,2 は、実行が許可されます
- ZoneId=3 は、SmartScreen による警告が表示されます
- ZoneId=4 は、基本的にブロックされます
デジタル署名を付与すると、制限が緩和される場合があります。
アーカイブからの継承
MoTW が付与された(Zone.Identifier ストリームが付与された)アーカイブを解凍したファイルに、対象属性値が継承されるかは、解凍ソフトが Zone.Identifier ストリームをどのように扱うかに依存します。
- Windows 標準 API を利用した解凍(Explorer、PowerShell Expand-Archive)
- アーカイブの ZoneId が、解凍後のファイルにも継承されます
- ZoneId 以外の属性値は継承されないことがあります(ReferrerUrl が、ダウンロード元の Web ページ URLではなく、ローカルの対象アーカイブパスに変更される等)
- 7zip、WinRAR などのサードパーティーソフト
- 基本的に、Zone.Identifier は継承されません
C# での操作
Zone.Identifier 存在確認
確認対象 <filename>
の場合、<filename>:Zone.Identifier
の存在有無で確認できます。
string filePath = @"C:\path\to\hoge.exe:Zone.Identifier";
// Zone.Identifier 存在確認
if (File.Exists(filePath))
{
Console.WriteLine("Zone.Identifier が存在します。");
}
else
{
Console.WriteLine("Zone.Identifier は存在しません。");
}
Zone.Identifier 内容取得
string filePath = @"C:\path\to\hoge.exe:Zone.Identifier";
// Zone.Identifier 存在確認
if (File.Exists(filePath))
{
// Zone.Identifier 内容取得
using (var reader = new StreamReader(filePath))
{
Console.WriteLine(reader.ReadToEnd());
}
}
else
{
Console.WriteLine("Zone.Identifier は存在しません。");
}
Zone.Identifier 削除
Windows 11:
<filename>:Zone.Identifier
を System.IO.File.DeleteFile すると、Zone.Identifier のみを削除できます。(後述、Windows 10 以前の手法でも削除可能)
string filePath = @"C:\path\to\hoge.exe:Zone.Identifier";
// Zone.Identifier 存在確認
if (File.Exists(filePath))
{
try
{
// Zone.Identifier 削除
File.Delete(filePath);
}
catch
{
Console.WriteLine("Zone.Identifier 削除に失敗しました。");
}
}
else
{
Console.WriteLine("Zone.Identifier は存在しません。");
}
Windows 10 以前:
Zone.Identifier のみを削除するには、WIN32API - DeleteFile 利用が必要です。
string filePath = @"C:\path\to\hoge.exe:Zone.Identifier";
// Zone.Identifier 存在確認
if (File.Exists(filePath))
{
// Zone.Identifier 削除
if (NativeMethods.DeleteFile(filePath))
{
Console.WriteLine("Zone.Identifier を削除しました。");
}
else
{
Console.WriteLine("Zone.Identifier 削除に失敗しました。");
}
}
else
{
Console.WriteLine("Zone.Identifier は存在しません。");
}
private static class NativeMethods
{
// WIN32QPI
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern bool DeleteFile(string name);
}
WIN32API を直接記述していますが、Microsoft が提供している CsWin32 を利用するという手もあります。
Zone.Identifier 更新
string filePath = @"C:\path\to\hoge.exe:Zone.Identifier";
var sb = new StringBuilder();
sb.AppendLine("[ZoneTransfer]");
sb.AppendLine("ZoneId=3");
sb.Append("ReferrerUrl=https://example.com");
try
{
// Zone.Identifier 更新
File.WriteAllText(filePath, sb.ToString());
}
catch
{
Console.WriteLine("Zone.Identifier 更新に失敗しました。");
}
PowerShell での操作
Zone.Identifier 存在確認
Get-Item -Path "C:\path\to\hoge.exe" -Stream Zone.Identifier
Zone.Identifier 内容表示
Get-Content -Path "C:\path\to\hoge.exe" -Stream Zone.Identifier
Zone.Identifier 削除
対象ファイルの Zone.Identifier 削除は、2パターン存在します。
Remove-Item -Path "C:\path\to\hoge.exe" -Stream Zone.Identifier
Unblock-File -Path "C:\path\to\hoge.exe"
フォルダ内のすべてのファイルを対象として、Zone.Identifier 削除は下記で可能です。
Get-ChildItem -Path "C:\path\to\folder" -Recurse | Unblock-File
Zone.Identifier 更新
# 既存のファイルの Zone.Identifier を上書き(完全に置き換える)
Set-Content -Path "C:\path\to\hoge.exe" -Stream "Zone.Identifier" -Value @(
"[ZoneTransfer]", "ZoneId=3", "ReferrerUrl=https://example.com")
# 既存のファイルの Zone.Identifier を保持し、新しいデータを追記
Add-Content -Path "C:\path\to\hoge.exe" -Value "追加の内容"
コマンドプロンプトでの操作
NTFS 代替データストリーム(ADS)を調査・管理するためのツールとして、Steram.exe - Sysinternals | Microsoft Learn が提供されていますが、標準コマンドの範囲で記載します。
Zone.Identifier 存在確認
dir を /r オプションで実行して <filename>
とペアで <filename>:Zone.Identifier:$DATA
が存在するか否かで確認できます。
dir <対象フォルダパス> /r
2025/06/01 00:00 1,234,567 hoge.zip
257 hoge.zip:Zone.Identifier:$DATA
Zone.Identifier 内容表示
more を利用することで、Zone.Identifier を表示することができます。
more < hoge.zip:Zone.Identifier
[ZoneTransfer]
ZoneId=3
ReferrerUrl=http://example.com
HostUrl=http://download.example.com/file.exe