This post is about running Microsoft SyncToy via PowerShell. For those that don’t know SyncToy:
SyncToy 2.1 is a free application that synchronizes files and folders between locations. Typical uses include sharing files, such as photos, with other computers and creating backup copies of files and folders.
SyncToy has been around already since good old Windows XP times and even though there are alternative freeware applications it’s still one of my favorite tools for the job. While SyncToy already comes with a commandline version out of the box, it’s lacking quite some features as compared to the graphical user interface:
-
No option to preview the sync operation
-
No progress indication
-
No option to exclude subfolders
-
No option to exclude files by attributes (e.g. hidden, system)
-
No option to specify recursion
-
No option to specify action for overwritten files
Googling around for solutions I came across two related posts on codeproject.com:
Following translating the suggest approach to PowerShell it seemed to be quite easy to accomplish what I wanted utilizing the SyncToyEngine.dll .NET assembly that comes with the SyncToy installation. Considering that I would have setup already a folder pairing called ‘Test’ using the GUI, the following code should initiate the sync operation (it’s important to use the correct version of PowerShell to test this (i.e. SyncToy(x64) needs to be run via PowerShell x64): [code language=”powershell”] $syncToyEnginePath = Resolve-Path ‘c:\Program Files*\SyncToy 2.1\SyncToyEngine.dll’ #load the dll Add-Type -Path $syncToyEnginePath
#retrieve the sync engine configuration $syncToyEngineConfigPath = “$env:LOCALAPPDATA\Microsoft\SyncToy\2.0\SyncToyDirPairs.bin” $bf = New-Object Runtime.Serialization.Formatters.Binary.BinaryFormatter $sr = New-Object IO.StreamReader($syncToyEngineConfigPath) do{ $seConfig = [SyncToy.SyncEngineConfig]$bf.Deserialize($sr.BaseStream) if ($seConfig.Name -eq ‘Test’){ $engineConfig = $seConfig break } } while($sr.BaseStream.Position -lt $sr.BaseStream.Length) $sr.Close() $sr.Dispose()
#invoke the sync $syncEngine = New-Object SyncToy.SyncEngine($engineConfig) $syncEngine.Sync() [/code] But unfortunately the last line causes PowerShell to hang. After multiple unsuccessful attempts to work around this (also implementing the same as a C# PowerShell cmdlet). I ended up writing a C# executable that only takes care of the synchronization and preview part, since I wanted to keep as much as possible of the code in PowerShell. The end result is a PowerShell module ‘SyncToy.psm1’ providing three functions:
Get-SyncConfig | To retrieve an existing sync configuration (FolderPair) either setup via Set-SyncConfig or GUI |
Set-SyncConfig | To configure a new Sync Configuration (FolderPair). Those can be stored into the default configuration that the GUI uses (default behaviour) or into a custom path |
Invoke-Sync | To preview a sync operation or to run the actual sync operation showing results and a progress bar |