7
votes

I'm attempting to use powershell to access a remote registry like so:

$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("LocalMachine", $server)
$key = $reg.OpenSubkey($subkeyPath)

Depending on some factors that I'm not yet able to determine I either get

Exception calling "OpenSubKey" with "1" argument(s): "Requested registry access is not allowed."

Or

System.UnauthorizedAccessException: Attempted to perform an unauthorized operation. at Microsoft.Win32.RegistryKey.Win32ErrorStatic(Int32 errorCode, String str) at Microsoft.Win32.RegistryKey.OpenRemoteBaseKey(RegistryHive hKey, String machineName)

It seems pretty clear that this is because the user I'm running the powershell script as doesn't have the appropriate credentials to access the remote registry. I'd like to be able to supply a set of credentials to use for the remote registry access, but I can find no documentation anywhere of a way to do this. I'm also not clear on exactly where to specify which users are allowed to access the registry remotely.

7
For what it's worth, I'm after the exact same solution. - The KZA

7 Answers

6
votes

Just thought I'd add my answer to anyone with this problem as well. It seems there is no way to add Credentials using RemoteRegistry. You can however use WMI to query a remote registry using alternative credentials as follows:

$reg = Get-WmiObject -List -Namespace root\default -ComputerName RemotePC -Credential "Domain\User" | Where-Object {$_.Name -eq "StdRegProv"}

From here you can call standard Registry methods. The below example will return the operating system.

$HKLM = 2147483650
$reg.GetStringValue($HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion","ProductName").sValue

Hope this helps someone :)

2
votes

Are you running remote registry service? It is disabled by default and that must be causing the issue. Check the status of this service on all remote machines you are trying to access.

2
votes

I couldn't comment directly on bentaylr's entry above, but I've taken what he contributed and added PSCredentials creation (figured out from here) to allow you to hard code credentials into the script.

Peace of mind disclaimer: Be careful when using plaintext credentials in a script. In my case, I'm using generic credentials on machines I'm launching. Depending on your case, you might consider creating an encrypted credential file to store the password in (see link above).

The credentials you use would need to be able to access the registry if you were logged into that user on the machine you are targeting.

$user = "Domain\Username"
$pass = ConvertTo-SecureString "Password" -AsPlainText -Force
$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user,$pass

$reg = Get-WmiObject -List -Namespace root\default -ComputerName $server -Credential $cred | Where-Object {$_.Name -eq "StdRegProv"}
$HKLM = 2147483650
$value = $reg.GetStringValue($HKLM,"Software\Microsoft\.NetFramework","InstallRoot").sValue
2
votes

$key.OpenSubKey($subkeyName) opens the subkey in write protected mode, $key.OpenSubKey($subkeyName,$true) opens it in writable mode

Therefore after $key.OpenSubKey($subkeyName,$true) you should be able to create a new subkey or value

If you try the same thing after $key.OpenSubKey($subkeyName) you will get "UnauthorizedAccessException"

1
votes
PS C:\>$regKey.OpenSubKey

OverloadDefinitions

Microsoft.Win32.RegistryKey OpenSubKey(string name, **bool Writable**)

try

PS C:\>$key.OpenSubKey($subkeyName,**$true**)

http://msdn.microsoft.com/en-us/library/xthy8s8d%28v=vs.110%29.aspx

0
votes

Came looking for the answer to your question, but in a little googling this morning I noticed that the first parameter is a type rather than a String... hope this helps:

$machine = "<Machine Name Goes Here>"
$type = [Microsoft.Win32.RegistryHive]::LocalMachine
$regkey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type,$machine)
$subkey = $regKey.OpenSubKey($key)
foreach ($sub in $regKey.GetSubKeyNames()){$sub}
0
votes

I wanted to first thank all for answers above really helpful, wanted to add that you can use Get-Credential command to collect credentials without having to hard code it in your script. I have written using the above suggestions into my script the following code and query:

$userCredentials = Get-Credential -Credential <domain\username>
$objReg = Get-WmiObject -List -Namespace root\default -ComputerName $server -Credential $userCredentials | Where-Object{$_.Name -eq "StdRegProv"}
$subKeyNames = $objReg.EnumKey($HKLM,"SOFTWARE\Microsoft\Updates\Microsoft .Net Framework 4.5.1").sNames

The above code returns all sub key names in the specified key so that I can determine installed updates other than OS which have been applied to a server. If you want to determine all collection possibilities with the $objReg variable then run:

$objReg | Get-Member

You will see a list of all possible queries which can be performed against the registry. Hope this helps!