AppLockerFoundry.psm1
<#
.SYNOPSIS Exports an AppLocker Foundry object to an AppLocker XML file. .DESCRIPTION Exports an AppLocker Foundry object to an AppLocker XML file. .PARAMETER Rsop The AppLocker Foundry object to export. .PARAMETER Path The directory path to export the AppLocker XML file to. .EXAMPLE Export-AlfXml -Rsop $Rsop -Path C:\AppLocker.xml Exports the AppLocker Foundry object $Rsop to C:\AppLocker .EXAMPLE Get-DatumRsop $datum (Get-DatumNodesRecursive -AllDatumNodes $Datum.AllNodes) | Export-AlfXml -Path C:\AppLocker Calculate policy objects from Datum and export them to C:\AppLocker #> function Export-AlfXml { [OutputType([System.IO.FileInfo])] [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [System.Collections.Specialized.OrderedDictionary] $Rsop, [Parameter(Mandatory = $true)] [string] $Path ) process { $xmlDoc = [System.Xml.XmlDocument]::new() $null = $xmlDoc.AppendChild($xmlDoc.CreateXmlDeclaration('1.0', 'UTF-8', $null)) $policyNode = $xmlDoc.CreateElement('AppLockerPolicy') $versionAttr = $xmlDoc.CreateAttribute('Version') $versionAttr.InnerText = '1' $null = $policyNode.Attributes.Append($versionAttr) Write-PSFMessage -Level Debug -Message ($Rsop | ConvertTo-Yaml) $domainPath = Join-Path -Path $Path -ChildPath $Rsop['Domain'] if (-not (Test-Path -Path $domainPath)) { Write-PSFMessage -Level Verbose -Message "Creating directory $domainPath" $null = New-Item -Path $domainPath -ItemType Directory } $policyPath = Join-Path -Path $domainPath -ChildPath ('{0}.xml' -f $Rsop['PolicyName']) Write-PSFMessage -Level Verbose -Message "Will export $($Rsop['PolicyName']) to $policyPath" foreach ($ruleCollection in $Rsop['RuleCollections'].GetEnumerator()) { $ruleCollectionNode = $xmlDoc.CreateElement('RuleCollection') $typeAttr = $xmlDoc.CreateAttribute('Type') $typeAttr.InnerText = $ruleCollection.Key $enforcementAttr = $xmlDoc.CreateAttribute('EnforcementMode') $enforcementAttr.InnerText = $ruleCollection.Value.EnforcementMode $null = $ruleCollectionNode.Attributes.Append($typeAttr) $null = $ruleCollectionNode.Attributes.Append($enforcementAttr) foreach ($rule in $ruleCollection.Value.Rules) { Write-PSFMessage -Level Verbose -Message "Adding rule $($rule.Name)" $guidAttr = $xmlDoc.CreateAttribute('Id') $guidAttr.InnerText = [System.Guid]::NewGuid().ToString() $nameAttr = $xmlDoc.CreateAttribute('Name') $nameAttr.InnerText = $rule.Name $descriptionAttr = $xmlDoc.CreateAttribute('Description') $descriptionAttr.InnerText = $rule.Description $userOrGroupAttr = $xmlDoc.CreateAttribute('UserOrGroupSid') $userOrGroupAttr.InnerText = $rule.UserOrGroupSid $actionAttr = $xmlDoc.CreateAttribute('Action') $actionAttr.InnerText = $rule.Action if ($rule.Contains('Path')) { # Path Rule $ruleNode = $xmlDoc.CreateElement('FilePathRule') $conditionNode = $xmlDoc.CreateElement('Conditions') foreach ($rulePath in $rule.Path) { $pathConditionNode = $xmlDoc.CreateElement('FilePathCondition') $pathAttr = $xmlDoc.CreateAttribute('Path') $pathAttr.InnerText = $rulePath $null = $pathConditionNode.Attributes.Append($pathAttr) $null = $conditionNode.AppendChild($pathConditionNode) } $null = $ruleNode.AppendChild($conditionNode) $exceptionsNode = $xmlDoc.CreateElement('Exceptions') foreach ($exception in $rule.Exceptions) { $exceptionConditionNode = $xmlDoc.CreateElement('FilePathCondition') $pathAttr = $xmlDoc.CreateAttribute('Path') $pathAttr.InnerText = $exception $null = $exceptionConditionNode.Attributes.Append($pathAttr) $null = $exceptionsNode.AppendChild($exceptionConditionNode) } $null = $ruleNode.AppendChild($exceptionsNode) } if ($rule.Contains('Data')) { # FileHash Rule $ruleNode = $xmlDoc.CreateElement('FileHashRule') $conditionNode = $xmlDoc.CreateElement('Conditions') $hashConditionNode = $xmlDoc.CreateElement('FileHashCondition') $hashNode = $xmlDoc.CreateElement('FileHash') $dataAttr = $xmlDoc.CreateAttribute('Data') $dataAttr.InnerText = $rule.Data $null = $hashNode.Attributes.Append($dataAttr) $hashTypeAttr = $xmlDoc.CreateAttribute('Type') $hashTypeAttr.InnerText = $rule.Type $null = $hashNode.Attributes.Append($hashTypeAttr) $sourceFileNameAttr = $xmlDoc.CreateAttribute('SourceFileName') $sourceFileNameAttr.InnerText = $rule.SourceFileName $null = $hashNode.Attributes.Append($sourceFileNameAttr) $sourceFileLengthAttr = $xmlDoc.CreateAttribute('SourceFileLength') $sourceFileLengthAttr.InnerText = $rule.SourceFileLength $null = $hashNode.Attributes.Append($sourceFileLengthAttr) $null = $hashConditionNode.AppendChild($hashNode) $null = $conditionNode.AppendChild($hashConditionNode) $null = $ruleNode.AppendChild($conditionNode) } if ($rule.Contains('PublisherName')) { # Publisher Rule $ruleNode = $xmlDoc.CreateElement('FilePublisherRule') $conditionNode = $xmlDoc.CreateElement('Conditions') $publisherConditionNode = $xmlDoc.CreateElement('FilePublisherCondition') $publisherNameAttr = $xmlDoc.CreateAttribute('PublisherName') $publisherNameAttr.InnerText = $rule.PublisherName $null = $publisherConditionNode.Attributes.Append($publisherNameAttr) $productNameAttr = $xmlDoc.CreateAttribute('ProductName') $productNameAttr.InnerText = $rule.ProductName $null = $publisherConditionNode.Attributes.Append($productNameAttr) $binaryNameAttr = $xmlDoc.CreateAttribute('BinaryName') $binaryNameAttr.InnerText = $rule.BinaryName $null = $publisherConditionNode.Attributes.Append($binaryNameAttr) $binaryVersionRangeNode = $xmlDoc.CreateElement('BinaryVersionRange') $binaryLowSectionAttr = $xmlDoc.CreateAttribute('LowSection') $binaryLowSectionAttr.InnerText = $rule.BinaryVersionRange.LowSection $null = $binaryVersionRangeNode.Attributes.Append($binaryLowSectionAttr) $binaryHighSectionAttr = $xmlDoc.CreateAttribute('HighSection') $binaryHighSectionAttr.InnerText = $rule.BinaryVersionRange.HighSection $null = $binaryVersionRangeNode.Attributes.Append($binaryHighSectionAttr) $null = $publisherConditionNode.AppendChild($binaryVersionRangeNode) $null = $conditionNode.AppendChild($publisherConditionNode) $null = $ruleNode.AppendChild($conditionNode) } $null = $ruleNode.Attributes.Append($guidAttr) $null = $ruleNode.Attributes.Append($nameAttr) $null = $ruleNode.Attributes.Append($descriptionAttr) $null = $ruleNode.Attributes.Append($userOrGroupAttr) $null = $ruleNode.Attributes.Append($actionAttr) $null = $ruleCollectionNode.AppendChild($ruleNode) $null = $policyNode.AppendChild($ruleCollectionNode) } } Write-PSFMessage -Level Verbose -Message "Exporting $($Rsop['PolicyName']) to $policyPath" Write-PSFMessage -Level Debug -Message $xmlDoc.ToString() $null = $xmlDoc.AppendChild($policyNode) $xmlDoc.Save($policyPath) Get-Item -Path $policyPath } } <# .SYNOPSIS Get AppLocker file information and convert it to YAML .DESCRIPTIOn Get AppLocker file information and convert it to YAML .PARAMETER Path The path to the file or directory to get AppLocker file information for. .EXAMPLE Get-ChildItem -Path "C:\Program Files" -Recurse -Filter *.exe | Get-AlfYamlFileInfo Get AppLocker file information for all files in "C:\Program Files" and convert it to YAML #> function Get-AlfYamlFileInfo { param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('FullName')] [string[]] $Path ) begin { $yamlObject = @{ RuleCollections = @{} } } process { $fileInfos = Get-AppLockerFileInformation -Path $Path :files foreach ($fileInfo in $fileInfos) { <# Exe: .exe and .com Msi: .msi, .msp, and .mst Script: .ps1, .bat, .cmd, .vbs, and .js StoreApps: .appx DLL: .dll and .ocx #> $ruleType = switch ([IO.Path]::GetExtension($fileInfo.Path.Path)) { { $_ -in '.exe', '.com' } { 'Exe' } { $_ -in '.msi', '.msp', '.mst' } { 'Msi' } { $_ -in '.ps1', '.bat', '.cmd', '.vbs', '.js' } { 'Script' } { $_ -in '.appx' } { 'StoreApps' } { $_ -in '.dll', '.ocx' } { 'Dll' } default { Write-Error -Message "Invalid file extension for AppLocker: $_" continue files } } if (-not $yamlObject['RuleCollections'].Contains($ruleType)) { $yamlObject['RuleCollections'][$ruleType] = @{ EnforcementMode = 'AuditOnly' Rules = [System.Collections.ArrayList]::new() } } $null = $yamlObject['RuleCollections'][$ruleType].Rules.Add( @{ Name = $fileInfo.Path.Path Description = $fileInfo.Path.Path Path = $fileInfo.Path.Path UserOrGroupSid = 'S-1-1-0' Action = 'Allow' } ) if ($fileInfo.Publisher) { # Ensure all those unnecessary custom types are converted $obj = @{ Name = '{0} - {1}' -f $fileInfo.Publisher.PublisherName, $fileInfo.Publisher.ProductName Description = '{0} - {1}' -f $fileInfo.Publisher.PublisherName, $fileInfo.Publisher.ProductName PublisherName = $fileInfo.Publisher.PublisherName ProductName = $fileInfo.Publisher.ProductName BinaryName = $fileInfo.Publisher.BinaryName BinaryVersionRange = @{ LowSection = $fileInfo.Publisher.BinaryVersion.ToString() HighSection = $fileInfo.Publisher.BinaryVersion.ToString() } } $null = $yamlObject['RuleCollections'][$ruleType].Rules.Add($obj) } if ($fileInfo.Hash) { $obj = @{ Name = '{0} - {1}' -f $fileInfo.Hash.SourceFileName, $fileInfo.Hash.HashType.ToString() Description = '{0} - {1}' -f $fileInfo.Hash.SourceFileName, $fileInfo.Hash.HashType.ToString() HashType = $fileInfo.Hash.HashType.ToString() HashDataString = $fileInfo.Hash.HashDataString SourceFileName = $fileInfo.Hash.SourceFileName SourceFileLength = $fileInfo.Hash.SourceFileLength } $null = $yamlObject['RuleCollections'][$ruleType].Rules.Add($obj) } } } end { $yamlObject | ConvertTo-Yaml } } |