Reading Group Policy Settings using C#
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).开发者_StackOverflow
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
- A good explanation with an example and example script!
- This one, tells you to go through the registry but you gotta figure out who to access the AD
- Pinvoke: Queries for a group policy override for specified power settings.
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.
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();
}
}
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
精彩评论