はじめに
この記事は身の回りの困りごとを楽しく解決! by Works Human Intelligence Advent Calendar 2025 8日目の記事です。
会社で特定の拡張子のファイルを一覧で取得したいと言われました。
基本的にプログラムを書く人が少ない今の環境で私もメンションに含まれているということは
「お前作れるやろ?やってや」
という意味でしょう。
スルーする度胸は無いのでおとなしく詳細な要件を聞いて作成していきたいと思います。
要件
要件は下記のとおりらしいです。
・一定期間を過ぎたファイルの一覧を出力する
・出力は.txtで良い
・ローカル環境で実行
要するに昔のファイルを一覧に出してもらえれば人間が削除してよいか判断するってことです。
(消してよいものだけ記載されたtxtファイルを参照して自動削除するプログラムも必要じゃない?)
新人は頼まれたことだけやりましょう。
プログラム作成
今回は.batと.ps1で作成していきます。
お客様の環境で実行するらしいので、ダブルクリックで実行できる.batを用意します。
基本的なプログラムそのものはPowerShellで実行していきます。
@echo off
echo Start Programs. Please wait...
@REM スクリプトパス
SET SCRIPT_PATH=".\\SearchFiles.ps1"
@REM PowerShellの実行許可を与えて実行
powershell.exe -ExecutionPolicy ByPass -File %SCRIPT_PATH%
echo Finished Programs. Please check the log file.
pause
# 検索対象の日付
$TargetStartDate = Get-Date "yyyy/MM/dd"
$SearchPath = "C:\\"
# 結果出力ファイルパス
$OutputPath = ".\\result.txt"
# ヘッダー行を追加
"CreationTime | Name | FullName" | Out-File -FilePath ${OutputPath} -Encoding UTF8 -Append
"----------------------|------|-------------------------------------------------------" | Out-File -FilePath ${OutputPath} -Encoding UTF8 -Append
Get-ChildItem -Path ${SearchPath} -Include "*.txt" -Recurse -ErrorAction SilentlyContinue |
Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $TargetStartDate } |
ForEach-Object {
$CreationTimeFormatted = $_.CreationTime.ToString("yyyy/MM/dd HH:mm:ss")
"${CreationTimeFormatted} | $($_.Name) | $($_.FullName)"
} |
Format-Table -AutoSize |
Out-File -FilePath ${OutputPath} -Encoding UTF8 -Append
プログラムの説明
batファイル
batファイルは工夫されているわけではないので簡単に
@echo off
@ echo offは出力時にファイルのコマンド内容まで表示しないための設定だそうです。
あえて設定しないことがあるのか分かりませんが、設定しないことが多いのであればデフォルトで表示しなければいいのに。。。
詳細は先人が書いた記事をご覧ください。
@REM スクリプトパス
SET SCRIPT_PATH=".\\SearchFiles.ps1"
今回始めて.batファイルを作成したのですがコメントアウトが@ REMで始まるんですね。
ネットで調べたところremarkの意味だそうです。
「注釈」とかの訳が個人的にはしっくりきました。
その後は変数設定を行い、ファイルパスを変数として格納します。
@REM PowerShellの実行許可を与えて実行
powershell.exe -ExecutionPolicy ByPass -File %SCRIPT_PATH%
Powershellの実行でPCの設定によっては実行を許可しない場合があります。
Restrictedが規定値です。
これを許可します。
ExecutionPolicyで検索すると分かりますが、普通であれば許可したものを戻す必要があります。
セキュリティの観点から勝手に実行しないように設定されているので今回のように問答無用でBypass実行することは普通推奨されません。
今回は業務上必要な実行であるということと、-FileオプションでBypassにするファイルを限定していることから戻す処理は不要です。
記載忘れそうでしたが、この処理で.ps1ファイルを呼び出し実行しています。
echo Finished Programs. Please check the log file.
pause
終わったことを人間へ伝えるためにコマンドプロンプトで文字表示をします。
pauseがないと一瞬表示されて人間の目では確認できないです。
無いなら無いでコマンドプロンプトが自動で終了するので、今回は無くても良い部分です。
ps1ファイル
# 検索対象の日付
$TargetStartDate = Get-Date "yyyy/MM/dd"
$SearchPath = "C:\\"
$OutputPath = ".\\result.txt"
PowerShellの方は変数を指定するときは先頭に$を付ける必要があります。
今回は検索対象となるフォルダと対象となる日付を変数指定します。
最後にログの出力先を指定すれば完了です。
# ヘッダー行を追加
"CreationTime | Name | FullName" | Out-File -FilePath ${OutputPath} -Encoding UTF8 -Append
"----------------------|------|-------------------------------------------------------" | Out-File -FilePath ${OutputPath} -Encoding UTF8 -Append
Get-ChildItem -Path ${SearchPath} -Include "*.txt" -Recurse -ErrorAction SilentlyContinue |
Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $TargetStartDate } |
ForEach-Object {
$CreationTimeFormatted = $_.CreationTime.ToString("yyyy/MM/dd HH:mm:ss")
"${CreationTimeFormatted} | $($_.Name) | $($_.FullName)"
} |
Format-Table -AutoSize |
Out-File -FilePath ${OutputPath} -Encoding UTF8 -Append
最初の部分はログファイルにヘッダーを追加するだけなので無視します。
Get-Childrenは中にあるファイル一覧を取得するコマンドです。
今回は引数として以下のものを利用しています。
| 1 | 2 |
|---|---|
| -Path | 検索するフォルダパスを指定します。 指定が無ければ現在のディレクトリから検索します。 |
| -Include | ファイル名の中に特定の内容が含まれているもののみにします。 -Filterもありますが、-Includeは複数条件をできるので個人的に便利だと思っています。(jpg,jpeg,JPGみたいな差分も条件にできる) |
| -Recurse | 特に引数はありませんが、-Includeの時にサブディレクトリなども検索します。 フォルダ指定をミスると実行時間が長くなるので注意 |
| -ErrorAction | エラー発生時の処理を決められます。今回は無視してその後を実行するようにしていますがStopも可能です。 |
Get-ChildItem -Path ${SearchPath} -Include "*.txt" -Recurse -ErrorAction SilentlyContinue
Where-Objectは発見されたファイルの中からさらに条件を絞りたいときに利用します。
Get-ChildItemにこいつを入れてくれれば一つで終わるのに・・・
基本的に$_は発見されたファイルのことを指していると考えて下さい。
PSIsContainerはそれがディレクトリであるかを確認します。
True or Falseで返されるので!によりFalseの時、Trueになります。
見つかったファイルがディレクトリではない(=ファイルである)かを確認します。
CreationTimeは作成日です。
更新日などでフィルターする場合は別の引数を利用してください。
作成日が特定の日付(TargetStartDate)以前であるかを確認しています。
Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $TargetStartDate }
ForEach-Objectは今までの条件を全て満たすファイルにのみ実行される内容です。
後々ログファイルに記載することを考えてフォーマット通りの記載になるように成型しているだけです。
ForEach-Object {
$CreationTimeFormatted = $_.CreationTime.ToString("yyyy/MM/dd HH:mm:ss")
"${CreationTimeFormatted} | $($_.Name) | $($_.FullName)"
}
Format-Table -AutoSizeは各要素の大きさなどから記載時の表(Table)を自動で良さげなサイズにします。
・・・「良さげ」の定義の決め方を知らないので何とも言えませんが。
最後にOut-Fileでファイルに出力します。 エンコードはUTF8を利用し、上書きではなく順番にログファイルに記載するために-Append引数を忘れずにつけておきます。
Format-Table -AutoSize |
Out-File -FilePath ${OutputPath} -Encoding UTF8 -Append
最後に
以上でプログラムファイルの流れを記載しました。
先ほどQiitaを記載している間に「ファイルの自動削除プログラム」を作成するように指示があったので、諦めて作るとします。。。
他のファイルを削除するわけは行かないので、丁寧に作成してきます。