An Administrator's guide to PowerShell

Friday, January 5, 2007

Powershell, Remote Registry and You! Part 1 (Overview)

I was reading the news groups (as I do all the time) and I have notice numerous request/questions regarding remote registry access in powershell. I thought I would try to see if I could shed some light on the subject. So without further delay... on with the show!

Overview:
----------
Registry access in Posh is realatively simple and extremely powerful.
From a local stand point its as simple as:
PS> Set-Location HKLM:System
From a remote standpoint... you have to utilize the powers of .NET.
$ServerKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, ServerName)

For the purpose of this post... I am going to focus on the remote aspect. Local is cover in tons of documentation. So, cause of time, I am only going to address the .NET method.

I will start by giving you the Remote Registry Object useful Properties/Methods

Object
-------
[Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine,MachineName)

Properties
-------------
Name
SubKeyCount
ValueCount


Methods (Not all.. just the ones I use often)
---------------------------------------------------
CreateSubKey
DeleteSubKey
DeleteSubKeyTree
DeleteValue
GetAccessControl
GetLifetimeService
GetSubKeyNames
GetType
GetValue
GetValueKind
GetValueNames
OpenSubKey
SetAccessControl
SetValue


As you can see... You can do basically everything you could ever want.

Now that you have a basic idea of what the .NET provider can give you... let put it to practical use.

Examples:
----------
Purpose: Get a list of Subkeys and Values of Specific Registry Key.
$key = "SOFTWARE\Microsoft\Windows\CurrentVersion"
$type = [Microsoft.Win32.RegistryHive]::LocalMachine
$regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $Srv)
$regKey = $regKey.OpenSubKey($key)
Write-Host "Sub Keys"
Write-Host "--------"
Foreach($sub in $regKey.GetSubKeyNames()){$sub}
Write-Host
Write-Host "Values"
Write-Host "------"
Foreach($val in $regKey.GetValueNames()){$val}

Result (only showing first 10 of each:)

Sub Keys
--------
App Management
App Paths
Applets
BITS
Control Panel
Controls Folder
CSCSettings
DateTimeDynamic
DirectoryExplorer

Values
------
DevicePath
MediaPath
Unexpanded
SM_GamesName
SM_Configure
ProgramsName
ProgramFilesDir
CommonFilesDir
ProductId
WallPaperDir
MediaPath
ProgramFilesPath

-------------------------------------------
Purpose: Get the Value of each of the Values.
$key = "SOFTWARE\Microsoft\Windows\CurrentVersion"
$type = [Microsoft.Win32.RegistryHive]::LocalMachine
$regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $Srv)
$regKey = $regKey.OpenSubKey($key)
Write-Host "Values"
Write-Host "------"
Foreach($val in $regKey.GetValueNames()){
Write-Host $val.PadRight(30) -nonewline
Write-Host $regKey.GetValue("$val")
}

Result (only showing first 10:)

Values
------
DevicePath = [C:\WINDOWS\inf;C:\Drivers\Broadcom\Win2003]
MediaPathUnexpanded = [C:\WINDOWS\Media]
SM_GamesName = [Games]
SM_ConfigureProgramsName = [Set Program Access and Defaults]
ProgramFilesDir = [C:\Program Files]
CommonFilesDir = [C:\Program Files\Common Files]
ProductId = [69713-640-4031427-45876]
WallPaperDir = [C:\WINDOWS\Web\Wallpaper]
MediaPath = [C:\WINDOWS\Media]
ProgramFilesPath = [C:\Program Files]

------------------------------------------------

Summary:
-----------
As you now can see. POSH is really powerful given its .NET access to the registry. Honestly... there is virtually nothing you can't do and its easy to boot. You have complete access to Registry keys/subkeys/values. You can even Create, Delete, and evaluate Values and keys. In the future I will be sharing a function I wrote to compare Registry Subkeys between machines. That has proven to be super valuable.

Well... That about does it (at least for today :) ) I think this is a pretty good start to your POSH .NET registry adventure. I will be expanding this as I have time.

As always... PLEASE PROVIDE FEEDBACK!!! :)

5 comments:

Jeffrey Snover said...

Cool stuff.

Have you tried out Here-Strings? I think you'll like them.

In your example, you do this:
Write-Host "Sub Keys"
Write-Host "--------"
Foreach($sub in $regKey.GetSubKeyNames()){$sub}
Write-Host
Write-Host "Values"
Write-Host "------"
Foreach($val in $regKey.GetValueNames()){$val}


Try this out and see if you like it (I just love Here-Strings because they make the code so much easier to write and read):

@"
Sub Keys
--------
$($regkey.GetSubKeyNames() |out-String)

Values
------
$($regkey.GetValuenames() |out-string)
"@


Jeffrey Snover [MSFT]
Windows PowerShell/MMC Architect
Visit the Windows PowerShell Team blog at: http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at: http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

/\/\o\/\/ said...

Nice work,

keep it up

Greetings /\/\o\/\/

PReetamZ said...

Thank you for your post. I was able to develop CMDLETS to gather IP of remote machine.

Roy said...

Does anybody know why this script is failing?

I've tried to extend a script describing how to use PowerShell with the RegistryKey CLR class (inspired by http://mybsinfo.blogspot.com/2007/01/powershell-remote-registry-and-you-part.html, along with Jeffrey Snover's enhancements). I was able to reproduce the effects of that script, which enumerates subkey names and value names on a remote registry. I have tried to use a different method of the [Microsoft.Win32.RegistryKey] class to create a new Subkey. My script is below. Also is the debug output (obtained by first running the set-psdebug commandlet).

(Note: For security reasons I have changed the name of the server for this posting ($Srv = "someserver"). You should be able to change that value to a valid server name and reproduce the results. I have confirmed I do have sufficient permissions on this server (I can make this change using RegEdit) and my PoSH is running under the correct security context.)

The script
$Srv = "someserver"
$key = "SOFTWARE"
$type = [Microsoft.Win32.RegistryHive]::LocalMachine
$regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $Srv)
$regKey = $regKey.OpenSubKey($key)
$key += "\\My Software Test"
$regKey = $regKey.OpenSubKey($key)
$regKey.LocalMachine.CreateSubKey($key)

The result:
You cannot call a method on a null-valued expression.
At line:1 char:34
+ $regKey.LocalMachine.CreateSubKey( <<<< $key)


The DEBUG output

PS C:\> set-psdebug -trace 2
DEBUG: 1+ set-psdebug -trace 2
PS C:\> $Srv = "someserver"
DEBUG: 1+ $Srv = "someserver"
DEBUG: ! SET $Srv = 'someserver'.
PS C:\> $key = "SOFTWARE"
DEBUG: 1+ $key = "SOFTWARE"
DEBUG: ! SET $key = 'SOFTWARE'.
PS C:\> $type = [Microsoft.Win32.RegistryHive]::LocalMachine
DEBUG: 1+ $type = [Microsoft.Win32.RegistryHive]::LocalMachine
DEBUG: ! SET $type = 'LocalMachine'.
PS C:\> $regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $Srv)
DEBUG: 1+ $regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $Srv)
DEBUG: ! CALL method 'static Microsoft.Win32.RegistryKey OpenRemoteBaseKey(RegistryHive hKey, String machineName)'
DEBUG: ! SET $regKey = 'HKEY_LOCAL_MACHINE'.
PS C:\> $regKey = $regKey.OpenSubKey($key)
DEBUG: 1+ $regKey = $regKey.OpenSubKey($key)
DEBUG: ! CALL method 'Microsoft.Win32.RegistryKey OpenSubKey(String name)'
DEBUG: ! SET $regKey = 'HKEY_LOCAL_MACHINE\SOFTWARE'.
PS C:\> $key += "\\My Software Test"
DEBUG: 1+ $key += "\\My Software Test"
DEBUG: ! SET $key = 'SOFTWARE\\My Software Test'.
PS C:\> $regKey = $regKey.OpenSubKey($key)
DEBUG: 1+ $regKey = $regKey.OpenSubKey($key)
DEBUG: ! CALL method 'Microsoft.Win32.RegistryKey OpenSubKey(String name)'
DEBUG: ! SET $regKey = ''.
PS C:\> $regKey.LocalMachine.CreateSubKey($key)
DEBUG: 1+ $regKey.LocalMachine.CreateSubKey($key)
DEBUG: 2+ if ($ErrorView -ne "CategoryView") {
DEBUG: 3+ $myinv = $_.InvocationInfo
DEBUG: ! SET $myinv = 'System.Management.Automation.InvocationInfo'.
DEBUG: 4+ switch -regex ($myinv.MyCommand.CommandType)
DEBUG: 24+ if ($myinv.MyCommand.Name)
DEBUG: 2+ if ($_.InvocationInfo) {
DEBUG: 3+ $posmsg = $_.InvocationInfo.PositionMessage
DEBUG: ! SET $posmsg = '
At line:1 char:34
+ $regKey.LocalMachine.CreateSubKey...'.
DEBUG: 7+ if ($ErrorView -eq "CategoryView") {
DEBUG: 11+ $_.Exception.Message + $posmsg
You cannot call a method on a null-valued expression.
At line:1 char:34
+ $regKey.LocalMachine.CreateSubKey( <<<< $key)
PS C:\>

Leo said...

I'm new to scripting and this has been the best information I have been able to find regarding using PowerShell and Remote Registries. However, I'm having problems coming up with a way to change the ACL for the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Classes and assigning an AD group Full Control. I've been given the task of creating a script to push to over 1500 machines and remove local administrative rights and this is the missing link. I need to have our users Full Control in order for some of our internal applications to function without the users having local administrator rights. Any help would be greatly appreciated as I have been searching for almost a month now and my deadline is quickly approaching.

Thanks.

About Me

Montclair, NJ, United States

technorati

Add to Technorati Favorites