In the past, AppLocker was available only for Windows Enterprise and Education subscribers. In this post, I will show you a way to use AppLocker on Windows 10 Pro and Windows 11 Pro.

AppLocker is a Group-Policy-based mechanism that allows you to control the applications that run on your PC. It is a core security feature.

Microsoft also lists other use cases, namely:

  • Application inventory
  • Licensing conformance
  • Software standardization

Unfortunately, Microsoft has decided to treat AppLocker as an enterprise benefit and has made it unavailable in the Home and Professional editions of Windows. However, ever since Microsoft has come up with Mobile Device Management (MDM) as a sort of Group Policy 2.0, its documentation now contains this claim:

You can use the AppLocker CSP to configure AppLocker policies on any edition of Windows 10 and Windows 11 supported by Mobile Device Management (MDM).

You might wonder which editions MDM supports—any edition, Microsoft has included MDM capabilities in all editions!

It did not take long until someone had a look at the internals and found out that not even MDM licenses were required to make it work. In fact, you only need to know how to script it.

Creating AppLocker rules ^

Sandy Zeng (Microsoft MVP) seems to be the first who published working scripts. However, Sandy did not go into detail about the syntax; she left us working examples, but she didn't explain how she put them together. This article fills this gap.

You will need Windows 10 Pro or Windows 11 Pro. Even though Windows 10 Home and Windows 11 Home allow applying these rules, there is no easy way to create these rules for the Window Home edition. Honestly, I don't think AppLocker is for the Home edition.

Note that all screenshots come from Windows 10 Pro. Things might look a bit different on Windows 11.

Disclaimer: If you are unaware, AppLocker is able to render the OS completely unusable when configured incorrectly. I recommend trying this on a virtual machine, which enables you to create and return to snapshots in case you lock yourself out.

First, open secpol.msc and navigate to Application control policies > AppLocker. Below that, you will see four sections containing governing rules for executables (.exe), Windows installer files (.msi and .msp), scripts (.ps1, .bat, .cmd, etc.), and packaged apps (modern apps from the Windows Store, including those preinstalled by Microsoft, such as the weather app, calculator, and Paint 3D).

If you were hoping Microsoft would let you use this built-in GUI, you would be mistaken. The GUI is for enterprise and education edition users only; using it on Pro does not enable AppLocker. Still, we will use it to create the scripts that will be used later to enable AppLocker on Windows 10 Pro and Windows 11 Pro.

We start by creating a rule for executables. To play it safe for these tests, let us first create the default rules. It is not the most secure configuration, but for this test, I recommend it. Right-click Executable Rules and select Create default rules. Three rules are created.

Now create a fourth rule that denies access to WordPad ("%ProgramFiles%\Windows NT\Accessories\wordpad.exe") for anyone.

Disallowing WordPad with AppLocker

Disallowing WordPad with AppLocker

Aren't rules 1 and 4 contradictory? Rule 4 will win since it is more specific than rule 1—that is how AppLocker works. WordPad will indeed be disallowed.

Next, we will open regedit and navigate to
HKEY_LOCAL_Machine\Software\Policies\Microsoft\Windows\SrpV2

Inside, open the Exe key. You should see something similar to this, just with different GUIDs:

Regedit showing EXE policies

Regedit showing EXE policies

There are four keys below the Exe key that correspond to our four rules; the Deny policy for WordPad is depicted. Now for the big aha: the data of the depicted registry value can be directly used in the syntax of our script. In other words, the AppLocker GUI uses the registry in a way that we don't need to convert or tamper with.

Okay, hold your horses for a moment, leave regedit open at that spot, open a text editor, and paste the following four lines:

<?xml version="1.0" encoding="utf-8" ?>
<RuleCollection Type="Exe" EnforcementMode="Enabled"> 

</RuleCollection>

Save that as C:\Applocker_on_Win10pro\exe.xml (later, we will use this path in PowerShell ISE). You will have noticed that blank line number 3. Fill it in with the contents of the Value entries of those four registry keys that complete exe.xml:

The EXE XML file

The EXE XML file

Now open powershell_ISE.exe as system account (!) using the following command on an elevated command prompt:

psexec -si powershell_ise

You can download psexec, which is a part of PsTools from Microsoft, and extract it to c:\windows.

In the ISE, paste the following code and save it as Create_Applocker_Exerule.ps1:

<#
.SYNOPSIS
    This function create new AppLocker settings using MDM WMI Bridge

.DESCRIPTION
    This script will create AppLocker settings for EXE

.NOTES
    File name: Create-AppLockerEXE.ps1
    VERSION: 2005a
    AUTHOR: Sandy Zeng
    Created:  2020-09-20
    Licensed under the MIT license.
    Please credit me if you find this script useful and do some cool things with it.

.VERSION HISTORY:
    1.0.0 - (2020-09-20) Script created
    1.0.1 - 
#>

$namespaceName = "root\cimv2\mdm\dmmap" #Do not change this
$className = "MDM_AppLocker_ApplicationLaunchRestrictions01_EXE03" #Do not change this
$GroupName = "AppLocker001" #You can use your own Groupname, don't use special characters or with space
$parentID = "./Vendor/MSFT/AppLocker/ApplicationLaunchRestrictions/$GroupName"
$policyData = Get-Content C:\Applocker_on_Win10pro\exe.xml -raw
Add-Type -AssemblyName System.Web
$pdata = [System.Web.HttpUtility]::HtmlEncode($policyData);
New-CimInstance -Namespace $namespaceName -ClassName $className -Property @{ParentID=$parentID;InstanceID="EXE";EnforcementMode="Enabled";Policy=$pData}

Note that I modified Sandy's original script by sourcing out the XML policy content to an extra file, which I believe makes it easier to handle.

Now, launch the script right from ISE. It needs to be executed as a system account, and, of course, the execution policy needs to be set to at least remotesigned. Afterward, try to launch WordPad; it should be blocked.

WordPad is blocked by AppLocker

WordPad is blocked by AppLocker

Deploying AppLocker rules with Group Policy ^

Now, let me show you a way to deploy and maintain this with GPOs if you want to use this in your Windows 10 professional network.

The network deployment is simple:

  • Create a GPO with AppLocker settings the regular way, as you would for the Enterprise edition. That GPO will deploy the registry settings that we need to configure the rules in the second step.
  • Deploy a scheduled task that runs a PowerShell script to utilize the WMI MDM Bridge to apply these rules. The script for step 2 will be the following (save it as applocker.ps1). I will omit the credits for Sandy Zeng to save space here, but if you decide to utilize it, please give her credit by including the notes, as seen in the script above):
###The first code block deletes all existing rules so that new rules can be written.###

$namespaceName = "root\cimv2\mdm\dmmap"
$GroupName = "AppLocker001"

$className = "MDM_AppLocker_ApplicationLaunchRestrictions01_EXE03"
$parentID = "./Vendor/MSFT/AppLocker/ApplicationLaunchRestrictions/$GroupName"
Get-CimInstance -Namespace $namespaceName -ClassName $className -Filter "ParentID=`'$parentID`' and InstanceID='EXE'"  | Remove-CimInstance

$className = "MDM_AppLocker_MSI03"
$parentID = "./Vendor/MSFT/AppLocker/ApplicationLaunchRestrictions/$GroupName"
Get-CimInstance -Namespace $namespaceName -ClassName $className -Filter "ParentID=`'$parentID`' and InstanceID='Msi'"  | Remove-CimInstance

$className = "MDM_AppLocker_Script03"
$parentID = "./Vendor/MSFT/AppLocker/ApplicationLaunchRestrictions/$GroupName"
Get-CimInstance -Namespace $namespaceName -ClassName $className -Filter "ParentID=`'$parentID`' and InstanceID='Script'"  | Remove-CimInstance

$className = "MDM_AppLocker_ApplicationLaunchRestrictions01_StoreApps03"
$parentID = "./Vendor/MSFT/AppLocker/ApplicationLaunchRestrictions/$GroupName"
Get-CimInstance -Namespace $namespaceName -ClassName $className -Filter "ParentID=`'$parentID`' and InstanceID='StoreApps'"  | Remove-CimInstance

###This code block will retrieve all rules from the registry and write them to temporary XML files (one for each of the 4 Applocker sections) in c:\windows\temp###
 
echo '<RuleCollection Type="Exe" EnforcementMode="Enabled">' | out-file $env:temp\exe.xml -Encoding utf8 
$keys = (reg query hklm\Software\Policies\Microsoft\Windows\SrpV2\Exe | findstr HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\SrpV2\Exe\)
foreach ($key in $keys) {(Get-ItemProperty -Path Registry::$key).Value | Out-file $env:temp\exe.xml -Encoding utf8 -Append} 
echo '</RuleCollection>'| Out-file $env:temp\exe.xml -Encoding utf8 -Append  

echo '<RuleCollection Type="Appx" EnforcementMode="Enabled">' | out-file $env:temp\StoreApps.xml -Encoding utf8 
$keys = (reg query hklm\Software\Policies\Microsoft\Windows\SrpV2\Appx | findstr HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\SrpV2\Appx\)
foreach ($key in $keys) {(Get-ItemProperty -Path Registry::$key).Value | Out-file $env:temp\StoreApps.xml -Encoding utf8 -Append} 
echo '</RuleCollection>'| Out-file $env:temp\StoreApps.xml -Encoding utf8 -Append  

echo '<RuleCollection Type="Script" EnforcementMode="Enabled">' | out-file $env:temp\script.xml -Encoding utf8 
$keys = (reg query hklm\Software\Policies\Microsoft\Windows\SrpV2\Script | findstr HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\SrpV2\Script\)
foreach ($key in $keys) {(Get-ItemProperty -Path Registry::$key).Value | Out-file $env:temp\script.xml -Encoding utf8 -Append} 
echo '</RuleCollection>'| Out-file $env:temp\script.xml -Encoding utf8 -Append  

echo '<RuleCollection Type="Msi" EnforcementMode="Enabled">' | out-file $env:temp\msi.xml -Encoding utf8 
$keys = (reg query hklm\Software\Policies\Microsoft\Windows\SrpV2\Msi | findstr HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\SrpV2\Msi\)
foreach ($key in $keys) {(Get-ItemProperty -Path Registry::$key).Value | Out-file $env:temp\msi.xml -Encoding utf8 -Append} 
echo '</RuleCollection>'| Out-file $env:temp\msi.xml -Encoding utf8 -Append

###This codeblock will apply all rules###

$namespaceName = "root\cimv2\mdm\dmmap"
$className = "MDM_AppLocker_ApplicationLaunchRestrictions01_EXE03"
$GroupName = "AppLocker001"
$parentID = "./Vendor/MSFT/AppLocker/ApplicationLaunchRestrictions/$GroupName"
$policyData = Get-Content $env:temp\exe.xml -Raw
Add-Type -AssemblyName System.Web
$pdata = [System.Web.HttpUtility]::HtmlEncode($policyData);
New-CimInstance -Namespace $namespaceName -ClassName $className -Property @{ParentID=$parentID;InstanceID="EXE";EnforcementMode="Enabled";Policy=$pData}

$className = "MDM_AppLocker_ApplicationLaunchRestrictions01_StoreApps03"
$parentID = "./Vendor/MSFT/AppLocker/ApplicationLaunchRestrictions/$GroupName"
$policyData = Get-Content $env:temp\StoreApps.xml -Raw
Add-Type -AssemblyName System.Web
$pdata = [System.Web.HttpUtility]::HtmlEncode($policyData);
New-CimInstance -Namespace $namespaceName -ClassName $className -Property @{ParentID=$parentID;InstanceID="StoreApps";EnforcementMode="Enabled";Policy=$pData}

$className = "MDM_AppLocker_Script03"
$parentID = "./Vendor/MSFT/AppLocker/ApplicationLaunchRestrictions/$GroupName"
$policyData = Get-Content $env:temp\Script.xml -Raw
Add-Type -AssemblyName System.Web
$pdata = [System.Web.HttpUtility]::HtmlEncode($policyData);
New-CimInstance -Namespace $namespaceName -ClassName $className -Property @{ParentID=$parentID;InstanceID="Script";EnforcementMode="Enabled";Policy=$pData}

$className = "MDM_AppLocker_MSI03"
$parentID = "./Vendor/MSFT/AppLocker/ApplicationLaunchRestrictions/$GroupName"
$policyData = Get-Content $env:temp\msi.xml -Raw
Add-Type -AssemblyName System.Web
$pdata = [System.Web.HttpUtility]::HtmlEncode($policyData);
New-CimInstance -Namespace $namespaceName -ClassName $className -Property @{ParentID=$parentID;InstanceID="Msi";EnforcementMode="Enabled";Policy=$pData}

The scheduled task that you use for this needs system privileges, so the executing account needs to be "System." I suggest making it an immediate task ("Immediate Task (at least Windows 7") so that it applies to any GPO background refresh. This script executes very quickly, which means no significant performance overhead.

Conclusion ^

I provided a helper script that automates rule processing to enable deploying AppLocker on Windows 10 Professional and Windows 11 Professional.

avatar
11 Comments
  1. Abhku 4 weeks ago

    —————————————————————————————————————-
    New-CimInstance : The requested object could not be found.
    At line:28 char:1
    + New-CimInstance -Namespace $namespaceName -ClassName $className -Prop …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (MDM_AppLocker_A…ictions01_EXE03:CimInstance) [New-CimInstance], CimException
    + FullyQualifiedErrorId : MI RESULT 6,Microsoft.Management.Infrastructure.CimCmdlets.NewCimInstanceCommand

    • Author
      Welf Alberts 3 weeks ago

      Hi Abhku.

      The error message proves that you have modified my script, since line 28 is empty, normally. Please use my script and see if it works unmodified. It it does, tell me what you are trying to change or let me look at your modified script.

  2. bunglegrind 3 weeks ago

    Please be aware of this issue:

    https://github.com/MicrosoftDocs/windows-itpro-docs/issues/6813

    I mean, adding rules for scripts it’s a matter of trial and error…
    Do you know any workaround?

  3. Author
    Welf Alberts 3 weeks ago

    @bundlegrind
    What do you need a workaround for? Please be specific.
    What you link shows that logging is not working as expected, still blocking works as expected.

  4. bunglegrind 3 weeks ago

    I mean, the audit mode is useless if I can’t see what is blocked and what not. And tuning becomes a very difficult task

    • Author
      Welf Alberts 3 weeks ago

      Agreed. I will look at audit mode logging soon and share feedback.

    • Author
      Welf Alberts 3 weeks ago

      @bunglegrind
      You are right, this MDM implementation has issues.
      If I take my script and change all 8 occurences of EnforcementMode=”Enabled” to EnforcementMode=”AuditOnly”, it works as expected (things run), but ONLY FOR EXE, the audit log is used, not for MSI or scripts. That is strange. Will need to investigate further.

      When I tested logging, I must admit that I did only .exe, assuming the rest would work as well (why shouldn’t it)…

  5. bunglegrind 3 weeks ago

    Thanks a lot!

    • Author
      Welf Alberts 3 weeks ago

      I found out what this is about.
      Although MS claims “all editions support this”, the logging only works for exe and appx since only those use SRPv2 (=Applocker) blocking, the rest still uses SRPv1 (Software restriction policies).. But there is a way to do logging for the rest:

      Just create the following Reg_SZ entry “LogfileName”at HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers
      with a value like c:\log\mylog.txt
      That log will be populated with entries for ALL types, example entries:

      cmd.exe (PID = 6852) identified C:\Users\a\test\test.bat as Disallowed using SRPv2 rule, Guid = {c71b5435-1293-4848-b0a3-b53066c76ca2}
      msiexec.exe (PID = 1496) identified C:\Users\a\Desktop\ISORecorder31x64.msi as Disallowed using SRPv2 rule, Guid = {c71b5435-1293-4848-b0a3-b53066c76ca2}

      So this interesting log shows the GUIDs of the rules, which it correctly identifies as applocker (=SRPv2) rules, but the GUIDs… where does it find those? No idea.
      And what if we want to do audit logging and receive these “would have been blocked” messages? Nope, can’t be done for MSI or script… in auditing mode, that SRP logfile would read
      msiexec.exe (PID = 9024) identified C:\Users\a\Desktop\ISORecorder31x64.msi as Unrestricted using SRPv2 rule, Guid = {c71b5435-1293-4848-b0a3-b53066c76ca2}

      Conclusion: not 100% the same when it comes to logging, only when it comes to blocking 😐

  6. bunglegrind 3 weeks ago

    Thank you very much for your effort. I’ve enabled the log file and it works!

    cheers

  7. bunglegrind 3 days ago

    Concerning the DLL rules (MDM_AppLocker_DLL03) it looks like it’s working correctly (your script doesn’t provide the DLL feature, but it could be easily extended). I’m running the DLL rules in audit mode, and logs are correctly showed in events manager.

Leave a reply

Your email address will not be published.

*

© 4sysops 2006 - 2022

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