Programmatically updating local policy in Windows

By: on March 25, 2013

“Group Policy is a feature of the Microsoft Windows NT family of operating systems that control the working environment of user accounts and computer accounts. Group Policy provides the centralized management and configuration of operating systems, applications, and users’ settings in an Active Directory environment…Local Group Policy (LGP) is a more basic version of the Group Policy used by Active Directory.” – Wikipedia

There are various settings in Windows that come under the remit of the group policy. Even for computers that do not belong to an Active Directory domain there are settings that can only be changed via the local group policy.

The graphical editor, gpedit.msc, is pretty easy to use. But what to do when we need to script policy changes?

There is the Group Policy Management Console Class Library, a .NET library, and also a set of Powershell cmdlets based on top of it. However there are frustrating problems with these.

Firstly, they only come packaged with Remote Server Administration Tools, which is a large Windows update. My use case is aimed at targeting policy settings on newly created machines – I don’t want to have to install an 100MB update and then install Windows features – I just want to update a file.

Secondly, and more damningly, this library, coming as it does in the Remote Server Administration Tools, is aimed at managing Active Directory based group policy. It can’t actually modify the local policy – at least so far as I can tell. Documentation is thin on the ground.

Instead, we need to take the following approach.

Firstly, discover which registry keys are changed when you make the change you are interested in using the GUI. Launch gpedit.msc. Additionally, launch ProcessMonitor with these filters active:

  • Process Name is mmc.exe
  • Operation is RegCreateKey
  • Operation is RegDeleteKey
  • Operation is RegSetValue
  • Operation is RegDeleteValue

Secondly, make the changes you want through the GUI, and take note of which registry keys have been changed.

However, you can’t just then apply those same registry changes directly and expect things to work. The group policy doesn’t actually use the registry to store its settings. Rather, it seems to temporarily write them there, and then compile them down to a binary .pol file that lives in C:WindowsSystem32GroupPolicy. We need to trigger this same process.

There exists a Win32 API for making these changes, that I discovered through this blog post, which I am indebted to. Using some hints from this other blog post, I have created a .NET library that allows managed access to this API.

Here is a code sample of using to change one of the RDP settings (my original use case!):

var gpo = new ComputerGroupPolicyObject();
const string keyPath = @"SOFTWAREPoliciesMicrosoftWindows NTTerminal Services";
using (var machine = gpo.GetRootRegistryKey(GroupPolicySection.Machine))
{
    using (var terminalServicesKey = machine.CreateSubKey(keyPath))
    {
        terminalServicesKey.SetValue("SecurityLayer", 00000000, RegistryValueKind.DWord);
    }
}
gpo.Save();

You can get the source or compiled assembly from BitBucket. Please note that this code is not thoroughly tested – I have yet to figure out how to write meaningful unit tests against a library that is so bound up in the OS – watch this space. If and when you find bugs, please raise issues over on BitBucket.

FacebookTwitterGoogle+

9 Comments

  1. Joshua M. Murphy says:

    This is something I’ve been looking for off and on for the past 5 or more years. I was about to resort to writing a tool solely to parse and modify registry.pol directly… but I’ll definitely be giving this a try. I have a few hundred systems with differing local policies that need a few added things set, and I believe you just saved me a lot of hours!

  2. Martin Eden says:

    Glad to be of assistance. :)

  3. Blain says:

    Hi, I’m not a coder at all but wondered if you could give me some guidance. This would be very handy but how would I make use of it?

    Thanks!

  4. Martin Eden says:

    This is just a code library. It won’t be of any help to you unless you know how to code in .NET. Sorry – I think the topic of how you could make use of this is too large to address in a blog comment – it involves learning how to write programs.

  5. Blain says:

    Understood thanks anyway!

  6. Ilja says:

    Thank you, exactly what I was looking for. But when I try to execute your usage example, i get a InvalidCastException for the cast at line 127 in GroupPolicyObject.cs
    My VS is not in english but here is a translation:
    Cannot cast a COM object of type LocalPolicy.COM.GPClass to interface type LocalPolicy.COM.IGroupPolicyObject (interface not supported).
    Do you have an idea of why this is happening ?

  7. Martin Eden says:

    Just investigated this. I got this error too and found this StackOverflow answer: http://stackoverflow.com/a/16943296/777939

    The solution is to add a [STAThread] attribute to your Main method.

    Note that you will also need to run as an administrator for accessing and modifying local group policy.

    I will update documentation and try and make the code throw a more helpful exception.

  8. Martin Eden says:

    I have updated the source and added an updated dll to the Bitbucket repository that catches this exception and wraps it in a more friendly explanatory version. I’ve also added a readme to the repo, that tells you how you need to run any programs built with this library.

  9. Ilja says:

    Wow that was fast. Thank you very much, it now works perfectly. Great work :)

Post a comment

Your email address will not be published.

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>