how to change an installed package?
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
Comments
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 FunctionThanks 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!
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?
> 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!
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.
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.)
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).
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.
>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.
> 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.
Would you like to reply?
Login or Register to post your comment.