In this howto, I'll explain how to create a basic ADMX template from scratch and use it in a working example. When I was writing my first application that works with GPOs, at the point of writing my first ADMX template, I realized that ADMX Migrator from Microsoft didn't work as expected. So I dug through official documentation, reverse engineered some existing templates, and found a way to write my own templates.

ADMX template structure ^

ADMX is the last format of Administrative Template used in group policy management; it is the successor of ADM. A group policy is a setting that manipulates one or more registry settings in the target computer. The ADMX template comprises one or more XML files that contain instructions for manipulating those registry settings.

As shown below, the typical tree structure of an ADMX template looks like this:

───ADMXfiles
    │   LogonMessageBox.admx
    │   MyCompany.admx
    │
    └───en-US
            LogonMessageBox.adml
            MyCompany.adml

ADML files are language localization files, which are loaded by the Group Policy Editor snap-in according to current locale settings.

Note that I created an additional template, MyCompany.admx/adml, which is a trick for grouping policies in a custom category.

The VBScript LogonMessage.vbs ^

I chose to implement a simple script that shows a message box at the user's logon. The message content, title, button sets, and icons are configurable via GPO. I chose to use VBScript for demonstration purposes. In your projects, you can use your language of choice.

Let's summarize what we will configure in the template:

ItemTypeDescription
Logon Message EnableEnable/DisableFlag that enables the message box display at user logon
Logon Message TitleTextText displayed on message box title bar
Logon Message PromptTextText displayed on message box body
Logon Message ButtonsSingle choice from a listButtons set of message box window
Logon Message IconSingle choice from a listIcon displayed in message box window

The ADMX template header ^

The opening of our ADMX template looks like this:

<policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.0" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">

<policyNamespaces>
    <target prefix="MyCompLogonMessageBox" namespace="MyCompany.LogonMessageBox" />
    <using prefix="mycompany" namespace="MyCompany.Policies.Common" />
    <using prefix="windows" namespace="Microsoft.Policies.Windows" />
</policyNamespaces>

<resources minRequiredRevision="1.0" />
  <categories>
    <category name="CtMyCompLogonMessageBox" displayName="$(string.CtmyCompLogonMessageBox)">
	<parentCategory ref="mycompany:CtMyCompany" />
	</category>
  </categories>

The block contained in <policyDefinitions> can be considered the standard opening of every template.

In <policyNamespaces>, besides the namespace Microsoft.Policies.Windows (which should be considered mandatory), I added a reference to MyCompany.Policies.Common; this is contained in MyCompany.admx file.

Using namespace is a strategy to reduce redundant information in your templates, such as category name.

In the categories section, you can see the main category CtMyCompLogonMessageBox, which refers to the parent category CtMyCompany included in the MyCompany.Policies.Common namespace.

As a result, the Group Policy Editor includes settings that appear under Administrative Templates\My Company\Logon Message Box.

ADML language files ^

The language file, which has an .adml extension, is used for translating strings and presentation elements according to the current user locale. If you consider this snippet of MyCompany.admx:

<categories>
    <category name="CtMyCompany" displayName="$(string.CtCategoryMyCompany)" />
</categories>

and its matching part in en-US\MyCompany.adml:

 <stringTable>
      <string id="CtCategoryMyCompany">My Company</string>      
	</stringTable>

it is easy to understand how a reference is created.

Template item: Enabled/Disabled ^

The first example of a template item is Enabled/Disabled. In the <policies> section, let's define a policy like this:

<policy name="LogonMessageBoxEnable" class="User" displayName="$(string.LogonMessageBoxEnable)" explainText="$(string.LogonMessageBoxEnable_Help)" key="Software\Policies\MyCompany\LogonMessage" valueName="MessageEnable">
    <parentCategory ref="CtMyCompLogonMessageBox" />
    <supportedOn ref="windows:SUPPORTED_WindowsVista" />
    <enabledValue>
        <decimal value="1" />
    </enabledValue>
    <disabledValue>
    <delete />
    </disabledValue>
</policy>

The table below provides descriptions of policy attributes:

Attribute NameExplanationPossible Values
nameUnique name of the policy item.A string, preferably without spaces or special chars
classWhere to place the policy item, computer, user, or both.“Machine”, “User”, or “Both”
displayNameThe name displayed in the GPMC snap-in.A reference to a string located in the ADML file
explainTextThe long explanation text displayed in the GPMC snap-in.A reference to a string located in the ADML file
keyThe relative path of the registry key. The path is relative to the class attribute.A registry key path
valueNameThe registry value name.A string

The tag parentCategory refers to the category (folder) in GPMC. In this case, the parent category is My Company\Logon Message Box.

The tag supportedOn refers to a Windows namespace (located in the Windows.admx file), which contains references to every Windows product you can support in your template.

The tags enabledValue and disabledValues contain the values that the registry key will assume if the policy is enabled or disabled.

Possible values are listed in the table below:

ValueExplanation
deleteThe registry key is deleted
decimal value = “%n”Where %n is a decimal number
String value = “%s”Where %s is a string

Consideration of used registry keys

Although you can manipulate any registry key as needed, it is advisable to use a subkey under Software\Policies (e.g., Software\Policies\MyCompany\LogonMessage). These subkeys are locked by the user editing the machine as part of the AD domain.

Template Item: String Input ^

This template item defines an input string entered by the user. Let's take the Logon message title as an example:

You can enclose one or more items in tag elements.

The text item defines an input string. In the corresponding ADML file, we see a new section called presentationTable, which is referred to by the presentation attribute in the ADMX policy section:

<presentationTable>     
      <presentation id="LogonMessageBoxTitle">
        <textBox refId="LogonMessageBoxTitle">
          <label>Message Box Title:</label>
        </textBox>
	 </presentation>	
</presentationTable>

This syntax instructs the GPMC snap-in to interpret the text with ID LogonMessageBoxTitle as a textbox.

GPMC renders as textbox

GPMC renders as textbox

Template Item: Dropdown List ^

This template item defines a dropdown list, from which users can select a single element. As an example, we'll use the Logon Message Icon:

<policy name="LogonMessageBoxIcon" class="User" displayName="$(string.LogonMessageBoxIcon)" explainText="$(string.LogonMessageBoxIcon_Help)" presentation="$(presentation.LogonMessageBoxIcon)" key="Software\Policies\MyCompany\LogonMessage">
      <parentCategory ref="CtMyCompLogonMessageBox" />
      <supportedOn ref="windows:SUPPORTED_WindowsVista" />
      <elements>
        <enum id="LogonMessageBoxIcon" valueName="MessageIcon">
          <item displayName="$(string.MessageIcon_Critical)">
            <value>
              <decimal value="16" />
            </value>
          </item>
          <item displayName="$(string.MessageIcon_Question)">
            <value>
              <decimal value="32" />
            </value>
          </item>
          <item displayName="$(string.MessageIcon_Exclamation)">
            <value>
              <decimal value="48" />
            </value>
          </item>
          <item displayName="$(string.MessageIcon_Information)">
            <value>
              <decimal value="64" />
            </value>
          </item>
        </enum>
      </elements>
    </policy>

The enum tag contains various items, each of which represents an entry in the dropdown list. The corresponding presentation section in the ADML files look like this:

<presentation id="LogonMessageBoxIcon">
        <dropdownList refId="LogonMessageBoxIcon" noSort="true">Icon</dropdownList>
</presentation>

Below you can see the results of these instructions:

GPMC renders a dropdown list

GPMC renders a dropdown list

Final result ^

You can put the ADMX templates in %WINDIR%\PolicyDefinitions or in the central store, create a GPO object, and edit the policy settings regarding the message box to add the LogonMessageBox.vbs script to user logon.

At user logon, you will see the message box with the settings defined in the policy:

Subscribe to 4sysops newsletter!

The script in action

The script in action

Conclusion ^

The ability to write ADMX templates can be useful in many Sysadmin/DevOps scenarios. Now you can control your users' logon scripts if you want. For a deeper look at this tutorial, see my github repo.

avatar
1 Comment
  1. Eric 3 months ago

    Excellent tutorial!

Leave a reply to Eric Click here to cancel the reply

Please enclose code in pre tags

Your email address will not be published. Required fields are marked *

*

© 4sysops 2006 - 2021

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account