Hi. Here’s another update on the Sync-Folder script. In this update Strict mode goes on, I make sure the statistics reset between runs, the Statistics output is rewritten and I add the option to only sync items that match a $Filter.
Update : I’ve revisited this script a few times with new additions and modifications.The latest full version of the script is here. That post also includes links covering the other revisions to the script.The first change was nice and easy;
$Changes=@()
This resets the statistics between each run of the script.
Catching that bug reminded me to add this to the start of the script though;
set-strictmode -version Latest
This ensures that any variables that are used in the script have to be declared first. It doesn’t help with the running of the script normally but makes bugs like the above less likely!
Next I optimised how it generates the statistics it displays at the end;
$FolderCreations=$FileCopies=$FileRemovals=$FolderRemovals=$FileUpdates=0 Foreach ($Change in $Changes) { switch ($Change.Process) { "Create Folder"{$FolderCreations+=1} "Copy File"{$FileCopies+=1} "Remove File"{$FileRemovals+=1} "Remove Folder"{$FolderRemovals+=1} "Update File"{$FileUpdates+=1} } } Write-Host "`nStatistics`n" Write-Host "Folder Creations: `t$FolderCreations" Write-Host "Folder Removals: `t$FolderRemovals" Write-Host "File Copies: `t`t$FileCopies" Write-Host "File Removals: `t`t$FileRemovals" Write-Host "File Updates: `t`t$FileUpdates`n"
In the previous script version it would loop for each statistic, going through every item in $Changes finding the matching attribute. With this update it only loops once through all the changes (instead of five times); much more efficient.
While I was there I added some tabs to the output (“`t“) so the statistics line up nicely.
The final update was adding the ability to only sync files that match a given filter.
First, I need to add the parameter to the main Sync-OneFolder function;
[string]$Filter="*"
The logic needed a small update too;
$SourceFiles+=$SourceList | ? {$_.PSIsContainer -eq $False -and $_.FullName -like $Filter -and !(Check-Exceptions $_.FullName $PassedExceptions)} $TargetFiles+=$TargetList | ? {$_.PSIsContainer -eq $False -and $_.FullName -like $Filter -and !(Check-Exceptions $_.FullName $PassedExceptions)}
So an additional -and clause was added to make sure the FullName matches the $Filter.
Finally I need to add the Filter switch to where the main function is called;
if ($PSBoundParameters.ContainsKey("SourceFolder")) { Write-Verbose "Syncing folder pair passed as parameters." Sync-OneFolder -SourceFolder $SourceFolder -TargetFolder $TargetFolder -PassedExceptions $Exceptions -Filter $Filter | Tee-Object -Variable Changes }else { Write-Verbose "Running with Configuration File : $ConfigurationFile" $Config=[xml](Get-Content $ConfigurationFile) foreach ($Pair in $Config.Configuration.SyncPair) { Write-verbose "Processing Pair" Sync-OneFolder -SourceFolder $Pair.Source -TargetFolder $Pair.Target -PassedExceptions $Pair.ExceptionList.Exception -Filter $Pair.Filter | Tee-Object -Variable Changes } }
I updated the default XML that is imported from the config file to include the Filter tag;
<Configuration> <SyncPair> <Source>d:\temp\test</Source> <Target>d:\temp2</Target> <Filter>*.jpg</Filter> <ExceptionList> <Exception>Backups*</Exception> </ExceptionList> </SyncPair> <SyncPair> <Source>d:\temp\test2</Source> <Target>d:\temp3</Target> <ExceptionList> </ExceptionList> </SyncPair> </Configuration>
So you can call the function with a configuration XML or via the command line switches.