最初のPowerShellスクリプトを書く方法:ファイルクリーンアップの自動化

コーディングする際に従うべき最も重要な方法論の一つは、コードがどのように「流れる」かを把握し管理することです。コードを流れとして考えると、枝分かれしたり、さまざまなポイントに戻ったり、多くの条件に遭遇したりすることがあります。

エラー処理は、予期しないことが起きたときにコードが流れるデフォルトの場所や「網」を設定することを確実にします。

PowerShellのエラー処理を扱う実際のシナリオを使って、自分が置かれるかもしれない現実世界の状況に対処していきましょう。

ファイルクリーンアップのための初期スクリプトの構築

古いファイルをクリーンアップする必要があります。ファイルサーバーは永遠に存在しており、スペースを整理する必要があります。管理部門は、特定の日数よりも古いすべてのファイルを削除することを決定しました。フォルダを再帰的に検索し、特定の日数よりも古いすべてのファイルを見つけて削除するスクリプトを構築する必要があります。

このタスクは十分に簡単そうですが、これはエラーハンドリングセクションなので、何かがうまくいかないことがわかります!

まず、エラーハンドリングが解決する問題を実証するために、エラーハンドリングのないシナリオのデモスクリプトを最初に構築することからエラーハンドリングを理解し始めましょうエラーハンドリングなしで

  1. まず、新しいVS Codeタブを開いてください。

    今はいくつか試しているだけなので、まだスクリプトを保存しません。一時的に、VS CodeにPowerShellを書くつもりであることを伝えてください。

    Ctrl-Shift-Pを押し、’lang’と入力し、言語モードを選択と入力し、’power`と入力してPowerShellを選択します。これで、VS CodeはPowerShellを書くことを認識します。

  2. 次に、問題をタスクに分け、最も明白なものから解決します。

    この場合、タスクはディレクトリ内のファイルを読み取るコマンドを考え出します。

    Get-ChildItem -Path C:\OldForgottenFolder
    
  3. Get-ChildItemは不要なディレクトリも返すので、ファイルのみを制限します。

    Get-ChildItem -Path C:\OldForgottenFolder -File
    
  4. サブディレクトリにファイルがある場合、それらもRecurseで取得する必要があります。

    Get-ChildItem -Path C:\OldForgottenFolder -File -Recurse
    
  5. コマンドとパラメータが揃ったので、すべてのファイルが返されています。特定の日数よりも古いファイルを見つける必要があります。

    Get-ChildItemが各ファイルをLastWriteTimeオブジェクトプロパティと共に返すため、そのプロパティでフィルターをかける必要があります。指定した日付よりもLastWriteTimeが古いファイルを見つけるためにWhereフィルターを使用します。

    (Get-ChildItem -Path C:\OldForgottenFolder -File -Recurse).Where{$_.LastWriteTime -le ?????}
    
  6. 日付は動的である必要があります。なぜなら、今日の「古い」は明日の「古い」とは異なるからです。

    前の行をコメントアウトしてください。なぜなら、後で必要になるからです。そして日付の状況を考えます。

    ## (Get-ChildItem -Path C:\\OldForgottenFolder -File -Recurse).Where{$_.LastWriteTime -le ?????}
    $Now = Get-Date
    $Now
    
  7. 今日の日付が分かったので、今日の特定の日数前の日付を見つけましょう。基本的なテストを行うために、ここに一時的に30を入れておきます。いくつかのファイルが5日以上古いことを知っているからです。

    ## (Get-ChildItem -Path C:\\OldForgottenFolder -File -Recurse).Where{$_.LastWriteTime -le ?????}
    $Now = Get-Date
    $LastWrite = $Now.AddDays(-30)
    $LastWrite
    
  8. 完了!ここまでまとめましょう。

    $Now = Get-Date
    $LastWrite = $Now.AddDays(-30)
    (Get-ChildItem -Path C:\OldForgottenFolder -File -Recurse).Where{$_.LastWriteTime -le $LastWrite}
    

    これで、特定の日数より古いディレクトリ内のすべてのファイルを見つける小さなスクリプトができました。

  9. 次に、古いファイルを削除する機能を追加する必要があります。これはRemove-Itemコマンドレットとパイプラインを使用することで簡単です。

    $Now = Get-Date
    $LastWrite = $Now.AddDays(-30)
    (Get-ChildItem -Path C:\OldForgottenFolder -File -Recurse).Where{$_.LastWriteTime -le $LastWrite} | Remove-Item
    
  10. 完了!でも待って、どのファイルが削除されたのか全くわからない。いくつかのエラーもあり、これについては数分後に対処する予定だ。基本的な機能を追加しよう。

    $VerbosePreference = 'Continue'
    
    $Now = Get-Date
    $LastWrite = $Now.AddDays(-30)
    $oldFiles = (Get-ChildItem -Path C:\OldForgottenFolder -File -Recurse).Where{$_.LastWriteTime -le $LastWrite}
    foreach ($file in $oldFiles) {
        Remove-Item -Path $file.FullName
        Write-Verbose -Message "成功裏に削除されました [$($file.FullName)]。"
    }
    
  11. 各ファイルに対して何らかのコードを実行するために、このようなループを含める必要がある。ここではパイプラインを使用せず、見つかったすべてのファイルをoldFiles変数、つまりファイルオブジェクトの配列に格納している。そして以前のように各ファイルに対してRemove-Itemを実行しているが、今回は削除されるファイルを知らせる詳細メッセージを含めている。

  12. さて、このコードを実行して何が起こるか見てみましょう。

    今、冗長メッセージを通じていくつかのファイルが削除されたことがわかります。今、私たちが持っているコードはスクリプトを作成するために必要な要素です。次のセクションでこのコードから実際のスクリプトを作成しましょう。

パラメータを使用して柔軟性と再利用性を最大化する

スクリプトを作成しましたが、それはまだ柔軟性があり再利用可能な可能性があります。どうやって?パラメータを使用することで、対象とするディレクトリとファイルの年齢を指定できるようになり、スクリプトが柔軟になります。

  1. さらに進む前に、作業内容を保存しましょう。名前をRemove-FileOlderThan.ps1と付けましょう。

    一貫性と可読性のために、できる限りPowerShellコマンドと同じ形式でスクリプト名を作成するようにします。

  2. まず、スクリプトは再利用可能であるべきです。おそらく、このスクリプトを異なるディレクトリや異なる日数で使用したいと思うかもしれません。いくつかのパラメータを導入する必要があります。そのために、何が変わるかを考えます。ディレクトリと日数ですね。

    param (
        [Parameter(Mandatory)]
        [string]$FolderPath,
    [Parameter(Mandatory)]
    [int]$DaysOld
    

    )

    $Now = Get-Date
    $LastWrite = $Now.AddDays(-30)
    $oldFiles = (Get-ChildItem -Path C:\OldForgottenFolder -File -Recurse).Where{$_.LastWriteTime -le $LastWrite}
    foreach ($file in $oldFiles) {
    Remove-Item -Path $file.FullName
    Write-Verbose -Message "Successfully removed [$($file.FullName)]."
    }

    最初に、スクリプトは再利用可能であるべきです。おそらく、このスクリプトを異なるディレクトリや異なる日数で使用したいと思うかもしれません。いくつかのパラメータを導入する必要があります。そのために、何が変わるかを考えます。ディレクトリと日数ですね。

  3. 以前のコードにあった静的な項目をパラメータの値に置き換えます。

    param (
        [Parameter(Mandatory)]
        [string]$FolderPath,
    [Parameter(Mandatory)]
    [int]$DaysOld
    

    )

    $Now = Get-Date
    $LastWrite = $Now.AddDays(-$DaysOld)
    $oldFiles = (Get-ChildItem -Path $FolderPath -File -Recurse).Where{$_.LastWriteTime -le $LastWrite}
    foreach ($file in $oldFiles) {
    Remove-Item -Path $file.FullName
    Write-Verbose -Message "[$($file.FullName)] を正常に削除しました。"
    }

  4. さて、スクリプトを実行して結果を見てみましょう。

    C:\Scripts\Remove-FileOlderThan.ps1 -FolderPath C:\OldForgottenFolder -DaysOld 30 -Verbose
    

    フォルダのパスと日数をパラメータとして指定する必要があることが分かります。 Verbose パラメータを使用して、Write-Verbose 行を表示できます。

    PowerShell は以前とまったく同じようにスクリプトを実行しましたが、今では任意のディレクトリやファイルの年齢を使用できるパラメータ化されたスクリプトを持っています!

    出力を見ると、赤いテキストがいくつか表示されました。権限がないか、ファイルが読み取り専用である可能性があります。しかし、どのファイルで失敗したのでしょうか?そして、それらのファイルも削除されるようにするにはどうすればよいでしょうか?

    結論

    このチュートリアルでは、ディレクトリから古いファイルをクリーンアップするスクリプトを作成し、パラメータを追加して柔軟性を確保しました。スクリプトは意図どおりに動作しますが、まだエラーハンドリングが対応されていないことがわかりました。これは実際のシナリオに取り組む際に重要です。

    今後は、エラー管理を追加することで、コマンドレットがエラーをスローしたり、ファイルにアクセスできないなどの問題に対処できるようになり、スクリプトの停止を回避し、何が間違ったのかについて詳細な洞察を提供できるようになります。

    次のデモをお楽しみに! PowerShell 101: Terminating, Non-Terminating Errors, and Try/Catch.

Source:
https://adamtheautomator.com/powershell-file-cleanup-script/