Share via


How to Restore a Domain's GPOs

This article illustrates using the Group Policy Management Console (GPMC) Class Library to restore the Group Policy objects (GPOs) that have been backed up to a specified folder. The first section details step-by-step instructions on implementing the code, while the example that follows is a working Visual C# console application that can be modified to fit your specific needs.

To restore a domain’s backed up GPOs

  1. Add the Microsoft.GroupPolicy.Management assembly to your project.

  2. Insert a using directive for the Microsoft.GroupPolicy namespace.

    using Microsoft.GroupPolicy;
    
  3. Instantiate a GPDomain object representing the domain whose Group Policy objects (GPOs) will be backed up. The following code snippet shows two different ways of instantiating a GPDomain object. The first example calls the default GPDomain constructor, which takes no parameters and uses the domain of the current user. The second example shows a hard-coded value being passed as the domain name that will be used in the construction of the GPDomain object.

    // Use current user’s domain 
    GPDomain domain = new GPDomain();
    
    // Use supplied domain name 
    GPDomain domain = new GPDomain("MyDomain");
    
  4. Instantiate a BackupDirectory object. This object represents the directory in which GPOs have been previously backed up. The following example specifies a backup folder of C:\GPOBackups and a backup GPO type of BackupType.Gpo (as opposed to BackupType.StarterGpo).

    // Get a BackupDirectory object
    BackupDirectory backupDir = new BackupDirectory(@"C:\GPOBackups", BackupType.Gpo);
    
  5. Use the GPSearchCriteria object to specify which backups you want to retrieve. The following example illustrates how to specify that you want the most recent backups.

    // Get the most recent backups for each GPO
    GPSearchCriteria searchCriteria = new GPSearchCriteria();
    searchCriteria.Add(SearchProperty.MostRecentBackup, SearchOperator.Equals, true);
    
  6. In the previous step, you created and filled in a GPSearchCriteria object that specified you wanted the most recent backup for each GPO. Now pass this GPSearchCriteria object to the BackupDirectory.SearchGpoBackups method. The result will be a GpoBackupCollection object that represents a collection of GpoBackup objects, each of which represents a GPO backup on the file system.

    // Get the backup collection for the specified search criteria
    GpoBackupCollection backups = backupDir.SearchGpoBackups(searchCriteria);
    
  7. After you have the GpoBackupCollection, you can simply iterate over that collection and, for each GpoBackup object, call the GPDomain.RestoreGpo method, passing to it the GpoBackup object.

    foreach (GpoBackup backup in backups)
    {
       GPStatusMessageCollection statusMessages;
       try
       {
          Gpo gpo = domain.RestoreGpo(backup, out statusMessages);
          Console.WriteLine("Restored successfully");
       }
       catch (Exception ex)
       {
          Console.WriteLine("Exception Caught: {0}", ex.Message);
          continue;
       }
    }
    

Example

The following is the complete code listing for a console application that restores GPOs from a previous backup.

/*----------------------------------------------------------------------
This file is part of the Microsoft Windows Server Update Services
API Code Samples.

DISCLAIMER OF WARRANTY: THIS CODE AND INFORMATION ARE PROVIDED "AS-IS."  
YOU BEAR THE RISK OF USING IT.  MICROSOFT GIVES NO EXPRESS WARRANTIES, 
GUARANTEES OR CONDITIONS.  YOU MAY HAVE ADDITIONAL CONSUMER RIGHTS 
UNDER YOUR LOCAL LAWS WHICH THIS AGREEMENT CANNOT CHANGE.  
TO THE EXTENT PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES 
THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
PURPOSE AND NON-INFRINGEMENT.
----------------------------------------------------------------------*/
using System;
using Microsoft.GroupPolicy;

/*
 * Purpose: This sample illustrates how to use the GPMC Class Library to restore
 * GPO backups from a specified folder.
 * Syntax: RestoreGPOs /f backupDirectory [/d domainName] [/t GPO | StarterGPO]
 * (Note that the doman defaults to the current domain if one is not specified.)
 */

namespace RestoreGPOs
{
  class Program
  {
    static void Main(string[] args)
    {
      Program program = new Program();
      program.Run(args);
    }

    // Initialize variables to track successful and failed restores
    int nSuccesses = 0;
    int nFailures = 0;

    // Variables obtained from user-supplied parameters and used for the restore procedure
    string domainName;
    string directory;
    BackupType backupType;

    GPDomain domain;
    BackupDirectory backupDir;

    void Run(string[] args)
    {
      try
      {
        InitUI();
        if (ParseParameters(args))
        {
          SetDomainObject();
          SetBackupDirectoryObject();

          GpoBackupCollection backups = SearchForBackups();
          RestoreGpos(backups);

          PrintSummary();
        }
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
      }
    }

    void InitUI()
    {
      // Clear console and output what we're doing
      Console.Clear();
    }

    bool ParseParameters(string[] args)
    {
      if (args.Length < 2) // need at least the /f param
      {
        return PrintSyntax();
      }

      // Check for syntax help request
      if (Array.IndexOf(args, "/?") != -1)
      {
        return PrintSyntax();
      }

      // Directory (/f) parameter MUST be passed
      int idx;
      if ((idx = Array.IndexOf(args, "/f")) != -1)
      {
        // backup directory/folder specified
        this.directory = args[idx + 1];
      }
      else
      {
        return PrintSyntax();
      }

      // Optional parameters; will default if value is not passed to the application by the user

      // Get domain name. If not supplied, we will use the current domain
      this.domainName = String.Empty;
      if ((idx = Array.IndexOf(args, "/d")) != -1)
      {
        // domain specified
        this.domainName = args[idx + 1];
      }

      // Get BackupGPOType. 
      // If supplied, value must be a valid BackupType
      // If not supplied, we will use BackupType.Gpo
      this.backupType = BackupType.Gpo;
      if ((idx = Array.IndexOf(args, "/t")) != -1)
      {
        // GPO type specified
        string backupTypeParam = args[idx + 1];
        if (backupTypeParam.ToLower().CompareTo(BackupType.Gpo.ToString().ToLower()) == 0)
        {
          this.backupType = BackupType.Gpo;
        }
        else if (backupTypeParam.ToLower().CompareTo(BackupType.StarterGpo.ToString().ToLower()) == 0)
        {
          this.backupType = BackupType.StarterGpo;
        }
        else
        {
          return PrintSyntax();
        }
      }

      return true; // successful parsing
    }

    bool PrintSyntax()
    {
      Console.WriteLine("Syntax: RestoreGPOs /f backupDirectory [/d domainName] [/t GPO | StarterGPO]");
      return false; // if we got here the command line parsing failed
    }

    void SetDomainObject()
    {
      // Get a GPDomain object
      Console.WriteLine("Connecting to domain '{0}'",
                        (domainName.Length > 0) ? domainName : "[default domain]");
      if (domainName.Length > 0)
      {
        this.domain = new GPDomain(domainName);
      }
      else
      {
        this.domain = new GPDomain();
      }
      Console.WriteLine("Successfully connected to domain");

    }

    void SetBackupDirectoryObject()
    {
      // Inform the user of what our parsing was able to distinguish from 
      // the parameters
      Console.WriteLine("Processing with the following input and default values\r\n" +
                        "\tDomain: {0}\r\n" +
                        "\tDirectory: {1}\r\n" +
                        "\tGPO Types: {2}\r\n",
                        this.domain.DomainName,
                        this.directory,
                        this.backupType.ToString());

      // Get a BackupDirectory object
      this.backupDir = new BackupDirectory(this.directory, this.backupType);

      BackupDirectory backupDir2 = new BackupDirectory(@"C:\GPOBackups", BackupType.StarterGpo);
    }

    GpoBackupCollection SearchForBackups()
    {
      // Get the most recent backups for each GPO in the specified backup location (directory)
      GPSearchCriteria searchCriteria = new GPSearchCriteria();
      searchCriteria.Add(SearchProperty.MostRecentBackup, SearchOperator.Equals, true);

      return this.backupDir.SearchGpoBackups(searchCriteria);
    }

    void RestoreGpos(GpoBackupCollection backups)
    {
      // See if any backups were found
      if (backups.Count == 0)
      {
        Console.WriteLine("No backups found at location " + this.backupDir.Directory);
      }
      else
      {
        Console.WriteLine("{0} backup{1} found at location {2}",
                          backups.Count,
                          (backups.Count > 1 ? "s" : ""),
                          this.backupDir.Directory);
      }

      // Iterate over the list of backups and process each
      foreach (GpoBackup backup in backups)
      {
        RestoreGpo(backup);
      }
    }

    void RestoreGpo(GpoBackup backup)
    {
      Console.Write("\nProcessing backed up GPO '{0}'... ", backup.DisplayName);

      // See if the domain matches - if it doesn't the restore will fail so we 
      // will skip any GPOs from a different domain.
      if (this.domain.DomainName.Equals(backup.DomainName) == false)
      {
        Console.WriteLine("Skipping because it is from a different domain.");
      }

      // Perform the restore
      GPStatusMessageCollection statusMessages;
      try
      {
        Gpo gpo = domain.RestoreGpo(backup, out statusMessages);
        Console.WriteLine("Restored successfully");

        // Increment our successes
        nSuccesses++;
      }
      catch (Exception ex)
      {
        Console.WriteLine("Exception Caught: {0}", ex.Message);

        // Increment the failures
        nFailures--;
      }
    }

    void PrintSummary()
    {
      Console.WriteLine("\nRestore Summary: {0} Successful , {1} Failed",
                        nSuccesses, nFailures);
    }
  }
}