Easily Compare Two Folders by Using PowerShell


Summary: Microsoft Scripting Guy Ed Wilson illustrates how to compare two folders by using Windows PowerShell.

 

Microsoft Scripting Guy Ed Wilson here. It is an absolutely beautiful day in Charlotte, North Carolina. The early morning rain gave way to a colorful rainbow.

Photo of a rainbow

My manager bought me a new laptop, and I have been busy working on it; installing software, copying files, and migrating settings. The old laptop will be paved, so it is important to ensure I get everything copied to the new laptop.

Most of the major things are automatically transferred, but there are always a few folders that seem to get left behind. This is especially true because I am still working while doing the migration, and there is always a danger of missing something.

In the past, I might write a script to compare two folders to ensure they are identical. However, with Windows PowerShell, I do not need to write a script. I can type a simple command to compare two folders.

For example, I use a folder named fso that is located directly off of the root of the C: drive as my scratch directory. I leave all kinds of stuff in that directory, including files that contains important sample scripts and sample text files, spreadsheets, and databases. I use these files when writing articles, teaching, or making presentations. This folder is shown in the following figure.

Image of Ed's fso folder

There is nothing vital in the folder, but it is useful to have those files, so I want to ensure I have a good copy of the folder. Also, I am not capable of quickly reading through a folder with 144 files to ensure nothing is missing. To compare two folders I perform the following steps:

  1. Use the Get-ChildItem cmdlet with the recurse switched parameter and the path parameter (points to the folder to use for reference) to obtain a collection of fileinfo objects. Store these objects in a variable.
  2. Use the Get-ChildItem cmdlet with the recurse switched parameter and the path parameter (points to the folder to use for comparison) to obtain a collection of fileinfo objects. Store these objects in a different variable.
  3. Use the Compare-Object cmdlet and specify the objects stored in the first variable to the ReferenceObject parameter. Supply the objects stored in the second variable to the DifferenceObject parameter.

Note   Do not get hung up on whether the first folder should be the reference object or the difference object. The position of the folder in the two parameters determines the direction of the comparison arrows, but as long as you know which folder is difference or reference, you will be fine.

The code I type on my laptop is shown here:

$fso = Get-ChildItem -Recurse -path C:\fso

$fsoBU = Get-ChildItem -Recurse -path C:\fso_BackUp

Compare-Object -ReferenceObject $fso -DifferenceObject $fsoBU

The code and associated output are shown in the following figure. The output tells me that inputobject (this is the difference object parameter) is missing three files: a.txt, b.txt, and c.txt. I need to copy these three files to the c:\fso_backup folder.

Image of code and associated output

Well, it is the weekend, and as you can see, it is a beautiful day. I am going to get back to work on my laptop. Hope you have an awesome weekend. See you tomorrow.

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

 

 

Comments (26)

  1. Anonymous says:

    To get to the full pathname, just step through the difference object items using for-each and examine item.FullName.

  2. Anonymous says:

    I forget to mention that you need to use the -Passthru parameter to actually get access to the directory items.

  3. jrv says:

    @mark – why?

    Robocopy does this internally and knows how to deal with long paths.

  4. The alias for Compare-Object is diff. For more details/info on this cmdlet see technet.microsoft.com/…/dd347568.aspx and technet.microsoft.com/…/ee156812.aspx

  5. Klaus Schulte says:

    Hi Ed,

    this is something that I usually do with a "real diff.exe" or my "totalcommander" which give me a list of different files. It's Ok to use powershell for that purpose and even for a more general purpose because we are not restricted to compare files … it's all about objects!

    But I'm afraid that we won't be able to use this technique comparing a large directory structure like a complete filesystem content which will give us hundreds of thousands of files! So … if we restrict it to some thousand files it may work very well 🙂

    Klaus.

  6. Ed Wilson says:

    @Craig Lussier You are correct. Thank you for the links

    @Klaus Schulte You are also correct. This is not going to be fast enough to work through thousands of files. What it IS good for is a simple comparison between two files. For example, I often will run a command against two servers, and then use Compare-Object to compare the output. This IS great to do when looking at the status of services between two "identical" servers for example.

  7. Juan says:

    Hello,

    Very useful, easy to use, thank you. I have a question, however.

    Is it possible to show the full path of the compared items? Just showing the item names that are different works fine, but when comparing folders with many subfolders and files, it's a bit more time-consuming to actually find where the items are. The script above is telling me that they are different, and which ones are different, but not exactly where they are located.

    Besides that, this works GREAT!

    Thanks.

  8. Ed Wilson says:

    @Juan the arrow points to the "side" containing the unique file. Therefore, the three files are in the c:fso folder, and not in the backup folder. The arrow points in the direction of the file. The reference object, c:fso contains the three files. The difference object c:fso_backup does not contain the files.

  9. Mark Hellervik says:

    I'm comparing two folders on different servers to make sure they robo copied correctly. I'm getting errors on path too long exception.

  10. William Tang says:

    Thank you, sir. This was quite helpful. I used this method to verify that I copied all the files from a folder to a DVD disc. I'm beginning to appreciate the simplicity and capabilities of power shell.

  11. Barry says:

    Neat trick, Ed.  I am looking for a way to locate edited/added folders on my music drive, which is not on my local PC, but on a WD MyBookLive.  I have the music share folder mapped to the Z drive, but the Get-ChildItem no habla Z drive:

    PS C:UsersAllison> $music = Get-ChildItem -Recurse -path Z:Shared Music

    Get-ChildItem : Cannot find path 'Z:Shared' because it does not exist.

    At line:1 char:23

    + $music = Get-ChildItem <<<<  -Recurse -path Z:Shared Music

       + CategoryInfo          : ObjectNotFound: (Z:Shared:String) [Get-ChildItem], ItemNotFoundException

       + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

    I have found much of the 'FileCompare' freeware that's out there to be lacking, so thanks for this…

  12. Kevin Lenzmeier says:

    The Compare-Object will compare the “string” value of the 2 files. It might be more useful if use something like Compare-Object -ReferenceObject $fso -DifferenceObject $fsoBU -Property Name,LastWriteTime,Length

  13. Jack says:

    Maybe someone can help. Compare-Object is acting up when I try to compare a previously saved txt file containing the get-childitem output of a directory to that of a real-time call to get-childitem of the same directory (where no changes have been made).
    It shows Name is changing when it clearly has not. Is it possible to compare a txt file containing get-childitem output to the output of a real-time call to get-childitem? Here is how I am attempting this: # $dir2.txt is a previously saved call to get-childitem
    of C:dir2 # $dir2.txt contents should match the get-childitem output from $dir1 $dir2 = get-content C:dir2.txt $dir1 = get-childitem -recurse C:dir1 Compare-Object $dir1 $dir2 -Property Name

  14. James Shawsa says:

    I need to be able to compare a directory to a text file. I.E. *.txt includes a list (1.txt, 2.txt, 3.txt…n) whereby it checks a directory to ensure the files in the directory correlate to the names in the text file, culminating in a list such as

    1.txt is PRESENT
    2.txt is PRESENT
    3.txt is ABSENT
    4.txt is EXTRA

    I am finding that simply using get-childitem of the directory, saving both the text file list to an array and the directory list, then comparing, does not give me the desired outcome.

  15. Margaret D. says:

    This worked except I don’t know which sub-folder the missing file is in. As there are hundreds of folders involved, this puts me back into hunt-and-peck mode….

  16. Bakkiethee says:

    @Margaret D.

    To get the directories of the files (plus the filename) that do not match you can use something like this:

    # Directories
    $sourcedir = Get-ChildItem -Path yoursourcepath -Recurse
    $destinationdir = Get-ChildItem -Path yourdestinationpath -Recurse

    # Differences
    $differentfiles = Compare-Object -ReferenceObject $sourcedir -DifferenceObject $destinationdir
    $differentfiles = $differentfiles.inputobject.fullname
    $differentfiles

  17. sandeep says:

    This is magic. Compared my 5 years backups in under 15 minutes. Thanks.

  18. Devin says:

    Thank you so much, I have 2-3TB hard drives that are nearly full and it’s really a pain to go folder by folder to find out where the differences are. This is awesome! Thanks a bunch! No doubt it’s still tedious, but once I get it organized the first time,
    I can run it once a week so to be sure no mistakes were made.

  19. Louis says:

    I wanted to say THANK YOU! This 3 line script is EXACTLY what I was looking for. Your 3 lines have out performed all of the software out there, that seemed to struggle with doing exactly what you have done in record time! THANK YOU!!

  20. Richard says:

    I know it’s not PowerShell, but I had to share my find. I use a product called Beyond Compare and I’m not sure I could live without it now. It also compares text files, pictures etc. It’s the only product on the market like it (that I’ve found).
    http://scootersoftware.com/

  21. alizee says:

    Faster and more relevant, pass -name to your two first commands so it will be only string comparison and also show you the full path of the files!

    Best,
    Alizee

  22. Rudenco Victor says:

    Thank you very much Ed. Useful article. I am following you for some time and I am amazed about how your are making complex thing look simple. Very good job. Keep going – wish the best for you and your family.

  23. Ray Avila says:

    Useful, Simple. I did run into a ton of false positives because a file path was to long. Found that 1 file and renamed and all of the false positives went away.

  24. Tom Hallam says:

    Isn’t this is actually comparing 2 arrays of items of the type System.IO.FileSystemInfo and not the actual files themselves?

  25. is there a way to compare the content of file and output the filenames that are different? say I updated a document and want that to be backed up. I ran the command it seems to only give files that didn’t exist, but doesn’t compare content.

  26. Dennis Wieck says:

    In order to also get the files that exist in both folders but are not the same version, you have to add a few changes:

    $fc1 = gci -Recurse $source | where {! $_.PSIsContainer}
    $fc2 = gci -Recurse $destination | where {! $_.PSIsContainer}
    Compare-Object $fc1 $fc2 -Property name,LastWriteTime

    name LastWriteTime SideIndicator
    —- ————- ————-
    Manual.txt 15.05.2013 12:41:04 =>
    Manual.txt 25.05.2016 14:44:36 <=

    You have to limit the output of get-childitem to files only, because only files retain their LastWriteTime property when being copied while a folder's LastWriteTime is always the time it was copied. Therefore folders would always show up in the results.
    The code is from a function from one of my sync scripts, so I'm using variables for the folders I'm comparing. You can, of course, put the paths into the script directly.