Thursday, October 29, 2015

Programmatically Creating Group Policy Shortcuts

.NET has official, documented, managed APIs for modifying registry-based Group Policy, but there are no such facilities for non-registry-based preferences like shortcuts. Some poking around in a shortcut-having policy object's folder in SYSVOL reveals that shortcuts are stored in an XML file called Shortcuts.xml in a folder called Shortcuts under Preferences in the GPO's folder. That format is easy to figure out, but I found that creating that structure manually had no effect. Strangely, the Group Policy Editor showed the shortcuts that I created, but neither the reporting module nor client computers paid it attention until I opened the shortcut properties in the GPE and saved it.

I concluded that there must be some other bookkeeping responsible for enabling types of preferences. There is indeed - I discovered that the Active Directory representation of Group Policy Objects includes two fields called gPCMachineExtensionNames and gPCUserExtensionNames. Those objects are found in the Policies container under System in the main directory partition, though it won't appear in Active Directory Users and Computers unless you enable advanced mode. Each field is a list of pairs of GUIDs, representing Group Policy client extensions. It looks like [{GUID}{GUID}][{GUID}{GUID}], where each bracket-enclosed GUID pair is one extension, and the exact number of entries depends on which preferences are present..

To enable the processing of shortcuts, prepend

[{00000000-0000-0000-0000-000000000000}{CEFFA6E2-E3BD-421B-852C-6F6A79A59BC1}]

and append

[{C418DD9D-0D14-4EFB-8FBF-CFE535C8FAC7}{CEFFA6E2-E3BD-421B-852C-6F6A79A59BC1}]

to the appropriate property on the policy object. You can discover the GUIDs of other extensions by creating a GPO with only administrative template policies, observing the field value, adding an entry of the desired type, and seeing what got added to the field.

The best way to fiddle with Active Directory directly in .NET is to use the DirectoryEntry class from System.DirectoryServices. Make sure to call CommitChanges on DirectoryEntry after you've changed the values.

No comments:

Post a Comment