ewall
ewall

Reputation: 28110

Can PowerShell trap errors in GetChildItem and continue looping?

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

Answers (4)

Qasmaj
Qasmaj

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

Kluk
Kluk

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

Jesse
Jesse

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

Matt
Matt

Reputation: 1969

have you used silentlycontinue?

foreach($file in Get-ChildItem $dirRoot -Recurse -ErrorAction silentlycontinue) {
    ...
}

Upvotes: 9

Related Questions