Use PowerShell to Copy Only Folders that Contain Files

Use PowerShell to Copy Only Folders that Contain Files

  • Comments 8
  • Likes

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to copy only folders that contain files.

Microsoft Scripting Guy, Ed Wilson, is here. In some respects, it seems like I have been using Windows PowerShell for a long time. In other respects, it seems like the journey begun only a short while ago. I mean, after writing five books about Windows PowerShell, it would seem that I know the product pretty well. And yet, I continue to amaze myself with the power of Windows PowerShell.

What am I talking about? Well, a few months ago, I created a whole bunch of folders based on dates in preparation for the Scripting Wife’s and my trip to Europe. Unfortunately, due to certain time issues, I did not always upload pictures every day into the folders. This caused some folders to not have pictures in them. Now when you are talking about 40 or so folders, it is annoying to click and not see anything. So I decided to delete folders that were not being used. At first I was going to do it by hand, but that was painful. I thought the code to clean up the empty folders might be too difficult to write, but in the end, it was not.

Delete empty folders

I opened the Windows PowerShell ISE, and created two variables to hold the source path and to hold the destination path. These two variables are shown here (note that you will not have these directories unless you have created them):

$path = 'C:\data\mypics\2012'

$destination = 'e:\data\mypics\archive\2012’

Now I use the Get-ChildItem cmdlet to collect all of my directories. I use the Directory switch that is available in Windows PowerShell 3.0 to do this. I send the directory objects down the pipeline. This is shown here.

Get-ChildItem $path -Directory |

Now I use the Foreach-Object cmdlet to work with each directory object. I call the EnumerateFiles method from the DirectoryInfo object to see if there are any files. I send the results to Measure-Object to count the files. I am sure this code could be cleaner, but it works:

Foreach-Object  {if (($_.enumeratefiles() | measure).count -gt 0)

If there are files, I copy the folder (and files) to the destination as shown here:

Copy-Item -path $_.fullname -Destination $destination -Recurse}

That is it. It did not take me very long at all to create the script. And it saved a whole lot of clicking. Here is the competed CopyOnlyFoldersWithFiles script.

CopyOnlyFoldersWithFiles.ps1

$path = 'C:\data\mypics\2012'

$destination = 'e:\data\mypics\archive\2012’

Get-ChildItem $path -Directory |

Foreach-Object  {if (($_.enumeratefiles() | measure).count -gt 0)

  {

   Copy-Item -path $_.fullname -Destination $destination -Recurse}

  }

Join me tomorrow when I will talk about more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • What if:

    What if a folder has no files but it has subfolders with files.

    Won't recurse force  you to always copy everything if any child has a file or subfolder?

    I don't think this works for all issues beyond top level folders of a path.  

  • In PoSh v2 syntax:

    (gci | ?{$_.directory}) | %{if (($_.name | Measure).count -gt 0){copy-item -path $_.fullname -Destination $dest -Recurse}}

    NOTE. 'enumeratefiles()' method and '-directory' parameter for cmdlet GCI does not exist in v2, which im assuming '-dir' just lists files only? at the moment im not near a v3 terminal

  • @jrv wouldn't '-r' parameter for gci cover subbies (sub-directories) in the example you set?

  • @Krunch - It looks to me like any yfile in any subfolder will cause ALL subfolders to be created including the empty ones.

    Remember that:\

    sub/sub1/sub11

    sub/sub2/sub21/(has file)

    Will cause all to report true on recurse.  Try it.

  • @jrv okay, its horribly long but:

    PoSH v2:

    (gci -r $path | ?{$_.directory}) | %{if (($_.name | Measure).count -gt 0){copy-item -path $_.fullname -Destination $dest -Recurse}}; sl $dest; (gci -force | ?{$_.directory}) | %{if (($_.name | Measure).count -lt 0){ri -path $_.fullname}}

    NOTE> i tried my original PoSh v2 way and didn't get the subbies in the directory ($dest), it might be, if your using v3, the '-dir' parameter

  • This seems like a perfect job for robocopy to be honest. No need to write elaborate scripts to do this. Keep in mind that there are other commandline tools that are superior to a powershell script, not only in performance but also in simplicity.

  • @Sebastian_Neumann not to be a bother but im going to assume your speaking to me, if that's not self-centered . i agree with your overall sentiment but the blog 'Hey Scripting Guy!' is a PoSh (PowerShell) blog; to use DOS (command prompt) to solve a problem would violate the spirit of the blog( ie. learn PoSh tips, tricks, basics and more)

  • You can use Long Path Tool if you have any problems as well.