Catching errors and handling blocked files in PowerShell

Viewed 114

The history of this question lies in an earlier question I asked here

I am running this command to get the file hashes of all files in a given location, but I need to capture any that are missed or inaccessible.

Get-ChildItem -Path $Path -Filter $Filename -File -Recurse -Force -ErrorVariable FailedItems -ErrorAction SilentlyContinue | ForEach-Object { Get-FileHash -Path $_.FullName | Select-Object * }
$FailedItems | Foreach-Object {$_.CategoryInfo.TargetName} | Out-File "C:\Users\sailingbikeruk\Desktop\noaccess.log"

In the earlier question I thought that I just needed to catch folders, and the answer given and accepted did capture any folder access denied messages but the command doesn't capture individual files that are inaccessible. The suggested answer (using -errorvariable) doesn't appear to record the path of these.

I am not clear as to why the -ErrorVariable is catching the paths from this error:

get-childitem : Access to the path 'C:\$Recycle.Bin\S-1-5-21-4167544967-4010527683-3770225279-9182' is denied.
At E:\git\Get-RemoteFileHashesRecursive\Get-FileHashesRecursive.ps1:14 char:9
+         get-childitem -path $path -filter $filename -Recurse -Force | ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : PermissionDenied: (C:\$Recycle.Bin...3770225279-9182:String) [Get-ChildItem], UnauthorizedAccessException
    + FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand

but not this one

Get-FileHash : The file 'E:\devices.csv' cannot be read: The process cannot access the file
'E:\devices.csv' because it is being used by another process.
At E:\Scripts\Ian\git\Get-RemoteFileHashesRecursive\Get-FileHashesRecursive.ps1:25 char:132
+ ... FailedItems | ForEach-Object { Get-FileHash -Path $_.FullName | Selec ...
+                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ReadError: (E:\devices.csv:PSObject) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : FileReadError,Get-FileHash

In this example I am writing $_.CategoryInfo.TargetName to the error log, but I have also tried writing $_.TargetObject and get the same results

1 Answers

The common parameters -ErrorVariable and -ErrorAction apply to a single command only. So you have to add them to Get-FileHash too:

Get-ChildItem -Path $Path -Filter $Filename -File -Recurse -Force -ErrorVariable FailedItems -ErrorAction SilentlyContinue | 
    ForEach-Object { 
        Get-FileHash -Path $_.FullName -ErrorVariable +FailedItems -ErrorAction SilentlyContinue | Select-Object * 
    }

$FailedItems | Foreach-Object {$_.CategoryInfo.TargetName} | Out-File "C:\Users\sailingbikeruk\Desktop\noaccess.log"

Note that I have inserted + in front of the error variable name for Get-FileHash to prevent it from clearing any errors produced by Get-ChildItem. See about_CommonParameters.

Unrelated improvements:

You can remove ForEach-Object and just pipe Get-ChildItem directly into Get-FileHash. Also Select-Object * is superfluous.

Get-ChildItem -Path $Path -Filter $Filename -File -Recurse -Force -ErrorVariable FailedItems -ErrorAction SilentlyContinue | 
    Get-FileHash -ErrorVariable +FailedItems -ErrorAction SilentlyContinue
Related