Jump to content
Sign in to follow this  
DrLarch

Yet another _RegWriteAllUsers

Recommended Posts

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

"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.

Share this post


Link to post
Share on other sites

"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

The do not have to be deleted, just moved.

#include <whatever.au3> expands the code exactly where it is added in script you see, that's why you mostly see them at top of script.

Share this post


Link to post
Share on other sites

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

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

    • By joseLB
      Hi
      This piece of code creates and reads OK a key at  "HKEY_LOCAL_MACHINE" and can be changed for a key at "HKEY_CURRENT_USER"
      $sta= RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor", "wav", "REG_SZ", "5555") MsgBox(4096,"wrote", $sta &@cr& @error) $zz= RegRead ("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor", "wav") MsgBox(4096,"readed","="&$zz &@cr& @error) Exit With  HKEY_CURRENT_USER, in RegEdit we can see the created key, and we can create the key by hand/RegEdit and everything Works OK.
      At  HKEY_LOCAL_MACHINE we can´t see the created key above  thru RegEdit, but it Works (even not seeing, I can read). But  if I create "by hand"/RegEdit  the key,  it can´t read it with   $zz= RegRead  ("HKEY_LOCAL_MACHINE.... above.
      I´m the PC´s WIN.7 administrator. Even so I ran RegEdit as administrator and also the compiled AU3 and also plain. No changes.
      edit: even if Try   "HKEY_LOCAL_MACHINE\SOFTWARE\AAA", "wav", the same holds true.
      $sta= RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\AAA", "wav", "REG_SZ", "4444") MsgBox(4096,"wrote", $sta &@cr& @error) $zz= RegRead ("HKEY_LOCAL_MACHINE\SOFTWARE\AAA", "wav") MsgBox(4096,"readed","="&$zz &@cr& @error) Exit Seems that it creates this key at another place.... I can read the above value ("4444"), even after a boot, even the key not showing in regedit. And if I create it by hand key AAA/wav with a distinct value (666), t, it continues Reading the old value = 444.
      Thanks
      Jose
       
    • By nacerbaaziz
      good morning everybody.
      today i liked to share an small example with you
      which it an function to read the registry values as an array
      the result array is 2d array witch
      $a_array[n][0] = value name
      $a_array[n][1] = value Data
      $a_array[0][0] = values count
      here's the function

      #include <Array.au3> #include <WinAPIReg.au3> #include <APIRegConstants.au3> Local $a_array = _RegReadToArray("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run") If @error Then     MsgBox(16, "error", @error)     Exit EndIf _ArrayDisplay($a_array) Func _RegReadToArray($s_RegKey)     Local $a_KeySplitInfo = StringSplit($s_RegKey, "\\", 2)     If UBound($a_KeySplitInfo) <= 1 Then         $a_KeySplitInfo = StringSplit($s_RegKey, "\", 2)         If UBound($a_KeySplitInfo) <= 1 Then Return (1, 1, 0)     EndIf     Local $H_KeyInfo = "", $s_RegKeyInfo = ""     Switch $a_KeySplitInfo[0]         Case "hklm", "HKEY_LOCAL_MACHINE", "hklm64", "HKEY_LOCAL_MACHINE64"             $H_KeyInfo = $HKEY_LOCAL_MACHINE         Case "hkCu", "HKEY_CURRENT_USER", "hkCU64", "HKEY_CURRENT_USER64"             $H_KeyInfo = $HKEY_CURRENT_USER         Case "hkCr", "HKEY_CLASSES_ROOT", "HKCR64", "HKEY_CLASSES_ROOT64"             $H_KeyInfo = $HKEY_CLASSES_ROOT         Case "HKU", "HKEY_USERS", "HKU64", "HKEY_USERS64"             $H_KeyInfo = $HKEY_USERS         Case Else             Return SetError(2, 2, 0)     EndSwitch     _ArrayDelete($a_KeySplitInfo, 0)     $s_RegKeyInfo = _ArrayToString($a_KeySplitInfo, "\")     Local $H_KeyInfoOpen = _WinAPI_RegOpenKey($H_KeyInfo, $s_RegKeyInfo, $KEY_READ)     Local $A_KeyInfo = _WinAPI_RegQueryInfoKey($H_KeyInfoOpen)     If @error Then Return SetError(1, 1, 0)     _WinAPI_RegCloseKey($H_KeyInfoOpen)     Local $A_RegVal[$A_KeyInfo[2] + 1][2]     Local $iV = 1, $s_RegRead = ""     While 1         $s_RegVal = RegEnumVal($s_RegKey, $iV)         If @error <> 0 Then ExitLoop         $s_RegRead = RegRead($s_RegKey, $s_RegVal)         If Not (@error) Then             $A_RegVal[$iV][0] = $s_RegVal             $A_RegVal[$iV][1] = $s_RegRead         EndIf         $iV += 1     WEnd     $A_RegVal[0][0] = UBound($A_RegVal) - 1     If $A_RegVal[0][0] >= 1 Then         Return $A_RegVal     Else         Return SetError(3, 3, 0)     EndIf EndFunc   ;==>_RegReadToArray
      i hope you benefit from it
      with my greetings
    • 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
    • By copyleft
      I've looked at a bunch of SetACL examples on this site and none seem to be able to convert this batch script into a working AutoIt script.
      BATCH
      @echo off "%~dp0setacl.exe" -on "HKEY_CLASSES_ROOT\CLSID\{9C60DE1E-E5FC-40f4-A487-460851A8D915}\DefaultIcon" -ot reg -actn setowner -ownr n:administrators >nul 2>nul "%~dp0setacl.exe" -on "HKEY_CLASSES_ROOT\CLSID\{9C60DE1E-E5FC-40f4-A487-460851A8D915}\DefaultIcon" -ot reg -actn ace -ace "n:administrators;p:full" >nul 2>nul Reg.exe add "HKCR\CLSID\{9C60DE1E-E5FC-40f4-A487-460851A8D915}\DefaultIcon" /ve /t REG_EXPAND_SZ /d "C:\My.ico" /f NON-WORKING AUTOIT
      RunWait('setacl.exe "HKCR64\CLSID\{9C60DE1E-E5FC-40f4-A487-460851A8D915}\DefaultIcon" -ot reg -actn setowner -ownr "n:administrators"') RunWait('setacl.exe "HKCR64\CLSID\{9C60DE1E-E5FC-40f4-A487-460851A8D915}\DefaultIcon" -ot reg -actn setowner -ownr "n:administrators;p:full"') RegWrite('HKCR64\CLSID\{9C60DE1E-E5FC-40f4-A487-460851A8D915}\DefaultIcon', '','REG_EXPAND_SZ','C:\Windows\My.ico') Any ideas on what I'm doing wrong?
       
    • 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!
       
       
       
       
       
×
×
  • Create New...