Copy-Item error and how to catch access is denied

217 views Asked by At

I have a script that backs up User Profiles Documents.

The code is:

$sourceFolder = "C:\Users\username\Documents"
$backupFolder = "C:\temp\Backup\profilefolders\username\Documents"
Copy-Item -Path $sourceFolder -Destination $backupFolder -Recurse -Force

However, When the cop hits a folder My Music, My Pictures, My Videos I am getting understandably an error Access to the path 'C:\Users\username\Documents\My Music' is denied. Since the folders are only shortcuts to folders in the users root folder.

I can add -ErrorAction SilentlyContinue to have the errors ignored.

But I want to show an error but not like this in red:

Copy-Item : Access to the path 'C:\Users\username\Documents\My Music' is denied.
At C:\Temp\scripts\folderbackups.ps1:60 char:13
+             Copy-Item -Path $sourceFolder -Destination $backupFolder  ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : PermissionDenied: (My Music:DirectoryInfo) [Copy-Item], UnauthorizedAccessException
    + FullyQualifiedErrorId : CopyDirectoryInfoItemUnauthorizedAccessError,Microsoft.PowerShell.Commands.CopyItemCommand

Is there a quick way to just have an error message that just shows with background in red:

"Error: access to C:\Users\username\Documents\My Music denied and not backed up."

Obviously use a variable that picks up the location.

Cheers

2

There are 2 answers

1
mklement0 On BEST ANSWER

To put it all together:

Copy-Item -Path $sourceFolder -Destination $backupFolder -Recurse -Force 2>&1 | 
  ForEach-Object { 
    Write-Host -BackgroundColor Red "Error: access to $($_.TargetObject) denied and not backed up." 
  }

Note:

  • The above assumes that all errors are access-denied errors; more work is needed to handle different types of errors.
0
Joel Coehoorn On

From what I've seen, Copy-Item won't do this.

One option, of course, is to programmatically recurse through the folder structure and copy each item by one at a time, so you can try/catch on individual items. But that's way slower and multiplies the code you need to write and maintain.

Fortunately there's another option. The thing to remember is Powershell is still a shell. That means you can also run basic command line utilities included with your platform... in this case the robocopy or xcopy programs built into Windows.

We still have a problem, though. I don't think either of these tools will do exactly what you want, in that they both have options similar to the -SilentlyContinue switch you've already found to be inadequate. However, robocopy does have a some logging options you can use in conjunction with /r:0 that might be enough for you to work with. The /V switch might also work here.