Hello all!

I've been messing about with the windows cleanup util (MSIZAP.exe) and trying to break my MSI as much as possible, to help simulate the actions of an extremely stupid user.. however i have got the point where Windows Installer still thinks many of my components exist despite there being no physical files and none of my registry entries exist... Giving a tonne of the following types of messages:

Disallowing uninstallation of component: {5C517030-1AA5-4018-82F2-A2D6F784EC04} since another client exists

I'm no expert on the ins and outs of windows installer so could someone advise the best course of action to remove the entries out of Windows installer so there are no associated records in there. Basically i am developing a cleanup utility to remove all the files/registry i put down including windows installer entries if an install became corrupt.

Regards

Paul
0 Comments   [ + ] Show Comments

Comments

Please log in to comment

Rating comments in this legacy AppDeploy message board thread won't reorder them,
so that the conversation will remain readable.

Answers

0
Hi Paul,

Thanks for that piece of information.
I was wondering how if shared components would get zipped or not and you just confirm that.

As other applications installed from an MSI also have installed that component (component GUID) you are not allowed to zap that component for the specific product you're choosing from msizap.

I guess you would have to change the counter for the shared component in the registry to 1 before using the msizip for the product having that component.
Answered 07/09/2007 by: AngelD
Red Belt

Please log in to comment
2
The keys will be written to here

HKLM\Software\microsoft\windows\currentversion\Installer\userdata\<xxxxxxx>\components

<xxxxxxx> depends on wether you deploy per user and or per machine.

per machine will be <S-1-5-18>

Inside there you will find a very messed up version of you component code.

{xxxxxxx-xxxx-xxxx-xxxx-xxxx) <---- i didnt count these

I dont know what the names are of the groups are but for the sake of this lets call them octets (like in subnets even though they are not really octets)

for the first three octets the entire octet is reversed

for the last 2 octets only every two are reversed

for example

{abcdefghijkl- is =
{lkjihgfedcba

and so on and so on.

then the last 2 octets only each 2 characters are reversed so

-ABCD- would become BADC

confusing i know but the powers at be say this saves space ? go figure ... my wisdom does not extend far enough to know exactly how this saves space cos in my eyes its exactly the same but jumbled up.

inside this key you will find another messed up GUID or maybe lots of them

When you mark a component DO NOT uninstall you are actually telling the install to write all {00000000000-0000000-00000-0000000} again i didnt count those.

so if you see all Zero's then you will know the component will not be uninstalled.

where you see more mixed up GUIDS you will find these guids are the product codes of the associated applications that have installed those components.

As such this is in effect how reference counting actually works.

It does not count the number of times components are installed it actually associated the products that have installed the component. As such when you uninstall an APP you remove the apps product from the component list.

that about covers your question i reckon.
Answered 07/09/2007 by: jmcfadyen
Fifth Degree Black Belt

Please log in to comment
0
I've discovered that MSIZAP doesn't zap all the detrius of per-user managed installs (used at my current client) so I'm building a script to handle those, using the output from MSIZAP as a guide to what I need to ditch (I know most of the locations but guarantee I'd miss one or more without that output...getting too old to rely on memory)
Answered 07/10/2007 by: VBScab
Red Belt

Please log in to comment
0
ORIGINAL: jmcfadyen
{xxxxxxx-xxxx-xxxx-xxxx-xxxx) <---- i didnt count these

I dont know what the names are of the groups are but for the sake of this lets call them octets (like in subnets even though they are not really octets)

for the first three octets the entire octet is reversed

for the last 2 octets only every two are reversed

for example

{abcdefghijkl- is =
{lkjihgfedcba

and so on and so on.

then the last 2 octets only each 2 characters are reversed so

-ABCD- would become BADC

confusing i know but the powers at be say this saves space ? go figure ... my wisdom does not extend far enough to know exactly how this saves space cos in my eyes its exactly the same but jumbled up.
This is documented as 'Darwinian transforms' on, IIRC, InstallSite but it's too much like hard work to translate every time so I have a VB Script function to do the work for you. Feed it a GUID and it squirts out the (what I call) munged string.
Answered 07/10/2007 by: VBScab
Red Belt

Please log in to comment
0
Ahh, cool, thanks for your input guys, no wonder i could not search for component guid in the registry due to the 'jumbling up' of the 'octets'.

VBScab i guess your using the split command and reversing it, would you mind letting take a peek at the code to do this?

Regards

Paul
Answered 07/10/2007 by: HotSpot
Orange Senior Belt

Please log in to comment
2
ORIGINAL: HotSpot
VBScab i guess your using the split command and reversing it, would you mind letting take a peek at the code to do this?
Kind of...


Option Explicit

Call ListCodes(path_containing_MSI_or_MSIs)

'=========================================================================================================
' Name: ListCodes
' Purpose: Passed a path, this routine tests for the presence of an MSI,
' interrogates it for its UpgradeCode and ProductCode, then returns those
' and their MS-munged versions
' Input: strRootPath - the folder to start listing from
'=========================================================================================================
Sub ListCodes(ByVal strRootPath)

Dim strDummy
Dim objInstaller_ROC
Dim objView
Dim objRecord
Dim objDatabase

Dim objFSO_ROC
Dim objFolder
Dim objFileCollection
Dim objFile
Dim strFiles
Dim strFileName
Dim strProperty
Dim intPropertyIndex
Dim strPropertyValue

'// Set which property you want to test for here
strProperty = "ProductCode"
intPropertyIndex = 2

Set objInstaller_ROC = CreateObject("WindowsInstaller.Installer")
Set objFSO_ROC = CreateObject("Scripting.FileSystemObject")

'// There should only be one, but this code iterates through all of them anyway
Set objFolder = objFSO_ROC.GetFolder(strRootPath)
Set objFileCollection = objFolder.Files

For Each objFile In objFileCollection
'// Files do not have an 'Extension' property in VBS, we have to do this nonsense...
If UCase(objFSO_ROC.GetExtensionName(objFile.Name)) = "MSI" Then

strFileName = strRootPath & "\" & objFile.Name

'// Open database
Set objDatabase = objInstaller_ROC.OpenDatabase(strFileName, 0)

'// Get property
Set objView = objDatabase.OpenView("SELECT * FROM Property WHERE Property = '" & strProperty & "'")
objView.Execute

Set objRecord = objView.Fetch
strPropertyValue = Empty
strPropertyValue = objRecord.StringData(intPropertyIndex)

If Len(strPropertyValue) = 0 Then
'// Display the error that occurred
strDummy = "Unable to retrieve value for MSI property '" & strProperty & "'."
MsgBox strDummy, vbExclamation, WSCript.ScriptName & ".ListCodes"
Exit Sub
End If

WScript.Echo "Getting " & strProperty & " for " & objFile.ParentFolder & "\" & objFile.Name
strDummy = GetMungedCode(strPropertyValue)
strDummy = vbTAB & strPropertyValue & vbTAB & strDummy & vbCRLF
WScript.Echo strDummy

'// Now do UpgradeCode
strProperty = "UpgradeCode"

'// Get property
Set objView = objDatabase.OpenView("SELECT * FROM Property WHERE Property = '" & strProperty & "'")
objView.Execute

Set objRecord = objView.Fetch
strPropertyValue = Empty
strPropertyValue = objRecord.StringData(intPropertyIndex)

If Len(strPropertyValue) = 0 Then
'// Display the error that occurred
strDummy = "Unable to retrieve value for MSI property '" & strProperty & "'."
MsgBox strDummy, vbExclamation, WSCript.ScriptName & ".ListCodes"
Exit Sub
End If

WScript.Echo "Getting " & strProperty & " for " & objFile.ParentFolder & "\" & objFile.Name
strDummy = GetMungedCode(strPropertyValue)
strDummy = vbTAB & strPropertyValue & vbTAB & strDummy & vbCRLF
WScript.Echo strDummy

objView.Close

Set objDatabase = Nothing
Set objView = Nothing
Set objRecord = Nothing
End If
Next

Set objFileCollection = Nothing
Set objFolder = Nothing
Set objFSO_ROC = Nothing
Set objInstaller_ROC = Nothing
End Sub

Function GetMungedCode(ByVal strCode)

Dim arrCharacterOrder
Dim intIndex
Dim strMungedCode

Const intArraySize = 32

arrCharacterOrder = Array(9,8,7,6,5,4,3,2,14,13,12,11,19,18,17,16,22,21,24,23,27,26,29,28,31,30,33,32,35,34,37,36)

'// Generate the munged version of the code
For intIndex = 0 to intArraySize - 1
strMungedCode = strMungedCode & Mid(strCode,arrCharacterOrder(intIndex),1)
Next

GetMungedCode = strMungedCode
End Function
Answered 07/10/2007 by: VBScab
Red Belt

Please log in to comment
0
[:)] Superstar! [:)]

Thanks

Paul
Answered 07/10/2007 by: HotSpot
Orange Senior Belt

Please log in to comment
0
Ian,

I don't recall if I have posted this vbscript before so here goes.
It will convert GUID to InstallerCode or as you said it "munged string" [:D] and vice versa


'// Convert ProductCode to InstallerCode and vice versa
Option Explicit
Const CodeIndex = 0

WScript.Echo ConvertGuid(CodeIndex, "{70F784E9-59C8-4EDD-BAEE-A0AF409CFF33}")
WScript.Echo ConvertGuid(CodeIndex, "726A9C95A4F54c7449DFA988F6A59C17")

Function ConvertGuid(iCodeIndex, sGuidCode)
Dim aCode, iIndex, sSectionCode, sSectionDigits, sGuid, bAddHyphen
bAddHyphen = True

sGuid = sGuidCode

iIndex = iCodeIndex
If iIndex = 0 Then
If InStr(sGuid, "-") Then bAddHyphen = False
End If

sGuid = ConvertCode(sGuid)
sGuid = ConvertSection(iIndex, sGuid)
ConvertGuid = sGuid

aCode = Split(sGuid, "-")
If iIndex = Ubound(aCode) Then Exit Function

sGuid = ConvertGuid(iIndex + 1, sGuid)

If Not bAddHyphen Then sGuid = Join(Split(sGuid, "-"),"")
If iIndex = 0 AND bAddHyphen Then sGuid = "{" & sGuid & "}"

ConvertGuid = sGuid
End Function
Function ConvertCode(sGuidCode)
Dim aGuidSection

If Left(sGuidCode, 1) = "{" Then sGuidCode = Replace(Replace(sGuidCode,"{",""),"}","")

If InStr(sGuidCode, "-") Then
aGuidSection = Split(sGuidCode, "-")
Else
Redim aGuidSection(4)
aGuidSection(0) = Left(sGuidCode, 8)
aGuidSection(1) = Mid(sGuidCode, 9, 4)
aGuidSection(2) = Mid(sGuidCode, 13, 4)
aGuidSection(3) = Mid(sGuidCode, 17, 4)
aGuidSection(4) = Right(sGuidCode, 12)
End If

ConvertCode = Join(aGuidSection, "-")
End Function
Function ConvertSection(iSectionIndex, sGuidCode)
Dim aGuidSection, iIndex, sSectionDigits

aGuidSection = Split(sGuidCode, "-")

If iSectionIndex <= 2 Then aGuidSection(iSectionIndex) = StrReverse(aGuidSection(iSectionIndex))
If iSectionIndex >= 3 Then
For iIndex = 0 To len(aGuidSection(iSectionIndex)) Step 2
sSectionDigits = sSectionDigits & StrReverse(Right(Left(aGuidSection(iSectionIndex), iIndex), 2))
Next
aGuidSection(iSectionIndex) = sSectionDigits
End If

sGuidCode = Join(aGuidSection, "-")

ConvertSection = sGuidCode
End Function
Answered 09/04/2007 by: AngelD
Red Belt

Please log in to comment
Answer this question or Comment on this question for clarity