Configure Applocker with Desired State Configuration

I was working with Desired State Configuration and wondered why a custom DSC resources hasn’t been published yet for Applocker.
Bitlocker has already its experimental DSC resource. Why Applocker doesn’t have one?

I also wondered what it really takes to configure Applocker with PowerShell Desired State Configuration.

First a quick disclaimer is required:

  • Do not apply this on your servers/workstations if you don’t understand what Applocker does.
  • The deny rules are just examples. I don’t have anything against these software editors.
  • Yes, I know that’s not the most secure Applocker configuration as the example below mixes both a very permissive (default) whitelist and a very specific blacklist.

Let’s also quickly examine the Applocker requirements:

  • Applocker rules can be imported from/exported to a XML file using the GUI or using the cmdlets of the built-in Applocker module (it exists since PowerShell version 2.0 on Windows 7).
    XML seems to better way to go although the Applocker policy can be found in the registry under the HKLM\SOFTWARE\Policies\Microsoft\Windows\SrpV2 key.
  • The applocker policy depends on the ‘Application Identity’ service to be enforced.

Based on the above light requirements, it seems that built-in DSC resources would actually make it and allow to deploy an Applocker policy locally.

To configure Applocker, I need first to export the Applocker policy to XML and dump its indented representation to a file.
To solve the indentation issue, I’ve used the Format-XML function written by Jeffrey Snover that you can find on this page.

# http://blogs.msdn.com/b/powershell/archive/2008/01/18/format-xml.aspx
function Format-XML ([xml]$xml, $indent=2)
{
    $StringWriter = New-Object System.IO.StringWriter
    $XmlWriter = New-Object System.XMl.XmlTextWriter $StringWriter
    $xmlWriter.Formatting = "indented"
    $xmlWriter.Indentation = $Indent
    $xml.WriteContentTo($XmlWriter)
    $XmlWriter.Flush()
    $StringWriter.Flush()
    Write-Output $StringWriter.ToString()
}
Format-XML ([xml](Get-AppLockerPolicy -Effective -Xml)) -indent 2 | 
Out-File -FilePath ~/Documents\Applocker-pol.xml -Encoding ascii

The second step consists in creating the file locally with the XML content thanks to the built-in File DSC resource.
To decide whether to apply the policy, I’ll export the current effective Applocker policy and compare it to the XML file.
Once the Applocker policy is applied, I’ll start the required service.

Here is what the DSC configuration looks like to deploy locally an Applocker policy.

Configuration localApplockerDSCConfig {
param
(
[string[]]$NodeName = 'localhost'
)
Node $NodeName
{
Service AppIDsvc {
Name = 'AppIDSvc'
StartupType = 'Automatic'
State = 'Running'
BuiltinAccount = 'LocalService'
DependsOn = "[File]XMLPol","[Script]ApplyLocalApplockerPol"
}
Script ApplyLocalApplockerPol {
GetScript = {
@{
GetScript = $GetScript
SetScript = $SetScript
TestScript = $TestScript
Result = ([xml](Get-AppLockerPolicy -Effective -Xml)).InnerXML
}
}
SetScript = {
Set-AppLockerPolicy -XMLPolicy 'C:\windows\temp\polApplocker.xml'
}
TestScript = {
if(
Compare-Object -ReferenceObject ([xml](Get-AppLockerPolicy -Effective -Xml)).InnerXML `
-DifferenceObject ([xml](Get-Content 'C:\windows\temp\polApplocker.xml')).InnerXml
) {
return $false
} else {
return $true
}
}
DependsOn = "[File]XMLPol"
}
File XMLPol {
DestinationPath = 'C:\windows\temp\polApplocker.xml'
Ensure = 'Present';
Force = $true
Contents = @'
<AppLockerPolicy Version="1">
<RuleCollection Type="Appx" EnforcementMode="Enabled">
<FilePublisherRule Id="a9e18c21-ff8f-43cf-b9fc-db40eed693ba" Name="(Default Rule) All signed packaged apps" Description="Allows members of the Everyone group to run packaged apps that are signed." UserOrGroupSid="S-1-1-0" Action="Allow">
<Conditions>
<FilePublisherCondition PublisherName="*" ProductName="*" BinaryName="*">
<BinaryVersionRange LowSection="0.0.0.0" HighSection="*" />
</FilePublisherCondition>
</Conditions>
</FilePublisherRule>
</RuleCollection>
<RuleCollection Type="Dll" EnforcementMode="NotConfigured" />
<RuleCollection Type="Exe" EnforcementMode="Enabled">
<FilePublisherRule Id="25118d14-e4db-482e-a936-447c8c93739a" Name="Signed by O=TREND MICRO, INC., L=TAIPEI, S=TAIWAN, C=TW" Description="" UserOrGroupSid="S-1-1-0" Action="Deny">
<Conditions>
<FilePublisherCondition PublisherName="O=TREND MICRO, INC., L=TAIPEI, S=TAIWAN, C=TW" ProductName="*" BinaryName="*">
<BinaryVersionRange LowSection="*" HighSection="*" />
</FilePublisherCondition>
</Conditions>
</FilePublisherRule>
<FilePublisherRule Id="9f30c729-3921-46d9-9df8-eecbfb014ecd" Name="Signed by O=ORACLE AMERICA, INC., L=REDWOOD SHORES, S=CALIFORNIA, C=US" Description="" UserOrGroupSid="S-1-1-0" Action="Deny">
<Conditions>
<FilePublisherCondition PublisherName="O=ORACLE AMERICA, INC., L=REDWOOD SHORES, S=CALIFORNIA, C=US" ProductName="*" BinaryName="*">
<BinaryVersionRange LowSection="*" HighSection="*" />
</FilePublisherCondition>
</Conditions>
</FilePublisherRule>
<FilePublisherRule Id="dcb1232c-6fed-4d95-935f-2dc3fd5ab90e" Name="MICROSOFT MONITORING AGENT, from O=MICROSOFT CORPORATION, L=REDMOND, S=WASHINGTON, C=US" Description="" UserOrGroupSid="S-1-1-0" Action="Deny">
<Conditions>
<FilePublisherCondition PublisherName="O=MICROSOFT CORPORATION, L=REDMOND, S=WASHINGTON, C=US" ProductName="MICROSOFT MONITORING AGENT" BinaryName="*">
<BinaryVersionRange LowSection="*" HighSection="*" />
</FilePublisherCondition>
</Conditions>
</FilePublisherRule>
<FilePathRule Id="68017eb1-38e2-4011-8e56-dc104b27b527" Name="%HOT%\*" Description="" UserOrGroupSid="S-1-1-0" Action="Deny">
<Conditions>
<FilePathCondition Path="%HOT%\*" />
</Conditions>
</FilePathRule>
<FilePathRule Id="921cc481-6e17-4653-8f75-050b80acca20" Name="(Default Rule) All files located in the Program Files folder" Description="Allows members of the Everyone group to run applications that are located in the Program Files folder." UserOrGroupSid="S-1-1-0" Action="Allow">
<Conditions>
<FilePathCondition Path="%PROGRAMFILES%\*" />
</Conditions>
</FilePathRule>
<FilePathRule Id="a61c8b2c-a319-4cd0-9690-d2177cad7b51" Name="(Default Rule) All files located in the Windows folder" Description="Allows members of the Everyone group to run applications that are located in the Windows folder." UserOrGroupSid="S-1-1-0" Action="Allow">
<Conditions>
<FilePathCondition Path="%WINDIR%\*" />
</Conditions>
</FilePathRule>
<FilePathRule Id="fd686d83-a829-4351-8ff4-27c7de5755d2" Name="(Default Rule) All files" Description="Allows members of the local Administrators group to run all applications." UserOrGroupSid="S-1-5-32-544" Action="Allow">
<Conditions>
<FilePathCondition Path="*" />
</Conditions>
</FilePathRule>
</RuleCollection>
<RuleCollection Type="Msi" EnforcementMode="Enabled">
<FilePublisherRule Id="1260ef26-70ff-4391-b719-ead2b2578cf8" Name="MICROSOFT MONITORING AGENT, from O=MICROSOFT CORPORATION, L=REDMOND, S=WASHINGTON, C=US" Description="" UserOrGroupSid="S-1-1-0" Action="Deny">
<Conditions>
<FilePublisherCondition PublisherName="O=MICROSOFT CORPORATION, L=REDMOND, S=WASHINGTON, C=US" ProductName="MICROSOFT MONITORING AGENT" BinaryName="*">
<BinaryVersionRange LowSection="*" HighSection="*" />
</FilePublisherCondition>
</Conditions>
</FilePublisherRule>
<FilePublisherRule Id="1f8d1b9c-997c-4ba0-8cf1-999559d44fef" Name="Signed by O=PUPPET LABS, L=PORTLAND, S=OREGON, C=US" Description="" UserOrGroupSid="S-1-1-0" Action="Deny">
<Conditions>
<FilePublisherCondition PublisherName="O=PUPPET LABS, L=PORTLAND, S=OREGON, C=US" ProductName="*" BinaryName="*">
<BinaryVersionRange LowSection="*" HighSection="*" />
</FilePublisherCondition>
</Conditions>
</FilePublisherRule>
<FilePublisherRule Id="42fdff7a-12ce-4b11-9f9b-dc85c02802b5" Name="Signed by O=TREND MICRO, INC., L=TAIPEI, S=TAIWAN, C=TW" Description="" UserOrGroupSid="S-1-1-0" Action="Deny">
<Conditions>
<FilePublisherCondition PublisherName="O=TREND MICRO, INC., L=TAIPEI, S=TAIWAN, C=TW" ProductName="*" BinaryName="*">
<BinaryVersionRange LowSection="*" HighSection="*" />
</FilePublisherCondition>
</Conditions>
</FilePublisherRule>
<FilePublisherRule Id="b7af7102-efde-4369-8a89-7a6a392d1473" Name="(Default Rule) All digitally signed Windows Installer files" Description="Allows members of the Everyone group to run digitally signed Windows Installer files." UserOrGroupSid="S-1-1-0" Action="Allow">
<Conditions>
<FilePublisherCondition PublisherName="*" ProductName="*" BinaryName="*">
<BinaryVersionRange LowSection="0.0.0.0" HighSection="*" />
</FilePublisherCondition>
</Conditions>
</FilePublisherRule>
<FilePathRule Id="465dec27-a086-4915-9f83-a1a697e63091" Name="%HOT%\*" Description="" UserOrGroupSid="S-1-1-0" Action="Deny">
<Conditions>
<FilePathCondition Path="%HOT%\*" />
</Conditions>
</FilePathRule>
<FilePathRule Id="5b290184-345a-4453-b184-45305f6d9a54" Name="(Default Rule) All Windows Installer files in %systemdrive%\Windows\Installer" Description="Allows members of the Everyone group to run all Windows Installer files located in %systemdrive%\Windows\Installer." UserOrGroupSid="S-1-1-0" Action="Allow">
<Conditions>
<FilePathCondition Path="%WINDIR%\Installer\*" />
</Conditions>
</FilePathRule>
<FilePathRule Id="64ad46ff-0d71-4fa0-a30b-3f3d30c5433d" Name="(Default Rule) All Windows Installer files" Description="Allows members of the local Administrators group to run all Windows Installer files." UserOrGroupSid="S-1-5-32-544" Action="Allow">
<Conditions>
<FilePathCondition Path="*.*" />
</Conditions>
</FilePathRule>
</RuleCollection>
<RuleCollection Type="Script" EnforcementMode="Enabled">
<FilePathRule Id="06dce67b-934c-454f-a263-2515c8796a5d" Name="(Default Rule) All scripts located in the Program Files folder" Description="Allows members of the Everyone group to run scripts that are located in the Program Files folder." UserOrGroupSid="S-1-1-0" Action="Allow">
<Conditions>
<FilePathCondition Path="%PROGRAMFILES%\*" />
</Conditions>
</FilePathRule>
<FilePathRule Id="082de031-a84f-4243-9efa-33d3389481f2" Name="%HOT%\*" Description="" UserOrGroupSid="S-1-1-0" Action="Deny">
<Conditions>
<FilePathCondition Path="%HOT%\*" />
</Conditions>
</FilePathRule>
<FilePathRule Id="9428c672-5fc3-47f4-808a-a0011f36dd2c" Name="(Default Rule) All scripts located in the Windows folder" Description="Allows members of the Everyone group to run scripts that are located in the Windows folder." UserOrGroupSid="S-1-1-0" Action="Allow">
<Conditions>
<FilePathCondition Path="%WINDIR%\*" />
</Conditions>
</FilePathRule>
<FilePathRule Id="ed97d0cb-15ff-430f-b82c-8d7832957725" Name="(Default Rule) All scripts" Description="Allows members of the local Administrators group to run all scripts." UserOrGroupSid="S-1-5-32-544" Action="Allow">
<Conditions>
<FilePathCondition Path="*" />
</Conditions>
</FilePathRule>
</RuleCollection>
</AppLockerPolicy>
'@
}
}
}
if (-not(test-path -Path C:\DSC -PathType Container)){
mkdir C:\DSC
}
# Compile the configuration file to a MOF format
localApplockerDSCConfig -OutputPath C:\DSC
# Run the configuration on localhost
Start-DscConfiguration -Path C:\DSC -ComputerName localhost -Verbose -Force -Wait

It only takes a service, a file, a script resource and less than 5 seconds to deploy an Applocker policy locally. 😎


If I apply it one more time, we can see that all the tests performed are skipped as my system is already in the desired state.


If I open the local group policy editor, we can see the following:

The above configuration was just for testing purposes, right 😉
Here’s how to achieve the exact opposite, i.e., clear the local Applocker policy and stop the required service.

Configuration NoLocalApplockerDSCConfig {
param
(
[string[]]$NodeName = 'localhost'
)
Node $NodeName
{
Service AppIDsvc {
Name = 'AppIDSvc'
StartupType = 'Manual'
State = 'Stopped'
BuiltinAccount = 'LocalService'
DependsOn = "[File]XMLPol","[Script]ApplyLocalApplockerPol"
}
Script ApplyLocalApplockerPol {
GetScript = {
@{
GetScript = $GetScript
SetScript = $SetScript
TestScript = $TestScript
Result = ([xml](Get-AppLockerPolicy -Effective -Xml)).InnerXML
}
}
SetScript = {
Set-AppLockerPolicy -XMLPolicy 'C:\windows\temp\polApplocker.xml'
}
TestScript = {
if(
Compare-Object -ReferenceObject ([xml](Get-AppLockerPolicy -Effective -Xml)).InnerXML `
-DifferenceObject ([xml](Get-Content 'C:\windows\temp\polApplocker.xml')).InnerXml
) {
return $false
} else {
return $true
}
}
DependsOn = "[File]XMLPol"
}
File XMLPol {
DestinationPath = 'C:\windows\temp\polApplocker.xml'
Ensure = 'Present';
Force = $true
Contents = @'
<AppLockerPolicy Version="1" />
'@
}
}
}
if (-not(test-path -Path C:\DSC -PathType Container)){
mkdir C:\DSC
}
# Compile the configuration file to a MOF format
NoLocalApplockerDSCConfig -OutputPath C:\DSC
# Run the configuration on localhost
Start-DscConfiguration -Path C:\DSC -ComputerName localhost -Verbose -Force -Wait

Let’s remove the existing Applocker local policy for the 1rst time:

Again, applied one more time, we can see that all the tests performed are skipped as my system is already in the desired state.


Nice, isn’t it? DSC and PowerShell bring more than just automation! I love it 😀

5 thoughts on “Configure Applocker with Desired State Configuration

  1. Pingback: Dew Drop – April 3, 2015 (#1987) | Morning Dew

  2. When I attempted this on Server 2016, I couldn’t use the Service resource to change the StartupType of Application Identity, because it’s a protected service.

    • Arg… yes, I know. Server 2016 is based on the 1607 branch. At the time of the blog post, it wasn’t released.
      In 1607 Microsoft hardened the AppidSvc and it could be only configured with a group policy. In later version, it started to get better (I recently tested 1903).

  3. If anyone runs into the same issue as jwmiles above, I had to create a registry resource to set the key located at “HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AppIDSvc”
    to a valueData of 2. This seems to be the easiest way to set the startup type for the AppIDSvc to automatic now.
    The full registry resource looks like this for me
    Registry AutoStartupAppID
    {
    Ensure = “Present”
    Key = “HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AppIDSvc”
    ValueName = “Start”
    ValueType = “Dword”
    ValueData = “2”
    Force = $true
    }

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.