locked
Editing GPO RRS feed

  • Question

  • Hi,

    I am developing an application in c# which edits the GPO settings programmatically. I am able to iterate all the GPO present in the AD, but i am not able to edit the settings programmatically. My application uses GPMGMT.dll. Thanks in advance.

    Regards

    Tuesday, June 26, 2012 11:18 AM

Answers

  • Hope this helps. Like I said, it's ugly but it works. You'll probably have to install the Group Policy Management Console so you can add a reference to GPMGMTLib.dll. This is directly from my code so you'll have to play with it but it should get you going in the right direction:

    Dim GPM As New GPMGMTLib.GPM
    Dim GPMConst As GPMGMTLib.GPMConstants = GPM.GetConstants
    Dim GPMDomain As GPMGMTLib.GPMDomain = GPM.GetDomain(Environment.GetEnvironmentVariable("USERDNSDOMAIN"), "", GPMConst.UseAnyDC)
    Dim RootDSE As New DirectoryServices.DirectoryEntry("LDAP://RootDSE")
    'Dim GPMSOM As GPMGMTLib.GPMSOM = GPMDomain.GetSOM("OU name") 'to link to specific OU
    Dim GPMSOM As GPMGMTLib.GPMSOM = GPMDomain.GetSOM(RootDSE.Properties("defaultNamingContext").Value.ToString()) '//DC=domain,DC=test

    '
    //=======================
    '//see if we already exist
    '
    //=======================
    Dim GPMSearchExisting As GPMGMTLib.GPMSearchCriteria = GPM.CreateSearchCriteria
    GPMSearchExisting.Add(GPMConst.SearchPropertyGPODisplayName, GPMGMTLib.GPMSearchOperation.opEquals, "Agent_Installation")
    Dim GPOListExisting As GPMGMTLib.GPMGPOCollection = GPMDomain.SearchGPOs(GPMSearchExisting)
    If GPOListExisting.Count <> 0 Then
       
    MsgBox("GPO already exists.")
       
    Exit Sub
    End If

    '//=============================================================================
    '
    //copy compressed GPO template from embedded resources to filesystem then unzip
    '//=============================================================================
    lblStatus.Text += "Copying embedded GPO template to filesystem..." & vbNewLine
    lblStatus.Refresh()
    My.Computer.FileSystem.WriteAllBytes("c:\Agent_Installation_GPO.zip", My.Resources.Agent_Installation_GPO, False)
    lblStatus.Text += "Extracting GPO template from archive..." & vbNewLine
    lblStatus.Refresh()
    Call UnZip("c:\Agent_Installation_GPO.zip", "c:\")

    '
    //=========================================================================================
    '//need to create a GPO migration table on the fly. see Create_Migration_Table() for details
    '
    //=========================================================================================
    lblStatus
    .Text += "Creating GPO migration table..." & vbNewLine
    lblStatus
    .Refresh()
    Call Create_Migration_Table("c:\Agent_Installation_GPO.migtable")

    lblStatus
    .Text += "Creating GPO..." & vbNewLine
    lblStatus
    .Refresh()

    Dim GPO As GPMGMTLib.GPMGPO = GPMDomain.CreateGPO
    GPO
    .DisplayName = "Agent_Installation"

    lblStatus
    .Text += "Linking GPO to domain..." & vbNewLine
    lblStatus
    .Refresh()

    '//===========================
    '
    //links the GPO to the domain
    '//===========================
    GPMSOM.CreateGPOLink(-1, GPO)

    Dim GPMSearchCriteria As GPMGMTLib.GPMSearchCriteria = GPM.CreateSearchCriteria
    GPMSearchCriteria.Add(GPMConst.SearchPropertyGPODisplayName, GPMGMTLib.GPMSearchOperation.opEquals, "Agent_Installation")
    Dim GPOList As GPMGMTLib.GPMGPOCollection = GPMDomain.SearchGPOs(GPMSearchCriteria)
    Dim GPMGPO As GPMGMTLib.GPMGPO = GPOList.Item(1)

    lblStatus.Text += "Importing settings from template..." & vbNewLine
    lblStatus.Refresh()

    '
    //========================================================
    '//link migration table to template and import all settings
    '
    //========================================================
    Dim GPMBackupDir As GPMGMTLib.GPMBackupDir = GPM.GetBackupDir("C:\Agent_Installation_GPO")
    Dim GPMBackup As GPMGMTLib.GPMBackup = GPMBackupDir.GetBackup("{193E0BEE-B37E-4472-A032-F297C4A5D8E1}")
    Dim GPMMigrationTable As GPMGMTLib.GPMMigrationTable = GPM.GetMigrationTable("c:\Agent_Installation_GPO.migtable")
    Dim GPMResult As GPMGMTLib.GPMResult = GPMGPO.Import(0, GPMBackup, GPMMigrationTable)

    lblStatus
    .Text += "Done"
    lblStatus
    .Refresh()

    And this this is the function that creates the migration table. For my test I used test.domain but as you can see I replace this with the current domain before I merge the XML. Note that the XML must be utf-16 or this won't work.

    Using objWriter As New System.IO.StreamWriter(strPath, False, System.Text.Encoding.Unicode) '//must be utf-16
        objWriter.WriteLine("<?xml version=""1.0"" encoding=""utf-16""?>")
        objWriter.WriteLine("<MigrationTable xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns=""http://www.microsoft.com/GroupPolicy/GPOOperations/MigrationTable"">")
        objWriter.WriteLine("  <Mapping>")
        objWriter.WriteLine("    <Type>UNCPath</Type>")
        objWriter.WriteLine("    <Source>\\test.domain\netlogon</Source>")
        objWriter.WriteLine("    <Destination>\\" & Environment.GetEnvironmentVariable("USERDNSDOMAIN") & "\netlogon</Destination>")
        objWriter.WriteLine("  </Mapping>")
        objWriter.Write("</MigrationTable>")
        objWriter.Close()
    End Using

    Regards, Tushar Capoor \n "Success is not permanent. The same is also true of failure." \n\n Don't forget to click [Vote] / [Good Answer] on the post(s) that helped you.\n\n\n I will not say I have failed 1000 times; I will say that I have discovered 1000 ways that can cause failure – Thomas Edison.

    Tuesday, June 26, 2012 11:43 AM

All replies

  • Is the assembly started with administrative rights?

    Regards, MusicDemon

    Tuesday, June 26, 2012 11:36 AM
  • Yes the application is given admin rights.
    Tuesday, June 26, 2012 11:37 AM
  • A workaround is editing the .pol file that is generated by the GPO's to save the registries entries. But again I am not able to find a single way to edit this .pol file with c#.
    Tuesday, June 26, 2012 11:39 AM
  • Hope this helps. Like I said, it's ugly but it works. You'll probably have to install the Group Policy Management Console so you can add a reference to GPMGMTLib.dll. This is directly from my code so you'll have to play with it but it should get you going in the right direction:

    Dim GPM As New GPMGMTLib.GPM
    Dim GPMConst As GPMGMTLib.GPMConstants = GPM.GetConstants
    Dim GPMDomain As GPMGMTLib.GPMDomain = GPM.GetDomain(Environment.GetEnvironmentVariable("USERDNSDOMAIN"), "", GPMConst.UseAnyDC)
    Dim RootDSE As New DirectoryServices.DirectoryEntry("LDAP://RootDSE")
    'Dim GPMSOM As GPMGMTLib.GPMSOM = GPMDomain.GetSOM("OU name") 'to link to specific OU
    Dim GPMSOM As GPMGMTLib.GPMSOM = GPMDomain.GetSOM(RootDSE.Properties("defaultNamingContext").Value.ToString()) '//DC=domain,DC=test

    '
    //=======================
    '//see if we already exist
    '
    //=======================
    Dim GPMSearchExisting As GPMGMTLib.GPMSearchCriteria = GPM.CreateSearchCriteria
    GPMSearchExisting.Add(GPMConst.SearchPropertyGPODisplayName, GPMGMTLib.GPMSearchOperation.opEquals, "Agent_Installation")
    Dim GPOListExisting As GPMGMTLib.GPMGPOCollection = GPMDomain.SearchGPOs(GPMSearchExisting)
    If GPOListExisting.Count <> 0 Then
       
    MsgBox("GPO already exists.")
       
    Exit Sub
    End If

    '//=============================================================================
    '
    //copy compressed GPO template from embedded resources to filesystem then unzip
    '//=============================================================================
    lblStatus.Text += "Copying embedded GPO template to filesystem..." & vbNewLine
    lblStatus.Refresh()
    My.Computer.FileSystem.WriteAllBytes("c:\Agent_Installation_GPO.zip", My.Resources.Agent_Installation_GPO, False)
    lblStatus.Text += "Extracting GPO template from archive..." & vbNewLine
    lblStatus.Refresh()
    Call UnZip("c:\Agent_Installation_GPO.zip", "c:\")

    '
    //=========================================================================================
    '//need to create a GPO migration table on the fly. see Create_Migration_Table() for details
    '
    //=========================================================================================
    lblStatus
    .Text += "Creating GPO migration table..." & vbNewLine
    lblStatus
    .Refresh()
    Call Create_Migration_Table("c:\Agent_Installation_GPO.migtable")

    lblStatus
    .Text += "Creating GPO..." & vbNewLine
    lblStatus
    .Refresh()

    Dim GPO As GPMGMTLib.GPMGPO = GPMDomain.CreateGPO
    GPO
    .DisplayName = "Agent_Installation"

    lblStatus
    .Text += "Linking GPO to domain..." & vbNewLine
    lblStatus
    .Refresh()

    '//===========================
    '
    //links the GPO to the domain
    '//===========================
    GPMSOM.CreateGPOLink(-1, GPO)

    Dim GPMSearchCriteria As GPMGMTLib.GPMSearchCriteria = GPM.CreateSearchCriteria
    GPMSearchCriteria.Add(GPMConst.SearchPropertyGPODisplayName, GPMGMTLib.GPMSearchOperation.opEquals, "Agent_Installation")
    Dim GPOList As GPMGMTLib.GPMGPOCollection = GPMDomain.SearchGPOs(GPMSearchCriteria)
    Dim GPMGPO As GPMGMTLib.GPMGPO = GPOList.Item(1)

    lblStatus.Text += "Importing settings from template..." & vbNewLine
    lblStatus.Refresh()

    '
    //========================================================
    '//link migration table to template and import all settings
    '
    //========================================================
    Dim GPMBackupDir As GPMGMTLib.GPMBackupDir = GPM.GetBackupDir("C:\Agent_Installation_GPO")
    Dim GPMBackup As GPMGMTLib.GPMBackup = GPMBackupDir.GetBackup("{193E0BEE-B37E-4472-A032-F297C4A5D8E1}")
    Dim GPMMigrationTable As GPMGMTLib.GPMMigrationTable = GPM.GetMigrationTable("c:\Agent_Installation_GPO.migtable")
    Dim GPMResult As GPMGMTLib.GPMResult = GPMGPO.Import(0, GPMBackup, GPMMigrationTable)

    lblStatus
    .Text += "Done"
    lblStatus
    .Refresh()

    And this this is the function that creates the migration table. For my test I used test.domain but as you can see I replace this with the current domain before I merge the XML. Note that the XML must be utf-16 or this won't work.

    Using objWriter As New System.IO.StreamWriter(strPath, False, System.Text.Encoding.Unicode) '//must be utf-16
        objWriter.WriteLine("<?xml version=""1.0"" encoding=""utf-16""?>")
        objWriter.WriteLine("<MigrationTable xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns=""http://www.microsoft.com/GroupPolicy/GPOOperations/MigrationTable"">")
        objWriter.WriteLine("  <Mapping>")
        objWriter.WriteLine("    <Type>UNCPath</Type>")
        objWriter.WriteLine("    <Source>\\test.domain\netlogon</Source>")
        objWriter.WriteLine("    <Destination>\\" & Environment.GetEnvironmentVariable("USERDNSDOMAIN") & "\netlogon</Destination>")
        objWriter.WriteLine("  </Mapping>")
        objWriter.Write("</MigrationTable>")
        objWriter.Close()
    End Using

    Regards, Tushar Capoor \n "Success is not permanent. The same is also true of failure." \n\n Don't forget to click [Vote] / [Good Answer] on the post(s) that helped you.\n\n\n I will not say I have failed 1000 times; I will say that I have discovered 1000 ways that can cause failure – Thomas Edison.

    Tuesday, June 26, 2012 11:43 AM
  • I have written software that does something similar to what you describe.  You may find this link helpful: http://msdn.microsoft.com/en-us/library/windows/desktop/aa374407(v=vs.85).aspx

    It would be greatly appreciated if you would mark any helpful entries as helpful and if the entry answers your question, please mark it with the Answer link.

    Tuesday, June 26, 2012 11:56 AM