Remote Registry Read/Write

Eventually you will need to verify registry keys on a list of computers, whether for security reasons, or some project. I find navigating the registry editor very tedious because of the sheer number of files that must be waded through. The endless collapsing and expanding…it’s just dreadful. Getting lost in a huge subfolder is one of my biggest annoyances. Registry read issues are further compounded when you have to deal with multiple computers. I find it much easier, and faster, to read and set values across many computers all at once using TSQL, or better yet, PowerShell.

SQL Server has a way to query and set values in the registry, although you may not realize it. This isn’t something everyone has to every day, but when you do, you want an easy way to handle it. The TSQL commands are actually relatively simple. XP_REGREAD and XP_REGWRITE can solve your read/write woes, but with limitations.

For all examples, I’ll be reading and writing values for UAC, which can be located in the registry under HKEY_LOCAL_MACHINE at Software\Microsoft\Windows\CurrentVersion\Policies\System controlled by the value EnableLUA. A value of 1 means UAC is On, while a value of 0 means UAC is Off.

To read a registry value using TSQL, run the following command:

EXECUTE MASTER.dbo.xp_regread
'HKEY_LOCAL_MACHINE' --HKEY directory
,'Software\Microsoft\Windows\CurrentVersion\Policies\System' --Registry Path
,'EnableLUA' --Registry Key

To set UAC On using TSQL, run the following command: (Set the last value to ‘0’ to turn UAC Off)

EXECUTE MASTER.dbo.xp_regwrite
'HKEY_LOCAL_MACHINE'
,'Software\Microsoft\Windows\CurrentVersion\Policies\System'
,'EnableLUA'
,'reg_sz' --Other options include reg_binary and reg_dword
,'1' --Key Value to set, in this case it would be 0 or 1

You may notice that the Results Pane indicates that 0 rows are affected. It made me angry when I tried to build these examples, but SQL Server is a liar here. Read the value of the registry key once again, and you will see that the value did update to your desired value. Flip the value on and off if you really don’t believe me. The problem with using TSQL lies in the limitations of SQL Server. Obviously you cannot read/write registry values of computers that do not have SQL running on them, and this includes passive nodes. How about PowerShell as a better solution?

PowerShell is a skill that is becoming more necessary as environments grow. I would argue that anytime you need to touch more than one computer, you should consider a remote solution using PowerShell. Plus, reading and writing to the registry just feels right when working through PowerShell.

The simple way of querying a registry value in PowerShell is as follows:

$Path = 'HKLM:Software\Microsoft\Windows\CurrentVersion\Policies\System'
$Key = 'EnableLUA'
Get-ItemProperty -Path $Path -Name $Key

However, unlike most Cmdlets, this one does not accept a ComputerName Property. Probably because Microsoft hates us. You can use a slightly more complicated method to query a remote registry though.

$Computer = "YourComputerHere"
$Path = 'Software\Microsoft\Windows\CurrentVersion\Policies\System'
$Key = 'EnableLUA'
$Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$Computer)
$RegKey = $Reg.OpenSubKey($Path)
$Value = $RegKey.GetValue($Key)
Write-Host "$Computer $Value"

Please note that I did not include HKLM: in the $Path variable this time. If you leave that in, you’ll receive an error stating that “You cannot call a method on a null-valued expression.” Using this script does not require the HK as it only deals with Registry Paths. The original Cmdlet we used, Get-ItemProperty, can get the properties of files, so it needs the extra distinction.

Next, we will expand the script slightly to include a ForEach statement in order to query multiple computers at once.

$ComputerList = "Computer1","Computer2"
ForEach ($Computer in $ComputerList)
{
$Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$Computer)
$RegKey = $Reg.OpenSubKey($Path)
$Value = $RegKey.GetValue($Key)
Write-Host $Computer $Value
}

PowerShell includes an equally easy way to set the registry values, can you guess what the Cmdlet name is? Luckily that was a rhetorical question, and I will not make you answer in the comments. You can use Set-ItemProperty to update registry values. However, you are still limited to the local computer with this method. Let’s skip straight to the multi-server solution, as the baby steps are the same as those we took above with the Get statement.

$Newvalue = 1
ForEach ($Computer in $ComputerList)
{
$Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$Computer)
$RegKey= $Reg.OpenSubKey($Path,$True)
$RegKey.SetValue($Key,$NewValue,[Microsoft.Win32.RegistryValueKind]::String)
$Value = $RegKey.GetValue($Key)
Write-Host $Computer $Value
}

I keep these scripts in a repository so I can quickly verify Registry Keys across my environment. PowerShell is a perfect solution for reading and writing settings remotely. There’s no limit to the number of bells and whistles you can add to PowerShell scripts,(try adding a Try-Catch for unreachable servers) but the important thing is getting the work done without having to touch every computer, one at a time. Don’t work hard; work smart, so you can read more blogs.

Advertisements

One thought on “Remote Registry Read/Write

  1. Pingback: PowerShell Solution to Java Version | SQL Sanctum

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s