Valid HTML 4.01 Transitional Valid CSS Valid SVG 1.0

Me, myself & IT

One-Click Setup of an AppLocker Policy

Purpose
Instructions
AppLocker Policy
AppLocker Policy XML Schema Definition
Message Box

Purpose

Present a Windows Script File (*.wsf) to deploy an (arbitrary) AppLocker policy with a single double-click.

Note: the script requires neither PowerShell with its AppLocker cmdlets nor Microsoft Management Console with its GPEdit.msc and SecPol.msc snap-ins!

Additionally present a generic AppLocker Policy (*.xml) for Windows 10 and later versions plus a XML Schema Definition (*.xsd) for validation of AppLocker Policy files.

Note: Windows 11 22H1 and later versions ship with a pair of identical, active but undocumented hidden DLL and executable rules.

Instructions

Perform the following 6 (plus 2 optional) simple steps to create, optionally sign and execute a Windows Script File *.wsf that sets an AppLocker policy on Windows 7 and later versions, then activate it and finally verify its proper function.
  1. Create a text file *.wsf, for example AppLocker.wsf, with the following content in an arbitrary directory:

    <?xml version='1.0' encoding='US-ASCII' standalone='yes' ?>
    <package>
        <comment>Copyright (C) 2009-2026, Stefan Kanthak</comment>
        <job>
            <object id='Application' progid='Shell.Application' />
            <object id='FSO' progid='Scripting.FileSystemObject' />
            <reference object='Scripting.FileSystemObject' />
            <runtime>
                <description>Deploy an AppLocker Policy on Windows 7 and later versions</description>
            </runtime>
            <script language='JScript'>
                if (WScript.Arguments.Length != 0)
                    WScript.Arguments.ShowUsage()
                else
                    if (FSO.FolderExists(FSO.BuildPath(FSO.GetSpecialFolder(WindowsFolder).Path, 'Sysnative')) == false)
                        Application.ShellExecute(WScript.FullName, '//Job:Policy ' + WScript.ScriptFullName, WScript.Path, 'RunAs', 1)
                    else
                        Application.ShellExecute(FSO.BuildPath(FSO.BuildPath(FSO.GetSpecialFolder(WindowsFolder).Path, 'Sysnative'), FSO.GetFileName(WScript.FullName)), '//Job:Policy ' + WScript.ScriptFullName, FSO.GetSpecialFolder(SystemFolder).Path, 'RunAs', 1)
            </script>
        </job>
        <job id='Policy'>
            <object id='AppIdPolicyHandler' classid='clsid:F1ED7D4C-F863-4DE6-A1CA-7253EFDEE1F3' />
            <object id='Application' progid='Shell.Application' />
            <object id='FSO' progid='Scripting.FileSystemObject' />
            <object id='Shell' progid='WScript.Shell' />
            <reference guid='85C3F8F7-CFCE-4259-87FF-CAB1F4521F6E' />
            <reference object='Scripting.FileSystemObject' />
            <reference object='WScript.Shell' />
            <resource id='Policy'><![CDATA[<AppLockerPolicy Version='1' />]]></resource>
            <runtime />
            <script language='JScript'>
                if (Application.IsServiceRunning('AppIdSvc') == false)
                    Application.ServiceStart('AppIdSvc', true)
                AppIdPolicyHandler.SetPolicy('', getResource('Policy'))
                for (var _ = new Enumerator(FSO.GetSpecialFolder(WindowsFolder).SubFolders); _.atEnd() == false; _.moveNext())
                    if (FSO.FileExists(FSO.BuildPath(_.item().Path, FSO.GetFileName(WScript.FullName))))
                        Shell.Run(FSO.BuildPath(_.item().Path, FSO.GetFileName(WScript.FullName)) + ' //Job:Registry ' + WScript.ScriptFullName, WshHide, true)
            //  WScript.Echo(Shell.Exec(FSO.BuildPath(FSO.GetSpecialFolder(SystemFolder).Path, 'GPUpdate.exe') + ' /Target:Computer').StdOut.ReadAll())
            </script>
        </job>
        <job id='Registry'>
            <object id='Shell' progid='WScript.Shell' />
            <reference object='WScript.Shell' />
            <runtime />
            <script language='JScript'>
                Shell.RegWrite('HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Script Host\\Settings\\IgnoreUserSettings', 1, 'REG_DWORD')
                Shell.RegWrite('HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Script Host\\Settings\\UseWinSAFER', 1, 'REG_DWORD')
                Shell.RegWrite('HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\Internet Explorer\\HTA\\DisableHTMLApplication', 1, 'REG_DWORD')
            </script>
        </job>
        <job id='Validate'>
            <object id='Document' progid='MSXML2.DOMDocument.6.0' />
            <object id='Schema' progid='MSXML2.XMLSchemaCache.6.0' />
            <reference object='MSXML2.DOMDocument.6.0' />
            <reference object='MSXML2.XMLSchemaCache.6.0' />
            <runtime>
                <description>Validate the AppLocker Policy embedded as resource in this Windows Script File</description>
                <unnamed helpstring='Mandatory Argument' name='"XML Schema Definition (*.xsd)"' required='1' />
            </runtime>
            <script language='JScript'>
                if (WScript.Arguments.Named.Length != 0
                 || WScript.Arguments.Unnamed.Length != 1)
                    WScript.Arguments.ShowUsage()
                else {
                    Document.async = false
                    Document.validateOnParse = true
                    if (Document.load(WScript.ScriptFullName) == false)
                        WScript.Echo('Error 0x' + (Document.parseError.errorCode &gt;&gt;&gt; 0).toString(16).toUpperCase() + ' at column ' + Document.parseError.linepos + ' in line ' + Document.parseError.line + ' of ' + Document.parseError.url + '\n' + Document.parseError.srcText + '\n' + Document.parseError.reason)
                    else {
                        Document.resolveExternals = true
                        Document.schemas = Schema
                        Document.schemas.add('', WScript.Arguments.Unnamed.Item(0))
                        if (Document.loadXML(Document.getElementsByTagName('resource').item(0).text) == false)
                            WScript.Echo('Error 0x' + (Document.parseError.errorCode &gt;&gt;&gt; 0).toString(16).toUpperCase() + ' at column ' + Document.parseError.linepos + ' in line ' + Document.parseError.line + '\nXPath ' + Document.parseError.errorXPath + '\n\n' + Document.parseError.srcText + '\n\n' + Document.parseError.reason)
                        else
                            WScript.Echo(Document.getElementsByTagName('*').length + ' valid XML nodes!')
                    }
                }
            </script>
        </job>
        <job id='Encode'>
            <object id='Encoder' progid='Scripting.Encoder' />
            <object id='FSO' progid='Scripting.FileSystemObject' />
            <reference object='Scripting.Encoder' />
            <reference object='Scripting.FileSystemObject' />
            <runtime>
                <description>Encode this Windows Script File</description>
            </runtime>
            <script language='JScript'>
                if (WScript.Arguments.Length != 0)
                    WScript.Arguments.ShowUsage()
                else {
                    var Reader = FSO.OpenTextFile(WScript.ScriptFullName, ForReading)
                    var Script = Reader.ReadAll()
                    Reader.Close()
                    var Writer = FSO.OpenTextFile(WScript.ScriptFullName, ForWriting)
                    Writer.Write(Encoder.EncodeScriptFile('.wsc', Script, 0, ''))
                    Writer.Close()
                }
            </script>
        </job>
        <job id='Sign'>
            <object id='Signer' progid='Scripting.Signer' />
            <reference object='Scripting.Signer' />
            <runtime>
                <description>Sign this Windows Script File</description>
                <unnamed helpstring='Mandatory Argument' name='"Certificate Name"' required='1' />
            </runtime>
            <script language='JScript'>
                if (WScript.Arguments.Named.Length != 0
                 || WScript.Arguments.Unnamed.Length != 1)
                    WScript.Arguments.ShowUsage()
                else
                    Signer.SignFile(WScript.ScriptFullName, WScript.Arguments.Unnamed.Item(0))
            </script>
        </job>
        <job id='Verify'>
            <object id='Signer' progid='Scripting.Signer' />
            <reference object='Scripting.Signer' />
            <runtime>
                <description>Verify the Authenticode Signature of this Windows Script File</description>
            </runtime>
            <script language='JScript'>
                if (WScript.Arguments.Length != 0)
                    WScript.Arguments.ShowUsage()
                else
                    Signer.VerifyFile(WScript.ScriptFullName, true)
            </script>
        </job>
    </package>
    Note: the third job is executed for every processor architecture – the registry entries it writes enable SAFER (either AppLocker or Software Restriction Policies) for the Windows Script Host and prevent to overrule this setting with the opposite value in the corresponding Registry key of any user account.

    Note: the policy to disable HTML Applications (*.hta) was introduced with security update 5018410 for Windows 10 21H2 respectively security update 5018418 for Windows 11 21H2 and documented in MSKB article 5022289.

  2. Replace the highlighted XML snippet – an (empty) allow all AppLocker policy – with the one you wish to deploy, for example the generic AppLocker policy for Windows 10 and later versions presented below, then save the modified Windows Script File *.wsf.

  3. (Optional) Start the Command Processor Cmd.exe, then execute the following command line to validate the AppLocker policy embedded in step 2. against an external XML Schema Definition, for example %SystemRoot%\Security\ApplicationId\PolicyManagement\AppIdPolicy.xsd shipped with Windows 7 and later versions, or the one presented below:

    CSCRIPT.EXE //Job:Validate ‹*.wsf› "%SystemRoot%\Security\ApplicationId\PolicyManagement\AppIdPolicy.xsd"
    Microsoft Windows [Version 6.1.7601]
    Copyright (c) 2009 Microsoft Corporation. All rights reserved.
    
    Microsoft (R) Windows Script Host Version 5.8
    Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.
    
    … valid XML nodes!
    CAVEAT: %SystemRoot%\Security\ApplicationId\PolicyManagement\AppIdPolicy.xsd has but multiple flaws – it allows decimal values like −3.14159265358979324 for the Version attribute of the AppLockerPolicy element, arbitrary values for the Type attribute of the RuleCollection element, invalid SID Strings like S-1-000 with no or more than 15 alias SID_MAX_SUB_AUTHORITIES sub-authorities as well as S-1-281474976710656-9999999999-4294967296-… with an authority value greater than 248−1 or with sub-authority values greater than 232−1 for the UserOrGroupSid attribute of the FileHashRule, FilePathRule and FilePublisherRule elements, reserved characters like <|> in the Path attribute of the FilePathCondition element, and invalid integer values greater than 65535 for all parts of the HighSection and LowSection attributes of the BinaryVersionRange element!
  4. (Optional) If you own a code signing certificate run the following command line to sign the Windows Script File modified in step 2.:

    CSCRIPT.EXE //Job:Sign ‹*.wsf› "‹certificate name›"
  5. Run the Windows Script File modified in step 2. and optionally signed in step 4. per double-click.

    Note: it requires Administrator rights and requests them if necessary via User Account Control.

  6. Restart Windows to activate the just set AppLocker policy.

  7. [Screen shot of error message box from 'Windows Script Host' on Windows 7] Log on to your (unprivileged) standard user account or the so-called Protected Administrator account created during Windows Setup and double-click the Windows Script File modified in step 2. again to confirm the successful activation of the AppLocker policy for scripts.

  8. [Screen shot of error message box from 'Windows host process (Rundll32)' for blocked DLL] Copy ShUnimpl.dll from the system directory %SystemRoot%\System32\ to the public user directory %PUBLIC%\, then execute the following command line via the Run box of the Start Menu to confirm the successful activation of the AppLocker policy for DLLs too:

    RunDLL32.exe "%PUBLIC%\ShUnimpl.dll",#0

AppLocker Policy

This generic AppLocker policy for Windows 10 and later versions redefines all default rules and fixes their loopholes – it denies execution in the well-known user-writable directories below the Windows directory %SystemRoot%\ and their Alternate Data Streams.

It uses the well-known groups S-1-5-113 alias NT AUTHORITY\Local account and S-1-5-114 alias NT AUTHORITY\Local account and member of Administrators group introduced with security update 2871997 and documented in security advisory Update to Improve Credentials Protection and Management instead of S-1-1-0 alias Everyone respectively S-1-5-32-544 alias BUILTIN\Administrators.

AppLocker Policy XML Schema Definition

This XML schema definition fixes all bugs of the schema definition %SystemRoot%\Security\ApplicationId\PolicyManagement\AppIdPolicy.xsd shipped with Windows 7 and later versions!

Message Box

Perform the following 2 simple steps to create a Scheduled Task that displays a message box to the interactive user when AppLocker writes an entry to the Event Log.
  1. Create the text file AppLocker.xml with the following content in an arbitrary directory:

    <?xml version='1.0' standalone='yes' ?>
    <!-- Copyright (C) 2011-2026, Stefan Kanthak -->
    <Task version='1.2' xmlns='http://schemas.microsoft.com/windows/2004/02/mit/task'>
        <Actions Context='Author'>
            <ShowMessage>
                <Body>Event: $(eventID)
    File: $(eventFilePath)
    Provider: $(eventProvider)
    Time: $(eventTime)
    User: $(eventUser)
    UserID: $(eventUserID)</Body>
                <Title>AppLocker</Title>
            </ShowMessage>
        </Actions>
        <Principals>
            <Principal id='Author'>
                <GroupId>S-1-5-4</GroupId>
                <RunLevel>LeastPrivilege</RunLevel>
            </Principal>
        </Principals>
        <RegistrationInfo>
            <Author>Stefan Kanthak</Author>
            <Date>2011-04-27T12:34:56.6789</Date>
            <Description>Display a message box to the interactive user when 'AppLocker' writes an entry to the event log</Description>
            <URI>https://skanthak.hier-im-netz.de/applocker.html</URI>
            <Version>0.8.15</Version>
        </RegistrationInfo>
        <Settings>
            <AllowHardTerminate>true</AllowHardTerminate>
            <AllowStartOnDemand>false</AllowStartOnDemand>
            <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
            <DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession>
            <Enabled>true</Enabled>
            <ExecutionTimeLimit>PT1H</ExecutionTimeLimit>
            <Hidden>false</Hidden>
            <IdleSettings>
                <Duration>PT5M</Duration>
                <RestartOnIdle>false</RestartOnIdle>
                <StopOnIdleEnd>true</StopOnIdleEnd>
                <WaitTimeout>PT1H</WaitTimeout>
            </IdleSettings>
            <MultipleInstancesPolicy>Queue</MultipleInstancesPolicy>
            <Priority>7</Priority>
            <RunOnlyIfIdle>false</RunOnlyIfIdle>
            <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
            <StartWhenAvailable>false</StartWhenAvailable>
            <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
            <UseUnifiedSchedulingEngine>false</UseUnifiedSchedulingEngine>
            <WakeToRun>false</WakeToRun>
        </Settings>
        <Triggers>
            <EventTrigger>
                <Enabled>true</Enabled>
                <Subscription>&lt;QueryList&gt;&lt;Query Id='0' Path='Microsoft-Windows-AppLocker/EXE and DLL'&gt;&lt;Select Path='Microsoft-Windows-AppLocker/EXE and DLL'&gt;Event[System[Provider[@Name='Microsoft-Windows-AppLocker'] and (Level=1 or Level=2 or Level=3)]]&lt;/Select&gt;&lt;Select Path='Microsoft-Windows-AppLocker/MSI and Script'&gt;Event[System[Provider[@Name='Microsoft-Windows-AppLocker'] and (Level=1 or Level=2 or Level=3)]]&lt;/Select&gt;&lt;/Query&gt;&lt;/QueryList&gt;</Subscription>
                <ValueQueries>
                    <Value name='eventChannel'>Event/System/Channel</Value>
                    <Value name='eventComputer'>Event/System/Computer</Value>
                    <Value name='eventCorrelation'>Event/System/Correlation</Value>
                    <Value name='eventFilePath'>Event/UserData/RuleAndFileData/FilePath</Value>
                    <Value name='eventID'>Event/System/EventID</Value>
                    <Value name='eventKeywords'>Event/System/Keywords</Value>
                    <Value name='eventLevel'>Event/System/Level</Value>
                    <Value name='eventOpcode'>Event/System/Opcode</Value>
                    <Value name='eventProcessID'>Event/System/Execution/@ProcessID</Value>
                    <Value name='eventProvider'>Event/System/Provider/@Name</Value>
                    <Value name='eventRecordID'>Event/System/EventRecordID</Value>
                    <Value name='eventTask'>Event/System/Task</Value>
                    <Value name='eventThreadID'>Event/System/Execution/@ThreadID</Value>
                    <Value name='eventTime'>Event/System/TimeCreated/@SystemTime</Value>
                    <Value name='eventUser'>Event/UserData/RuleAndFileData/TargetUser</Value>
                    <Value name='eventUserID'>Event/System/Security/@UserID</Value>
                    <Value name='eventVersion'>Event/System/Version</Value>
                </ValueQueries>
            </EventTrigger>
        </Triggers>
    </Task>
  2. Create a Scheduled Task from the task definition file AppLocker.xml created in step 1.:

    SCHTASKS.EXE /CREATE /TN "AppLocker Alert" /XML AppLocker.xml
    SUCCESS: The scheduled task "AppLocker Alert" has successfully been created.

Contact and Feedback

If you miss anything here, have additions, comments, corrections, criticism or questions, want to give feedback, hints or tipps, report broken links, bugs, deficiencies, errors, inaccuracies, misrepresentations, omissions, shortcomings, vulnerabilities or weaknesses, …: don’t hesitate to contact me and feel free to ask, comment, criticise, flame, notify or report!

Use the X.509 certificate to send S/MIME encrypted mail.

Note: email in weird format and without a proper sender name is likely to be discarded!

I dislike HTML (and even weirder formats too) in email, I prefer to receive plain text.
I also expect to see your full (real) name as sender, not your nickname.
I abhor top posts and expect inline quotes in replies.

Terms and Conditions

By using this site, you signify your agreement to these terms and conditions. If you do not agree to these terms and conditions, do not use this site!

Data Protection Declaration

This web page records no (personal) data and stores no cookies in the web browser.

The web service is operated and provided by

Telekom Deutschland GmbH
Business Center
D-64306 Darmstadt
Germany
<‍hosting‍@‍telekom‍.‍de‍>
+49 800 5252033

The web service provider stores a session cookie in the web browser and records every visit of this web site with the following data in an access log on their server(s):


Copyright © 1995–2026 • Stefan Kanthak • <‍stefan‍.‍kanthak‍@‍nexgo‍.‍de‍>