Prof. Powershell
Riding Remote Registries
After the last two columns, I know you want to work with registries from other computers. It's a bit complicated, but here's a start.
- By Jeffery Hicks
- 09/15/2009
If you recall when we started looking at the registry PSDrive provider, I mentioned that it only works locally. That is true. However, we can use the same .NET classes used by the provider and access registries on remote computers.
Now before you get too excited there are a few ground rules. First you can't access the hive of the currently logged on user. You can query HKCU on a remote machine, but it will be your data, not the user. I'm aware there are ways to load a hive, modify it and return it but that's frankly more work than it is worth and there are likely better ways to achieve the same results, such as going through Group Policy. Plus I don't have that much space. More than likely you will want to work with HKEY_LOCAL_MACHINE on the remote computer.
The other caveat is that there really isn't a way to specify alternate credentials, so what ever account you are using in PowerShell most likely will need administrator rights on the remote computer.
Let's begin by defining a variable for the computer we want to connect to. I'm doing all of this on PowerShell 1.0.
PS C:\> $computer="JDHIT-DC01"
Since I don't have any cmdlets or PSDrive provider I have to all the heavy lifting myself. First I'll create a base registry object for HKLM on the remote computer. The following is a one line command:
PS C:\> $regbase=[Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey
([Microsoft.Win32.RegistryHive]::LocalMachine,$computer)
Pipe $regbase to Get-Member to discover how to use this object. The GetSubKeyNames() method is handy here:
PS C:\> $regbase.getsubkeynames()
HARDWARE
SAM
SECURITY
SOFTWARE
SYSTEM
There aren't any values yet for us to deal with. How about if we get the same Windows Update information we got last time for the local computer? I find this easier to create a new variable.
PS C:\> $regkey=$regbase.OpenSubKey("SOFTWARE\
Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\Results")
PS C:\> $regkey.GetSubKeyNames()
Detect
Download
Install
That should look familiar. However coaxing the values out is a bit more convoluted. You need to use the GetValue() method to return the value. The method requires the name of the registry entry, such as LastSuccessTime. Since I already know what values I want, I could have simply asked for them.
Instead, I have a solution that uses the GetValueNames() method which enumerates names of values. This is helpful when working your way through a registry and you don't know in advance what value names might be. Here's my solution, although it is not necessarily the only one:
PS C:\> $regkey.GetSubKeyNames() | foreach {
>> $action=$_
>> $subkey=$regkey.openSubKey($_)
>> $subkey.GetValueNames() | foreach {
>> $_ | Select @{Name="Action";Expression={$action}},`
>> @{name="Name";Expression={$_}},`
>> @{name="Value";Expression={$subkey.getvalue($_)}}
>> }
>> } | ft -auto
>>
Action Name Value
------ ---- -----
Detect LastSuccessTime 2009-08-26 15:02:16
Detect LastError 0
Download LastSuccessTime 2009-08-26 15:03:18
Download LastError 0
Install LastSuccessTime 2009-08-26 00:28:00
Install LastError -2145099769
Working the .NET library and remote registries is a bit more complicated and most likely will mean a little scripting on your end. If you get stuck, feel free to join me in the PowerShell forum at ScriptingAnswers.com.
About the Author
Jeffery Hicks is an IT veteran with over 25 years of experience, much of it spent as an IT infrastructure consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He is a multi-year recipient of the Microsoft MVP Award in Windows PowerShell. He works today as an independent author, trainer and consultant. Jeff has written for numerous online sites and print publications, is a contributing editor at Petri.com, and a frequent speaker at technology conferences and user groups.