
【ツール】ZIP/Officeファイル内検索ツール
ZIP/Officeファイル検索ツールの紹介
過去に、Officeの作成者情報などを消すツールを紹介しましましたが今回は、ZIPファイルやOfficeドキュメント内の検索を簡単に行えるWindows向けツールを作ってみました。業務でZIPファイルやExcel、Word、PowerPointなどのドキュメントを扱うことが多い方には、便利?かなと。
背景と必要性
業務では、多くのZIPファイルやOfficeドキュメントが頻繁に使用されます。特に、会社で他社にファイルを送る際には、ファイルの中に消したつもりの情報が残っていることがセキュリティ上の問題となることがあります。例えば、Officeファイルには埋め込みオブジェクトやメタデータが残っている場合があり、これらを見落とすと機密情報が意図せず共有されてしまうリスクがあります。また、共有リンクの情報がファイルに残ったままになることもあります。このように、埋め込みファイルやメタデータ、リンク情報など、ファイル内部に残る情報について注意が必要です。
Excelファイルを例に取ると、共有リンクやピボットテーブルのデータなどが`xml`形式でファイル内部に保存されています。これらは通常、Excelを通して削除しても、内部構造に残っている場合があり、実際には他者と共有した際に意図しない情報が流出するリスクを含んでいます。
例えば、Excelファイルの内部構造は次のような複数のXMLファイルで構成されています:
`xl/externalLinks/externalLink1.xml`:外部参照リンクの情報が格納されています。外部のExcelファイルやデータソースへの参照がここに残っていることがあります。このような情報が残ると、意図しないデータの漏洩につながる可能性があります。
`xl/pivotTables/pivotTable1.xml`:ピボットテーブルのデータが格納されているファイルです。ピボットテーブルの内容は、元データを参照しており、これが残っていると意図しない情報が他者に伝わるリスクがあります。
`xl/pivotCache/pivotCacheDefinition1.xml`:ピボットテーブルが参照しているデータソース情報が保存されています。これにより、過去のデータソースやリンク情報がファイルに残ることがあります。
このようなXMLファイルを調べることで、共有リンクやピボットテーブルの残存情報を確認することができます。このツールを使用すれば、Excelファイル内に`xl/externalLinks/externalLink1.xml`が含まれていないかなどをチェックできます。
このように、Officeファイルの内部構造を理解し、それをチェックすることで、送付前に適切にセキュリティリスクを軽減することができます。例えば、Officeファイルには埋め込みオブジェクトやメタデータが残っている場合があり、これらを見落とすと機密情報が意図せず共有されてしまうリスクがあります。また、共有リンクの情報がファイルに残ったままになることもあります。このように、埋め込みファイルやメタデータ、リンク情報など、ファイル内部に残る情報について注意が必要です。
また、ZIPファイル内に含まれるファイルに関しても、適切にチェックされないとセキュリティ上のリスクとなることがあります。社内の情報をZIPファイルで圧縮して送付した際に、削除し忘れたファイルが残っているケースなどは、その代表的な問題です。このようなセキュリティリスクを未然に防ぐためには、送信前にファイルの内容を十分に確認することが重要です。しかし、手動でこれらを行うのは非常に手間がかかる上、見落としのリスクもあります。
そこで、ZIPファイルやOfficeドキュメントの中身を簡単に確認・検索できるツールがあると、こうした問題を大幅に軽減することができます。このツールを使うことで、隠れた情報や意図せず残ったファイルの検出が容易になり、結果として業務効率化とセキュリティの向上に寄与します。
メタ情報ではなく中身にあるかどうかは全文検索ソフトのほうが有効です。
ツールの主な機能
このツールはPowerShellをベースにしたGUIアプリケーションで、以下の機能があります:
ZIPファイルおよびOfficeファイル内の検索
検索結果のCSVエクスポート
ZIPファイルやOfficeファイル内の主要コンテンツのプレビュー表示
右クリックメニューでのファイルやフォルダの直接開く操作
まとめ
ZIPファイルやOfficeドキュメントを大量に扱う業務において、必要な情報を効率よく見つけ出すことは非常に重要です。このツールを使えば、従来の手間のかかる作業が大幅に効率化され、より素早く目的の情報にたどり着けます。特に、セキュリティリスクを軽減するための確認作業が容易になる点は非常に有益です。
コード
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object System.Windows.Forms.Form
$form.Text = 'ZIP/Officeファイル内 検索ツール(圧縮ファイル内のファイル名検索)'
$form.Size = New-Object System.Drawing.Size(600, 600)
$form.MinimumSize = New-Object System.Drawing.Size(600, 600)
$form.StartPosition = 'CenterScreen'
$historyFilePath = "folder_history.json"
$folderHistory = @()
# 履歴の読み込み
if (Test-Path $historyFilePath) {
try {
$folderHistory = Get-Content -Path $historyFilePath | ConvertFrom-Json
} catch {
$folderHistory = @()
}
}
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10, 20)
$label.Size = New-Object System.Drawing.Size(580, 20)
$label.Text = '検索対象フォルダを選択してください:'
$form.Controls.Add($label)
# 履歴用コンボボックス
$comboBox = New-Object System.Windows.Forms.ComboBox
$comboBox.Location = New-Object System.Drawing.Point(10, 50)
$comboBox.Size = New-Object System.Drawing.Size(480, 20)
$comboBox.DropDownStyle = 'DropDownList'
$comboBox.Anchor = 'Top, Left, Right'
# 履歴をコンボボックスに追加
foreach ($folder in $folderHistory) {
$comboBox.Items.Add($folder) | Out-Null
}
$form.Controls.Add($comboBox)
$comboBox.Add_SelectedIndexChanged({
if ($comboBox.SelectedItem) {
Update-ListView (Get-ChildItem -Path $comboBox.SelectedItem -Include *.zip, *.docx, *.xlsx, *.pptx, *.docm, *.xlsm, *.pptm -Recurse)
}
})
$button = New-Object System.Windows.Forms.Button
$button.Location = New-Object System.Drawing.Point(500, 50)
$button.Size = New-Object System.Drawing.Size(75, 23)
$button.Text = '参照'
$button.Anchor = 'Top, Right'
$button.Add_Click({
$foldername = New-Object System.Windows.Forms.FolderBrowserDialog
$foldername.Description = "フォルダを選択してください"
$result = $foldername.ShowDialog((New-Object System.Windows.Forms.Form -Property @{TopMost = $true }))
if ($result -eq [Windows.Forms.DialogResult]::OK) {
$comboBox.Items.Add($foldername.SelectedPath) | Out-Null
$comboBox.SelectedItem = $foldername.SelectedPath
# 履歴に追加
if (-not $folderHistory.Contains($foldername.SelectedPath)) {
$folderHistory += $foldername.SelectedPath
# 履歴を保存
$folderHistory | ConvertTo-Json | Set-Content -Path $historyFilePath -Encoding UTF8
}
Update-ListView (Get-ChildItem -Path $foldername.SelectedPath -Include *.zip, *.docx, *.xlsx, *.pptx, *.docm, *.xlsm, *.pptm -Recurse)
}
})
$form.Controls.Add($button)
$listView = New-Object System.Windows.Forms.ListView
$listView.Location = New-Object System.Drawing.Point(10, 150)
$listView.Size = New-Object System.Drawing.Size(575, 250)
$listView.View = [System.Windows.Forms.View]::Details
$listView.FullRowSelect = $true
$listView.GridLines = $true
$listView.CheckBoxes = $true
$listView.Anchor = 'Top, Bottom, Left, Right'
$listView.Columns.Add("ファイル名", 370) | Out-Null
$listView.Columns.Add("ステータス", 100) | Out-Null
$listView.Columns.Add("対象ファイル/フォルダ", 100) | Out-Null
$form.Controls.Add($listView)
# 検索ラベルと検索テキストボックス
$searchLabel = New-Object System.Windows.Forms.Label
$searchLabel.Location = New-Object System.Drawing.Point(10, 90)
$searchLabel.Size = New-Object System.Drawing.Size(100, 20)
$searchLabel.Text = '検索文字列:'
$form.Controls.Add($searchLabel)
$searchTextBox = New-Object System.Windows.Forms.TextBox
$searchTextBox.Location = New-Object System.Drawing.Point(110, 90)
$searchTextBox.Size = New-Object System.Drawing.Size(200, 20)
$searchTextBox.Anchor = 'Top, Left, Right'
$form.Controls.Add($searchTextBox)
# 検索ボタン
$searchButton = New-Object System.Windows.Forms.Button
$searchButton.Location = New-Object System.Drawing.Point(330, 90)
$searchButton.Size = New-Object System.Drawing.Size(150, 23)
$searchButton.Text = 'ZIP/Officeファイル内検索'
$searchButton.Anchor = 'Top, Right'
$searchButton.Add_Click({
foreach ($item in $listView.CheckedItems) {
$file = Get-Item -Path $item.Text
$searchString = $searchTextBox.Text
try {
Add-Type -AssemblyName 'System.IO.Compression.FileSystem'
$zipFile = [System.IO.Compression.ZipFile]::OpenRead($file.FullName)
$found = $false
$matchedEntries = @()
foreach ($entry in $zipFile.Entries) {
if ($entry.FullName -like "*$searchString*") {
$found = $true
$matchedEntries += $entry.FullName
}
}
if ($found) {
$item.SubItems[1].Text = "見つかりました"
$item.SubItems[2].Text = ($matchedEntries -join ", ")
} else {
$item.SubItems[1].Text = "見つかりませんでした"
$item.SubItems[2].Text = ""
}
} catch {
$item.SubItems[1].Text = "エラー"
} finally {
if ($zipFile) {
$zipFile.Dispose()
}
}
}
})
$form.Controls.Add($searchButton)
# プレビュー用テキストボックス
$previewTextBox = New-Object System.Windows.Forms.TextBox
$previewTextBox.Location = New-Object System.Drawing.Point(10, 420)
$previewTextBox.Size = New-Object System.Drawing.Size(575, 100)
$previewTextBox.Multiline = $true
$previewTextBox.ReadOnly = $true
$previewTextBox.Anchor = 'Bottom, Left, Right'
$form.Controls.Add($previewTextBox)
# 右クリックメニューの作成
$contextMenu = New-Object System.Windows.Forms.ContextMenuStrip
$openFileMenuItem = New-Object System.Windows.Forms.ToolStripMenuItem("ファイルを開く")
$openFolderMenuItem = New-Object System.Windows.Forms.ToolStripMenuItem("フォルダを開く")
$openFileMenuItem.Add_Click({
if ($listView.SelectedItems.Count -gt 0) {
Start-Process -FilePath $listView.SelectedItems[0].Text
}
})
$contextMenu.Items.Add($openFileMenuItem)
$openFolderMenuItem.Add_Click({
if ($listView.SelectedItems.Count -gt 0) {
$directory = Split-Path $listView.SelectedItems[0].Text -Parent
Start-Process explorer.exe -ArgumentList $directory
}
})
$contextMenu.Items.Add($openFolderMenuItem)
$listView.ContextMenuStrip = $contextMenu
# リストビュー選択時のプレビュー表示
$listView.Add_SelectedIndexChanged({
if ($listView.SelectedItems.Count -gt 0) {
$selectedFile = $listView.SelectedItems[0].Text
try {
if ($selectedFile -match '\.zip$') {
# ZIPファイルのプレビュー
Add-Type -AssemblyName 'System.IO.Compression.FileSystem'
$zipFile = [System.IO.Compression.ZipFile]::OpenRead($selectedFile)
$entryNames = $zipFile.Entries | ForEach-Object { $_.FullName }
$previewTextBox.Text = ($entryNames -join "`r`n")
$zipFile.Dispose()
} elseif ($selectedFile -match '\.(docx|xlsx|pptx|docm|xlsm|pptm)$') {
# Officeファイルのプレビュー
Add-Type -AssemblyName 'System.IO.Compression.FileSystem'
$zipFile = [System.IO.Compression.ZipFile]::OpenRead($selectedFile)
# Officeファイルのメインコンテンツ抽出
$entry = $zipFile.Entries | Where-Object { $_.FullName -match 'word/document.xml' -or $_.FullName -match 'xl/sharedStrings.xml' -or $_.FullName -match 'ppt/slides/slide1.xml' }
if ($entry) {
$reader = [System.IO.StreamReader]::new($entry.Open())
$xmlContent = $reader.ReadToEnd()
$reader.Dispose()
# XMLのテキスト内容を簡易的に表示(タグを削除)
$previewTextBox.Text = [regex]::Replace($xmlContent, '<[^>]+>', '')
} else {
$previewTextBox.Text = "プレビューできる内容がありません"
}
$zipFile.Dispose()
} else {
# その他のテキストファイルのプレビュー
$previewTextBox.Text = Get-Content -Path $selectedFile -First 10 -ErrorAction Stop
}
} catch {
$previewTextBox.Text = "プレビューできません"
}
}
})
# CSV出力ボタン
$csvExportButton = New-Object System.Windows.Forms.Button
$csvExportButton.Location = New-Object System.Drawing.Point(10, 530)
$csvExportButton.Size = New-Object System.Drawing.Size(150, 30)
$csvExportButton.Text = '結果をCSVにエクスポート'
$csvExportButton.Anchor = 'Bottom, Left'
$csvExportButton.Add_Click({
$csvFilePath = (Join-Path (Split-Path -Parent (Get-Location)) '検索結果.csv')
$data = @()
foreach ($item in $listView.Items) {
$data += [PSCustomObject]@{
ファイル名 = $item.Text
ステータス = $item.SubItems[1].Text
対象ファイルフォルダ = $item.SubItems[2].Text
}
}
$data | Export-Csv -Path $csvFilePath -NoTypeInformation -Encoding UTF8
[System.Windows.Forms.MessageBox]::Show("結果がCSVにエクスポートされました: $csvFilePath", "完了", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
})
$form.Controls.Add($csvExportButton)
function Update-ListView($files) {
$listView.Items.Clear()
foreach ($file in $files) {
$item = New-Object System.Windows.Forms.ListViewItem($file.FullName)
$item.SubItems.Add("未処理") | Out-Null
$item.SubItems.Add("") | Out-Null
$item.Checked = $true
$listView.Items.Add($item) | Out-Null
}
}
$form.Add_Shown({$comboBox.Select()})
$result = $form.ShowDialog()