Reading Group Policy Settings using C#

21,483

Solution 1

That question got me hyped so I went to research it. So a +1

Some solutions I found from the top being the best to bottom being the worst

Solution 2

I had a similar problem, and didn't want to download and install the Microsoft GPO library (Microsoft.GroupPolicy.Management). I wanted to do it all with System.DirectoryServices. It took a little digging, but it can be done.

First retrieve your container using DirectorySearcher. You'll need to have already opened a directory entry to pass into the searcher. The filter you want is:

string filter = "(&" + "(objectClass=organizationalUnit)" + "(OU=" + container + "))";

and the property you're interested in is named "gPLink", so create an array with that property in it:

string[] requestProperties = { "gPLink" };

Now retrieve the results, and pull out the gPLink, if available.

using (var searcher = new DirectorySearcher(directory, filter, properties, SearchScope.Subtree))
{
    SearchResultCollection results = searcher.FindAll();
    DirectoryEntry entry = results[0].GetDirectoryEntry();
    string gpLink = entry.Properties["gPLink"].Value;

If gpLink is null, there is no GPO associated with the container (OU). Otherwise, gpLink will contain a string such as this:

"[LDAP://cn={31B2F340-016D-11D2-945F-00C04FB984F9},cn=policies,cn=system,DC=Test,DC=Domain;0]"

In the text above, you can see a CN for the GPO. All we need to do now is retrieve the GPO from the DC.

For that, we use a filter that looks like this:

string filter = "(&" +
    "(objectClass=groupPolicyContainer)" +
    "(cn={31B2F340-016D-11D2-945F-00C04FB984F9}))";

You'll want to create a Properties array that include the following:

Properties = { "objectClass", "cn", "distinguishedName", "instanceType", "whenCreated",
    "whenChanged", "displayName", "uSNCreated", "uSNChanged", "showInAdvancedViewOnly",
    "name", "objectGUID", "flags", "versionNumber", "systemFlags", "objectCategory", 
    "isCriticalSystemObject", "gPCFunctionalityVersion", "gPCFileSysPath",
    "gPCMachineExtensionNames", "dSCorePropagationData", "nTSecurityDescriptor" };

Now use DirectorySearcher to retrieve the GPO. You'll get back a DirectoryEntry in the results that contains all of the above fields in the Properties collection. Some are COM objects, so you'll have to handle those appropriately.

Solution 3

UPDATED: Working copy. You can now use c# to get read and parse a given GPO without having to use Powershell or write anything to disk.

using Microsoft.GroupPolicy;

var guid = new Guid("A7DE85DE-1234-F34D-99AD-5AFEDF7D7B4A");
var gpo = new GPDomain("Centoso.local");
var gpoData = gpo.GetGpo(guid);
var gpoXmlReport = gpoData.GenerateReport(ReportType.Xml).ToString();

using (XmlReader reader = XmlReader.Create(new StringReader(gpoXmlReport)))
{
    string field;
    while (reader.MoveToNextAttribute())
    {
        foreach (string attr in attributes)
        {
            // do something
        }
    }            
}

This uses the Group Policy Management Console (GPMC) tools: https://msdn.microsoft.com/en-us/library/windows/desktop/aa814316(v=vs.85).aspx

Microsoft.GroupPolicy Namespace https://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.grouppolicy(v=vs.85).aspx

Solution 4

Here is a better and more complete example then above.

class Program
{
    static void Main(string[] args)
    {
        DirectoryEntry rootDse = new DirectoryEntry("LDAP://rootDSE");
        DirectoryEntry root = new DirectoryEntry("GC://" + rootDse.Properties["defaultNamingContext"].Value.ToString());
        DirectorySearcher searcher = new DirectorySearcher(root);
        searcher.Filter = "(objectClass=groupPolicyContainer)";

        foreach (SearchResult gpo in searcher.FindAll())
        {
            var gpoDesc = gpo.GetDirectoryEntry().Properties["distinguishedName"].Value.ToString();
            Console.WriteLine($"GPO: {gpoDesc}");

            DirectoryEntry gpoObject = new DirectoryEntry($"LDAP://{gpoDesc}");

            try
            {
                Console.WriteLine($"DisplayName: {gpoObject.Properties["displayName"].Value.ToString()}");
            }
            catch
            {
            }

            try
            {
                Console.WriteLine($"PCFileSysPath: {gpoObject.Properties["gPCFileSysPath"].Value.ToString()}");
            }
            catch
            {
            }

            try
            {
                Console.WriteLine($"VersionNumber: {gpoObject.Properties["versionNumber"].Value.ToString()}");
            }
            catch
            {
            }

            try
            {
                Console.WriteLine($"UserExtensionNames: {gpoObject.Properties["gPCUserExtensionNames"].Value.ToString()}");
            }
            catch
            {
            }

            try
            {
                Console.WriteLine($"MachineExtensionNames: {gpoObject.Properties["gPCMachineExtensionNames"].Value.ToString()}");
            }
            catch
            {
            }


            try
            {
                Console.WriteLine($"PCFunctionality: {gpoObject.Properties["gPCFunctionalityVersion"].Value.ToString()}");
            }
            catch
            {
            }

        }

        Console.ReadKey();
    }
}
Share:
21,483
Nasir
Author by

Nasir

Updated on July 18, 2022

Comments

  • Nasir
    Nasir almost 2 years

    How do I go about iterating over available and/or set settings in a given GPO (using name or GUID) in an AD domain? Without having to export to XML/HTML using powershell, etc.

    I'm using C# (.NET 4.0).