Parsers/GPO/Registry.ps1

# Create a variable so we can set DependsOn values between passes.
New-Variable -Name GlobalDependsOn -Value @() -Option AllScope -Scope Script -Force
$GlobalDependsOn = @()
Function Write-GPORegistryXMLData
{
    [CmdletBinding()]
    [OutputType([String])]
    param
    (
        [Parameter(Mandatory=$true)]
        [System.Xml.XmlElement]$XML    
    )
    
    $regHash = @{}
    $regHash.ValueType = "None"
    $regHash.ValueName = ""
    $regHash.ValueData = ""
    $regHash.Key = ""

    $Properties = $XML.Properties

    $ValueData = 1
    if (!([int]::TryParse($Properties.Value, [ref]$ValueData)))
    {
        $ValueData = "'$($Properties.ValueData)'" -replace "[^\u0020-\u007E]", ""
    }

    $regHash.ValueData = $ValueData 
    $regHash.ValueName = $Properties.name -replace "[^\u0020-\u007E]", ""

    switch ($Properties.hive)
    {
        "HKEY_LOCAL_MACHINE" { $regHash.Key = "HKLM:\" }
    }

    $regHash.Key = Join-Path -Path $regHash.Key -ChildPath $Properties.Key

    switch ($Properties.type)
    {
        "REG_SZ" { $reghash.ValueType = "String" }
        "REG_NONE" { $reghash.ValueType = "None" }
        "REG_EXPAND_SZ" { $reghash.ValueType = "ExpandString" }
        "REG_DWORD" { $reghash.ValueType = "DWORD" }
        "REG_QWORD" { $reghash.ValueType = "QWORD" }    
        "REG_BINARY" { $reghash.ValueType = "Binary" }  
        "REG_MULTI_SZ" { $reghash.ValueType = "MultiString" }
        Default { $regHash.ValueType = "None" }
    }

    if ($regHash.ValueType -eq "DWORD" -and ($ValueData -match "(Disabled|Enabled|Not Defined|True|False)" -or $ValueData -eq "''"))
    {
        # This is supposed to be an INT and it's a String
        [int]$regHash.ValueData = @{"Disabled"=0;"Enabled"=1;"Not Defined"=0;"True"=1;"False"=0;''=0}.$ValueData
    }
    elseif ($regHash.ValueType -eq "String" -or $regHash.ValueType -eq "MultiString")
    {
        [string]$regHash.ValueData = [string]$ValueData
    }

    if ($regHash.ValueType -eq "None")
    {
        # The REG_NONE is not allowed by the Registry resource.
        $regHash.Remove("ValueType")
    }

    if ([string]::IsNullOrEmpty($regHash.ValueName))
    {
        $regHash.Remove("ValueData")
    }

    $CommentOUT = $false
    
    Write-DSCString -Resource -Name "XML_$(Join-Path -Path $regHash.Key -ChildPath $regHash.ValueName)" -Type Registry -Parameters $regHash -CommentOUT:$CommentOUT
}

Function Write-GPORegistryPOLData
{
    [CmdletBinding()]
    [OutputType([String])]
    param
    (
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [psobject]$Data    
    )

    $regHash = @{}
    $regHash.ValueName = ""
    $regHash.Key = "HKLM:\"

    $regHash.ValueName = $Data.ValueName -replace "[^\u0020-\u007E]", ""
    $regHash.Key = Join-Path -Path $regHash.Key -ChildPath $Data.KeyName
   
    # Process any pol instructions.
    switch -regex ($regHash.ValueName)
    {
        "\*\*del\.(?<ValueName>.*)$" 
        {
            $regHash.ValueName = $Matches.ValueName
            $regHash.Ensure = "Absent"
            $Name = "DEL_$((Join-Path -Path $regHash.Key -ChildPath $regHash.ValueName).TrimStart("HKLM:"))"
            
            $script:GlobalDependsOn += $Name

            # This is only a delete so return from here.
            return Write-DSCString -Resource -Name $Name  -Type Registry -Parameters $regHash -CommentOUT:$CommentOUT
        }

        "\*\*delvals\."
        {
            $regHash.Ensure = "Present"
            $regHash.ValueName = ""
            $regHash.Exclusive = $true
            $Name = "DELVALS_$($regHash.Key.TrimStart("HKLM:"))"

            $script:GlobalDependsOn += $Name
            # This is only a delete so return from here.
            return Write-DSCString -Resource -Name $Name  -Type Registry -Parameters $regHash -CommentOUT:(!$ExclusiveFlagAvailable)
        }

        "\*\*DeleteValues"
        {
            $Data.ValueData = $Data.ValueData -replace "[^\u0020-\u007E]", ""
            foreach ($ValueName in ($Data.ValueData -split ";"))
            {          
                $regHash.Ensure = "Absent"
                $Name = "DELETEVALUES_$((Join-Path -Path $regHash.Key -ChildPath $regHash.ValueName).TrimStart("HKLM:"))"

                $script:GlobalDependsOn += $Name

                # This is only a delete so return from here.
                Write-DSCString -Resource -Name $Name  -Type Registry -Parameters $regHash -CommentOUT:$CommentOUT
            }

            return
        }

        "\*\*DeleteKeys"
        {
            $Data.ValueData = $Data.ValueData -replace "[^\u0020-\u007E]", ""
            foreach ($Key in ($Data.ValueData -split ";"))
            {          
                $regHash.Ensure = "Absent"
                $Name = "DELETEKEYS_$($regHash.Key.TrimStart("HKLM:"))"

                $script:GlobalDependsOn += $Name

                # This is only a delete so return from here.
                Write-DSCString -Resource -Name $Name  -Type Registry -Parameters $regHash -CommentOUT:$CommentOUT
            }

            return
        }

        "\*\*SecureKey"
        {
            $Name = "SECUREKEY_$($regHash.Key)"

            # This is only a delete so return from here.
            return Write-DSCString -Resource -Name $Name  -Type Registry -Parameters $regHash -CommentOUT:$true
        }
    }

    # Now setup the rest of the Params Hashtable values.
    $regHash.ValueType = "None"
    $regHash.ValueData = ""

    $ValueData = 1
    if (!([int]::TryParse($Data.ValueData, [ref]$ValueData)))
    {
        $ValueData = "'$($Data.ValueData)'" -replace "[^\u0020-\u007E]", ""
    }

    $regHash.ValueData = $ValueData
    switch ($Data.ValueType)
    {
        "REG_SZ" { $reghash.ValueType = "String" }
        "REG_NONE" { $reghash.ValueType = "None" }
        "REG_EXPAND_SZ" { $reghash.ValueType = "ExpandString" }
        "REG_DWORD" { $reghash.ValueType = "DWORD" }
        "REG_QWORD" { $reghash.ValueType = "QWORD" }    
        "REG_BINARY" { $reghash.ValueType = "Binary" }  
        "REG_MULTI_SZ" { $reghash.ValueType = "MultiString" }
        Default { $regHash.ValueType = "None" }
    }

    if ($regHash.ValueType -eq "DWORD" -and ($ValueData -match "(Disabled|Enabled|Not Defined|True|False)"  -or $ValueData -eq "''"))
    {
        # This is supposed to be an INT and it's a String
        [int]$regHash.ValueData = @{"Disabled"=0;"Enabled"=1;"Not Defined"=0;"True"=1;"False"=0;''=0}.$ValueData
    }
    elseif ($regHash.ValueType -eq "String"  -or $regHash.ValueType -eq "MultiString")
    {
        [string]$regHash.ValueData = [string]$ValueData
    }

    if ($regHash.ValueType -eq "None")
    {
        # The REG_NONE is not allowed by the Registry resource.
        $regHash.Remove("ValueType")
    }

    if ([string]::IsNullOrEmpty($regHash.ValueName))
    {
        $regHash.Remove("ValueData")
    }

    $DependsOn = @()
    $delVals = "DELVALS_$($regHash.Key.TrimStart("HKLM:"))"
    if ($script:GlobalDependsOn -contains $delVals -and $ExclusiveFlagAvailable)
    {
        $DependsOn += "[Registry]$delVals"
    }

    $delVal_ValueName = "DEL_$((Join-Path -Path $regHash.Key -ChildPath $regHash.ValueName).TrimStart("HKLM:"))"
    if ($script:GlobalDependsOn -contains $delVal_ValueName)
    {
        $DependsOn += "[Registry]$delVal_ValueName"
    }

    $deleteKeys = "DELETEKEY_$($regHash.Key.TrimStart("HKLM:"))"
    if ($script:GlobalDependsOn -contains $deleteKeys)
    {
        $DependsOn += "[Registry]$deleteKeys"
    }

    $deleteValue = "DELETEVALUES_$((Join-Path -Path $regHash.Key -ChildPath $regHash.ValueName).TrimStart("HKLM:"))"
    if ($script:GlobalDependsOn -contains $deleteValue)
    {
        $DependsOn += "[Registry]$deleteValue"
    }

    if ($DependsOn.count -gt 0)
    {
        $regHash.DependsOn = $DependsOn
    }

    Write-DSCString -Resource -Name "Registry(POL): $(Join-Path -Path $regHash.Key -ChildPath $regHash.ValueName)" -Type Registry -Parameters $regHash -CommentOUT:$CommentOUT
}

Function Write-GPORegistryINFData
{
    [CmdletBinding()]
    [OutputType([String])]
    param
    (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$Key,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$ValueData
    )

    $regHash = @{}
    $regHash.ValueType = "None"
    $regHash.ValueName = ""
    $regHash.ValueData = ""
    $regHash.Key = ""

    $values = $ValueData -split ","
            
    $KeyPath = $Key
            
    $ValueName = Split-Path -Leaf $KeyPath
    $regHash.ValueName = $ValueName -replace "[^\u0020-\u007E]", ""
    $regHash.Key = Split-Path -Parent $KeyPath
    $regHash.Key = $regHash.Key -replace "MACHINE\\", "HKLM:\" 
    Try
    {
        $tmpValueData = $values[1..$values.count] -join ","
    }
    Catch 
    {
        $tmpValueData = $null
        $regHash.Remove("ValueData")
        continue    
    }
        
    switch ($values[0]) 
    { 
        "1" 
        { 
            # Not sure what type the legal caption is. Is it an array of strings?
            if ($regHash.ContainsKey("ValueData"))
            {
                $regHash.ValueData = "'$($tmpValueData)'" -replace "[^\u0020-\u007E]", ""
            }
            $regHash.ValueType = "String"
        } 
                        
        "7" 
        { 
            if ($regHash.ContainsKey("ValueData"))
            {
            $regHash.ValueData = @"
$($tmpValueData)
"@
 -replace "[^\u0020-\u007E]", ""
            }
            $regHash.ValueType = "MultiString"
        }
                        
        "4" 
        { 
            if ($regHash.ContainsKey("ValueData"))
            {
                $tstValueData = 1
                if (!([int]::TryParse($tmpValueData, [ref]$tstValueData)))
                {
                    Write-Error "Cannot Parse Value for $ValueData at key $KeyData, setting value to 0"
                    $tmpValueData = 0
                }

                [int]$regHash.ValueData = $tstValueData
            }
            $regHash.ValueType = "DWORD"
        }
                        
        "3" 
        { 
            if ($regHash.ContainsKey("ValueData"))
            {
                $hexified = $tmpValueData -split "," | ForEach-Object { "0x$_"}
            }
            $regHash.ValueData = [byte[]]$hexified
            $regHash.ValueType = "Binary"
        } 

        Default
        {
            Write-Warning "Cannot parse RegistryINF Data"
            Write-Warning "$_"
            return ""
        }
    }
    
    if ($regHash.ValueType -eq "DWORD" -and ($regHash.ValueData -match "(Disabled|Enabled|Not Defined|True|False)" -or $regHash.ValueData -eq "''"))
    {
        # This is supposed to be an INT and it's a String
        [int]$regHash.ValueData = @{"Disabled" = 0; "Enabled" = 1; "Not Defined" = 0; "True" = 1; "False" = 0; '' = 0}.$regHash.ValueData
    }
    elseif ($regHash.ValueType -eq "String" -or $regHash.ValueType -eq "MultiString")
    {
        [string]$regHash.ValueData = [string]$regHash.ValueData
    }
    
    if ($regHash.ValueType -eq "None")
    {
        # The REG_NONE is not allowed by the Registry resource.
        $regHash.Remove("ValueType")
    }

    if ([string]::IsNullOrEmpty($regHash.ValueName))
    {
        $regHash.Remove("ValueData")
    }

    $CommentOUT = $false

    Write-DSCString -Resource -Name "Registry(INF): $(Join-Path -Path $regHash.Key -ChildPath $regHash.ValueName)" -Type Registry -Parameters $regHash -CommentOUT:$CommentOUT
}