Getting Registry Values from Remote Computers

Being able to use the Windows registry effectively is a very powerful tool for a Windows administrator. There are a number of ways to change settings: GPO, SCCM, logon scripts (not recommended), and of course the manual option of regedit. However, as far as I know, there isn’t really a good way to find out what registry settings are currently set on a bunch of computers. In order to alleviate that, I put together the below script to facilitate such queries:

Function Get-RegistryKeyValue
{
    <#
        .SYNOPSIS
        This script is used to get the value of a registry key for multiple computer

        .DESCRIPTION
        This will use PSRemoting to talk computers throughout the domain to retrieve the registry key

        .PARAMETER RegistryKey
        The key to retrieve from the registry. This can contain wildcards such as *, or %UserSID% to match against users in case you're searching in HKU

        .PARAMETER ComputerName
        One or more computers

        .EXAMPLE
        Get-RegistryKeyValue -ComputerName Computer1 -RegistryKey "HKEY_USERS\%UserSID%\Microsoft\Office\12.0\Word\Security\VBAWarnings"
        This will get the value of VBAWarnings for the computer Computer1
    #>
    [CmdletBinding()]
    param(
        [Parameter(Position=1,ValueFromPipeline=$True)][String[]]$ComputerName,
        [Parameter(Position=2,Mandatory=$True)][String]$RegistryKey,
        [PSCredential]$Credential
    )

    Begin { }

    Process
    {
        # Create a scriptblock that will be run on target computer
        $ScriptBlock =
        {
            #Setup a parameter for the registry key
            param($RegistryKey)

            # Check to see if it's a user key
            If ($RegistryKey -like "*HKEY_USERS*")
            {
                If (-not $RegistryKey.Contains("%UserSID%"))
                {
                    # Throw an error
                    Throw "You must have %UserSID% included in your RegistryKey value when searching in HKEY_USERS"
                }
                
                # For each user select their name
                Foreach ($UserSID in $(Get-ChildItem Registry::HKEY_USERS -Exclude ".Default","*Classes*" | Select-Object Name -ExpandProperty Name))
                {
                    # Get the user's SID
                    $UserSID = $UserSID.SubString(11)
        
                    # Convert the SID into a username
                    $UserName = (New-Object System.Security.Principal.SecurityIdentifier($UserSID)).Translate([System.Security.Principal.NTAccount]) | `
                                 Select -ExpandProperty Value

                    # Check if if it's an actual user
                    If ($UserName -notlike "NT*" ) 
                    {           
                        # Fill-in the SID for the RegistryKey
                        $RegistryKey = $RegistryKey.Replace("%UserSID%",$UserSID)
                        
                        # Set the name of the hive our key is in
                        $Hive = "Registry::$($RegistryKey.Substring(0,$RegistryKey.LastIndexOf("\")))"
                    
                        # Check if the hive exists
                        If (Test-Path -Path $Hive)
                        {
                            # Set the name of the key we're looking to get
                            $Key = $RegistryKey.Split("\")[-1]

                            # Check to see if there are any existing values
                            If ((Get-ItemProperty -Path $Hive) -and ((Get-ItemProperty -Path $Hive | `
                                 Get-Member | `
                                 Where-Object {$_.MemberType -eq "NoteProperty"} | `
                                 Select -ExpandProperty Name) -like $Key))
                            {
                                # Try to get the key values
                                $Values = Get-ItemProperty -Path $Hive
                            }

                            Else
                            {
                                # Set the value to say that it didn't exist
                                $Values = "[Key not present]"
                            }

                            # Foreach value returned in case there are more than one
                            Foreach ($Value in $Values)
                            {
                                # Create a hashtable containg the user's name, the printers they have, and which is the default
                                $Properties = @{'UserName'=$UserName;
                                                'Path'=$Value.PSPath.Split(":")[-1];
                                                'Key'=$Key;
                                                'Value'=$Value | Select-Object -ExpandProperty $Key}

                                # Create an object with the above properties
                                $Object = New-Object -TypeName PSObject -Property $Properties
                    
                                # Output the object
                                Write-Output $Object
                            }
                        }
                    }
                }
            } 
            
            Else
            {
                # Set the name of the hive our key is in
                $Hive = "Registry::$($RegistryKey.Substring(0,$RegistryKey.LastIndexOf("\")))"
                    
                # Check if the hive exists
                If (Test-Path -Path $Hive)
                {
                    # Set the name of the key we're looking to get
                    $Key = $RegistryKey.Split("\")[-1]

                    # Check to see if the value exists
                    If ((Get-ItemProperty -Path $Hive | `
                         Get-Member | `
                         Where-Object {$_.MemberType -eq "NoteProperty"} | `
                         Select -ExpandProperty Name) -like $Key)
                    {
                        # Try to get the key value
                        $Values = Get-ItemProperty -Path $Hive
                    }

                    Else
                    {
                        # Set the value to say that it didn't exist
                        $Values = "[Key not present]"
                    }

                    # Foreach value returned in case there are more than one
                    Foreach ($Value in $Values)
                    {
                        # Create a hashtable containg the user's name, the printers they have, and which is the default
                        $Properties = @{'Path'=$Value.PSPath.Split(":")[-1];
                                        'Key'=$Key;
                                        'Value'=$Value | Select-Object -ExpandProperty $Key}

                        # Create an object with the above properties
                        $Object = New-Object -TypeName PSObject -Property $Properties
                    
                        # Output the object
                        Write-Output $Object
                    }
                }
            }
        }

        If ($Credential)
        {
            # Run the above script block on the passed computers
            Invoke-Command -ComputerName $ComputerName -ScriptBlock $ScriptBlock -ArgumentList $RegistryKey -Credential $Credential
        }

        Else
        {
            # Run the above script block on the passed computers
            Invoke-Command -ComputerName $ComputerName -ScriptBlock $ScriptBlock -ArgumentList $RegistryKey
        }
    }

    End { }
}

To run this, simply specify one or more computers and the hive to search. The name of the hive is pretty forgiving. For example, you can use HKLM:\<path> or HKEY_LOCAL_MACHINE\<path>, either will work fine.

Leave a Reply

Your email address will not be published. Required fields are marked *