Jump to content

Yet another _RegWriteAllUsers


DrLarch
 Share

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

Link to comment
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.

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

Monkey's are, like, natures humans.

Link to comment
Share on other sites

  • Moderators

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.

Link to comment
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.

Link to comment
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.

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

Monkey's are, like, natures humans.

Link to comment
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
Link to comment
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.

Link to comment
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
 Share

×
×
  • Create New...