Flynn
Flynn

Reputation: 193

Reg Query script for batch script

I tried asking this once, but I think there was some confusion so I'm going to try this fresh. Here is the code:

set regVar=HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
set excluded=Microsoft MDOP Dell 
set count=0
for /f "tokens=2,*" %%a in ('Reg Query %regVar% /S^|find " DisplayName" ^| findstr /v "%excluded%"') do (
    set /a count+=1
    setlocal EnableDelayedExpansion
    for %%n in (!count!) do (
        endlocal
        set product[%%n]=%%b
        echo  %%n.%tab%%%b
        echo  %%a
    )   
)

What this does is go through all uninstall registries and then adds each DisplayName key into an array called product[] and then prints the result for the current number it's on i the loop to the screen for a menu. What you can then do is type in the number, and it returns the Display name in that array:

So this as it stands filters out everything microsoft, mdop, and dell

What I want it to do is ALSO look in that key for that DisplayName and return another key called UninstallString and assign that to the array uninstallprod[] with the same associated index. The issue I'm running into is that I cant figure out how to either query using a statement like you can in sql

Select UninstallString from REGISTRY where DisplayName="Program name"

with program name being the string returned from the DisplayName you selected, or to have a SINGLE query that will allow me to both filter out the DisplayNames like you see above and also include the UninstallString value in the same statement. The problem with trying it any other way is I can't filter and do both arrays without it ending up with indexes completely wrong (it'll skip a display name but still assign the uninstallstring because its not letting me filter both)

UPDATE:

At this point I have it pulling back both a DisplayName and Uninstall string, but it's not advancing the counter correctly. In it's current state, it assigns 2 variables, the name of the key (%%a) to use for assigning and comparing what the key is, and the value of the key (%%c) which is either the name of the program or the uninstall path (string) to use for uninstallation later in the script. So what ends up happening is that I end up with a list of skipped numbers because the counter is getting advanced even when there is no displayname being printed to the list. Here is the code I am now working with.

@echo off
set tab=    
set regVar=HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
set excluded=Microsoft MDOP Dell 
set count=1
for /f "tokens=1,2,*" %%a in ('Reg Query %regVar% /S^|findstr "DisplayName UninstallString" ^| findstr /v "%excluded%"') do (
    setlocal EnableDelayedExpansion
    for %%n in (!count!) do (
        endlocal
        if "%%a"=="DisplayName" set product[%%n]=%%c&echo %%n.%tab%%%c
        if "%%a"=="UninstallString" if defined product[%%n] set uninstall[%%n]==%%c&set/a count+=1
    )
)

Just as an example, I have Sublime Text 2.0.1 and 64 bit HP CIO Components Installer on my list. What ends up happening is I get a list like this:

1.  Sublime Text 2.0.1
3.  64 bit HP CIO Components Installer

So for some reason the counter is getting advanced past 2 even though no product[2] is being defined. And in the 32 bit version I have 5 entries showing up, one of them is blank, which prints like this:

1.  Adobe Flash Player 11 ActiveX
2.  Google Chrome
3.  TeamViewer 8
4.  
4.  Google Update Helper.

Upvotes: 2

Views: 6321

Answers (1)

Magoo
Magoo

Reputation: 80023

You'd need to let both "UninstallString" and "Displayname" through the initial gate, so change

for /f "tokens=2,*" %%a in ('Reg Query %regVar% /S^|find " DisplayName" "...

to

for /f "tokens=1,2,*" %%a in ('Reg Query %regVar% /S^|FINDSTR "Displayname UninstallString"...

Which will set %%a to Displayname or UninstallString and %%c to the data value required.

THEN you have to deal with the sequence

Displayname x
Displayname y
Uninstall y

or

Displayname y
Uninstall y
Uninstall z

Which actually isn't particularly hard.

You are already setting Product[n] - you need to do this for every %%a==Displayname. Repeat for Uninstall[n] - do this for every %%a==UninstallString BUT only if Product[n] is defined.

IF "%%a"=="UninstallString" if defined Product[%%n] set uninstall[%%n]=%%c&set/a count+=1

take the count-increment before the SETLOCAL out, as it needs to be done only if you have a matching pair of PRODUCT and UNINSTALL; change your initial value to 1 (unless you like counting from zero)

and pray that you don't get a sequence

Displayname y
Uninstall z

Now, if you DO get this sequence, simply find a convenient string to ALSO let through the gate - like, perhaps "HKEY_" and if %%a begins "HKEY_" then set "Product[%%n]=" to clear any Displayname appearing without an uninstallstring.

You may even want to change that around a little.

If you set

  • Product against the first Displayname
  • uninstall against the first uninstall string (ie. only if not defined unistall[%%n])
  • When a HKEY_ appears, increment the counter if both product[%%n] and uninstall[%%n] are defined, else set product[%%n] and uninstall[%%n] to [nothing]

then the sequence of uninstall and displayname is not relevant, although you'd need to repeat the HKEY_ test after the loop to take care of the very last instance...


Addendum for solving some problems discussed

@ECHO OFF
setlocal
set regVar=HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
set excluded=/c:" Microsoft" /c:"MDOP" /c:"Dell" 
set count=1
for /f "tokens=1,2,*" %%a in ('Reg Query %regVar% /S^|findstr "DisplayName HKEY_ UninstallString" ^| findstr /v %excluded%') do (
    setlocal EnableDelayedExpansion
    for %%n in (!count!) do (
        ENDLOCAL
        SET HKEY=Y
        IF "%%a"=="DisplayName" SET "HKEY="&set product[%%n]=%%c
        IF "%%a"=="UninstallString" SET "HKEY="&IF NOT DEFINED uninstall[%%n] set uninstall[%%n]=%%c
        IF "%%a"=="QuietUninstallString" SET "HKEY="&IF NOT DEFINED uninstall[%%n] set uninstall[%%n]=%%c
    IF DEFINED hkey IF DEFINED product[%%n] IF defined uninstall[%%n] SET /a count+=1&SET "hkey="
    IF DEFINED hkey set "product[%%n]="&SET "uninstall[%%n]="
    )   
)

::
:: Last entry may not be complete
::
IF NOT DEFINED product[%count%] SET "uninstall[%count%]="&SET /a count-=1
IF NOT DEFINED uninstall[%count%] SET "product[%count%]="&SET /a count-=1

ECHO %count% entries found
SET prod
SET unins

Note that since HKEY is now allowed through the gate, but it's a pain to test line beginning HKEY, if it's NOT one of the strings "Displayname", "UninstallString" or "QuietUninstallString" then it's presumed to be HKEY. IF DEFINED works on the RUN-TIME presence/absence of a variable which permits easy - er, koff - programming.


Display data from an "array"

FOR /l %%i IN (1,1,%count%) DO (
CALL ECHO %%i. %%product[%%i]%%
)

Additional data 20130419-1756Z

@echo OFF
setlocal
set tab=    
set regVar=HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
set excluded=Microsoft MDOP Dell 
FOR /f "delims=" %%i IN ('Reg Query %regVar% /S^|find "HKEY_"') DO (
 FOR %%s IN (dn us qu pu dn ut) DO SET "%%s="
 FOR /f "tokens=1,2,*delims= " %%s IN ('Reg Query "%%i" /S') DO (
  if /i "%%s"=="Displayname" SET /a dn+=1&SET dn=%%u
  if /i "%%s"=="Uninstallstring" SET /a us+=1&SET ut=%%u
  if /i "%%s"=="quietUninstallstring" SET /a qu+=1
  if /i "%%s"=="publisher" SET pu=%%u
 )
 FOR %%s IN (dn us qu) DO SET /a %%s+=0
 CALL :report
)

GOTO :eof

:report
SET /a tus=us+qu
ECHO %dn%   %us%   %qu%   %tus%   %pu% %dn% %ut%
GOTO :eof

This procedure should show interesting details.

The report columns are

  1. Number of 'displayname's found
  2. Number of 'Uninstallstring's found
  3. number of 'quiteuninstallstring's found
  4. total of previous 2 columns
  5. publisher string - if found
  6. displayname - if found
  7. uninstall text - if found

I'd suggest you use this data to do your filtering and assignment to your array - the inner loop is dealing with a single uninstall item. Select the required parts and add them or don't to your arrays.

Upvotes: 2

Related Questions