ファイルのインデックスをSQLiteのテーブルとして保存しテーブルからファイルを検索するスクリプトです。
モジュールのインストール
Install-Module SQLite
スクリプト
ファイル名:PowerSearch.ps1
<#
.SYNOPSIS
ファイルを検索するスクリプト
.DESCRIPTION
要SQLite
.EXAMPLE
.\PowerSearch.ps1 -SearchWord "a%"
.OUTPUTS
PSCustomObject
.PARAMETER SearchWord
検索文字
.PARAMETER Update
インデクスを更新
.PARAMETER Help
ヘルプを表示
.LINK
関連URL
#>
using namespace System.Data.SQLite
param(
[string]
$SearchWord,
[switch]
$Update,
[switch]
$Help
)
if ($Help) {
Get-Help $PSCommandPath
Exit 1
}
# モジュールのインポート
Import-Module SQLite
# 検索対象のフォルダー
$SearchFolders = @("H:\ps1\PowerSearch\data")
# 最終更新日時ファイルのパス
$LastUpdatePath = Join-Path (Split-Path $PSCommandPath -Parent) "lastupdate.txt"
# ファイルデータベースのパス
$FileDBPath = Join-Path (Split-Path $PSCommandPath -Parent) "files.db"
# コネクションオブジェクトの生成
$Connection = [SQLiteConnection]::new() | % {
$_.ConnectionString = ("Data Source = {0}"-f $FileDBPath)
$_.Open()
$_
}
# テーブル作成
$Command = [SQLiteCommand]::new()
$Command.Connection = $Connection
$Command.CommandText = @"
CREATE TABLE IF NOT EXISTS files (
full_name text,
name text,
lastwreite text,
size long,
primary key(full_name)
)
"@
$Command.ExecuteNonQuery() | Out-Null
# インデックスの作成
$Command.CommandText = @"
CREATE INDEX IF NOT EXISTS files_name ON files(name)
"@
$Command.ExecuteNonQuery() | Out-Null
# 最終更新日時ファイル作成
if (-not (Test-Path $LastUpdatePath)) {
"1970/01/01 00:00" | Out-File -FilePath $LastUpdatePath
}
# 最終更新日時を保存
function SaveLastUpdate {
# 1分前
$dt = (Get-Date).AddMinutes(-1).ToString("yyyy/MM/dd HH:mm")
$dt | Out-File -FilePath $LastUpdatePath
}
#SaveLastUpdate
# 最終更新日時を読み込み
function LoadLastUpdate {
Get-Content -LiteralPath $LastUpdatePath
}
#LoadLastUpdate
# データベースを更新
function UpdateDB {
param (
[string]
$fullName,
[string]
$name,
[string]
$lastwrite,
[long]
$size
)
$fullName = $fullName -replace "'", "''"
$name = $name -replace "'", "''"
$Command.CommandText = @"
SELECT COUNT(*) AS CNT FROM files WHERE full_name = '$fullName'
"@
$rec = $Command.ExecuteReader()
$cnt = $rec["CNT"]
$rec.Close()
if ($cnt -eq 0) {
$Command.CommandText = @"
INSERT INTO files (full_name, name, lastwreite, size) values ('$fullName', '$name', '$lastwrite', $size)
"@
Write-Host $Command.CommandText
} else {
$Command.CommandText = @"
UPDATE files SET name = '$name', lastwreite = '$lastwreite', size = $size WHERE full_name = '$fullName'
"@
}
$Command.ExecuteNonQuery() | Out-Null
}
# テーブルの削除
function DeleteTable {
param (
[string]
$fullName
)
$fullName = $fullName -replace "'", "''"
$Command.CommandText = @"
DELETE FROM files WHERE full_name = '$fullName'
"@
$Command.ExecuteNonQuery() | Out-Null
}
# インデクスの更新
function UpdateIndex {
$dt = [DateTime](LoadLastUpdate)
Write-Host ("前回更新:{0}以降のファイルを検索更新" -f $dt)
SaveLastUpdate
$SearchFolders | ForEach-Object {
$SearchFolder = $_
Get-ChildItem -LiteralPath $SearchFolder -File -Recurse | Where-Object {
$_.LastWriteTime -gt $dt
} | ForEach-Object {
UpdateDB $_.FullName $_.Name $_.LastWriteTime.ToString("yyyy/MM/dd HH:mm") $_.Length
}
}
}
# 検索文字
function SearchIndex {
$deleteFiles = @()
$Command.CommandText = @"
SELECT full_name, name, lastwreite, size FROM files WHERE name like '$SearchWord'
"@
$rec = $Command.ExecuteReader()
while ($rec.Read()) {
$fullName = $rec['full_name']
if (Test-Path -LiteralPath $fullName) {
[PSCustomObject]@{
"Name"=$rec['name']
"Location"=(Split-Path $rec['full_name'] -Parent)
"LastWrite"=$rec['lastwreite']
"Size" = $rec['size']
}
} else {
$deleteFiles += $fullName
}
}
$rec.Close()
$deleteFiles | ForEach-Object { DeleteTable $_ }
}
# 更新
if ($Update) {
UpdateIndex
}
# 検索
if ($SearchWord -ne "") {
SearchIndex
}
# コネクションを閉じる
$Connection.Close()
使い方
・検索フォルダの設定はスクリプト内の$SearchFoldersにパスをセット(複数指定可)
・インデックスの更新
.\PowerSearch.ps1 -Update
・検索
.\PowerSearch.ps1 -SearchWord "a%"
例は、aから始まるファイル名を検索します。
(%は任意の0文字以上の文字列、_は任意の1文字とマッチングします。)
コメント