PowerShell: Copy-Item -recurse -force Does Not Create Directories when Using Get-ChildItem -include

I recently wrote a PowerShell script which copied documents from a filter to my local hard drive. I chose PowerShell for this task because it was one of the few programs actually allowed on my ultra locked-down workstation (and ‘cuz I love it.)

Because I only wanted specific types of files, I gathered the list of documents using get-childitem -recurse -include and then copied the files using copy-item. What I didn’t initially realize was that copy-item’s -recurse and -force switches are ineffective in my script because 1.) I’m passing the copy-item command one item at a time and 2.) the get-childitem include switch is “best considered a file filter,” according to Lee Holmes of Microsoft’s PowerShell team..

I got around this by manually creating the directory structure as needed using if (!(test-path($dir))) { mkdir $dir }. The entire script can be found below:

Chrissy is a Cloud and Datacenter Management & Data Platform MVP who has worked in IT for over 20 years. She is the creator of the popular SQL PowerShell module dbatools, holds a master's degree in Systems Engineering and is coauthor of Learn dbatools in a Month of Lunches. Chrissy is certified in SQL Server, Linux, SharePoint and network security. You can follow her on Twitter at @cl.

Posted in PowerShell
5 comments on “PowerShell: Copy-Item -recurse -force Does Not Create Directories when Using Get-ChildItem -include
  1. Frank says:

    I spent too much time trying to figure out how to do this, then spent too much time trying to find how to do this on the web. I'm thankful I found your script. It's much appreciated.

  2. jgraglia says:

    Thank you so much!!!! This save my day!

  3. Perry says:

    Thank you Chrissy.
    I wanted to move the files and keep a reference of the folder they were moved from but leaving the original folder if there were other files. Your script was instrumental and I’ve included my modification so others could use if they have the smae situation.

    $source = “L:\”
    $destination = “C:\docs\”
    $since = (Get-date).AddDays(-365)
    $includes =”*.doc*”,”*.pdf”,”*.xls*”,”*.ppt*”

    $items = get-childitem $source -recurse -include $includes | where-object {$_.LastAccessTime –gt $since}

    foreach ($item in $items)
    $dir = $item.DirectoryName.Replace($source,$destination)
    $target = $item.FullName.Replace($source,$destination)

    if (!(test-path($dir))) { mkdir $dir }

    Move-Item -Force -path $item.FullName -destination $target

  4. Andrew L says:

    Thanks a lot! Saved a production script issue a week before go-live. Many thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *