XMLOps/New-CertificateSignerRules.psm1

Function New-CertificateSignerRules {
    <#
    .SYNOPSIS
        Creates new Signer rules for Certificates, in the XML file
        The level is Pca/Root/Leaf certificate, meaning there is no certificate publisher mentioned
        Only Certificate TBS and its name is used.
    .PARAMETER SignerData
        The SignerData to be used for creating the rules
    .PARAMETER XmlFilePath
        The path to the XML file to be modified
    .INPUTS
        PSCustomObject[]
        System.IO.FileInfo
    .OUTPUTS
        System.Void
    #>

    [CmdletBinding()]
    [OutputType([System.Void])]
    Param (
        [Parameter(Mandatory = $true)][PSCustomObject[]]$SignerData,
        [Parameter(Mandatory = $true)][System.IO.FileInfo]$XmlFilePath
    )
    Begin {
        . "$([WDACConfig.GlobalVars]::ModuleRootPath)\CoreExt\PSDefaultParameterValues.ps1"

        # Load the XML file
        [System.Xml.XmlDocument]$Xml = Get-Content -Path $XmlFilePath

        # Define the namespace manager
        [System.Xml.XmlNamespaceManager]$Ns = New-Object -TypeName System.Xml.XmlNamespaceManager -ArgumentList $Xml.NameTable
        $Ns.AddNamespace('ns', 'urn:schemas-microsoft-com:sipolicy')

        # Find the Signers Node
        [System.Xml.XmlElement]$SignersNode = $Xml.SelectSingleNode('//ns:Signers', $Ns)

        # Find the ProductSigners Nodes
        [System.Xml.XmlElement]$UMCI_ProductSigners_Node = $Xml.SelectSingleNode('//ns:SigningScenarios/ns:SigningScenario[@Value="12"]/ns:ProductSigners', $Ns)
        [System.Xml.XmlElement]$KMCI_ProductSigners_Node = $Xml.SelectSingleNode('//ns:SigningScenarios/ns:SigningScenario[@Value="131"]/ns:ProductSigners', $Ns)

        # Find the CiSigners Node
        [System.Xml.XmlElement]$CiSignersNode = $Xml.SelectSingleNode('//ns:CiSigners', $Ns)
    }

    Process {

        foreach ($Data in $SignerData) {

            # Create a unique ID for the Signer element
            [System.String]$Guid = [System.Guid]::NewGuid().ToString().replace('-', '').ToUpper()

            [System.String]$SignerID = "ID_SIGNER_R_$Guid"

            # Create the new Signer element
            [System.Xml.XmlElement]$NewSignerNode = $Xml.CreateElement('Signer', $SignersNode.NamespaceURI)
            $NewSignerNode.SetAttribute('ID', $SignerID)
            $NewSignerNode.SetAttribute('Name', $Data.SignerName)

            # Create the CertRoot element and add it to the Signer element
            [System.Xml.XmlElement]$CertRootNode = $Xml.CreateElement('CertRoot', $SignersNode.NamespaceURI)
            $CertRootNode.SetAttribute('Type', 'TBS')
            $CertRootNode.SetAttribute('Value', $Data.TBS)
            [System.Void]$NewSignerNode.AppendChild($CertRootNode)

            # Add the new Signer element to the Signers node
            [System.Void]$SignersNode.AppendChild($NewSignerNode)

            # For User-Mode files
            if ($Data.SiSigningScenario -eq '1') {

                # Check if AllowedSigners node exists, if not, create it
                $UMCI_Temp_AllowedSignersNode = $UMCI_ProductSigners_Node.SelectSingleNode('ns:AllowedSigners', $Ns)

                if ($Null -eq $UMCI_Temp_AllowedSignersNode) {

                    [System.Xml.XmlElement]$UMCI_Temp_AllowedSignersNode = $Xml.CreateElement('AllowedSigners', $Ns.LookupNamespace('ns'))
                    [System.Void]$UMCI_ProductSigners_Node.AppendChild($UMCI_Temp_AllowedSignersNode)

                }

                # Create Allowed Signers inside the <AllowedSigners> -> <ProductSigners> -> <SigningScenario Value="12">
                [System.Xml.XmlElement]$NewUMCIAllowedSignerNode = $Xml.CreateElement('AllowedSigner', $UMCI_Temp_AllowedSignersNode.NamespaceURI)
                $NewUMCIAllowedSignerNode.SetAttribute('SignerId', $SignerID)
                [System.Void]$UMCI_Temp_AllowedSignersNode.AppendChild($NewUMCIAllowedSignerNode)

                # Create a CI Signer for the User Mode Signer
                [System.Xml.XmlElement]$NewCiSignerNode = $Xml.CreateElement('CiSigner', $CiSignersNode.NamespaceURI)
                $NewCiSignerNode.SetAttribute('SignerId', $SignerID)
                [System.Void]$CiSignersNode.AppendChild($NewCiSignerNode)
            }

            # For Kernel-Mode files
            elseif ($Data.SiSigningScenario -eq '0') {

                # Check if AllowedSigners node exists, if not, create it
                $KMCI_Temp_AllowedSignersNode = $KMCI_ProductSigners_Node.SelectSingleNode('ns:AllowedSigners', $Ns)

                if ($Null -eq $KMCI_Temp_AllowedSignersNode) {

                    [System.Xml.XmlElement]$KMCI_Temp_AllowedSignersNode = $Xml.CreateElement('AllowedSigners', $Ns.LookupNamespace('ns'))
                    [System.Void]$KMCI_ProductSigners_Node.AppendChild($KMCI_Temp_AllowedSignersNode)

                }

                # Create Allowed Signers inside the <AllowedSigners> -> <ProductSigners> -> <SigningScenario Value="131">
                [System.Xml.XmlElement]$NewKMCIAllowedSignerNode = $Xml.CreateElement('AllowedSigner', $KMCI_Temp_AllowedSignersNode.NamespaceURI)
                $NewKMCIAllowedSignerNode.SetAttribute('SignerId', $SignerID)
                [System.Void]$KMCI_Temp_AllowedSignersNode.AppendChild($NewKMCIAllowedSignerNode)

                # Kernel-Mode signers don't need CI Signers
            }
        }
    }

    End {
        # Save the modified XML back to the file
        $Xml.Save($XmlFilePath)
    }
}
Export-ModuleMember -Function 'New-CertificateSignerRules'