Video Screencast Help
Search Video Help Close Back
to help
New in the Rewards Catalog: Vouchers for "Symantec Technical Specialist" and "Symantec Certified Specialist" exams.

how to change an installed package?

Updated: 22 May 2010 | 10 comments
Alan Sinclair 2's picture
0 0 Votes
Login to vote

During uninstall my package runs a custom action to remove a device driver. Unfortunately I didn't allow for upgrades -- the driver must NOT be uninstalled by RemoveExistingProducts (because once removed it cannot be added until after a reboot). I should have included the condition NOT UPGRADINGPRODUCTCODE.

I'm really not explaining this very clearly -- the newer-version MSI which fires off RemoveExistingProducts must change the installed MSI so that (during the uninstall that's run by RemoveExistingProducts) the condition NOT UPGRADINGPRODUCTCODE is applied to the CA that removes the driver.

I think it's possible to edit the tables in an installed package from the running install. In outline, how?  I'm fine with adding a C++ DLL to do the work, and have used the automation interface to edit tables via SQL in scripts, but need to know what to do to edit an MSI that's installed and about to be run. How do I identify the about-to-be-uninstalled MSI? And how do I edit it?

I hope this is the right forum -- don't know my way around Symantec yet (and miss the simpler old forum!)
Thanks

discussion Filed Under:

Comments

AngelD's picture
06
Apr
2009
1 Vote +1
Login to vote

Update the cached MSI?

Is this attended as a vendor package or installed in a corporate environment?
For the latter:
you could update the cached MSI for the "old" package before performing the upgrade.


A sample vbscript to perform this could look like:

Const msiOpenDatabaseModeTransact = 1

Dim ProductCode : ProductCode = "{CC14CF6A-7D60-413A-934C-3150D422DA6D}"	'// ProductCode for the installed product
Dim Table : Table = "InstallExecuteSequence"

Dim ActionIdentifier : ActionIdentifier = "RemoveDeviceDriverCustomAction"	'// change to the custom action's identifier from the CustomAction table
Dim ActionColumn : ActionColumn = "Action"
Dim ConditionColumn : ConditionColumn = "Condition"
Dim ConditionColumnValue : ConditionColumnValue = "NOT UPGRADINGPRODUCTCODE"

Dim msiPath, propertyKey, propertyValue
Dim Installer, Database, View, Record

'// Product not installed! (Exit vbscript)
If Not IsProductInstalled(ProductCode) Then Wscript.Quit

Dim InstallSource : InstallSource = Installer.ProductInfo(ProductCode, "LocalPackage")

Set Installer = CreateObject("WindowsInstaller.Installer")
Set Database = Installer.OpenDatabase(InstallSource, msiOpenDatabaseModeTransact)
Set View = Database.OpenView("SELECT * FROM `" & Table & "` WHERE `" & ActionColumn & "` = '" & ActionIdentifier & "'")
View.Execute : Set Record = View.Fetch

'// only update table entry if identifier is found
If Not (Record Is Nothing) Then
	Set View = Database.OpenView("UPDATE " & Table & " SET " & ConditionColumn & " = '" & ConditionColumnValue & "' WHERE " & ActionColumn & " = '" & ActionIdentifier & "'")
	View.Execute : Database.Commit
End If

Set Record = Nothing
Set View = Nothing
Set Installer = Nothing

'// check if designated product is installed
Function IsProductInstalled(ProductCode)
	Dim ProductState
	IsProductInstalled = False
	
	ProductState = Installer.ProductState(ProductCode)
	If ProductState <> 5 Then
		Exit Function
	End If
	
	IsProductInstalled = True
End Function

Alan Sinclair 2's picture
06
Apr
2009
0 Votes 0
Login to vote

Thanks for the suggestiona

Thanks for the suggestiona and the script but that's not an option we can use. It's a package that's shipped out to non-tech customers and installed by them, not a corporate environment. End-users can't be asked to run a separate script; the change to the installed package must all be done from the new package.

An extra layer of complication is that the piece I produce is a merge module. I shipped the last version of the merge module (which the vendors built into their product) without the NOT UPGRADINGPRODUCTCODE condition, and that's what my new merge module has to fix. The new msm will also be built into an MSI by the product vendor, not by me.

My new merge module won't even know (in the hardcoded sense) the upgradecode or the productcode for the package it's merged into -- it will have to get the upgradecode programmatically, then presumably get the productcode for the installed package somehow?

Thanks for any advice!

AngelD's picture
06
Apr
2009
0 Votes 0
Login to vote

Your not making it easy

Your not making it easy, are ya ;)
Okey, so this is a merge module that is given to others as a 3rd-party module.


What does the CA actually do?
Are you using Microsoft's Driver Install Framework (DIFxApp) to handle the device driver?

Is the reboot really required?
Is it a system/kernel driver?

Can't you rely on "PendingFileRenameOperations" to replace the driver (file) during next reboot?

Alan Sinclair 2's picture
06
Apr
2009
0 Votes 0
Login to vote

> Your not making it easy,

> Your not making it easy, are ya ;)

Well, no, I'm not clever enough to make it easy :-(   But please keep the ideas coming!!

Windows locks the driver (it's an "earlyload" kernel device) so it cannot be uninstalled then installed again without an intervening reboot. We're not using MS's DIFxApp (I don't write the device installer; I just provide a C++ DLL that execs the driver installer, which is a stand-alone exe.) 

The custom action that installs the driver runs a DLL that execs the device installer with a command line, something like this:
    devinstall -install -name MYDEVICE -location "<path>\mydriver.sys"

The CA which removes the driver is similar:
    devinstall -uninstall -name MYDEVICE

Where devinstall.exe is the stand-alone driver installer.

I don't know how to use PendingFileRenameOperation so I'll go read up on that now to see if it might help. It would be ok to defer replacement of the driver until the reboot, because there's always a mandatory reboot at the end of the install, but I don't think that's a solution. The problem is that RemoveExistingProducts uninstalls the driver, and the custom action to reinstall the driver cannot be run until after the reboot. So the action to install the driver would also have to be run after the reboot and PendingFileRenameOperation wouldn't provide for that.

If there's a way, I think I have to edit the installed MSI before it's run via RemoveExistingProducts!

EdT's picture
07
Apr
2009
0 Votes 0
Login to vote

PendingFileRenameOperations

PendingFileRenameOperations is a Reg_Multi_Sz registry key that is created specifically when a locked system file needs to be replaced at the next reboot (or deleted for that matter).
The new file is copied to a temp location, and the regkey pointed at the existing file and the replacement. Right at the beginning of the next boot, before any drivers are loaded, the file is deleted and replaced (if a replacement was specified).

Google on the topic and you will find more information

If your issue has been solved, please use the "Mark as Solution" link on the most relevant thread.

Alan Sinclair 2's picture
07
Apr
2009
0 Votes 0
Login to vote

Thanks Ed.

Thanks Ed. PendingFileRenameOperations sounds nice for some things but I don't think it can help with this problem. Unless the installed package is edited, the driver will be removed during RemoveExistingProduct and cannot be reinstalled (which has to be done programatically) until after a reboot. Just replacing the driver file is not enough.

For an upgrade I need to suppress the CA that removes the driver (by conditioning the CA on NOT UPGRADINGPRODUCTCODE.)

AngelD's picture
07
Apr
2009
0 Votes 0
Login to vote

Any component in the MSM

Do you have any components in the MSM or just this CA to handle the device driver?
In such case you could search for the component's GUID (Packad format) under "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData". If found then "convert" that Package ProductCode GUID as a Normal GUID and try to update the cached MSI for that custom action with a custom action (ex. vbscript such as above).

Alan Sinclair 2's picture
08
Apr
2009
0 Votes 0
Login to vote

There are components in the

There are components in the MSM so that's probably the best approach. Thanks!  I'll give it a try and report back (probably not for some days as other stuff's come up.)

I wonder if Vista will allow script to modify the cached MSI? Will it have to run deferred so it can run in system context? Unfortunately the customer who's affected by this has RemoveExistingProducts between InstallValidate and InstallInitialize so the CA tro run the script can only be immediate.

EdT's picture
09
Apr
2009
0 Votes 0
Login to vote

>Thanks Ed.

>Thanks Ed. PendingFileRenameOperations sounds nice for some things but I don't think it can help >with this problem. Unless the installed package is edited, the driver will be removed during >RemoveExistingProduct and cannot be reinstalled (which has to be done programatically) until after a >reboot. Just replacing the driver file is not enough.

I would expect the PendingFileRenameOperations key to be created by the RemoveExistingProducts action as this will be the only way to nuke the locked file over the ensuing reboot.
If at this time you have the replacement driver already in a temp area, and modify the PendingFileRenameOperations key to handle the removal as a "replacement" operation instead of just a "Delete" operating, then unless there are other issues associated with the installation of the newer driver, it should be possible to achieve over a single reboot.

If your issue has been solved, please use the "Mark as Solution" link on the most relevant thread.

Alan Sinclair 2's picture
10
Apr
2009
0 Votes 0
Login to vote

> I would expect the

> I would expect the PendingFileRenameOperations key to be created by the RemoveExistingProducts action as this will be the only way to nuke the locked file over the ensuing reboot.
If at this time you have the replacement driver already in a temp area, and modify the PendingFileRenameOperations key to handle the removal as a "replacement" operation instead of just a "Delete" operating, then unless there are other issues associated with the installation of the newer driver, it should be possible to achieve over a single reboot. <

Ah, clever!  We were snipped off the net yesterday so I've just read this, and will go off and experiment asap. Many thanks.