如何检测并跳过 PowerShell 脚本中的锁定文件?

如何检测并跳过 PowerShell 脚本中的锁定文件?

因此,我编写了一个 PowerShell 脚本,经过一番苦恼之后,终于开始使用它。它可以删除我不再需要的文件,而且一切都很顺利。只有一个问题,无论文件是否被其他程序打开,它都会删除该文件,这很糟糕。我的代码如下:

# 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 7 SP1 上运行 PowerShell 2.0。

答案1

通常,尝试测试文件是否锁定可能会导致各种竞争条件,因为文件可能在我们检查后立即被另一个线程/进程锁定。并且检查本身需要锁定,除非它不是通过仅从 Windows Vista 开始提供的 Restart Manager 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
        }
    }
}

相关内容