1

Так что у меня есть сценарий 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

Мне просто нужен сценарий, чтобы увидеть, что файл открыт, пропустить указанный файл и двигаться дальше. Я использую PowerShell 2.0 на Windows 7 SP1.

1 ответ1

1

Как правило, попытка тестирования заблокирована или нет, может привести к всевозможным состояниям гонки, поскольку файл может быть заблокирован другим потоком / процессом сразу после нашей проверки. А проверка требует самой блокировки, если только она не выполняется через API Restart Manager, который доступен только из Windows Vista (см. Этот ответ). Так что вы были предупреждены.

Вот функция 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
        }
    }
}

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .