Uninstalling an old version from within msi
Hi,
I am creating an msi file to install a program but if the old version is already installed on the pc it needs to have the old version uninstalled first. I will be running the msi with a transform file but have edited the msi to include a custom script to check if the old version is installed first and if so uninstall it before installing the new version.
However when I run the cmd line for the msi and mst it errors saying that there is an old version on the pc already so it is obviously ignoring my line in the script to uinstall.
This is the script I have got:-
Option Explicit
Dim objShell, objFSO, WScript, strcomputer, strPath
Set objShell = CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
strPath = "C:\Program Files\Bentley\MX"
' ####### Search PC for Bentley MX V8 #######
' ###########################################
If objFSO.FileExists("C:\Program Files\Bentley\MX\mfw\inst\uninst\setup.exe") Then
'#### Uninstall old Bentley MX V8 ####
'#####################################
CopyFile "\\ntserv01\sms\Bentley XM\Bentley MX\Bentley MX V8 XM\setup.iss", "C:\Program Files\Bentley\MX\mfw\inst\uninst\"
objShell.Run "cmd /c CD c:.. & cd Program Files\Bentley\MX\mfw\inst\uninst\ & setup.exe -s -f1setup.iss"
'WScript.Sleep(150000)
End If
' ######## CopyFile Function ########
Sub CopyFile(strSource, strDest)
Dim lfsObject
Dim Source
On Error Resume Next
Set lfsObject = CreateObject("Scripting.FileSystemObject")
Set Source = lfsObject.GetFile(strSource)
Source.Copy strDest
Set lfsObject = nothing
If Err.Number <> 0 Then WriteErr( strUserID & ": Copy " & strSource & " to " & strDest & " " & Err.Description & " " & Now() )
End Sub
'WScript.quit
The copy file part works so I know it is running the script and detects the old version on there but it seems to not even attempt to uninstall it.
Can anyone offer me some advice to how to get this to work? I am new to scripting and have never done custom actions in msi before!
Thanks
I am creating an msi file to install a program but if the old version is already installed on the pc it needs to have the old version uninstalled first. I will be running the msi with a transform file but have edited the msi to include a custom script to check if the old version is installed first and if so uninstall it before installing the new version.
However when I run the cmd line for the msi and mst it errors saying that there is an old version on the pc already so it is obviously ignoring my line in the script to uinstall.
This is the script I have got:-
Option Explicit
Dim objShell, objFSO, WScript, strcomputer, strPath
Set objShell = CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
strPath = "C:\Program Files\Bentley\MX"
' ####### Search PC for Bentley MX V8 #######
' ###########################################
If objFSO.FileExists("C:\Program Files\Bentley\MX\mfw\inst\uninst\setup.exe") Then
'#### Uninstall old Bentley MX V8 ####
'#####################################
CopyFile "\\ntserv01\sms\Bentley XM\Bentley MX\Bentley MX V8 XM\setup.iss", "C:\Program Files\Bentley\MX\mfw\inst\uninst\"
objShell.Run "cmd /c CD c:.. & cd Program Files\Bentley\MX\mfw\inst\uninst\ & setup.exe -s -f1setup.iss"
'WScript.Sleep(150000)
End If
' ######## CopyFile Function ########
Sub CopyFile(strSource, strDest)
Dim lfsObject
Dim Source
On Error Resume Next
Set lfsObject = CreateObject("Scripting.FileSystemObject")
Set Source = lfsObject.GetFile(strSource)
Source.Copy strDest
Set lfsObject = nothing
If Err.Number <> 0 Then WriteErr( strUserID & ": Copy " & strSource & " to " & strDest & " " & Err.Description & " " & Now() )
End Sub
'WScript.quit
The copy file part works so I know it is running the script and detects the old version on there but it seems to not even attempt to uninstall it.
Can anyone offer me some advice to how to get this to work? I am new to scripting and have never done custom actions in msi before!
Thanks
0 Comments
[ + ] Show comments
Answers (21)
Please log in to answer
Posted by:
anonymous_9363
15 years ago
objShell.Run "cmd /c CD c:.. & cd Program Files\Bentley\MX\mfw\inst\uninst\ & setup.exe -s -f1setup.iss"Hi, Sarah. I can't see how this part of the script would ever run. Apart from anything else, you'd need quote marks around the paths. I wouldn't bother with launching CMD, either, as you're launching a console which then runs a windowing app! How about (untested, just OTTOMH):
Dim strCmdLine
strPath = strPath & "\mfw\inst\uninst"
strCmdLine = Chr(34) & strPath & "\setup.exe & Chr(34) & " -s -f1" & Chr(34) & strPath & Chr(34) & "\setup.iss" & Chr(34)
objShell.Run strCmdLine
Posted by:
SarahG
15 years ago
Posted by:
anonymous_9363
15 years ago
Posted by:
SarahG
15 years ago
Posted by:
jmpouliot
15 years ago
Posted by:
anonymous_9363
15 years ago
ORIGINAL: jmpouliotJean, you have assumed that the old install was MSI-based. The giveaway that it isn't is the reference to an ISS file. These are files containing recorded installation steps and get passed to an InstallShield set-up stub executeable.
Why don't you use the uninstall registry key?? located in
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
and do a simple script which will get the uninstall string.
Posted by:
jmpouliot
15 years ago
ORIGINAL: VBScab
ORIGINAL: jmpouliotJean, you have assumed that the old install was MSI-based. The giveaway that it isn't is the reference to an ISS file. These are files containing recorded installation steps and get passed to an InstallShield set-up stub executeable.
Why don't you use the uninstall registry key?? located in
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
and do a simple script which will get the uninstall string.
yeah I forgot, you got a point !!
Posted by:
SarahG
15 years ago
Posted by:
anonymous_9363
15 years ago
Posted by:
timmsie
15 years ago
Posted by:
SarahG
15 years ago
Posted by:
SarahG
15 years ago
In my script it copies the iss file to the pc and then is supposed to run the uninstall using the iss file. I have run the msi + mst and logged it and it comes back with the Return value of 0 but I have checked and it has copied the iss file, it just never seems to of run the uninstall.
Below is a copy of my script incase you can spot anything obvious?!?! Also, it didn't like wscript.sleep command, what command can I use to make it wait a couple of mins for the uninstall to happen before it moves onto the next action?
Dim strCmdLine, objShell, strpath
Set objShell = CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
strPath = "C:\Program Files\Bentley\MX\mfw\inst\uninst"
'If objFSO.FileExists(Chr(34) & strPath & "\setup.exe" & Chr(34)) Then
'#### Uninstall old Bentley MX V8 ####
'#####################################
CopyFile "\\ntserv01\sms\Bentley XM\Bentley MX\Bentley MX V8 XM\setup.iss", strpath & "\"
strCmdLine = Chr(34) & strPath & "\setup.exe" & Chr(34) & " -s -f1" & Chr(34) & strPath & "\setup.iss" & Chr(34)
objShell.Run strCmdLine
' WScript.Sleep(150000)
'End If
' ######## CopyFile Function ########
Sub CopyFile(strSource, strDest)
Dim lfsObject
Dim Source
On Error Resume Next
Set lfsObject = CreateObject("Scripting.FileSystemObject")
Set Source = lfsObject.GetFile(strSource)
Source.Copy strDest
Set lfsObject = nothing
If Err.Number <> 0 Then WriteErr( strUserID & ": Copy " & strSource & " to " & strDest & " " & Err.Description & " " & Now() )
End Sub
Below is a copy of my script incase you can spot anything obvious?!?! Also, it didn't like wscript.sleep command, what command can I use to make it wait a couple of mins for the uninstall to happen before it moves onto the next action?
Dim strCmdLine, objShell, strpath
Set objShell = CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
strPath = "C:\Program Files\Bentley\MX\mfw\inst\uninst"
'If objFSO.FileExists(Chr(34) & strPath & "\setup.exe" & Chr(34)) Then
'#### Uninstall old Bentley MX V8 ####
'#####################################
CopyFile "\\ntserv01\sms\Bentley XM\Bentley MX\Bentley MX V8 XM\setup.iss", strpath & "\"
strCmdLine = Chr(34) & strPath & "\setup.exe" & Chr(34) & " -s -f1" & Chr(34) & strPath & "\setup.iss" & Chr(34)
objShell.Run strCmdLine
' WScript.Sleep(150000)
'End If
' ######## CopyFile Function ########
Sub CopyFile(strSource, strDest)
Dim lfsObject
Dim Source
On Error Resume Next
Set lfsObject = CreateObject("Scripting.FileSystemObject")
Set Source = lfsObject.GetFile(strSource)
Source.Copy strDest
Set lfsObject = nothing
If Err.Number <> 0 Then WriteErr( strUserID & ": Copy " & strSource & " to " & strDest & " " & Err.Description & " " & Now() )
End Sub
Posted by:
anonymous_9363
15 years ago
ORIGINAL: SarahGYou can't use any 'WScript[dot]' directive bcause that is explicitly for Windows Scripting Host. The VB Script engine in Windows Installer is self-contained and knows nothing of WSH.
Also, it didn't like wscript.sleep command, what command can I use to make it wait a couple of mins for the uninstall to happen before it moves onto the next action?
Here's a delay Sub:
Sub Sleep(ByVal intDelayInSecs)
Dim datStart
Dim blnCompleted
datStart = Now()
blnCompleted = False
While Not blnCompleted
If DateDiff("s", datStart, Now()) >= CInt(intDelayInSecs) Then
blnCompleted = True
End If
Wend
End Sub
However, because your script has no control over how long the uninstall will take, it would be much neater to wait in a loop until the folder has been deleted, then wait another couple of seconds, THEN continue.On that point, I wonder if the uninstall is failing because it's trying to remove the folder but cannot because it contains the ISS file? Try copying the ISS file to %TEMP% instead.
Posted by:
SarahG
15 years ago
Ahh so is that why my uninstall isn't working as I have the line Set objShell = CreateObject("WScript.Shell") in there? How do I go about running the uninstall then without using that wscript.shell??
Thanks for the delay sub, do I run it by having sleep 120 in there?
Sorry for my apparent ignorance at this scripting malarky, as I said, I am new to it especially now I can't use wscript!
Thanks for the delay sub, do I run it by having sleep 120 in there?
Sorry for my apparent ignorance at this scripting malarky, as I said, I am new to it especially now I can't use wscript!
Posted by:
anonymous_9363
15 years ago
Posted by:
SarahG
15 years ago
Ahh, after leaving my pc alone for a while after I thought it had failed I noticed that the uninstall part carried on and finally did uninstall the product. I added in your sleep sub and now it has time to uninstall before the new install starts! :) HURRAH! So it looks like it was the wscript.sleep line that was the problem all along!
If I have the old version of the software installed and I comment out the IF statement lines it runs fine, uninstalls and installs new version. However, I do need it to check if the old product exists on the pc so it only runs the script if the software exists and ignores the script if it isn't installed. Should I be able to use IF statements in MSI VB Scripting or is it a different type of code for this?
Many thanks for all your help so far VBScab, Very Much Appreciated!! :)
If I have the old version of the software installed and I comment out the IF statement lines it runs fine, uninstalls and installs new version. However, I do need it to check if the old product exists on the pc so it only runs the script if the software exists and ignores the script if it isn't installed. Should I be able to use IF statements in MSI VB Scripting or is it a different type of code for this?
Many thanks for all your help so far VBScab, Very Much Appreciated!! :)
Posted by:
anonymous_9363
15 years ago
There's no reason why you couldn't add it to your script but the "best practise" way to do this would be to create a property and give it a nonsense value, e.g. 0 or "NotPresent". Then you'd use AppSearch to populate that property if a file or registry entry relating to the old product was present. Then, you'd add a condition to the one which your CA hopefully already has (If NOT Installed) which tests for that property NOT being the nonsense value. Thus, if your property was 'ISV5PRESENT' with a default value of 0, your CA's condition would change from
. If NOT Installed
to
. If NOT Installed AND ISV5PRESENT<>0
Do remember to ditch the delay functionality in your release version. I appreciate you're new to scripting but lessons learned now will serve you well in the future. Too many scripts make assumptions about software environments and, whilst they work in a perfect environment, when was the last time YOU worked in such an environment? The sort of thing I'm talking about would be, for example, if your script has code to create a directory, it should check immediately aftertrwards whether that directory got created and not simply rely on an error being generated by the scripting runtime.
Good luck!
. If NOT Installed
to
. If NOT Installed AND ISV5PRESENT<>0
Do remember to ditch the delay functionality in your release version. I appreciate you're new to scripting but lessons learned now will serve you well in the future. Too many scripts make assumptions about software environments and, whilst they work in a perfect environment, when was the last time YOU worked in such an environment? The sort of thing I'm talking about would be, for example, if your script has code to create a directory, it should check immediately aftertrwards whether that directory got created and not simply rely on an error being generated by the scripting runtime.
Good luck!
Posted by:
SarahG
15 years ago
Action ended 10:45:40: AppSearch. Return value 1.
Action start 10:45:40: CheckOldVersionInstalled.
Action ended 10:48:40: CheckOldVersionInstalled. Return value 0.
Posted by:
anonymous_9363
15 years ago
ORIGINAL: SarahGThe value '1' doesn't mean that it's run: it means that it returned a value "ERROR_SUCCESS". Yet another perversity of WI is that the engine translates success values (normally 0 in Wndows) to '1'. So, your log entry 'Return value 0.' means that no success value was returned.
Shouldn't my CheckOldVersionInstalled have a return value of 1 if it has run?
That doesn't necessarily mean that the script failed, only that it didn't reurn a success value.You need to force it to do that.
- Move your code into a function
- Change the script type to 'Executefrom installation' and add the function call name.
- Have your script exit with whatever the return value from the function was. For example:
Dim intReturn
intReturn = Main()
WScript.Quit(intReturn) '// Note that we can use WScript directive here because the script is external to the WI engine
Function Main()
Dim blnReturn
'// Always assume the worst
Main = 3 '// 3 is interpreted as 'Fatal error'
'// Do something which could succeed or fail
blnReturn = CallSomeOtherFunctionOrSub
If blnReturn = False Then
Exit Function
End If
Main = 0
End Function
Now, if the call CallSomeOtherFunctionOrSub is successful, Main returns 0 which WI will translate to 1 and you'll get the desired result.Lastly, I don't think the value being returned in your current script is being acted on, as the install continues even though the CA didn't succeed. Make sure you have the processing option for the CA to NOT ignore errors, if you want the install to stop if removal of th eold version fails.
Posted by:
SarahG
15 years ago
Posted by:
anonymous_9363
15 years ago
Well, if it makes you feel any better, I see scripts like that all the time and is why I keep banging on about robust code. For example, if you're going to use 'On Error Resume Next', you *MUST* check for errors after *EACH* operation. Thus, in your example, the line 'Set Source = lfsObject.GetFile(strSource)' would have produced an error, since (as you now know) the source file doesn't exist.
In my Production code, I typically use a routine which parses a file's path and checks that each part of it exists. Thus, for any error, I can tell the user EXACTLY which folder is missing.
OK, coming the Sleep part, did I say you should ditch it? I think I said you should not rely on a simple delay but should check for the folder's removal. You can do that but you need to retain the delay. Once you've added the robustness noted above, you will know how to test for a folder's existence. Thus, your code might look something like this:
or
NB!
If this were me, I'd build in ANOTHER loop so that, if for some reason the folder didn't get deleted, the script would continue in some capacity. As the code above is now, it would loop forever! I'm sure by now, though, you get the idea.
In my Production code, I typically use a routine which parses a file's path and checks that each part of it exists. Thus, for any error, I can tell the user EXACTLY which folder is missing.
OK, coming the Sleep part, did I say you should ditch it? I think I said you should not rely on a simple delay but should check for the folder's removal. You can do that but you need to retain the delay. Once you've added the robustness noted above, you will know how to test for a folder's existence. Thus, your code might look something like this:
While objFSO.FolderExists(strPath)
Call Delay(1) '// Just twiddle your thumbs for 1 second
Wend
'// Carry on with next part of the script
or
Do
Call Delay(1)
Loop Until Not objFSO.FolderExists(strPath)
'// Carry on with next part of the script
NB!
If this were me, I'd build in ANOTHER loop so that, if for some reason the folder didn't get deleted, the script would continue in some capacity. As the code above is now, it would loop forever! I'm sure by now, though, you get the idea.
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.