Jump to content
Sign in to follow this  
DrLarch

Yet another _RegWriteAllUsers

Recommended Posts

DrLarch

Just wanted to post my _RegWriteAllUsers script (started off modifying the code >here, but ended up pretty much being a rewrite for my own purposes). I'd ultimately like to be able to use "Larry's" >code (DllCall) to load/unload hives (more elegant) instead of RunWaits, but haven't had the chance to track this one all the way down and figure it out, so if anyone knows this off-hand I'd appreciate it.

Anyway, the script will do multiple entries (input is an array), but has only been designed/tested on Win7/64. Account names can be filtered out with multiple search terms. One thing I'm wondering about regarding coding techniques is how #includes are properly done within a function.

Script:

#include-once

; #FUNCTION# ========================================================================================================================
; Name...........: _RegWriteAllUsers
; Description ...: Writes multiple registry entries to local user accounts (filterable).
; Syntax.........: _RegWriteAllUsers($InputArray)
; Parameters ....: $InputArray - Array containing registry path, key name, key type, data and filter
;                  Array is two-dimensional, at least two rows by five columns ([2][5]).
;                  First row & column [0][0] contains row count (updated by the function) but must be declared in addition to
;                  subsequent data rows.
;                  Subsequent rows are data: Column [0]:Registry path relative to HKCU\ or HKEY_USERS\{NAME]\
;                                                       Do NOT include leading backslash!
;                                            Column [1]:Key Name
;                                            Column [2]:Key Type: "REG_SZ", "REG_MULTI_SZ", "REG_EXPAND_SZ", "REG_DWORD", "REG_QWORD",
;                                                       or "REG_BINARY"
;                                            Column [3]:Data
;                                            Column [4]:Filter search terms to remove user names with substrings that match,
;                                                       semicolon delimited (ie. "example1;example2"). Entry in the first row
;                                                       of the array is only entry used.
; Author ........: DrLarch
; ===================================================================================================================================

Func _RegWriteAllUsers($InputArray)
    #include <_RegEnumKeyValEx.au3>
    ;_RegEnumKeyValEx by DXRW4E found at:
    ;http://www.autoitscript.com/forum/topic/144234-regenumkeyvalex-regenumkeyex-regenumvalex/
    #include <Array.au3>

    $InputArray[0][0] = UBound($InputArray, 1) - 1;Correct row count

    ;Pull profile list from registry -----------------------------------------------
    $ProfileKey = "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"

    $aProfileList = _RegEnumKeyEx($ProfileKey, 1)

    $aHKUSList = _RegEnumKeyEx("HKEY_USERS", 1)
    ;_ArrayDisplay($aHKUSList,"HKEY_USERS")

    Local $aKill[1]
    $aKill[0] = 0

    ;Remove profiles from list that don't have a GUID ------------------------------
    For $i = 1 To $aProfileList[0]
        Local $sGUIDTest = RegRead($aProfileList[$i], "Guid")
        If @error <> 0 Then
            _ArrayAdd($aKill, $i)
            $aKill[0] += 1
        EndIf
    Next

    _ArrayDelete($aProfileList, $aKill)
    $aProfileList[0] = UBound($aProfileList) - 1


    ;Change array $aProfileList to ProfileImagePath --------------------------------
    Local $aKill[1]
    $aKill[0] = 0

    For $i = 1 To $aProfileList[0]
        $aProfileList[$i] = RegRead($aProfileList[$i], "ProfileImagePath")
        If @error <> 0 Then
            _ArrayAdd($aKill, $i)
            $aKill[0] += 1
        EndIf
    Next

    _ArrayDelete($aProfileList, $aKill)
    $aProfileList[0] = UBound($aProfileList) - 1


    ;Remove user names by filter----------------------------------------------------
    Local $aKill[1], $aKillSearchTerms[1]
    $aKill[0] = 0
    $aKillSearchTerms[0] = 0


    ;Remove currently logged in user (add to $sKillFilter), will handle via HKCU
    $sKillFilter = $InputArray[1][4]

    If StringLen($sKillFilter) > 0 Then
        $sKillFilter = $sKillFilter & ";" & @UserName
    Else
        $sKillFilter = @UserName
    EndIf


    $aKillSearchTerms[0] = _ArrayAdd($aKillSearchTerms, $sKillFilter, 1, ";")
    ;_ArrayDisplay($aKillSearchTerms,"Search Terms")


    For $i = 1 To $aProfileList[0]
        For $j = 1 To $aKillSearchTerms[0]
            ;MsgBox(0,"test","Looking for: " & $aKillSearchTerms[$j] & " in: " & $aProfileList[$i])

            If StringInStr($aProfileList[$i], $aKillSearchTerms[$j]) <> 0 Then
                ;MsgBox(0,"test","Found: " & $aKillSearchTerms[$j] & " in: " & $aProfileList[$i])
                _ArrayAdd($aKill, $i)
                $aKill[0] += 1
                ExitLoop
            EndIf
        Next
    Next

    _ArrayDelete($aProfileList, $aKill)
    $aProfileList[0] = UBound($aProfileList) - 1

    ;_ArrayDisplay($aProfileList,"After Filter")


    ;Double check that ntuser.dat files actually exists-----------------------------
    ;probably not necessary, but just in case
    Local $aKill[1]
    $aKill[0] = 0

    For $i = 1 To $aProfileList[0]
        Local $sNTUser = FileExists($aProfileList[$i] & "\NTUSER.DAT")
        If $sNTUser = 0 Then
            _ArrayAdd($aKill, $i)
            $aKill[0] += 1
        EndIf
    Next

    _ArrayDelete($aProfileList, $aKill)
    $aProfileList[0] = UBound($aProfileList) - 1


    ;Create new $aProfileUserList array from $aProfileList to incorporate user names---------------------
    Local $aFullList[UBound($aProfileList)][2] = [[0, ""]]
    $aFullList[0][0] = $aProfileList[0]

    For $i = 1 To $aProfileList[0]
        $aFullList[$i][0] = $aProfileList[$i]
        $aPathSplit = StringSplit($aProfileList[$i], "\")
        $aFullList[$i][1] = $aPathSplit[UBound($aPathSplit) - 1]
    Next

    ;Add DEFAULT user to $aFullList-------------------------------------------------
    _ArrayAdd($aFullList, "C:\Users\Default|Default8a7h6u8x9u0")
    $aFullList[0][0] += 1

    ;_ArrayDisplay($aFullList)


    ;Load Hives---------------------------------------------------------------------
    $errloop = 0

    Do
        For $i = 1 To $aFullList[0][0]
            RunWait('reg load "HKEY_USERS\' & $aFullList[$i][1] & '" "' & $aFullList[$i][0] & '\NTUSER.DAT"', "", @SW_HIDE)
            Sleep(100)
        Next

        Sleep(1000)
        $aHKUSListCheck = _RegEnumKeyEx("HKEY_USERS", 1)

        If $errloop > 5 Then
            MsgBox(0, "Error", "All hives didn't load - retrying...")
            ExitLoop
        EndIf

        $errloop += 1

    Until $aHKUSListCheck[0] = $aHKUSList[0] + $aFullList[0][0]

    ;MsgBox(0,"test","Loaded...")

    ;Write changes-------------------------------------------------------------------
    For $i = 1 To $aFullList[0][0]
        For $l = 1 To $InputArray[0][0]
            RegWrite("HKEY_USERS\" & $aFullList[$i][1] & "\" & $InputArray[$l][0], $InputArray[$l][1], $InputArray[$l][2], $InputArray[$l][3])
        Next
    Next

    ;Write to Current User
    For $l = 1 To $InputArray[0][0]
        RegWrite("HKCU\" & $InputArray[$l][0], $InputArray[$l][1], $InputArray[$l][2], $InputArray[$l][3])
    Next

    ;MsgBox(0,"test","Written...")


    ;Unload Hives--------------------------------------------------------------------
    Do
        For $i = 1 To $aFullList[0][0]
            RunWait('reg unload "HKEY_USERS\' & $aFullList[$i][1] & '"', "", @SW_HIDE)
            Sleep(100)
        Next

        Sleep(1000)
        $aHKUSListCheck = _RegEnumKeyEx("HKEY_USERS", 1)

        If $errloop > 5 Then
            MsgBox(0, "Error", "Warning: Not all hives could be unloaded properly!")
            ExitLoop
        EndIf

        $errloop += 1

    Until $aHKUSListCheck[0] = $aHKUSList[0]

EndFunc   ;==>_RegWriteAllUsers

Usage:

$sHexStr = '500044004600430072006500610074006f00720000000000000000000000000000000000000000000000000000' & _
'0000000000000000000000000000000000000001040006dc005c0353ef8101010001009a0b3408640001000f005802020001' & _
'005802030001004c006500740074006500720000000000000000000000000000000000000000000000000000000000000000'

$bBinary=Binary('0x'&$sHexStr)

Dim $RegArray[3][5] = _
                    [ _
                    [0,"","","",""], _
                    ["Printers\DevModePerUser","Printer1","REG_BINARY",$bBinary,"sa_smp"], _
                    ["Printers\DevModes2","Printer1","REG_BINARY",$bBinary,""] _
                    ]


_RegWriteAllUsers($RegArray)

It works fine for my purposes, and feedback is appreciated. Hopefully it's useful...

Share this post


Link to post
Share on other sites
JohnOne

"One thing I'm wondering about regarding coding techniques is how #includes are properly done within a function."

What do you mean by that?

If you mean conditional includes, that is not possible, if you put #include directive in a function, you run the risk of nested functions which are not allowed in AutoIt3.


AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Share this post


Link to post
Share on other sites
SmOke_N

Does this belong in the Example script forum DrLarch?  Let me know and I'll move it.


Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Share this post


Link to post
Share on other sites
DrLarch

"One thing I'm wondering about regarding coding techniques is how #includes are properly done within a function."

What do you mean by that?

If you mean conditional includes, that is not possible, if you put #include directive in a function, you run the risk of nested functions which are not allowed in AutoIt3.

 

Ok, so it's not possible or I run the risk of nested functions which aren't allowed anyway (won't compile, I'm assuming). So then it really isn't an issue, it seems. I wasn't really wondering for my sake, but anyone else who uses the code. I guess if they received an error then the include within my function would need to be moved/deleted due to the conflict.

 

Does this belong in the Example script forum DrLarch?  Let me know and I'll move it.

 

Sure, I guess. Perhaps I should've posted there first, but wanted feedback as well, hence the post here.

Share this post


Link to post
Share on other sites
ViciousXUSMC

I could really make use of a strong working RegWriteAllUsers.  I have a script I made that loads/unloads hives but I never polished it off.

I'll throw my code in just incase it helps in any way.   I later modified this to give me an input box so I could type in the name of the profile I wanted to add keys too, and never got around to it but was going to set it up to update all profiles in a loop.

One of the strange issues I had is that the hive would not always unload so as I was testing the script I would get failure to load the hive, and that was because it never finished unloading from the last run.  So that is why I had that little Do Until loop at the end for unloading.  Once I put that into place this was working perfectly for me. 

#RequireAdmin

$pHive = "HKEY_USERS\Temp\" ;Path\Name of Loaded Hive

Run(@ComSpec & " /c reg.exe load HKU\Temp C:\Users\Default\NTUSER.dat")

Sleep(1000)

$RegTest = RegRead("HKEY_USERS\Temp\Environment", "Temp")


If $RegTest <> "" Then

#Region Cache Terminal
RegWrite($pHive & "Software\InterSystems\Cache Terminal", "LastComm", "REG_SZ", "Winsock")
RegWrite($pHive & "Software\InterSystems\Cache Terminal", "DisableMouse", "REG_SZ", "0")
RegWrite($pHive & "Software\InterSystems\Cache Terminal", "ANSIColor15", "REG_SZ", "255,255,255")
#EndRegion Cache Terminal

#Region Cache Terminal\Winsock
RegWrite($pHive & "Software\InterSystems\Cache Terminal\Winsock", "numnodes", "REG_SZ", "2")
RegWrite($pHive & "Software\InterSystems\Cache Terminal\Winsock", "Port1", "REG_SZ", "23")

Do
    Sleep(200)
    Run(@ComSpec & " /c reg.exe unload HKU\Temp")
    RegRead("HKEY_USERS\Temp\Environment", "Temp")
Until @Error <> ""

MsgBox(0, "Black Magic Installer", "Casewatch Settings Installed for Default User Profile")
#EndRegion Cache Terminal\Winsock
Else
    MsgBox(0, "Black Magic Installer", "Could not load the Default User Hive")
EndIf

Share this post


Link to post
Share on other sites
DrLarch

One of the strange issues I had is that the hive would not always unload so as I was testing the script I would get failure to load the hive, and that was because it never finished unloading from the last run.  So that is why I had that little Do Until loop at the end for unloading.  Once I put that into place this was working perfectly for me.

 

Yeah, that's what I experienced too. I used a Do Until loop as well to repeat the unload attempt (fails and warns after five tries) until the HKU count matched the initial HKU count before loading the hives. Hopefully the DllCall method is more reliable, but like I said, haven't got that figured out yet.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Similar Content

    • GeorgeB
      By GeorgeB
      I'm writing a little applet that basically tells you when Windows was installed.  There is a REG_DWORD in Windows that gives you this. It's basically a value that is the # of seconds from 1970.
      The location is:  "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\InstallDate"
      So if I run this in AutoIT, I should get the value displayed within the msgbox:
      MsgBox($MB_SYSTEMMODAL, "InstallDate Test", RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "InstallDate"))
      However, what happens is it always returns a value of "0"  I tried this on several machines (Windows 8, Windows 8.1 and Windows 10). 
      Am I missing something?  If I manually view this REG_DWORD with RegEdit, it shows me the HEX value, or I can view the Decimal value. I don't care which value AutoIT reads, as I can always convert back and forth, but I just don't see why it can't read a value from this REG_DWORD.  As a test, I've read other REG_DWORD values, and with most it doesn't return any value, not even a 0.
      Please, even if you guys have some other (perhaps better) way to read the Windows install date, I would still like to find a resolution to this problem, because I want to understand why I am having so much difficulty with reading REG_DWORD values from the Windows Registry with AutoIT.
      Thanks for any help!
       
       
       
       
       
    • cahsobo
      By cahsobo
      Hello,

      I need help inserting these keys and values to registry
       
      [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DirectDraw\Compatibility\WK.1.exe]
      "Flags"=hex:00,08,00,00
      "ID"=hex:ec,33,74,3b
       
      Still can't figure out how...
    • nitron
      By nitron
      Hy to all, 
      I am really Sorry to come up with this question but i can't seem to solve the Problem.
      Its quite easy, I have been using RegNumKey for Years, but i seemed to lose track of something.
      For $ZaehlerLocal = 1 to 1200
            $RegKey = RegEnumKey("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall", $ZaehlerLocal)
            If @error <> 0 then ExitLoop
            $RegKey2=RegRead("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\"&$RegKey,"DisplayName")
            $RegKey3=RegRead("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\"&$RegKey,"UninstallString")
            $RegKey4=RegRead("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\"&$RegKey,"QuietUninstallString")

            if StringInStr($RegKey,"_Office15")==0 and StringInStr($RegKey2,"(German) 2013")==0 and StringInStr($RegKey,".KB")==0 and StringInStr($RegKey2,"Security update")==0 and StringInStr($RegKey2,"Framework")==0 Then
              FileWrite($FileHandleLocal,$RegKey&";")
              FileWrite($FileHandleLocal,$RegKey2&";")
              FileWrite($FileHandleLocal,$RegKey3&";")
              FileWriteline($FileHandleLocal,$RegKey4&";")
           EndIf
         Next
       
      Ive been using this to get all uninstall Strings from the Registry but for some reason, this doesn't work anymore. 
      I get some keys but not all, nore does it start with the first registry.
      As you can see in the picture, the Registry starts with {13DA9C7C-EBFB-40D0-94A1-55B42883DF21}
      but RegNumKey starts with Adressbook.
      Any Ideas what I am doing wrong? I tried HKLM64 instead as well, but with same result.
      Again sorry to bother, but i can't Find the mistake.
       

    • Simpel
      By Simpel
      Hi,
      I wondered why negative integers I wrote into registry (e.g. negative x-coordinates of a gui if using two monitors and the right one is the main one) wouldn't return right when reading. Now I know: it is saved as an unsigned integer (without algebraic sign). So here is a snippet that is changing unsigned to signed integer:
      Global Const $g_sRegKey = "HKEY_CURRENT_USER\Software\" & @ScriptName ; path to registry RegWrite($g_sRegKey, "Value", "REG_DWORD", -2147483647) ; write some negative integer into registry; -2147483647 highest possible negative integer , 2147483648 highest possible positive integer if talking of 32bit Local $sValue = RegRead($g_sRegKey, "Value") ; read out registry ConsoleWrite("Value: " & $sValue & @CRLF) ; show real value in console Local $sResult = _SignedInteger($sValue) ; change to signed value ConsoleWrite("Result: " & $sResult & @CRLF) ; and show it in console Func _SignedInteger($iUnsignedInteger) Local $iSignedInteger If $iUnsignedInteger > (2^31) Then ; then it means a negative integer $iSignedInteger = $iUnsignedInteger - (2^32) Else $iSignedInteger = $iUnsignedInteger EndIf Return $iSignedInteger EndFunc It took me some time to find out the problem and so I hope I can help somebody with this.
      Regards, Conrad
    • GreenSparks
      By GreenSparks
      Hi!
      I post here because i was wonderring if someone in this forum could help me with my script.
      What i'm trying to do, is to basically install a new keyboard layout in Windows and activate it. I want to acheive by the registry or the command line, but not with the autoit automation tools, i don't find it stable...
      Thanks for your help and have a good day!
×