How to create an ADMX template

Contents of this article

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:

1234567 ───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:

Item Type Description
Logon Message Enable Enable/Disable Flag that enables the message box display at user logon
Logon Message Title Text Text displayed on message box title bar
Logon Message Prompt Text Text displayed on message box body
Logon Message Buttons Single choice from a list Buttons set of message box window
Logon Message Icon Single choice from a list Icon displayed in message box window

The ADMX template header ^

The opening of our ADMX template looks like this:

1234567891011121314 <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 TemplatesMy CompanyLogon 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:

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

and its matching part in en-USMyCompany.adml:

123 <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:The table
below provides descriptions of policy attributes:

12345678910 <policy name=”LogonMessageBoxEnable” displayName=”$(string.LogonMessageBoxEnable)” explainText=”$(string.LogonMessageBoxEnable_Help)” key=”SoftwarePoliciesMyCompanyLogonMessage” 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 Name Explanation Possible Values
name Unique name of the policy item. A string, preferably without spaces or special chars
class Where to place the policy item, computer, user, or both. “Machine”, “User”, or “Both”
displayName The name displayed in the GPMC snap-in. A reference to a string located in the ADML file
explainText The long explanation text displayed in the GPMC snap-in. A reference to a string located in the ADML file
key The relative path of the registry key. The path is relative to the class attribute. A registry key path
valueName The registry value name. A string

The tag parentCategory refers to the category (folder) in GPMC. In this case, the parent category is My CompanyLogon 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:

Value Explanation
delete The 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 SoftwarePolicies (e.g., SoftwarePoliciesMyCompanyLogonMessage). 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:

1234567 <policy name=”LogonMessageBoxTitle” displayName=”$(string.LogonMessageBoxTitle)” explainText=”$(string.LogonMessageBoxTitle_Help)” presentation=”$(presentation.LogonMessageBoxTitle)” key=”SoftwarePoliciesMyCompanyLogonMessage”>    <parentCategory ref=”CtMyCompLogonMessageBox” />     <supportedOn ref=”windows:SUPPORTED_WindowsVista” />     <elements>        <text id=”LogonMessageBoxTitle” valueName=”LogonMessageBoxTitle” required=”true” />     </elements>   </policy>

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:

1234567 <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:

12345678910111213141516171819202122232425262728 <policy name=”LogonMessageBoxIcon” displayName=”$(string.LogonMessageBoxIcon)” explainText=”$(string.LogonMessageBoxIcon_Help)” presentation=”$(presentation.LogonMessageBoxIcon)” key=”SoftwarePoliciesMyCompanyLogonMessage”>      <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:

123 <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:

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.