- Context:
A colleague of mine was working on Applocker rules and the installer he was working on was so badly designed that we thought it would easier to restore the worst and most dangerous default rule named “*” for the built-in administrators.
If you restore this evil rule, you cannot and should not leave it there. You also have to delete it after it has been used to install successfully that ugly software.
- Problem:
I started looking around using my google fu but only found the following web page from Microsoft named delete-an-applocker-rule that tells you actually how to clear *all* the rules. It’s a dead end and really not what we want 😦
- Solution:
Instead I wrote the following function. Before looking at its code, let me tell you the following:
If you specify the first parameter to indicate what type of rules you want to delete, a Exe, Script, Msi, Appx, Dll, it will be used in the dynamic parameters block to enumerate all rules names found for this type.
Let’s see this in action:
You may also notice in the body of the function that the XML representation of Applocker rules never touches the disk. The rule is removed from the XML and its result is directly merged/reimported.
The function specifies a ‘high’ ConfirmImpact and SupportsShouldProcess because it’s destructive. There’s no backup of the rules or the rule being removed.
Last but not least, the rule is deleted but the group policies (GPO) are not refreshed. You’ll see its impact once the GPO have been reapplied.
Here’s the function:
#Requires -RunAsAdministrator | |
#Requires -Version 3.0 | |
#Requires -PSEdition Desktop | |
Function Remove-LocalApplockerPolicyRule { | |
[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] | |
Param( | |
[ValidateSet('Exe','Script','Msi','Appx','Dll')] | |
[Parameter(Mandatory)] | |
[String]$Type | |
) | |
DynamicParam { | |
$Dictionary = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameterDictionary | |
#region helper function | |
Function New-ParameterAttributCollection { | |
[CmdletBinding()] | |
Param( | |
[Switch]$Mandatory, | |
[Switch]$ValueFromPipeline, | |
[Switch]$ValueFromPipelineByPropertyName, | |
[String]$ParameterSetName, | |
[Parameter()] | |
[ValidateSet( | |
'Arguments','Count','Drive','EnumeratedArguments','Length','NotNull', | |
'NotNullOrEmpty','Pattern','Range','Script','Set','UserDrive' | |
)][string]$ValidateType, | |
[Parameter()] | |
$ValidationContent | |
) | |
Begin { | |
}Process { | |
$c = New-Object System.Collections.ObjectModel.Collection[System.Attribute] | |
$a = New-Object System.Management.Automation.ParameterAttribute | |
if ($Mandatory) { | |
$a.Mandatory = $true | |
} | |
if ($ValueFromPipeline) { | |
$a.ValueFromPipeline = $true | |
} | |
if ($ValueFromPipelineByPropertyName) { | |
$a.ValueFromPipelineByPropertyName=$true | |
} | |
if ($ParameterSetName) { | |
$a.ParameterSetName = $ParameterSetName | |
} | |
$c.Add($a) | |
if ($ValidateType -and $ValidationContent) { | |
try { | |
$c.Add((New-Object "System.Management.Automation.Validate$($ValidateType)Attribute"( | |
$ValidationContent | |
))) | |
} catch { | |
Throw $_ | |
} | |
} | |
$c | |
} | |
End {} | |
} | |
#endregion | |
try { | |
$LocalApplockerPolicyXml = [xml](Get-AppLockerPolicy -Local -Xml -ErrorAction Stop) | |
} catch { | |
Throw 'Failed to read the local Applocker policy into XML' | |
} | |
#region param Rule | |
$Dictionary.Add( | |
'Rule', | |
(New-Object System.Management.Automation.RuntimeDefinedParameter( | |
'Rule', | |
[string], | |
(New-ParameterAttributCollection -Mandatory -ValidateType Set -ValidationContent ( | |
$LocalApplockerPolicyXml.SelectNodes("/AppLockerPolicy/RuleCollection[@Type='$($PSBoundParameters['Type'])']").ChildNodes| ForEach-Object { $_.Name } | |
)) | |
)) | |
) | |
$Dictionary | |
} | |
Begin { | |
} | |
Process { | |
Write-Verbose -Message "Dealing with Rule Collection type: $($PSBoundParameters['Type'])" | |
Write-Verbose -Message "Dealing with Rule Name: $($PSBoundParameters['Rule'])" | |
# Select node | |
$n = $LocalApplockerPolicyXml.SelectNodes("/AppLockerPolicy/RuleCollection[@Type='$($PSBoundParameters['Type'])']").ChildNodes | | |
Where { $_.Name -eq "$($PSBoundParameters['Rule'])" } | |
if ($pscmdlet.ShouldProcess("$($n.OuterXml)", 'Remove rule')) { | |
try { | |
# Remove rule from xml | |
$null = $LocalApplockerPolicyXml.SelectNodes("/AppLockerPolicy/RuleCollection[@Type='$($PSBoundParameters['Type'])']").RemoveChild($n) | |
# Re-apply/import all rules except the removed rule | |
[Microsoft.Security.ApplicationId.PolicyManagement.PolicyModel.AppLockerPolicy]::FromXml($LocalApplockerPolicyXml.outerXML) | | |
Set-AppLockerPolicy -ErrorAction Stop | |
Write-Verbose -Message 'Successfully removed rule, a group policies refresh is required to see the impact of the removed rule' | |
} catch { | |
Throw "Something went wrong while trying to remove the applocker rule: $($_.Exception.Message)" | |
} | |
} | |
} | |
End { | |
} | |
} # endof Remove-LocalApplockerPolicyRule | |
Export-ModuleMember -Function 'Remove-LocalApplockerPolicyRule' |
Pingback: Dew Drop – August 5, 2019 (#3004) | Morning Dew