Wie kann ich gesperrte Dateien in einem PowerShell-Skript erkennen und überspringen?

7723
user1210394

Also habe ich selbst ein PowerShell-Skript, das ich nach vielen Kopfschmerzen zum Laufen brachte. Ich lösche Dateien, die ich nicht mehr will und alles ist großartig. Nur ein Problem, es wird eine Datei gelöscht, unabhängig davon, ob sie von einem anderen Programm geöffnet wurde oder nicht. Mein Code lautet wie folgt:

# 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 

Ich brauche nur eine Möglichkeit für das Skript, um zu sehen, dass eine Datei geöffnet ist. Diese Datei überspringen und fortfahren. Ich führe PowerShell 2.0 unter Windows 7 SP1 aus.

1
Sind Sie sicher, dass die Dateien beim Öffnen gesperrt sind? Häufig erstellen Programme eine temporäre Kopie (oder laden sie ganz in den Speicher) und geben dann die Dateisperre frei, damit andere darauf zugreifen können. Wenn Sie das nächste Mal speichern, wird die Datei gerade lange genug gesperrt, um sie zurückzuspeichern. Grundsätzlich kann also nicht festgestellt werden, ob die Datei verwendet wird oder nicht - je nach dem Programm, das sie geöffnet hat. Ƭᴇcʜιᴇ007 vor 9 Jahren 0
Zum Beispiel habe ich einen Ordner mit MP3s getestet. Als ich versuchte, alles in diesem Ordner zu löschen, löschte es alles außer der Datei, die ich mir angehört habe, aber es wurden Fehler gemacht. Es sagte, dass es von einem anderen Prozess verwendet wurde. Ich brauche nur einen Weg, um diese Dateien zu überspringen, nur für den Fall, dass ich auf dieses Problem stoße. Es wird jedoch hauptsächlich zum Löschen von TXT-Dateien verwendet. user1210394 vor 9 Jahren 0

1 Antwort auf die Frage

1
beatcracker

Im Allgemeinen kann der Versuch, zu prüfen, ob eine Datei gesperrt ist oder nicht, zu allen möglichen Race-Bedingungen führen, da die Datei unmittelbar nach unserer Prüfung durch einen anderen Thread / Prozess gesperrt werden könnte. Die Überprüfung erfordert eine Sperre selbst, es sei denn, dies erfolgt nicht über die Restart Manager-API, die nur unter Windows Vista verfügbar ist (siehe Antwort ). Sie wurden also gewarnt.

Hier ist die PowerShell-Funktion, die prüft, ob die Datei gesperrt ist oder nicht. An die PowerShell von dieser Frage angepasst: https://stackoverflow.com/questions/876473/is-there-a-way-to-check-if-a-file-is-in-useuse

Kopieren Sie es oder speichern Sie es zusammen mit Ihrem Skript als Test-IsFileLocked.ps1und verwenden Sie Dot-Sourcing, um Folgendes zu laden:

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

Ändern Sie dann die letzte Zeile Ihres Skripts in:

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

Test-IsFileLocked Funktion selbst:

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 } } }