Click here to Skip to main content
15,880,956 members
Articles / Programming Languages / C#
Article

Run Microsoft SyncToy from a Console Application

Rate me:
Please Sign up or sign in to vote.
3.86/5 (6 votes)
14 Jun 20073 min read 65.1K   475   27   24
An article that shows how to run the Microsoft's SyncTool application from a console application.

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:

C#
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.

C#
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:

C#
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.

C#
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


Written By
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 ? Pin
kiquenet.com31-Dec-10 0:38
professionalkiquenet.com31-Dec-10 0:38 
QuestionSyncToy v2 Pin
Dean Moe3-Aug-08 10:48
Dean Moe3-Aug-08 10:48 
AnswerRe: SyncToy v2 Pin
AToad4-Aug-08 7:31
AToad4-Aug-08 7:31 
NewsRe: SyncToy v2 Pin
Koen Zomers14-Nov-08 2:34
Koen Zomers14-Nov-08 2:34 
GeneralRe: SyncToy v2 Pin
kiquenet.com30-Dec-10 12:13
professionalkiquenet.com30-Dec-10 12:13 
GeneralRe: SyncToy v2 Pin
Koen Zomers30-Dec-10 21:02
Koen Zomers30-Dec-10 21:02 
GeneralReadOnly Attributes Pin
GutterBoy13-Jun-07 6:09
GutterBoy13-Jun-07 6:09 
GeneralRe: ReadOnly Attributes Pin
AToad13-Jun-07 11:19
AToad13-Jun-07 11:19 
QuestionWhat text ConfigFile include? Pin
offliao22-May-07 17:22
offliao22-May-07 17:22 
GeneralCompiliation problems ... Pin
akseli27-Feb-07 7:58
akseli27-Feb-07 7:58 
GeneralRe: Compiliation problems ... Pin
AToad27-Feb-07 9:28
AToad27-Feb-07 9:28 
GeneralRe: Compiliation problems ... Pin
akseli27-Feb-07 10:20
akseli27-Feb-07 10:20 
QuestionWrite SyncToy Config to a file Pin
Curt McNamee15-Dec-06 8:29
Curt McNamee15-Dec-06 8:29 
GeneralSnapshot files Pin
ratty761-Dec-06 2:12
ratty761-Dec-06 2:12 
GeneralRe: Snapshot files Pin
AToad1-Dec-06 7:01
AToad1-Dec-06 7:01 
GeneralRe: Snapshot files Pin
ratty761-Dec-06 7:27
ratty761-Dec-06 7:27 
QuestionArrayList? Pin
Steve Hansen30-Nov-06 21:53
Steve Hansen30-Nov-06 21:53 
AnswerRe: ArrayList? Pin
AToad1-Dec-06 7:08
AToad1-Dec-06 7:08 
Hi Steve:

I guess that old habits are slow to die! Using a generic list would probably be a better choice.

Actually, I started this project with the code from Domenic's article "Quietly run Microsoft's SyncToy" and translated it into C#. The ArrayList just came along for the ride.

Allen W. Todd
AllenWTodd@msn.com

GeneralReally helpful Pin
Gallus29-Nov-06 22:56
Gallus29-Nov-06 22:56 
GeneralRe: Really helpful Pin
AToad30-Nov-06 9:48
AToad30-Nov-06 9:48 
GeneralRunning unattended Pin
mmedic14-Nov-06 11:39
mmedic14-Nov-06 11:39 
GeneralRe: Running unattended Pin
AToad15-Nov-06 17:55
AToad15-Nov-06 17:55 
GeneralVery useful! Pin
Coyote Technology14-Nov-06 11:37
Coyote Technology14-Nov-06 11:37 
GeneralRe: Very useful! Pin
rlobrecht4-Dec-06 7:03
rlobrecht4-Dec-06 7:03 

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

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