Compartilhar via


How to Import GPOs from a Backup

This article illustrates using the Group Policy Management Console (GPMC) Class Library to import a Group Policy object's (GPO) settings from a backed-up GPO. 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 import a backed-up GPO's settings to another GPO

  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 that contains, or will contain, the target GPO. 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. Get the GPBackup object representing a backed-up GPO. In the following example, you know the name of the GPO but not the GUID. Therefore, the code must first search for the most recent backup of the named GPO. This is done by first instantiating a GPSearchCriteria object and adding to it two rules: one specifying the name of the backed-up GPO and a second rule specifying that the backup should be the most recent. Once the GPSearchCriteria object has been instantiated and configured, the BackupDirectory.SearchGpoBackups method is used to return a GpoBackupCollection object containing the most recent backup of the specified GPO.

    // Set up the GPSearchCriteria to find the most recent backup.
    GPSearchCriteria searchCriteria = new GPSearchCriteria();
    searchCriteria.Add(SearchProperty.GpoDisplayName, SearchOperator.Equals, "My backed up GPO");
    searchCriteria.Add(SearchProperty.MostRecentBackup, SearchOperator.Equals, true);
    
    // Get a BackupDirectory object
    BackupDirectory backupDir = new BackupDirectory(@"c:\backups", BackupType.Gpo);
    
    // Obtain the backup collection that matches the search criteria
    GpoBackupCollection backups = backupDir.SearchGpoBackups(searchCriteria);
    
    // Check for no backup collection or empty collection (no backups)
    if ((backups == null) || (backups.Count <= 0))
    {
      // No backups were found with the specified search criteria. 
    }
    else
    {
      // Backups[0] is a GPBackup object representing the most recent backup of the requested GPO
    }
    
  5. Obtain a Gpo object representing the target GPO that will contain the backed-up GPO's settings. Note that the GPDomain.GetGpo method is called to retrieve the GPO either by display name or by GUID. Passing the GUID guarantees at most a single hit, while passing the display name might yield more than one GPO. Therefore, as the code below is searching by display name, the MultipleGroupPolicyObjectsFoundException is being caught in case there are multiple GPOs with the specified display name. In addition, the System.ArgumentException is being caught as that is thrown by GPDomain.GetGpo if the GPO is not found. If the GPO is not found, the code calls the GPDomain.CreateGpo method to create a new GPO into which the backed-up GPO's settings will be copied.

    Gpo gpoTarget = null;
    
    try
    {
      gpoTarget = domain.GetGpo("My Imported GPO");
    }
    catch (MultipleGroupPolicyObjectsFoundException ex)
    {
      // Multiple GPOs exist with the specified Display Name
    }
    catch (System.ArgumentException ex)
    {
      // GPO not found so create it
      gpoTarget = domain.CreateGpo(gpoTargetName);
    }
    
  6. Get a GPMigrationTable object. Migration tables are not required for an import, but they do allow you to map security principals and Universal Naming Convention (UNC) paths across domains. To instantiate a GPMigrationTable object, simply call its constructor and pass to it the physical file path of the migration table file.

    GPMigrationTable migrationTable = new GPMigrationTable(@"c:\backups\myMigrationTable.mig");
    
  7. Call the target GPO's Gpo.Import method. The import operation transfers the policy settings from the backed-up GPO in the file system to the target GPO. Note that the import operation erases any previous policy settings in the GPO. There are several overloads for the Gpo.Import method, and the code below shows two of them. In each case, a GpoBackup object is being passed along with a GPStatusMessageCollection object (to hold any status messages regarding the import). The only difference between these two method calls is that the first one passes in a GPMigrationTable object while the second does not.

    GPStatusMessageCollection statusMessages = null;
    if (migrationTable != null)
    {
      gpoTarget.Import(gpoBackup, migrationTable, out statusMessages);
    }
    else
    {
      gpoTarget.Import(gpoBackup, out statusMessages);
    }
    

Example

The following is the complete code listing for a console application that imports GPOs from a previous backup where the syntax is as follows:

ImportGPOsFromBackup /f backupDirectory /b backupGpoName /t targetGPOName [/m migrationTableName] [/d domainName]

/*----------------------------------------------------------------------
This file is part of the Microsoft GPMC 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 System.Text;
using Microsoft.GroupPolicy;

namespace GpmcSamples
{
  class ImportGPOsFromBackup
  {
    // Command-line parameters
    string backupFolderName;
    string gpoBackupName;
    string gpoTargetName;
    string domainName;
    string migrationTableName;

    static void Main(string[] args)
    {
      ImportGPOsFromBackup program = new ImportGPOsFromBackup();
      program.Run(args);
    }

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

          GPDomain domain = GetDomainObject();
          GpoBackup gpoBackup = GetBackupGpo();
          Gpo gpoTarget = GetTargetGpo(domain);
          GPMigrationTable migrationTable = GetMigrationTable();

          ImportFromBackup(gpoTarget, gpoBackup, migrationTable);

          Console.WriteLine("GPO successfully imported!");
        }
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
      }
    }

    void InitUI()
    {
      // 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" +
                        "  Domain:\t\t{0}\r\n" + 
                        "  Directory:\t\t{1}\r\n" +
                        "  Backup GPO:\t\t{2}\r\n" +
                        "  Target GPO:\t\t{3}\r\n" +
                        "  Migration Table:\t{4}\r\n",
                        (this.domainName.Length > 0 ? this.domainName : "<Current Domain>"),
                        this.backupFolderName,
                        this.gpoBackupName,
                        this.gpoTargetName,
                        this.migrationTableName);
    }

    bool ParseParameters(string[] args)
    {
      if (args.Length < 4) // need at least the /f, /b and /t parameters
      {
        return PrintSyntax();
      }

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

      // Backup folder parameter 
      int idx;
      if ((idx = Array.IndexOf(args, "/f")) != -1)
      {
        this.backupFolderName = args[idx + 1];
      }
      else
      {
        return PrintSyntax();
      }

      // Backup GPO name parameter
      this.gpoBackupName = String.Empty;
      if ((idx = Array.IndexOf(args, "/b")) != -1)
      {
        this.gpoBackupName = args[idx + 1];
      }
      else
      {
        return PrintSyntax();
      }

      // Target GPO name parameter
      this.gpoTargetName = String.Empty;
      if ((idx = Array.IndexOf(args, "/t")) != -1)
      {
        this.gpoTargetName = 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)
      {
        this.domainName = args[idx + 1];
      }

      // Get MigrationTable
      this.migrationTableName = String.Empty;
      if ((idx = Array.IndexOf(args, "/m")) != -1)
      {
        this.migrationTableName = args[idx + 1];
      }

      return true; // successful parsing
    }

    bool PrintSyntax()
    {
      Console.WriteLine("\r\nSyntax: ImportGPOsFromBackup /f backupDirectory /b backupGpoName /t targetGPOName [/m migrationTableName] [/d domainName]");
      return false; // if we got here the command line parsing failed
    }

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

      return domain;
    }

    GpoBackup GetBackupGpo()
    {
      // Set up the GPSearchCriteria to find the most recent backup.
      GPSearchCriteria searchCriteria = new GPSearchCriteria();
      searchCriteria.Add(SearchProperty.GpoDisplayName, SearchOperator.Equals, gpoBackupName);
      searchCriteria.Add(SearchProperty.MostRecentBackup, SearchOperator.Equals, true);

      // Get a BackupDirectory object
      BackupDirectory backupDir = new BackupDirectory(this.backupFolderName, BackupType.Gpo);

      // Obtain the backup collection that matches the search criteria
      GpoBackupCollection backups = backupDir.SearchGpoBackups(searchCriteria);

      // Throw an exception if no backup collection or collection is empty
      if ((backups == null) || (backups.Count <= 0))
      {
        StringBuilder error = new StringBuilder();
        error.AppendFormat("No backups found for '{0}'", gpoBackupName);
        throw new Exception(error.ToString());
      }

      // Returning most recent backup (could be more than 1)
      return backups[0];
    }
    
    Gpo GetTargetGpo(GPDomain domain)
    {
      Gpo gpoTarget = null;
      
      try
      {
        gpoTarget = domain.GetGpo(this.gpoTargetName);
      }
      catch (MultipleGroupPolicyObjectsFoundException ex)
      {
        gpoTarget = null;
        throw new System.Exception("Cannot proceed as multiple GPOs exist with the specified Display Name");
      }
      catch (System.ArgumentException ex)
      {
        // Create the gpo and return normally
        gpoTarget = domain.CreateGpo(gpoTargetName);
      }
      
      return gpoTarget;
    }

    GPMigrationTable GetMigrationTable()
    {
      GPMigrationTable migrationTable = null;
      
      if (this.migrationTableName.Length > 0)
      {
        migrationTable = new GPMigrationTable(this.migrationTableName);
      }

      return migrationTable;
    }

    public void ImportFromBackup(Gpo gpoTarget, GpoBackup gpoBackup, GPMigrationTable migrationTable)
    {
      if (gpoTarget != null)
      {
        GPStatusMessageCollection statusMessages = null;
        if (migrationTable != null)
        {
          gpoTarget.Import(gpoBackup, migrationTable, out statusMessages);
        }
        else
        {
          gpoTarget.Import(gpoBackup, out statusMessages);
        }
      }
    }

  }
}