#169155 - 2006-10-10 02:46 PM
enumkey in array
|
vroedie
Fresh Scripter
Registered: 2006-10-05
Posts: 30
|
Hi,
I'm trying to build a script that will read all values from a registry key and put them in an array. So that I can reuse this array and enumerate all registry keys from below those registry keys.
I have created the following so far, but I can't seem to get it into an array:
Code:
Dim $Indx, $Keyname, $KeyArr $Indx = 0
While @ERROR = 0 $Keyname = ENUMKEY("HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\", $Indx) If $Keyname <> "" ? "Name found: $Keyname" $KeyArr[$Indx] = $Keyname $Indx = $Indx + 1 Endif Loop
I took most of this code from the manual, but it was used in an "If, Endif, goto" construction and I'd rather not use goto's in my script.
regards,
jeroen
|
Top
|
|
|
|
#169156 - 2006-10-10 04:01 PM
Re: enumkey in array
|
Witto
MM club member
Registered: 2004-09-29
Posts: 1828
Loc: Belgium
|
Code:
If NOT @LOGONMODE Break On Else Break Off EndIf Dim $RC $RC = SetOption("Explicit","On") $RC = SetOption("NoVarsInStrings","On") $RC = SetOption("NoMacrosInStrings","On") $RC = SetOption("WrapAtEOL","On")
Dim $Indx, $Keyname, $KeyArr[] $Indx = 0
While @ERROR = 0 $Keyname = EnumKey( "HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\", $Indx) If $Keyname <> "" ? "Name found: "+$Keyname ReDim Preserve $KeyArr[$Indx] $KeyArr[$Indx] = $Keyname $Indx = $Indx + 1 EndIf Loop ? "Number of keys found: "+(Ubound($KeyArr)+1) For Each $Keyname In $KeyArr ? "- "+$Keyname Next
|
Top
|
|
|
|
#169157 - 2006-10-10 04:46 PM
Re: enumkey in array
|
Richard H.
Administrator
Registered: 2000-01-24
Posts: 4946
Loc: Leatherhead, Surrey, UK
|
The loop will be better constructed like this, to avoid false positives on the @ERROR test: Code:
Dim $sKey $sKey="HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\" $Keyname = EnumKey( $sKey, $Indx) While @ERROR = 0 If $Keyname <> "" ? "Name found: "+$Keyname ReDim Preserve $KeyArr[$Indx] $KeyArr[$Indx] = $Keyname $Indx = $Indx + 1 EndIf $Keyname = EnumKey( $sKey, $Indx) Loop
|
Top
|
|
|
|
#169158 - 2006-10-10 06:44 PM
Re: enumkey in array
|
Witto
MM club member
Registered: 2004-09-29
Posts: 1828
Loc: Belgium
|
Richard, I do not think there will be false positives, because when there is no key anymore, $Keyname will be "" and an error will be raised. The last loop will skip the If/EndIf because of the statement: Code:
If $Keyname <> ""
Don't you think so?
|
Top
|
|
|
|
#169160 - 2006-10-11 09:40 AM
Re: enumkey in array
|
vroedie
Fresh Scripter
Registered: 2006-10-05
Posts: 30
|
Hi,
Thanks! Because I'm still learning I would like to know what you did and how you did it. I've got some questions about it, but this is how I interpret your code:
Code:
If NOT @LOGONMODE Break On Else Break Off EndIf
;I do not know the Break option, so I don't know why this is done
Dim $RC $RC = SetOption("Explicit","On") $RC = SetOption("NoVarsInStrings","On") $RC = SetOption("NoMacrosInStrings","On") $RC = SetOption("WrapAtEOL","On")
Dim $Indx, $Keyname, $KeyArr[] ;the brackets are for the declaration of an array , that's what I missed.
$Indx = 0
While @ERROR = 0 $Keyname = EnumKey( "HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\", $Indx)
If $Keyname <> "" ? "Name found: "+$Keyname ReDim Preserve $KeyArr[$Indx] ; Here is stated that the values in the array need to be saved $KeyArr[$Indx] = $Keyname $Indx = $Indx + 1 EndIf Loop ? "Number of keys found: "+(Ubound($KeyArr)+1) ;what is the Ubound for? the plus 1 is because the array starts with 0. For Each $Keyname In $KeyArr ? "- "+$Keyname ; this I can use to rerun the code for any subkeys. Next
regards,
jeroen
|
Top
|
|
|
|
#169161 - 2006-10-11 10:16 AM
Re: enumkey in array
|
vroedie
Fresh Scripter
Registered: 2006-10-05
Posts: 30
|
And now, if I wanted to create a function out of this (or use an UDF) and I want to reuse the array so I can do the same to the subkeys of the array I just created.
This is what I've got so far (I added the prints so I could see what values the variables got, but It wasn't much):
Code:
$MainKey = "HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\" ? $MainKey
$Step1[] = ReadRegArr($MainKey) ? $Step1 For Each $Key in $Step1 $Ind2 = 0 Redim Preserve $Step2[] $Step2[$Ind2] = ReadRegArr($MainKey + "\" + $Key) ? $Step2 ? $Key $Ind2 = $Ind2 + 1 ? $Ind2 Next
Function ReadRegArr($RegKey)
Dim $Indx, $CurrentKeyname, $KeyArr[], $Regkey $Indx = 0
While @ERROR = 0 $Keyname = ENUMKEY($RegKey, $Indx) If $Keyname <> "" ? "Name found: $Keyname" Redim Preserve $KeyArr[$Indx] $KeyArr[$Indx] = $Keyname $Indx = $Indx + 1 Endif Loop ? "Number of keys found: "+(Ubound($KeyArr)+1) For Each $Keyname In $KeyArr ? "- "+$Keyname Next
EndFunction
regards,
jeroen
|
Top
|
|
|
|
#169162 - 2006-10-11 10:34 AM
Re: enumkey in array
|
Richard H.
Administrator
Registered: 2000-01-24
Posts: 4946
Loc: Leatherhead, Surrey, UK
|
Quote:
Richard, I do not think there will be false positives, because when there is no key anymore, $Keyname will be "" and an error will be raised. The last loop will skip the If/EndIf because of the statement: Code: --------------------------------------------------------------------------------
If $Keyname <> ""
--------------------------------------------------------------------------------
Don't you think so?
Yes...and no
While that would work in this specific case there are two problems. The first is that the loop executes one more time that necessary. More importantly is that if the coder adds extra commands then there is a danger of causing a false positive on the error check.
Here is a very simple example. All that I've done is read an entry "FOO" from each of the subkeys. Assume that the entry will exist on some keys but not on others.
Here is the code: Code:
Break ON $Key = "HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\" "Method 1 (fails)"+@CRLF "----------------"+@CRLF $Indx=0 While @ERROR = 0 $Keyname = EnumKey($Key, $Indx) If $Keyname <> "" "Name found: "+$Keyname+@CRLF ReDim Preserve $KeyArr[$Indx] ; Here is stated that the values in the array need to be saved $KeyArr[$Indx] = $Keyname "Value of 'FOO' in key is: "+ReadValue($Key+"\"+$Keyname,"FOO")+@CRLF $Indx=$Indx+1 EndIf Loop @CRLF "Method 2 (works)"+@CRLF "----------------"+@CRLF $Indx=0 $Keyname = EnumKey($Key, $Indx) While Not @ERROR "Name found: "+$Keyname+@CRLF ReDim Preserve $KeyArr[$Indx] ; Here is stated that the values in the array need to be saved $KeyArr[$Indx] = $Keyname "Value of 'FOO' in key is: "+ReadValue($Key+"\"+$Keyname,"FOO")+@CRLF $Indx=$Indx+1 $Keyname = EnumKey($Key, $Indx) Loop
And here is the output: Code:
Method 1 (fails) ---------------- Name found: BACKUP OF Outlook Value of 'FOO' in key is: Method 2 (works) ---------------- Name found: BACKUP OF Outlook Value of 'FOO' in key is: Name found: Outlook Value of 'FOO' in key is: Name found: RH Value of 'FOO' in key is:
As you can see, the error caused by the missing entry actually causes the loop to exit early in method 1. Method 2 does not suffer from this problem, and in addition does not iterate the loop for the error pass.
For this reason method 2 is recommended, especially for starters. Once you have the habit of coding loops this way you will avoid some of the confusing and hard to find errors that the alternative methods allow.
|
Top
|
|
|
|
#169163 - 2006-10-11 01:56 PM
Re: enumkey in array
|
vroedie
Fresh Scripter
Registered: 2006-10-05
Posts: 30
|
Tnx,
but how can I use the values of an array in an new array? (See my previous example)
regards,
jeroen
|
Top
|
|
|
|
#169164 - 2006-10-11 02:43 PM
Re: enumkey in array
|
Richard H.
Administrator
Registered: 2000-01-24
Posts: 4946
Loc: Leatherhead, Surrey, UK
|
Like this: Code:
Break ON $=SetOption("Explicit","ON") Dim $sRootKey $sRootKey="HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\" Dim $sMain,$sSub,$asMain,$asSub $asMain=ReadRegArr($sRootKey) For Each $sMain in $asMain "Main key: "+$sMain+@CRLF $asSub=ReadRegArr($sRootKey+"\"+$sMain) For Each $sSub in $asSub " Sub key: "+$sSub+@CRLF Next Next Exit 0 Function ReadRegArr($sKey) Dim $i,$sSubKey Redim $ReadRegArr[0] $i=0 $sSubKey=EnumKey($sKey,$i) While Not @ERROR ReDim Preserve $ReadRegArr[$i] $ReadRegArr[$i]=$sSubKey $i=$i+1 $sSubKey=EnumKey($sKey,$i) Loop If @ERROR=259 Exit 0 Else Exit @ERROR EndIf EndFunction
You could also create a recursive function to load the entire tree, but that is a little more complex and may not fit your needs.
|
Top
|
|
|
|
#169165 - 2006-10-11 04:36 PM
Re: enumkey in array
|
Witto
MM club member
Registered: 2004-09-29
Posts: 1828
Loc: Belgium
|
"Break" is documented in the kix2010.doc. If a KiX script is broken (p.e. via task manager and use of the "End Task" button on the "Applications" tab), the user will be logged of. The Break is Off. This behaviour of KiXtart is good during logon scripts, but unwanted in (most of the) other cases. Normally, we want the Break Off during logon scripts and we want the Break On in any other case. So we could write: Code:
If NOT @LOGONMODE Break On EndIf
But maybe, one day, the KiX community and Ruud will decide that Break should be On per default. To be prepared for that switch, I write Code:
If NOT @LOGONMODE Break On Else Break Off EndIf
|
Top
|
|
|
|
#169166 - 2006-10-11 04:50 PM
Re: enumkey in array
|
Witto
MM club member
Registered: 2004-09-29
Posts: 1828
Loc: Belgium
|
UBound is also documented in kix2010.doc. It counts the number of elements in an array, starting from 0. The next code will return 2 for the UBound Function. Code:
If NOT @LOGONMODE Break On Else Break Off EndIf Dim $RC $RC = SetOption("Explicit","On") $RC = SetOption("NoVarsInStrings","On") $RC = SetOption("NoMacrosInStrings","On") $RC = SetOption("WrapAtEOL","On")
Dim $arrElements $arrElements = "One","Two","Three" ? Ubound($arrElements) For $rc = 0 to Ubound($arrElements) ? "- "+$RC+": "+$arrElements[$RC] Next
|
Top
|
|
|
|
#169167 - 2006-10-11 04:58 PM
Re: enumkey in array
|
vroedie
Fresh Scripter
Registered: 2006-10-05
Posts: 30
|
Hi,
Great this was exectly what I was looking for, thanks!
I've adjusted the code and function so it can read multiple registry entries, their sub entries, their value's and their value data.
Code:
Break ON $=SetOption("Explicit","ON")
If RedirectOutput("test.txt") = 0 EndIf Dim $sRootKey $sRootKey="HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\" Dim $sMain,$sSub,$asMain,$asSub,$sSub2,$asSub2,$Val $asMain=ReadRegArr($sRootKey) For Each $sMain in $asMain ;"Main key: "+$sMain+@CRLF $asSub=ReadRegArr($sRootKey+"\"+$sMain) For Each $sSub in $asSub ;" Sub key: "+$sSub+@CRLF $asSub2=ReadRegValArr($sRootKey+"\"+$sMain+"\"+$sSub) For Each $sSub2 in $asSub2 ;" sub - Sub key: "+$sSub2+@CRLF $Val = ReadValue($sRootKey+"\"+$sMain+"\"+$sSub, $sSub2) If INSTR($Val,".pst") ? "Value data: " + $Val+@CRLF EndIf Next Next Next Exit 0 Function ReadRegArr($sKey) Dim $i,$sSubKey Redim $ReadRegArr[0] $i=0 $sSubKey=EnumKey($sKey,$i) While Not @ERROR ReDim Preserve $ReadRegArr[$i] $ReadRegArr[$i]=$sSubKey $i=$i+1 $sSubKey=EnumKey($sKey,$i) Loop If @ERROR=259 Exit 0 Else Exit @ERROR EndIf EndFunction
Function ReadRegValArr($sVKey) Dim $iV,$sVSubKey Redim $ReadRegValArr[0] $iV=0 $sVSubKey=EnumValue($sVKey,$iV) While Not @ERROR ReDim Preserve $ReadRegValArr[$iV] $ReadRegValArr[$iV]=$sVSubKey $iV=$iV+1 $sVSubKey=EnumValue($sVKey,$iV) Loop If @ERROR=259 Exit 0 Else Exit @ERROR EndIf EndFunction
Function ReadRegValArr2($sV2Key,$sV2Value) Dim $iV2,$sV2SubKey Redim $ReadRegValArr2[0] $iV2=0 $sV2SubKey=ReadValue($sV2Key,$iV2) While Not @ERROR ReDim Preserve $ReadRegValArr2[$iV2] $ReadRegValArr2[$iV2]=$sV2SubKey $iV2=$iV2+1 $sV2SubKey=ReadValue($sV2Key,$iV2) Loop If @ERROR=259 Exit 0 Else Exit @ERROR EndIf EndFunction
So if someone can use this, it works!
regards,
jeroen
|
Top
|
|
|
|
Moderator: Jochen, Allen, Radimus, Glenn Barnas, ShaneEP, Ruud van Velsen, Arend_, Mart
|
1 registered
(Allen)
and 466 anonymous users online.
|
|
|