UserRegistryDSC.psm1

##################
## UserRegistry ##
##################

<#
.SYNOPSIS
    Returns the current value of a registry setting in all HKUSER hives.
.PARAMETER Key
    Registry key where the setting is located.
.PARAMETER ValueName
    Name of the value to get.
#>


function Get-UserRegistry {
    Param(
        [Parameter(Mandatory)][string]$Key,

        [Parameter(Mandatory)][string]$ValueName
    )

    $UserProfileList = [System.Collections.Generic.List[PSCustomObject]]::new()

    $UserProfiles = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*" | 
        Where-Object {$_.PSChildName -match "S-1-5-..-.*"} | 
            Select-Object @{Name = 'SID'     ; Expression = {$_.PSChildName}},
                          @{Name = 'UserHive'; Expression = {"$($_.ProfileImagePath)\NTuser.dat"}} |
                            ForEach-Object {$UserProfileList.Add($_) | Out-Null}

    $DefaultUser = [PSCustomObject]@{
        SID      = 'DEF'
        UserHive = "$((Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList").Default)\NTuser.dat"
    }
     
    $UserProfileList.Add($DefaultUser)

    $get = foreach ($UserProfile in $UserProfileList) {
        if (Test-Path $($UserProfile.UserHive)) {
            
            $Loaded = Test-Path "Registry::HKEY_USERS\$($UserProfile.SID)"
            
            if (-not $Loaded) {
                reg.exe LOAD "HKU\$($UserProfile.SID)" "$($UserProfile.UserHive)" | Out-Null
            }

            $UserKey = $Key.Replace('HKEY_CURRENT_USER',"Registry::HKEY_USERS\$($UserProfile.SID)")

            try {
                $Value = (Get-ItemProperty -Path $UserKey -Name $ValueName -ErrorAction Stop).$ValueName
            }
            catch {
                $Value = $null
            }
            
            [PSCustomObject]@{
                SID       = $($UserProfile.SID)
                UserHive  = $($UserProfile.UserHive)
                ValueData = $Value
            }
        }
    }

    return $get
}

<#
.SYNOPSIS
    Tests the current value of a registry setting in all HKUSER hives against the desired value and returns a boolean.
    If one or more users don't have the desired value the function will return $false.
.PARAMETER Key
    Registry key where the setting is located.
.PARAMETER ValueName
    Name of the value to get.
.PARAMETER ValueData
    Desired value of the setting.
#>


function Test-UserRegistry {
    Param(
        [Parameter(Mandatory)][string]$Key,

        [Parameter(Mandatory)][string]$ValueName,

        [Parameter(Mandatory)][int]$ValueData
    )

    $get = Get-UserRegistry -Key $this.Key -ValueName $this.ValueName

    foreach ($entry in $get) {
        if ($entry.ValueData -eq $ValueData) {
            $test = $true
        }
        else {
            $test = $false
            break
        }
    }

    if ($test -eq $true) {
        Write-Verbose -Message "$(Join-Path -Path $Key -ChildPath $ValueName) is in desired state"
    }

    return $test
}

<#
.SYNOPSIS
    Changes the value of a registry setting in all necessary HKUSER hives to the desired value.
.PARAMETER Key
    Registry key where the setting is located.
.PARAMETER ValueName
    Name of the value to get.
.PARAMETER ValueData
    Desired value of the setting.
#>


function Set-UserRegistry {
    Param(
        [Parameter(Mandatory)][string]$Key,

        [Parameter(Mandatory)][string]$ValueName,

        [Parameter(Mandatory)][string]$ValueType,

        [Parameter(Mandatory)][int]$ValueData
    )

    $get = Get-UserRegistry -Key $this.Key -ValueName $this.ValueName

    $set = $get | Where-Object {$_.ValueData -ne $ValueData}

    foreach ($UserProfile in $set) {
        $UserKey = $Key.Replace('HKEY_CURRENT_USER',"Registry::HKEY_USERS\$($UserProfile.SID)")

        $Loaded = Test-Path "Registry::HKEY_USERS\$($UserProfile.SID)"
            
        if (-not $Loaded) {
            reg.exe LOAD "HKU\$($UserProfile.SID)" "$($UserProfile.UserHive)" | Out-Null
        }

        if ( -not (Test-Path $UserKey) ) {
            New-Item $UserKey -Force | Out-Null
        }

        try {
            Write-Verbose -Message "Changing Value for $(Join-Path -Path $UserKey -ChildPath $ValueName) from $($UserProfile.Value) to $ValueData"
            Set-Itemproperty -Path $UserKey -Name $ValueName -Value $ValueData -Force -ErrorAction Stop | Out-Null
        }
        catch {
            Write-Verbose -Message "Creating $(Join-Path -Path $Key -ChildPath $ValueName) with value $ValueData"
            New-ItemProperty -LiteralPath $UserKey -Name $ValueName -Value $ValueData -Type $ValueType -Force | Out-Null
        }

        if (-not $Loaded) {
            reg.exe UNLOAD "HKU\$($UserProfile.SID)" | Out-Null
        }
    }
}

<#
.SYNOPSIS
    Class-based DSC resource to modify registry settings for all users in the HKEY_USERS hive.
.PARAMETER Key
    Registry key where the setting is located.
.PARAMETER ValueName
    Name of the value to get.
.PARAMETER ValueData
    Desired value of the setting.
#>


[DscResource()]
class UserRegistry {
    [DSCProperty(Key)]
    [string]$Key

    [DSCProperty(Key)]
    [string]$ValueName

    [DSCProperty(Mandatory)]
    [string]$ValueType

    [DSCProperty(Mandatory)]
    [int]$ValueData

    [DSCProperty(NotConfigurable)]
    [string]$SID

    [DSCProperty(NotCOnfigurable)]
    [string]$UserHive

    [UserRegistry] Get () {
        $get = Get-UserRegistry -Key $this.Key -ValueName $this.ValueName
        return $get
    }

    [void] Set () {
        $set = Set-UserRegistry -Key $this.Key -ValueName $this.ValueName -ValueType $this.ValueType -ValueData $this.ValueData
    }

    [bool] Test () {
        $test = Test-UserRegistry -Key $this.Key -ValueName $this.ValueName -ValueData $this.ValueData
        return $test
    }
}