Interesting Stuff

  • Working with Group Policy Objects Programmatically - Determining registry values to Enable/Disable/Set a specific policy.

    Greetings!

    Over the past few months our team has seen a number of customer requesting information on how to programmatically/create/edit/read registry based GPO information.  I took some time to combine a couple of samples into one that illustrates a number of these concepts.

    The first question one must answer when working with a registry based GPO is the programmatic modification of this GPO setting supported by Microsoft.  The general answer to that question is that if their exist public documentation on the MSDN or Tech Net site that provides information on the registry key paths and the possible values then, yes, programmatic modification is supported.  In my sample, I used the excel spreadsheet available at the following MSDN link:

    http://www.microsoft.com/downloads/details.aspx?familyid=41dc179b-3328-4350-ade1-c0d9289f09ef&displaylang=en

    The spreadsheet contains a list of policies and their associated registry keys.

     Remember, the GPO can have information stored in 3 different places:

    1. The Active Directory in the form of a GroupPolicyContainer object.
    2. The Sysvol of any DC, where GPO related INI file or POL file is created.   The POL file is then written into the local machine registry in either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER. In addition to these two files, the GPO could store private data in a format known only to the GPO extension.
    3. The client system where a GPO extension could exist to process GPO private data.

    The next step is to determine exactly what values need to be written to the keys in order to enable/disable/set the policy.  While the key values are generally documented, there can be subtle differences in the values that the GUI recognizes and uses to determine if a GPO is enable/disable or set.  I find that using the empirical method works best to solve this problem.   Using the Group Policy Management Console GUI tool, I create a GPO with a specific display name like "MaxVs Test Policy".   I set the policy that I want to set programmatically.   Then I do a query in the Active Directory Users and computers tool to locate the GPO  Object in the Active Directory.  The GPO object contains a CN that is a GUID.  This GUID can be used to locate the NTFS folder on the SYSVOL of a DC that the policy registry information was written to.

     For example, if I created a GPO that sets the "Prevent access to the command prompt" under the "User Configuration" node:

    User Configuration -> Policies -> Administrative Templates -> Security -> "Prevent access to the command prompt"

     I enable it and set it.  When I click the Apply button, a Registry.POL file will be created on the sysvol in a directory named after the common name of the GroupPolicyContainer object created in the AD.  The path will look similar to the following:

    C:\Windows\SYSVOL\sysvol\maxv08.nttest.microsoft.com\Policies\{529AB3E5-3818-42F5-9BDE-95629F33780C}\User

    Where "maxv08.nttest.microsoft.com" will be the domain name of your domain and the GUID string will be the display name of the GPO you just created.  At this point, you can view the POL file in notepad or using a binary file editor.  If you use notepad, the contents would be similar to the following:

    PReg   [ S o f t w a r e \ P o l i c i e s \ M i c r o s o f t \ W i n d o w s \ S y s t e m   ; D i s a b l e C M D   ;    ;    ;    ]

    To see the actual values written in the key, you would need to use a binary editor that displays the binary representation for the values displayed above.

    Copy this file to another location with a name that indicates the setting values.

    Repeat this process for all the settings you wish to duplicate programmatically.

    Once you know the registry values to write, we are ready to write the C++ code to set them.

    Keep watching this blog, I will make another post  that provides a function that illustrates how to set the "Prevent access to the command prompt" policy.

     

  • Creating a new UserPrincipal or GroupPrincipal for existing object when saved causes object to be deleted

    We have been encountered a number of issues regarding the System.DirectoryService.Accountmanagement namespace over the past few weeks.   One of these issues is the following:

     

    PROBLEM:

    =========

    Suppose you want to create a new principal, pick one: userprincipal or groupprincipal, and that principal already exists in your specified context. 

     

    If you use the new operator with the principal, then call the Save method, you will receive the following exception:

     

    "System.DirectoryServices.AccountManagement.PrincipalExistsException: The object already 

    exists." 

     

    As a bonus, the namespace will delete the existing object from the Active directory. 

     

    RESOLUTION:

    =========== 

    This is a known issue with the System.DirctoryServices.AccountManagment namespace and will be addressed in a future update/release to the .Net framework.

     

    WORK AROUND:

    ============

    The simple work around is to test to see if the object exists in the Active Directory before calling the New operator to attempt to create a UserPrincipal or GroupPrincipal associated with it.

     

    Or just use the System.DirectoryServices namespace to create either the user or the group.

     

     

    Steps To Reproduce:

    ====================

    The example is using the GroupPrincipal class.  The same issue can be reproduced with using the UserPrincipal class.

     

    1. Create a simple VB.Net console application and add the following code to the main function:

     

     

     Dim newGroupPrincipal As GroupPrincipal

     Using ouPrincipalContext As PrincipalContext = New PrincipalContext(ContextType.Domain,

                                      "MyDomain.Com", "OU=My Group,DC=MyDomain,DC=Com")

     

                Try

                    newGroupPrincipal = New GroupPrincipal(ouPrincipalContext)

                    With newGroupPrincipal

                        .Name = "test group that will be deleted"

                        .IsSecurityGroup = True

                        .GroupScope = GroupScope.Global

                        .SamAccountName = "test group that will be deleted"

                        .Save()

                    End With

                Catch ex As Exception

                    Debug.WriteLine(ex.ToString)

                End Try

     End Using

     

     

    2. Run this code twice.  The second time around you will receive the

     

    "System.DirectoryServices.AccountManagement.PrincipalExistsException" and you will notice that the principal has been deleted. 

     

    3. Run it a third time and the principal will be created anew.

     

    Stack Trace:

     

    System.DirectoryServices.AccountManagement.PrincipalExistsException: The object already exists. (Exception from

     

    HRESULT: 0x80071392) ---> System.DirectoryServices.DirectoryServicesCOMException (0x80071392): The object already exists. (Exception from HRESULT: 0x80071392)

       at System.DirectoryServices.DirectoryEntry.CommitChanges()

    ....

  • Who is this Max guy anyway?

    Greetings!

    Its difficult to know what one should drop into a blog post.  I've been told that I should provide a post that states who I am and why the information I might post would be interesting.

    Well.... here it goes:

    I've been working at Microsoft for 14 years, covering the heady days of the Win95 launch all the way through to the present.  All 14 years have been spent in the Developer Support organization working with our developer customers.  I've supported a number of different Microsoft API sets from the old Lan Man APIs in the late 90's to the new .Net Powershell Automation classes of today.  In the early part of my career at Microsoft I was known as the "Thunk Master" working with thunk dlls to call the 16 bit Lan Man APIs from 32 bit Windows 95/98 applications.

    For the past 6 years I have been supporting ADSI and the LDAP API sets. Recently, I've added generic WMI and Powershell to the products I support.  If you can do it programmatically with  the Active Directory I support it. 

     As I find interesting tid bits of information about ADSI/WMI/PSH I'll post them here as a way of documenting them.

    My hope is you will find the information useful and interesting.

     


© 2010 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker