Someone at work asked me if I knew a quick way in PowerShell to compare the contents of two folders. I asked a few questions and it turned out he was trying to rationalize all the music folders he had scattered round on his families computers. He wanted a way to look at all the files in a folder and check if an identical file (by identical he meant the same size) was present in a second folder.
I quickly thrashed out a line which he later said did the trick;
gci c:\source | %{$Found=$false;foreach($Item2 in $( gci d:\target)){if($_.Name -eq $Item2.Name -and $_.Length -eq $Item2.Length){$Found=$true}}; if (-not $Found){"$($_.Name) not matched."}}
Explanation about how it works below the line.
The command loops through all the items in the source folder and then for each source item it loops through all the items in the target folder and checks if there is a match. If the entire target folder is checked without a match for the source item this is written to the screen.
gci c:\source | : gci is an alias for Get-ChildItem. This returns all the objects in c:\source and passes them down the pipeline.
%{$Found=$false; : % is an alias for ForEach-Object. This takes every object passed from the pipeline (all the folders and files in c:\source) and for each it executes a script block (everything within the braces, {}). The first command in the script block sets $Found to be $false.
foreach($Item2 in $(gci d:\target)){ : This enumerates every file and folder in the target folder (d:\target). Each item is named $Item2 while it is being processed by the following script block (started with {).
if($.Name -eq $Item2.Name -and $.Length -eq $Item2.Length){$Found=$true}}; : The script block checks if the source item’s Name and Length matches the target item’s Name and Length. If it does, $Found is set to $true. This completes the second command in the original script block.
if (-not $Found){“$($_.Name) not matched.”}} : This displays the Name of the item being processed from c:\source if there is not a matching item in d:\target. This is the final command in the script block and it’s closed with }.
You can’t put a reference to a property of an object variable in a string (like “$_.Name is here!”) without encapsulating the whole thing in $().
I think there missing some brakets…;-)
Fixed. Thanks!