Solved

vb.net and reading remote registry

Posted on 2014-11-06
20
497 Views
Last Modified: 2014-11-08
I am trying to read a remote registry entry.  I have domain admin rights, can someone tell me why i keep getting the error: "Object reference not set to an instance..."

Dim baseKey As RegistryKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "remoteworkstation")
        Dim key As RegistryKey = baseKey.OpenSubKey("SOFTWARE\Microsoft\MPSD\OSD")

        Dim computerName As [String] = key.GetValue("MachineUserID").ToString()
        TextBox1.Text = computerName

Open in new window

0
Comment
Question by:derek7467
  • 11
  • 7
20 Comments
 
LVL 142

Expert Comment

by:Guy Hengel [angelIII / a3]
ID: 40426133
You need to check after each of those lines if a returned object is null or not...
0
 

Author Comment

by:derek7467
ID: 40426139
machineuserid is not null, im looking at it in the registry...
0
 

Author Comment

by:derek7467
ID: 40426158
wierd, i changed the location and now it works.  HKEY current user works, but local machine doesnt.  The key i need to read is in localmachine.  How can i impersonate so it uses my credentials?
0
 

Author Comment

by:derek7467
ID: 40426172
getting even weirder.  I go to localmachine and read another key and it works, just not the one i want.  Scratching my head...
0
 

Author Comment

by:derek7467
ID: 40426181
Going to close this question, i have to figure out why i can read one key and not another.
0
 
LVL 32

Expert Comment

by:it_saige
ID: 40426205
What Guy is saying is this:
Private Function GetMachineUserID(ByVal workstation As String) As String
	Dim machineID As String = String.Empty
	Try
		Dim baseKey As RegistryKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, workstation)
		If Not baseKey Is Nothing Then
			Dim key As RegistryKey = baseKey.OpenSubKey("SOFTWARE\Microsoft\MPSD\OSD")
			If Not key Is Nothing Then
				machineID = key.GetValue("MachineUserID")
				If String.IsNullOrEmpty(machineID) Then
					machineID = "Counld not retrieve machine ID"
				End If
			End If
		End If
	Catch ex As Exception
		machineID = ex.Message
	End Try
	Return machineID
End Function

Open in new window


You could then call this function when setting the TextBox.
TextBox1.Text = GetMachineUserID("remoteworkstation")

Open in new window


-saige-
0
 

Author Comment

by:derek7467
ID: 40426797
Saige appreciate the help, but my textbox doesnt return the key
0
 
LVL 32

Expert Comment

by:it_saige
ID: 40426909
What do you get in the text box?

-saige-
0
 

Author Comment

by:derek7467
ID: 40426928
its just blank.  no error or nothing and im positive the key isnt blank.
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 32

Expert Comment

by:it_saige
ID: 40426952
Try changing the code to this:
Private Function GetMachineUserID(ByVal workstation As String) As String
	Dim machineID As String = String.Empty
	Try
		Dim baseKey As RegistryKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, workstation)
		If Not baseKey Is Nothing Then
			Dim key As RegistryKey = baseKey.OpenSubKey("SOFTWARE\Microsoft\MPSD\OSD")
			If Not key Is Nothing Then
				machineID = key.GetValue("MachineUserID")
				If String.IsNullOrEmpty(machineID) Then
					machineID = "Counld not retrieve machine ID from OSD subkey"
				End If
			Else
				machineID = "OSD subkey could not be opened"
			End If
		Else
			machineID = "Base key could not be opened"
		End If
	Catch ex As Exception
		machineID = ex.Message
	End Try
	Return machineID
End Function

Open in new window


This way we can determine which key is not being accessed.

-saige-
0
 

Author Comment

by:derek7467
ID: 40426970
It writes back:
OSD subkey could not be opened

So its seeing it as empty?
0
 
LVL 32

Accepted Solution

by:
it_saige earned 500 total points
ID: 40427140
Not quite.  It just means that the OpenSubKey function could not access that key.  Since we are not getting an exception thrown (which would indicate a problem with security or that the registry key object was closed), that means the only other issue is that you are running this as a 32-bit application on a 64-bit machine.  This means that the key you are looking for is actually in the native node and not the Wow6432Node.

So a couple of choices here.

Either rebuild the application marked to run on 'Any CPU' or
Add code to get the value from the Wow6432Node and if that is not available check for the value in the native node:
Imports Microsoft.Win32
Imports System.Runtime.InteropServices
Imports System.Text


Class RegistryExample
	Shared Sub Main()
		Try
			Console.WriteLine(GetMachineUserID("RICHARD-HP"))
		Catch e As Exception
			Console.WriteLine(e.ToString())
		End Try
		Console.ReadLine()
	End Sub

	Private Shared Function GetMachineUserID(ByVal workstation As String) As String
		Dim machineID As String = String.Empty
		Try
			Console.WriteLine(String.Format("Opening the remote key - {0}; on - {1}", RegistryHive.LocalMachine, workstation))
			Dim baseKey As RegistryKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, workstation)
			If Not baseKey Is Nothing Then
				Console.WriteLine(String.Format("Remote key - {0}; on - {1}; opened", RegistryHive.LocalMachine, workstation))
				Console.WriteLine(String.Format("Opening the sub key - SOFTWARE\Microsoft\MPSD\OSD\; on - {0}", workstation))
				Dim key As RegistryKey = baseKey.OpenSubKey("SOFTWARE\Microsoft\MPSD\OSD\")
				If Not key Is Nothing Then
					Console.WriteLine(String.Format("Sub key - SOFTWARE\Microsoft\MPSD\OSD\; on - {0}; opened", workstation))
					Console.WriteLine(String.Format("Retrieving MachineUserID; on - {0}", workstation))
					machineID = key.GetValue("MachineUserID")
					Console.WriteLine(String.Format("MachineUserID - {0}; on - {1}; retreived", machineID, workstation))
				Else
					Console.WriteLine(String.Format("Could not open Wow6432Node sub key; Opening Native sub key SOFTWARE\Microsoft\MPSD\OSD\; on - {0}", workstation))
					key = baseKey.OpenSubKey("SOFTWARE\Microsoft\MPSD\OSD\", False, RegistryWOW6432.RegWow64Options.KEY_WOW64_64KEY)
					If Not key Is Nothing Then
						Console.WriteLine(String.Format("Native sub key - SOFTWARE\Microsoft\MPSD\OSD\; on - {0}; opened", workstation))
						Console.WriteLine(String.Format("Retrieving MachineUserID; on - {0}", workstation))
						machineID = key.GetValue("MachineUserID")
						Console.WriteLine(String.Format("MachineUserID - {0}; on - {1}; retreived", machineID, workstation))
					Else
						machineID = "Could not open native sub key"
					End If
				End If
			Else
				machineID = "Could not open base key"
			End If
		Catch ex As Exception
			machineID = ex.Message
		End Try
		Return machineID
	End Function
End Class

''' <summary>
''' An extension class to allow a registry key to allow it to get the
''' registry in the 32 bit (Wow6432Node) or 64 bit regular registry key
''' </summary>
Public Module RegistryWOW6432
#Region "Member Variables"
#Region "Read 64bit Reg from 32bit app"
	<DllImport("Advapi32.dll")> _
	Private Function RegOpenKeyEx(ByVal hKey As IntPtr, ByVal lpSubKey As String, ByVal ulOptions As UInteger, ByVal samDesired As Integer, ByRef phkResult As Integer) As Integer
	End Function

	<DllImport("Advapi32.dll")> _
	Private Function RegCloseKey(ByVal hKey As Integer) As UInteger
	End Function

	<DllImport("advapi32.dll", EntryPoint:="RegQueryValueEx")> _
	Public Function RegQueryValueEx(ByVal hKey As Integer, ByVal lpValueName As String, ByVal lpReserved As Integer, ByRef lpType As RegistryValueKind, ByVal lpData As StringBuilder, ByRef lpcbData As UInteger) As Integer
	End Function

	<DllImport("advapi32.dll", CharSet:=CharSet.Unicode, EntryPoint:="RegQueryValueEx")> _
	Private Function RegQueryValueEx(ByVal hKey As Integer, ByVal lpValueName As String, ByVal lpReserved As Integer, ByRef lpType As RegistryValueKind, <Out()> ByVal lpData As Byte(), ByRef lpcbData As UInteger) As Integer
	End Function
#End Region
#End Region

#Region "Functions"
	''' <summary>Open a registry key using the Wow64 node instead of the default 32-bit node.</summary>
	''' <param name="Key">Parent key to the key to be opened.</param>
	''' <param name="SubKeyName">Name of the key to be opened</param>
	''' <param name="Writable">Whether or not this key is writable</param>
	''' <param name="Options">32-bit node or 64-bit node</param>
	''' <returns></returns>
	<System.Runtime.CompilerServices.Extension()> _
	Public Function OpenSubKey(ByVal Key As RegistryKey, ByVal SubKeyName As String, ByVal Writable As Boolean, ByVal Options As RegWow64Options) As RegistryKey
		'Sanity check
		If Key Is Nothing OrElse Key.GetHandle() = IntPtr.Zero Then
			Return Nothing
		End If

		'Set rights
		Dim rights As Integer = If(Writable, CInt(RegistryRights.WriteKey), CInt(RegistryRights.ReadKey))

		'Call the native function >.<
		Dim subKeyHandle As Integer, result As Integer = RegOpenKeyEx(Key.GetHandle(), SubKeyName, 0, rights Or CInt(Options), subKeyHandle)

		'If we errored, return null
		If result <> 0 Then
			Return Nothing
		End If

		'Get the key represented by the pointer returned by RegOpenKeyEx
		Dim hKey As IntPtr = New IntPtr(subKeyHandle)
		Dim subKey As RegistryKey = hKey.PointerToRegistryKey(Writable, False)
		Return subKey
	End Function

	''' <summary>Get a pointer to a registry key.</summary>
	''' <param name="Key">Registry key to obtain the pointer of.</param>
	''' <returns>Pointer to the given registry key.</returns>
	<System.Runtime.CompilerServices.Extension()> _
	Private Function GetHandle(ByVal Key As RegistryKey) As IntPtr
		'Get the type of the RegistryKey
		Dim registryKeyType As Type = GetType(RegistryKey)
		'Get the FieldInfo of the 'hkey' member of RegistryKey
		Dim fieldInfo As System.Reflection.FieldInfo = registryKeyType.GetField("hkey", System.Reflection.BindingFlags.NonPublic Or System.Reflection.BindingFlags.Instance)

		'Get the handle held by hkey
		Dim handle As SafeHandle = DirectCast(fieldInfo.GetValue(Key), SafeHandle)
		'Get the unsafe handle
		Return handle.DangerousGetHandle()
	End Function

	''' <summary>
	''' Get a registry key from a pointer.
	''' </summary>
	''' <param name="hKey">Pointer to the registry key</param>
	''' <param name="writable">Whether or not the key is writable.</param>
	''' <param name="ownsHandle">Whether or not we own the handle.</param>
	''' <returns>Registry key pointed to by the given pointer.</returns>
	<System.Runtime.CompilerServices.Extension()> _
	Private Function PointerToRegistryKey(ByVal hKey As IntPtr, ByVal writable As Boolean, ByVal ownsHandle As Boolean) As RegistryKey
		'Get the BindingFlags for private contructors
		Dim privateConstructors As System.Reflection.BindingFlags = System.Reflection.BindingFlags.Instance Or System.Reflection.BindingFlags.NonPublic
		'Get the Type for the SafeRegistryHandle
		Dim safeRegistryHandleType As Type = GetType(Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid).Assembly.[GetType]("Microsoft.Win32.SafeHandles.SafeRegistryHandle")
		'Get the array of types matching the args of the ctor we want
		Dim safeRegistryHandleCtorTypes As Type() = New Type() {GetType(IntPtr), GetType(Boolean)}
		'Get the constructorinfo for our object
		Dim safeRegistryHandleCtorInfo As System.Reflection.ConstructorInfo = safeRegistryHandleType.GetConstructor(privateConstructors, Nothing, safeRegistryHandleCtorTypes, Nothing)
		'Invoke the constructor, getting us a SafeRegistryHandle
		Dim safeHandle As [Object] = safeRegistryHandleCtorInfo.Invoke(New [Object]() {hKey, ownsHandle})

		'Get the type of a RegistryKey
		Dim registryKeyType As Type = GetType(RegistryKey)
		'Get the array of types matching the args of the ctor we want
		Dim registryKeyConstructorTypes As Type() = New Type() {safeRegistryHandleType, GetType(Boolean)}
		'Get the constructorinfo for our object
		Dim registryKeyCtorInfo As System.Reflection.ConstructorInfo = registryKeyType.GetConstructor(privateConstructors, Nothing, registryKeyConstructorTypes, Nothing)
		'Invoke the constructor, getting us a RegistryKey
		Dim resultKey As RegistryKey = DirectCast(registryKeyCtorInfo.Invoke(New [Object]() {safeHandle, writable}), RegistryKey)
		'return the resulting key
		Return resultKey
	End Function
#End Region

#Region "Enums"
	Public Enum RegWow64Options
		None = 0
		KEY_WOW64_64KEY = &H100
		KEY_WOW64_32KEY = &H200
	End Enum

	Public Enum RegistryRights
		ReadKey = 131097
		WriteKey = 131078
	End Enum
#End Region
End Module

Open in new window

In the registry I added the path specifed to the native node -Capture.JPGAnd created the value -Capture.JPGRan the application and produced the following output:Capture.JPG
One other option is to convert your project to use .NET 4 and use the RegistryView enumeration.

http://msdn.microsoft.com/en-us/library/dd411615(v=vs.100).aspx

-saige-
0
 
LVL 32

Expert Comment

by:it_saige
ID: 40427172
By the same rights, if I move the MachineUserID property and it's associated keys into the Wow6432Node, the program returns without needing to look in the native node:Registry path showing keys in Wow6432NodeMachine User ID modifed to reflect new nodeRunning the above program produces new results based on key location.
0
 

Author Comment

by:derek7467
ID: 40428202
IM already set to ANY CPU and im using .NET 4.5  Im going try the native mode code and see if that works.
0
 

Author Comment

by:derek7467
ID: 40428257
Saige, wish i could change my answer to yours.  I changed my cpu target to 64 bit and it works fine.  Since my entire environment is 64 bit, i will stick with that.  Thank you!
0
 

Author Comment

by:derek7467
ID: 40428337
last question saige, now that this works, i am trying to edit that entry when its incorrect.  I set the app.manifest to always prompt for UAC as ONLY admins should be using this tool i create, i always get a "cannot write to registry".  I manually tested and i can write to this location fine if i manually open regedit and do it.  Any ideas on why i cant write to the registry?  Code im using:

 Dim RC As String = TextBox1.Text
        Dim environmentKey As RegistryKey
        ' Open HKEY_CURRENT_USER\Environment on a remote computer.
        environmentKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, RC)
        environmentKey = environmentKey.OpenSubKey("SOFTWARE\Microsoft\MPSD\OSD")
        environmentKey.SetValue("MachineUserID", "test")

Open in new window

0
 
LVL 32

Expert Comment

by:it_saige
ID: 40428408
In order to write to the registry key, you have to specify that you what to open the subkey with read and write rights.  Something like:
Dim RC As String = TextBox1.Text
Dim environmentKey As RegistryKey
' Open HKEY_CURRENT_USER\Environment on a remote computer.
environmentKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, RC)
environmentKey = environmentKey.OpenSubKey("SOFTWARE\Microsoft\MPSD\OSD", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.FullControl)
environmentKey.SetValue("MachineUserID", "test")

Open in new window


I would highly recommend, though, that you enclose these into a try catch block, if you haven't already.

Also to reassign the solution to your question, you only need to put in a request to have the question reopened.  At the top of this solution block, right below where you asked your question, there is a Request attention link.

-saige-
0
 

Author Comment

by:derek7467
ID: 40428413
thanks i will try that and i did request for this to be reopened to reassign credit to you.  Thanks much for your help!
0
 
LVL 32

Expert Comment

by:it_saige
ID: 40428418
Not a problem, let us know if you have any further questions.

-saige-
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now