Click here to Skip to main content
Click here to Skip to main content
 

Run Microsoft SyncToy from a Console Application

By , 14 Jun 2007
Rate this:
Please Sign up or sign in to vote.

Introduction

Microsoft's SyncToy is a quality tool that allows you to synchronize a set of directory pairs. It is very useful for maintaining a backup of your critical files. SyncToy has a very nice GUI and is intended to be run interactively. When I set up a scheduled task to run my SyncToy configuration as a nightly, unattended job, it failed because it was not able to interact with the desktop. This limitation was bothersome, so I put that idea aside, hoping that one day Microsoft would release an updated version that supported unattended execution.

I was therefore pleasantly surprised to find a recent article posted on CodeProject that solved this problem. The article "Quietly run Microsoft's SyncToy" by Domenic demonstrated how to call the SyncToyEngine.dll from your own code. This solved the problem of running SyncToy unattended.

Background

Domenic demonstrated how to read the SyncToy configuration file, instantiate the SyncEngine and call the Preview and Sync methods. This is what is needed to operate the SyncToy engine. When I ran to code, it worked very well. On closer inspection, however, I noticed that only the first folder pair in my configuration was being used. After inspecting the SyncToyEngine in the object browser, I could find no indication of a way to iterate through the set of folder pairs in the configuration file. After groping around in SyncToy.exe using ILDASM, I noticed that there was a call that used an array list of "Engines." So, now I knew that different instances of the engine needed to be created and configured with the needed folder pair data. The solution was to keep reading the configuration file stream to obtain all of the configured folder pairs.

Using the code

This code was inspired by and based on the work of Domenic in his article "Quietly run Microsoft's SyncToy." Being a console application, the path to the SyncToy configuration file is passed in as a command line argument. Typically, this path will look like: C:\Documents and Settings\<username>\My Documents\SyncToyData\SyncToyDirPairs.bin</username>. This is accomplished in the Main program:

static void Main(string[] args)
{
    Console.WriteLine("SyncToyExec Starting {0}", 
        DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));

    string ConfigFileName = args[0];
    if (ConfigFileName.Length > 0)
    {
        SyncToyExec app = new SyncToyExec();
        app.SyncFolderPairs(ConfigFileName);
    }
    else
    {
        Console.WriteLine("No SyncToy Configuration " + 
            "File Name Supplied. Aborting...");
    }
    Console.WriteLine("SyncToyExec Ending {0}", 
            DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
}

Once the name of the configuration file is known, the file is read in the SyncFolderPairs method. SyncFolderPairs reads the input stream, deserializes it into a series of SyncToy.SyncEngineConfig objects and stores them in an ArrayList.

public void SyncFolderPairs(string ConfigFileName)
{
    SyncToy.SyncEngineConfig SEConfig = null;
    ArrayList EngineConfigs = new ArrayList();
    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = 
       new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

    Console.WriteLine("SyncToy Configuration File = {0}", ConfigFileName);
    try
    {
        using (StreamReader sr = new StreamReader(ConfigFileName))
        {
            do
            {
                SEConfig = (SyncToy.SyncEngineConfig)
                    bf.Deserialize(sr.BaseStream);
                EngineConfigs.Add(SEConfig);
            }
            while (sr.BaseStream.Position < sr.BaseStream.Length);
            sr.Close();
        }
        foreach(SyncToy.SyncEngineConfig Config in EngineConfigs)
        {
            SyncFolderPair(Config);
        }
   }
   catch (Exception ex)
   {
        EventLog.WriteEntry("SyncToy", ex.Message, EventLogEntryType.Error);
        Console.WriteLine("SyncToy Exception -> {0}", ex.Message);
   }
}   //SyncFolderPairs

Once the SyncToy.SyncEngineConfig objects have been read, they are passed to the SyncFolderPair method that actually performs the SyncToy actions:

private void SyncFolderPair(SyncToy.SyncEngineConfig Config)
{
    PercentComplete = 0;
    SyncToy.SyncEngine Engine = new SyncToy.SyncEngine(Config);
    Engine.syncEvent += 
       new SyncToy.SyncEventHandler(SyncEngineEventHandler);
    Console.WriteLine("Analyzing...");
    Engine.Preview();
    Console.WriteLine("Completed Analyzing...\r\n");
    Console.WriteLine("Syncronizing...");
    Engine.Sync();
    EventLog.WriteEntry("SyncToy", Engine.StatSummary, 
       EventLogEntryType.Information);
    Console.WriteLine("Sync Status: {0}\r\n", Engine.StatSummary);
    Engine.syncEvent -= 
       new SyncToy.SyncEventHandler(SyncEngineEventHandler);
    Engine = null;
}   // SyncFolderPair

As SyncToy.SyncEngine processes each entry in the folder pair configuration, it raises a number of events that can be of use to you. Here, an event handler, SyncEngineEventHandler, receives the event stream and uses the PercentComplete property to update the user regarding progress.

public void SyncEngineEventHandler(object sender, 
    SyncToy.SyncEventArgs SEArgs)
{
    if (SEArgs.Failed)
    {
        string Msg = string.Format("Error: {0}", SEArgs.Action.ToErrorText());
        EventLog.WriteEntry("SyncToy", Msg, EventLogEntryType.Error);
        Console.WriteLine(Msg);
    }

    if (SEArgs.Type == SyncToy.SyncEventType.ActionStarting && 
        File.Exists(SEArgs.Action.DestinationFullPath))
    {
        File.SetAttributes(SEArgs.Action.DestinationFullPath, 
            FileAttributes.Normal);
    }
    else if (SEArgs.Type == SyncToy.SyncEventType.ActionAttempted && 
        File.Exists(SEArgs.Action.DestinationFullPath) && 
        File.Exists(SEArgs.Action.SourceFullPath))
    {
        File.SetAttributes(SEArgs.Action.DestinationFullPath, 
            File.GetAttributes(SEArgs.Action.SourceFullPath));
    }

    if ((SEArgs.PercentComplete > 0) &&
        (SEArgs.PercentComplete != PercentComplete) &&
        (SEArgs.PercentComplete % 5 == 0))
    {
        PercentComplete = SEArgs.PercentComplete;
        Console.WriteLine("{0}% Completed", PercentComplete);
    }
}   // SyncEngineEventHandler

Usage

I have been using SyncToyExec to run scheduled backups of my files. I just copy SyncToyExec.exe into the same folder used by SyncToy.exe and then I set up a task in Scheduled Tasks to run every night. So far, it has been very successful.

History

  • Version 1.0 -- 4 November, 2006.
  • Version 1.1 -- 30 November, 2006.
  • Version 1.2 -- 13 June, 2007.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

AToad
Software Developer (Senior)
United States United States
I have been programming professionally since the early eighties. I cut my teeth on the Apple II, but the WinTel platform has been my focus for remainder of my career. I am currently employed in the gaming industry working on data systems and Windows applications. When not working, I can be found wandering the fields and forests of western Oregon while dreaming of the beaches of Thailand!

Comments and Discussions

 
QuestionHow create folders pairs programatically ? Pinmemberalhambra-eidos31-Dec-10 0:38 
GeneralReadOnly Attributes PinmemberGutterBoy13-Jun-07 6:09 
GeneralRe: ReadOnly Attributes PinmemberAToad13-Jun-07 11:19 
QuestionWhat text ConfigFile include? Pinmemberoffliao22-May-07 17:22 
GeneralCompiliation problems ... Pinmemberakseli27-Feb-07 7:58 
GeneralRe: Compiliation problems ... PinmemberAToad27-Feb-07 9:28 
GeneralRe: Compiliation problems ... Pinmemberakseli27-Feb-07 10:20 
QuestionWrite SyncToy Config to a file PinmemberCurti McNamee15-Dec-06 8:29 
GeneralSnapshot files Pinmemberratty761-Dec-06 2:12 
GeneralRe: Snapshot files PinmemberAToad1-Dec-06 7:01 
GeneralRe: Snapshot files Pinmemberratty761-Dec-06 7:27 
QuestionArrayList? PinmemberSteve Hansen30-Nov-06 21:53 
AnswerRe: ArrayList? PinmemberAToad1-Dec-06 7:08 
GeneralReally helpful PinmemberGallus29-Nov-06 22:56 
GeneralRe: Really helpful PinmemberAToad30-Nov-06 9:48 
GeneralRunning unattended Pinmembermmedic14-Nov-06 11:39 
GeneralRe: Running unattended PinmemberAToad15-Nov-06 17:55 
GeneralVery useful! PinmemberCoyote Technology14-Nov-06 11:37 
GeneralRe: Very useful! Pinmemberrlobrecht4-Dec-06 7:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140421.2 | Last Updated 14 Jun 2007
Article Copyright 2006 by AToad
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid