Powershell - Skip files that cannot be accessed
If you want to suppress the error message and continue executing, you need to use -ErrorAction Ignore
or -ErrorAction SilentlyContinue
.
See Get-Help about_CommonParameters
:
-ErrorAction[:{Continue | Ignore | Inquire | SilentlyContinue | Stop | Suspend }] Alias: ea Determines how the cmdlet responds to a non-terminating error from the command. This parameter works only when the command generates a non-terminating error, such as those from the Write-Error cmdlet. The ErrorAction parameter overrides the value of the $ErrorActionPreference variable for the current command. Because the default value of the $ErrorActionPreference variable is Continue, error messages are displayed and execution continues unless you use the ErrorAction parameter. The ErrorAction parameter has no effect on terminating errors (such as missing data, parameters that are not valid, or insufficient permissions) that prevent a command from completing successfully. Valid values: Continue. Displays the error message and continues executing the command. "Continue" is the default value. Ignore. Suppresses the error message and continues executing the command. Unlike SilentlyContinue, Ignore does not add the error message to the $Error automatic variable. The Ignore value is introduced in Windows PowerShell 3.0. Inquire. Displays the error message and prompts you for confirmation before continuing execution. This value is rarely used. SilentlyContinue. Suppresses the error message and continues executing the command. Stop. Displays the error message and stops executing the command. Suspend. This value is only available in Windows PowerShell workflows. When a workflow runs into terminating error, this action preference automatically suspends the job to allow for further investigation. After investigation, the workflow can be resumed.
If you're having terminating errors that -ErrorAction
is not trapping, then you have to trap them yourself with a try / catch.
Here's a naive example:
Get-ChildItem "C:\Users\user\Desktop\The_folder\*" -Recurse -Force `
| Sort-Object -Property FullName -Descending `
| ForEach-Object {
try {
Remove-Item -Path $_.FullName -Force -ErrorAction Stop;
}
catch { }
}
Here, I'm using -ErrorAction Stop
to turn all non-terminating errors into terminating errors. Try
will trap any terminating error. The catch
block is empty, however, so you're trapping everything and then not doing any error handling. The script will continue silently. This is basically equivalent to VBScript's On Error Resume Next
. You have to iterate through the files, however, otherwise Remove-Item
will stop at the first error.
Note that I have a Sort-Object
in there. That's so the items coming through the pipeline are in reverse order. That way, files and subdirectories will be deleted before the directories that contain them. I'm not 100% sure if that method is perfect, but I think it should work. The alternative is really messy.
Obviously, there's no way to tell from output when an error occurs or what wasn't deleted. We're trapping all errors and then throwing them away. Usually an empty catch
block is a really bad idea, so use this method with caution!
You'll note that I'm not actually testing to see if the file is opened or locked. That's because it's kind of a waste of time. We don't really care why the file can't be deleted, just that it can't and when it can't we skip it. It's easier (and faster) to try to delete the file and trap the failure than it is to check if it's locked, use a conditional to decide to delete the file, and then delete the file or continue.