.\Matthew Long

{An unsorted collection of thoughts}

Scripting Series – Interesting things you can do with VBScript and Powershell – Part 5, Issues with Copy-item and Remove-Item

Posted by Matthew on October 13, 2011

In the final part of this series I’m going to show two strange behaviours you can get when running the Remove-Item and Copy-Item powershell cmdlets on the file system provider.

Remove-Item

This one is fairly simple – essentially what happens is you may find when you ask Remove-Item to delete a folder structure using the -Recurse  switch that it has a tendency to trip over itself and leave folders behind as they are still marked in use.. by the cmdlet!  To overcome this we can simply setup a Do While loop to check if the folder exists and attempt to remove it (and all contents) continuously until we succeed (usually completes within 2 loops).


Do
{
      Write-Host "Attempting to remove Files Recursively.."
      Start-Sleep -Seconds 1
      Remove-Item $FilesLocation -Recurse -Force -ErrorAction SilentlyContinue
}
While (Test-Path $FilesLocation -ErrorAction SilentlyContinue)

For those unfamiliar, the Do..While construct will attempt an action once, and then check the criteria to see if the action should be repeated.  In this case Test-Path will return true if the path exists and false if it does not.  So if the folder has been deleted, another attempt will be made.  The -ErrorAction SilentlyContinue parameters simply stop the commands from writing out either the error condition we are explicitly handling (files locked in use) or that the path does not exist (which is what we want in this scenario, so lets not raise an error for that state).

Copy-Item

This one has been around the internet a few times already, and in this case the solution was one I came across.  Unfortunately I’m not sure who the original author is, but if anyone knows I’ll gladly accredit it.  Anyway, the issue is that Copy-Item has a slight behavioural quirk; if you try to copy a folder, and the destination folder name already exists, the item(s) to be copied are instead placed inside the pre-existing destination folder, in a subfolder.

The result is that if you tried to copy the contents of c:\foo to c:\bar, and bar already existed you’d wind up with all your files from c:\foo inside the c:\bar\bar folder!

Thankfully, the function below sorts this behaviour out –

Function Copy-Directory
{
       Param(
       [System.String]$Source,
       [System.String]$Destination)
       $Source = $Source -replace '\*$'
       If (Test-Path $Destination)
       {
              Switch -regex ($Source)
              {
                  '\\$' {$Source = "$Source*"; break}
                  '\w$' {$Source = "$Source\*"; break}
                  Default {break}
              }
      }
      Copy-Item $Source $Destination -recurse -force
}

Now you can call Copy-Directory folder1 folder2 and get consistent results – if the destination does not exist, it is created. If the destination does exist, then all files are copied into the pre-existing folder.

The function works by testing if the destination folder already exists, and if it does, modifying the source criteria so that copy-item is instead looking for a wildcard match on the folders contents, rather than the source folder itself.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s