Reputation: 28110
I have a PowerShell script that is recursing down thru the file system using GetChildItem in a for-loop. As it travels, it is fixing ACL issues it finds (mostly where someone has blocked the BUILTIN\Administrators account)... but there are some it can't handle on it's own, like when I get [System.UnauthorizedAccessException] if there is an explicit "Deny" ACE.
The line of code looks like this:
foreach($file in Get-ChildItem $dirRoot -Recurse -ErrorAction Continue) {
...
}
When it stumbles on a path it can't read, it gives this exception:
Get-ChildItem : Access to the path 'C:\TEMP\denied' is denied. At Fix-ACLs.ps1:52 char:31 + foreach($file in Get-ChildItem <<<< $dirRoot -Recurse -ErrorAction Continue) { + CategoryInfo : PermissionDenied: (C:\TEMP\denied:String) [Get-ChildItem], Unauthorized AccessException + FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
I would like to try/catch or trap the error so that I can repair the ACL (that is, remove the "Deny") in-place, and--most importantly--continue the loop without losing my place. Any suggestions for me?
Upvotes: 8
Views: 19709
Reputation: 11
Try and Catch blocks will only handle terminating errors so if (as it is in this case) the error is non terminating you will need to define an error action that terminates. If you change your error action to 'Stop' it will jump to the Catch block(s) and then carry on with your script.
You can then create a specific catch block for that error and then attempt to remediate your issue / test.
More info below: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-7.2
With that in mind you could do something like the below:
foreach($file in Get-ChildItem $dirRoot -Recurse -ErrorAction Stop) {
...
}
Catch [System.UnauthorizedAccessException]{
#Catch error in question, remediate, log or 'PAUSE' for manual intervention
}
Catch{
#Deal with any other errors
}
Hopefully that is useful.
Upvotes: 1
Reputation: 135
I would use this to:
ForEach($file in Get-ChildItem $dirRoot -Recurse -ErrorAction silentlycontinue) {
...
}
And then, you can filter $Error to get specifically Permission Denied type errors:
$permError += $Error | Where-Object { $_.CategoryInfo.Category -eq 'PermissionDenied' }
ForEach($deniedAccess in $permError)
{
$deniedAccess.CategoryInfo.TargetName | Do Stuff
}
Upvotes: 0
Reputation: 51
How about Inquire?
foreach($file in Get-ChildItem $dirRoot -Recurse -ErrorAction Inquire) {
...
}
Maybe open up a second PS window to troubleshoot the error then continue the command in the first PS window by selecting Y for continue.
You can also use ErrorVariable
foreach($file in Get-ChildItem $dirRoot -Recurse -ErrorVariable a) {
...
}
Get-Variable a or $a will show you all the errors incurred by the command. You can also use +variablename (+a) to add errors to an existing variable.
foreach($file in Get-ChildItem $dirRoot -Recurse -ErrorVariable +a) {
...
}
Upvotes: 5
Reputation: 1969
have you used silentlycontinue?
foreach($file in Get-ChildItem $dirRoot -Recurse -ErrorAction silentlycontinue) {
...
}
Upvotes: 9