Tuesday, October 21, 2008

Registry and the dreaded HKCU

Good to be back in the swing of things.  Last month I spent some time at DisneyWorld and had a blast.  When I came back, another hot issue on the table for this script master to solve.

I can't tell you how many times I've need to add/delete/modify a key in the HKEY Current Users hive on remote machines.  WMI does provide a registry object that you can use and it does include an HKCU hive...  However, as some of you may know, when you access that HKCU hive, it's not the actual HKCU but rather the HKCU for the account you are using to run the script.  Not very useful.


There are several ways to get in the actual HKCU but my personal method is a three step process.  We already know that there is another hive, HKEY Users, that contains all the users on that machine. And we have no problem getting into that hive remotely.  But, that hive uses SID values to identify each unique user.  My process is to identify the current user, get the SID for that user, then drill into the HKU\SID hive. 


Step One: Get the current user of a machine.

For this I use a function (as I usually do):


Function GetCurrentUser2(sstrComputer)
    On Error Resume Next
    Dim sstrKeyPath,sstrCU,sstrCUD,sstrCurrentUser,sstrCurrentUserDomain
    sHKEY_LOCAL_MACHINE = &H80000002
    Set sobjRegistry = GetObject("winmgmts:\\" & sstrComputer & "\root\default:StdRegProv")
    sstrKeyPath = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon"
    sstrCU = "DefaultUserName"
    sstrCUD = "DefaultDomainName"
    sobjRegistry.GetStringValue sHKEY_LOCAL_MACHINE, sstrKeyPath, sstrCU, sstrCurrentUser
    sobjRegistry.GetStringValue sHKEY_LOCAL_MACHINE, sstrKeyPath, sstrCUD, sstrCurrentUserDomain
    GetCurrentUser2 = sstrCurrentUserDomain & "\" & sstrCurrentUser
End Function


Simply pass the computer name and it returns the user as "domain\logon".  This works fairly well unless you have some sort of security policy that is removing that value from the remote registry. You'll notice that my function is called GetCurrentUsers2.  The original function I used looked up the explorer.exe and found the owner of that process.  That worked, but not 100%.

Now that we have the current user stored as a "domain\logon" variable, we can then query the domain to get the associated SID for that user.  Again, another function.


Function GetSIDFromUser(UserName)
'Input: UserName as domain\logon
'Output: SID
  Dim DomainName, Result, WMIUser
  If InStr(UserName, "\") > 0 Then
    DomainName = Mid(UserName, 1, InStr(UserName, "\") - 1)
    UserName = Mid(UserName, InStr(UserName, "\") + 1)
    DomainName = CreateObject("WScript.Network").UserDomain
  End If
  On Error Resume Next
  Set WMIUser = GetObject("winmgmts:{impersonationlevel=impersonate}!" _
    & "/root/cimv2:Win32_UserAccount.Domain='" & DomainName & "'" _
    & ",Name='" & UserName & "'")
  If Err = 0 Then Result = WMIUser.SID Else Result = ""
  On Error GoTo 0
  GetSIDFromUser = Result
End Function


This function will query the domain for the user and return the unique SID for the user.  Now you can put two and two together and access HKEY_Users\SID to get the HKCU hive on a machine.


I have some functions for accessing the registry remotely.  Each of them rely on these two functions for support when accessing HKCU.  I will posting up new articles with those functions soon.  In the meantime, if you have any questions on these functions or suggestions for new ones, please let me know by clicking the email icon below.