Reputation: 193
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
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
if not defined unistall[%%n]
)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
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