Passing MSI properties when using VBScript automation for repairs
I have been looking at how to pass MSI properties to Windows Installer when performing repairs of installed MSI packages using the automation interface (COM object: WindowsWindowsInstaller.Installer) for VBScript. The two methods available for doing repairs are:
Example: When Office 2003 applications are run for the first time by a new user, they trigger a repair of the installation. In the log file for the repair you can see that Windows Installer is called using the following MSI properties:
REINSTALL=OfficeUserData REINSTALLMODE=ocmu MSICLIENTUSESEXTERNALUI=1
Both "REINSTALL" and "REINSTALLMODE" are handled as arguments to the ReinstallFeature method above but how do I pass the value for "MSICLIENTUSESEXTERNALUI" to Windows Installer when doing the repair?
I have looked at creating a Session object for the installation by using the OpenProduct method and setting properties that way using the property "Property" for the session object. Unfortunately, the repair cannot take place as long as the session object remains active and when it is closed any properties set using it are discarded.
Another alternative, which would be closer to how Msiexec.exe could be called from the command line, is to use the method "InstallProduct" of the Installer object. However, this method requires as an argument the path to an MSI file and can not use the product code of an installed package. I can not assume that I will always have access to the original source media where the MSI file is located. Although it might be possible in some cases to use the INSTALLPROPERTY_LOCALPACKAGE property of the installed package to get the locally cached MSI package this seems somewhat unreliable according to the MSI documentation:
http://msdn.microsoft.com/en-us/library/aa370130.aspx
Any suggestions on a good, generic way of solving this? I am not looking for specific pointers for the Office 2003 repair but rather how this should be solved for any type of installation.
Note: Using msiexec.exe to perform the repairs is not an option.
- ReinstallProduct (repairs an MSI package based on product code)
- ReinstallFeature (repairs the specified feature based on feature name and product code)
Example: When Office 2003 applications are run for the first time by a new user, they trigger a repair of the installation. In the log file for the repair you can see that Windows Installer is called using the following MSI properties:
REINSTALL=OfficeUserData REINSTALLMODE=ocmu MSICLIENTUSESEXTERNALUI=1
Both "REINSTALL" and "REINSTALLMODE" are handled as arguments to the ReinstallFeature method above but how do I pass the value for "MSICLIENTUSESEXTERNALUI" to Windows Installer when doing the repair?
I have looked at creating a Session object for the installation by using the OpenProduct method and setting properties that way using the property "Property" for the session object. Unfortunately, the repair cannot take place as long as the session object remains active and when it is closed any properties set using it are discarded.
Another alternative, which would be closer to how Msiexec.exe could be called from the command line, is to use the method "InstallProduct" of the Installer object. However, this method requires as an argument the path to an MSI file and can not use the product code of an installed package. I can not assume that I will always have access to the original source media where the MSI file is located. Although it might be possible in some cases to use the INSTALLPROPERTY_LOCALPACKAGE property of the installed package to get the locally cached MSI package this seems somewhat unreliable according to the MSI documentation:
http://msdn.microsoft.com/en-us/library/aa370130.aspx
MsiGetProductInfo(INSTALLPROPERTY_LOCALPACKAGE) does not necessarily return a path to the cached package. The cached package is for internal use only.
Any suggestions on a good, generic way of solving this? I am not looking for specific pointers for the Office 2003 repair but rather how this should be solved for any type of installation.
Note: Using msiexec.exe to perform the repairs is not an option.
0 Comments
[ + ] Show comments
Answers (17)
Please log in to answer
Posted by:
AngelD
16 years ago
You need to write the properties to the registry during install and then read them back during a repair using AppSearch.
Have a look at http://etlengineering.com/installer/repair.txt
Have a look at http://etlengineering.com/installer/repair.txt
Posted by:
Jonas Olsson
16 years ago
ORIGINAL: AngelD
You need to write the properties to the registry during install and then read them back during a repair using AppSearch.
Have a look at http://etlengineering.com/installer/repair.txt
I'm afraid that's not an option in this case since I can't make any changes to the installed package or reinstall it using a transform, patch, etc.
Posted by:
AngelD
16 years ago
Posted by:
aogilmor
16 years ago
[/align]
[blockquote]
Sounds like you've dug yourself into a hole by only using VBScript automation to install.
Why are you using such an inflexible method?
What are you trying to accomplish?
[/blockquote]
[blockquote]
ORIGINAL: Jonas Olsson
ORIGINAL: AngelD
You need to write the properties to the registry during install and then read them back during a repair using AppSearch.
Have a look at http://etlengineering.com/installer/repair.txt
I'm afraid that's not an option in this case since I can't make any changes to the installed package or reinstall it using a transform, patch, etc.
Sounds like you've dug yourself into a hole by only using VBScript automation to install.
Why are you using such an inflexible method?
What are you trying to accomplish?
[/blockquote]
Posted by:
Jonas Olsson
16 years ago
ORIGINAL: aogilmor
Sounds like you've dug yourself into a hole by only using VBScript automation to install.
Why are you using such an inflexible method?
What are you trying to accomplish?
The reason I have been looking at VBScript automation to repair products and features is because it circumvents a domain group policy in use at the enterprise in question, forbidding ordinary users from running the msiexec.exe executable (security by obscurity, I know, but making changes to the group policy is difficult for political reasons). Using VBScript automation allows our users to repair installed MSI packages anyway as part of their login routine. We do this for users logging on to a workstation for the first time (only local, non-roaming profiles in use) in order to populate their profiles with some initial settings which we then make changes to.
Mind you, we do not currently use VBScript automation to install MSI packages. That is done using msiexec.exe. However, I am not sure I agree that VBScript automation in general is an inflexible method for working with Windows Installer. Although it seems Microsoft hasn't included the ability to send along MSI properties when performing repairs using the reinstall methods above and has not enabled the "InstallProduct" method to use product codes instead of MSI package paths, there are many other methods and properties in the interface which allows you to dig pretty deep into the Windows Installer environment using API calls.
Posted by:
anonymous_9363
16 years ago
Jonas, at the risk of possibly violating forum rules, I have a script-friendly interface to MSI.DLL via a VB-authored ActiveX DLL. I presently use it ONLY to access the CreateAdvertiseScript which enables my current client to add MSIs to Group Policy Objects entirely in script. As you know, adding MSIs to GPOs involves so much clicking and browsing that it drives most people nuts when performed enough times. Well, for me, I figured there had to be a way to automate it and set about that task. Many times, I wish I hadn't, thanks to missing/poor documentation but with the judicious use of ProcMon (sigh...), AD Explorer and other similar tools, I worked it out. The major fly in the ointment was access to the CerateAdvertsieScript function. This has been added (apparently) to MSI v4 but we're not using that yet (and no propsect likely for a long while, bearing in mind the client only migrated to XP LAST December!) so I had to persist.
Anyway, to my point! If you'd like a copy of my DLL, PM me and I'll pop it on to SendUIt.com for you. The DLL will be provided to you - and only you - on a strictly for-experimentation-only basis. I do not expect to see copies of it floating around the web, thanks. The major caveat is that I have not tested ANY OTHER FUNCTION that it interfaces with other than CreateAdvertiseScript so you're on your own in using it. I can advise you of parameter data types (although they'll be the same as on MSDN) and so on but, other than that....
Anyway, to my point! If you'd like a copy of my DLL, PM me and I'll pop it on to SendUIt.com for you. The DLL will be provided to you - and only you - on a strictly for-experimentation-only basis. I do not expect to see copies of it floating around the web, thanks. The major caveat is that I have not tested ANY OTHER FUNCTION that it interfaces with other than CreateAdvertiseScript so you're on your own in using it. I can advise you of parameter data types (although they'll be the same as on MSDN) and so on but, other than that....
Posted by:
Jonas Olsson
16 years ago
ORIGINAL: VBScab
Anyway, to my point! If you'd like a copy of my DLL, PM me and I'll pop it on to SendUIt.com for you. The DLL will be provided to you - and only you - on a strictly for-experimentation-only basis. I do not expect to see copies of it floating around the web, thanks. The major caveat is that I have not tested ANY OTHER FUNCTION that it interfaces with other than CreateAdvertiseScript so you're on your own in using it. I can advise you of parameter data types (although they'll be the same as on MSDN) and so on but, other than that....
VBScab, thanks for the offer but unfortunately it does not seem that being able to call functions directly from MSI.DLL will help with the challenge introduced by Microsoft's limited API. The scriptable automation interface seems to correspond well to the functions available in MSI.DLL for performing the tasks that I am interested in:
MsiInstallProduct
MsiReinstallProduct
MsiReinstallFeature
These functions use the same parameters as their automation interface counterparts so you would still be unable to combine using product codes for repairs with sending along MSI properties at run-time.
Thanks anyway though.
Posted by:
aogilmor
16 years ago
REINSTALL=OfficeUserData REINSTALLMODE=ocmu MSICLIENTUSESEXTERNALUI=1
ORIGINAL: Jonas Olsson
ORIGINAL: VBScab
Anyway, to my point! If you'd like a copy of my DLL, PM me and I'll pop it on to SendUIt.com for you. The DLL will be provided to you - and only you - on a strictly for-experimentation-only basis. I do not expect to see copies of it floating around the web, thanks. The major caveat is that I have not tested ANY OTHER FUNCTION that it interfaces with other than CreateAdvertiseScript so you're on your own in using it. I can advise you of parameter data types (although they'll be the same as on MSDN) and so on but, other than that....
VBScab, thanks for the offer but unfortunately it does not seem that being able to call functions directly from MSI.DLL will help with the challenge introduced by Microsoft's limited API. The scriptable automation interface seems to correspond well to the functions available in MSI.DLL for performing the tasks that I am interested in:
MsiInstallProduct
MsiReinstallProduct
MsiReinstallFeature
These functions use the same parameters as their automation interface counterparts so you would still be unable to combine using product codes for repairs with sending along MSI properties at run-time.
Thanks anyway though.
Maybe I'm just being dense, but I still don't get it....
If vbscript doesn't support this, use a simple command line, use another tool to run the command (wisesscript?) or shell out the command with vbscript, bat, powershell, WMI or however fits best for you.
Just for giggles I ran an office reinstall of 2003 on my own machine. msiexec /i {90110409-6000-11D3-8CFE-0150048383C9} REINSTALL=OfficeUserData REINSTALLMODE=ocmu MSICLIENTUSESEXTERNALUI=1, and it worked fine.
I guess my point is that lack of support from one msft tool shouldn't prevent you from accomplishing your desired user config.
Posted by:
Jonas Olsson
16 years ago
ORIGINAL: aogilmor
Maybe I'm just being dense, but I still don't get it....
If vbscript doesn't support this, use a simple command line, use another tool to run the command (wisesscript?) or shell out the command with vbscript, bat, powershell, WMI or however fits best for you.
Well, as I wrote in an earlier post, a domain group policy is in effect at the enterprise in question preventing ordinary users from running the msiexec.exe executable. For this reason a per-user repair can not be initiated for these users using msiexec.exe directly. It doesn't matter if the command is called from a script or from another compiled executable.
To access the Windows Installer functionality and perform the repair, the Windows Installer automation interface or its API (from MSI.DLL) must be used to initiate the operation. Although I am sure there are several more or less ugly hacks around the domain group policy, for example making a copy of the msiexec.exe file and renaming and/or editing its contents and then running it, these types of solutions are not what I am looking for.
Actually there is a solution to the problem, which I mentioned in my original post. You can get the locally cached MSI package file path for the installed MSI package using the property INSTALLPROPERTY_LOCALPACKAGE or, failing that and using other methods, the path to the actual installation source for the package. The MSI package source path could then be used with the automation interface method "InstallProduct" to send along the appropriate MSI properties to perform the repair, including any extra properties required.
The reason I discarded this method in my original post was due to the uncertainty of whether or not the INSTALLPROPERTY_LOCALPACKAGE would be populated for all installed MSI packages. The real installation source path was also not available on some of the client platforms where this solution was supposed to work.
This may however be a method I will use if the need arises again but for now it seems that Office 2003 can be repaired sufficiently well using only the ReinstallFeature method, the product code and the feature name. The additional MSI property MSICLIENTUSESEXTERNALUI=1 used by Office applications when they initiate the repair does not seem to be necessary for successfully completing the per-user repair.
Posted by:
aogilmor
16 years ago
ORIGINAL: Jonas Olsson
ORIGINAL: aogilmor
Maybe I'm just being dense, but I still don't get it....
If vbscript doesn't support this, use a simple command line, use another tool to run the command (wisesscript?) or shell out the command with vbscript, bat, powershell, WMI or however fits best for you.
Well, as I wrote in an earlier post, a domain group policy is in effect at the enterprise in question preventing ordinary users from running the msiexec.exe executable. For this reason a per-user repair can not be initiated for these users using msiexec.exe directly. It doesn't matter if the command is called from a script or from another compiled executable.
To access the Windows Installer functionality and perform the repair, the Windows Installer automation interface or its API (from MSI.DLL) must be used to initiate the operation. Although I am sure there are several more or less ugly hacks around the domain group policy, for example making a copy of the msiexec.exe file and renaming and/or editing its contents and then running it, these types of solutions are not what I am looking for.
I'd favor fixing the policy rather than chasing down ugly hacks, but maybe that's just me....
Never heard of a policy that wouldn't even let a user execute msiexec.exe...why? With proper user lockdown they can't install programs anyway.
Posted by:
anonymous_9363
16 years ago
ORIGINAL: aogilmorIt does seem bizarre to block MSIExec when it can be bypassed by another route but then I gave up questioning management decrees years ago. They're generally sourced from a bigoted POV in the first place and no amount of engaging head with wall will change that.
I'd favor fixing the policy rather than chasing down ugly hacks, but maybe that's just me....
Posted by:
AngelD
16 years ago
Posted by:
aogilmor
16 years ago
Believe me, i've been stuck with my share of bad implementations, like having to do runas and use sanur to do office patches with a vbscript. Even that would do no good here; he needs to apply user settings and it would apply under the wrong user context. Is there anything you could run under an admin context that'll kick off a reinstall of all users' settings? Not to my knowledge.....
Posted by:
yshariff
16 years ago
Hello, I have written a script to run a MSi along with multiple instances of transforms and it throws an error called script time exceeded....
'==========================================================================
'
' APPLICATION NAME: Adobe Acrobat 9 Standard
' AUTHOR: DDS
' DATE : 7/092008
' COMMENT: Script to install Adobe Acrobat 9 Standard Version 9
'
'==========================================================================
On Error Resume Next
'--------------------------------------------------------------------------
'Set Variables
'--------------------------------------------------------------------------
Set WshShell = CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
Set WshNetwork = WScript.CreateObject("WScript.Network")
DATE = WshShell.ExpandEnvironmentStrings("%DATE%")
TIME = WshShell.ExpandEnvironmentStrings("%TIME%")
DATE_TIME = DATE & ":" & TIME &"-"
'---------------------------------------------------------------------------
'Script Path
'---------------------------------------------------------------------------
ScriptPath = Left(WScript.ScriptFullName, Len(WScript.ScriptFullName) - Len(WScript.ScriptName))
AppName = "AcroStan.msi"
AppName1 = "1031.mst"
AppName2 = "1033.mst"
AppName3 = "1036.mst"
'---------------------------------------------------------------------------
'LogFile
'---------------------------------------------------------------------------
'Check for temp folder and create if not present
if Not fso.FolderExists ("C:\Program Files\\Logs\Adobe\Acrobat 9.0") Then
fso.CreateFolder "C:\Program Files\"
fso.CreateFolder "C:\Program Files\DDS"
fso.CreateFolder "C:\Program Files\Logs"
fso.CreateFolder "C:\Program Files\\DDS\Logs\Adobe\Acrobat 9.0"
end If
Set LogFile = fso.CreateTextFile("C:\Program Files\BNYMELLON\DDS\Logs\Adobe\Acrobat 9.0\install.log")
LogFile.WriteLine(DATE_TIME & WshNetwork.UserDomain & "\" & WshNetwork.UserName & " executing on " & WshNetwork.ComputerName)
LogFile.WriteLine(DATE_TIME & "Executing " & WScript.ScriptFullName)
LogFile.WriteLine(DATE_TIME & "Beginning...")
LogFile.WriteLine(DATE_TIME & "Installing Adobe Acrobat 9.0")
'---------------------------------------------------------------------------
' Begins the Install process
'---------------------------------------------------------------------------
Return = WshShell.Run("msiexec/i" chr(34) & ScriptPath &AppName &chr(34) &"TRANSFORMS=" & chr(34) &"AppName1" &chr(34) &"/qb!", 1, True)
If Return = 0 Or Return = 3010 Then
WshShell.Popup AppName & " installation complete!", 10, "Install Status", 64
LogFile.WriteLine( DATE_TIME & "success" )
LogFile.WriteLine( DATE_TIME & "Setup.exe returned " & Return )
Else
WshShell.Popup AppName & " installation failed! Setup returned: " & Return & ".", 10, "Install Status", 16
LogFile.WriteLine( DATE_TIME & "Error...success" )
LogFile.WriteLine( DATE_TIME & "Setup.exe returned " & Return )
End If
'-----------------------------------------------------------------------------
LogFile.Close
'Final Return check
WScript.Quit Return
Please Help Me soughting out this error.
'==========================================================================
'
' APPLICATION NAME: Adobe Acrobat 9 Standard
' AUTHOR: DDS
' DATE : 7/092008
' COMMENT: Script to install Adobe Acrobat 9 Standard Version 9
'
'==========================================================================
On Error Resume Next
'--------------------------------------------------------------------------
'Set Variables
'--------------------------------------------------------------------------
Set WshShell = CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
Set WshNetwork = WScript.CreateObject("WScript.Network")
DATE = WshShell.ExpandEnvironmentStrings("%DATE%")
TIME = WshShell.ExpandEnvironmentStrings("%TIME%")
DATE_TIME = DATE & ":" & TIME &"-"
'---------------------------------------------------------------------------
'Script Path
'---------------------------------------------------------------------------
ScriptPath = Left(WScript.ScriptFullName, Len(WScript.ScriptFullName) - Len(WScript.ScriptName))
AppName = "AcroStan.msi"
AppName1 = "1031.mst"
AppName2 = "1033.mst"
AppName3 = "1036.mst"
'---------------------------------------------------------------------------
'LogFile
'---------------------------------------------------------------------------
'Check for temp folder and create if not present
if Not fso.FolderExists ("C:\Program Files\\Logs\Adobe\Acrobat 9.0") Then
fso.CreateFolder "C:\Program Files\"
fso.CreateFolder "C:\Program Files\DDS"
fso.CreateFolder "C:\Program Files\Logs"
fso.CreateFolder "C:\Program Files\\DDS\Logs\Adobe\Acrobat 9.0"
end If
Set LogFile = fso.CreateTextFile("C:\Program Files\BNYMELLON\DDS\Logs\Adobe\Acrobat 9.0\install.log")
LogFile.WriteLine(DATE_TIME & WshNetwork.UserDomain & "\" & WshNetwork.UserName & " executing on " & WshNetwork.ComputerName)
LogFile.WriteLine(DATE_TIME & "Executing " & WScript.ScriptFullName)
LogFile.WriteLine(DATE_TIME & "Beginning...")
LogFile.WriteLine(DATE_TIME & "Installing Adobe Acrobat 9.0")
'---------------------------------------------------------------------------
' Begins the Install process
'---------------------------------------------------------------------------
Return = WshShell.Run("msiexec/i" chr(34) & ScriptPath &AppName &chr(34) &"TRANSFORMS=" & chr(34) &"AppName1" &chr(34) &"/qb!", 1, True)
If Return = 0 Or Return = 3010 Then
WshShell.Popup AppName & " installation complete!", 10, "Install Status", 64
LogFile.WriteLine( DATE_TIME & "success" )
LogFile.WriteLine( DATE_TIME & "Setup.exe returned " & Return )
Else
WshShell.Popup AppName & " installation failed! Setup returned: " & Return & ".", 10, "Install Status", 16
LogFile.WriteLine( DATE_TIME & "Error...success" )
LogFile.WriteLine( DATE_TIME & "Setup.exe returned " & Return )
End If
'-----------------------------------------------------------------------------
LogFile.Close
'Final Return check
WScript.Quit Return
Please Help Me soughting out this error.
Posted by:
AngelD
16 years ago
Posted by:
AngelD
16 years ago
Posted by:
anonymous_9363
16 years ago
You will never get the timeout value right. Too low and the same will happen, too high and scripts could potentially lock up the machine.
Use WMI to create the process and get its Process ID then build a loop (with its own timeout) to check for when that Process ID no longer exists. Alternatively, given your basic scripting capability (no slight intended, BTW), build a loop which checks for the existence of the products 'Uninstall' registry entry, since creating that entry is one of the last things which the WI engine does.
Use WMI to create the process and get its Process ID then build a loop (with its own timeout) to check for when that Process ID no longer exists. Alternatively, given your basic scripting capability (no slight intended, BTW), build a loop which checks for the existence of the products 'Uninstall' registry entry, since creating that entry is one of the last things which the WI engine does.
Rating comments in this legacy AppDeploy message board thread won't reorder them,
so that the conversation will remain readable.
so that the conversation will remain readable.