web-dev-qa-db-ja.com

PowerShellスクリプトでロックされたファイルを検出してスキップするにはどうすればよいですか?

ですから、私は自分自身にPowerShellスクリプトを持っており、多くの頭痛の種の後で仕事に取り掛かりました。 Iiは不要になったファイルを削除し、すべてが素晴らしいです。唯一の問題は、別のプログラムによって開かれているかどうかに関係なくファイルを削除することです。これは悪いことです。私のコードは次のとおりです。

# Change the value $oldTime in order to set a limit for files to be deleted.
$oldTime = [int]30 # 30 days
foreach ($path in Get-Content "pathList.txt") {
        # Write information of what it is about to do
        Write-Host "Trying to delete files older than $oldTime days, in the folder $path" -ForegroundColor Green
        # deleting the old files
        Get-ChildItem $path -Recurse -filter "*EDI*" | WHERE {$_.LastWriteTime -le $(Get-Date).AddDays(-$oldTime)} | Remove-Item -Force

スクリプトがファイルが開いていることを確認し、そのファイルをスキップして次に進む方法が必要です。 Windows 7SP1でPowerShell2.0を実行しています。

1
user1210394

一般に、テストしようとするとファイルがロックされているかどうかに関係なく、チェックの直後に別のスレッド/プロセスによってファイルがロックされる可能性があるため、あらゆる種類の競合状態が発生する可能性があります。また、WindowsVistaからのみ利用可能なRestartManager APIを介して行われない限り、チェックにはロック自体が必要です( この回答 を参照)。だからあなたは警告されました。

これがPowerShell関数で、ファイルがロックされているかどうかをチェックします。この質問からPowerShellに適応: https://stackoverflow.com/questions/876473/is-there-a-way-to-check-if-a-file-is-in-use

コピーして貼り付けるか、スクリプトと一緒にTest-IsFileLocked.ps1として保存し、ドットソーシングを使用して以下を読み込みます。

$ScriptDir = Split-Path $script:MyInvocation.MyCommand.Path
. (Join-Path -Path $ScriptDir -ChildPath 'Test-IsFileLocked.ps1')

次に、スクリプトの最後の行を次のように変更します。

Get-ChildItem $path -Recurse -filter "*EDI*" | WHERE {($_.LastWriteTime -le $(Get-Date).AddDays(-$oldTime)) -and !(Test-IsFileLocked -Files $_.FullName)} | Remove-Item -Force

Test-IsFileLocked関数自体:

function Test-IsFileLocked
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [ValidateNotNullOrEmpty()]
        [string[]]$Files
    )

    Process
    {
        # Foreach loop to accept arrays either from pipeline or Files parameter
        foreach ($file in $Files)
        {
            $Locked = $false

            try
            {
                # Try to open file
                $Test = [System.IO.File]::Open($file, 'Open', 'ReadWrite', 'None')

                # Close file and dispose object if succeeded
                $Test.Close()
                $Test.Dispose()
            }
            catch
            {
                # File is locked!
                $Locked =  $true
            }

            # Write file status to pipeline
            $Locked
        }
    }
}
1
beatcracker