Issue with installing exe from MSI
Hello,
I got a Package "Odyssey 4.8", its a Vendor MSI which call exe in it.
Installation works fine..
During Uninstallation,I have added vbscript in msi for uninstallation of exe and after that I have added Custom action to delete application folder after UninstallDriver Custom action.
I have put UninstallDriver Custom action in Synchronous mode still the Uninstallation of MSI finishes first and uninstallation of exe continues..
Is there any way to hold that Custom action "UninstallDriver" till it finishes in MSI?
I have added following Custom action in MSI in Immediate Execution
Return = WshShell.Run("C:\Program Files\Juniper Networks\Odsyssey Acces client\uninstall.exe", , true)
Custom action works fine but MSI finishes its Uninstallation and exit while execution of exe continues..
Thanks in advance !
I got a Package "Odyssey 4.8", its a Vendor MSI which call exe in it.
Installation works fine..
During Uninstallation,I have added vbscript in msi for uninstallation of exe and after that I have added Custom action to delete application folder after UninstallDriver Custom action.
I have put UninstallDriver Custom action in Synchronous mode still the Uninstallation of MSI finishes first and uninstallation of exe continues..
Is there any way to hold that Custom action "UninstallDriver" till it finishes in MSI?
I have added following Custom action in MSI in Immediate Execution
Return = WshShell.Run("C:\Program Files\Juniper Networks\Odsyssey Acces client\uninstall.exe", , true)
Custom action works fine but MSI finishes its Uninstallation and exit while execution of exe continues..
Thanks in advance !
0 Comments
[ + ] Show comments
Answers (9)
Please log in to answer
Posted by:
anonymous_9363
14 years ago
Nice. Here's something I knocked up a while ago, to sit and wait for one of those wretched Java-based setups to finish. Ignore the tests for Custom Action - I've been including that code in all my scripts for eons and can't be bothered to remove it. I've left in the Constants for Wordpad and Notepad so that you can test and tweak before letting it loose.
'// Ian Northwood, DeepNet Limited. Programming obfuscation a speciality
Option Explicit
Dim blnResult
Dim blnIsCustomAction
Dim intIndex
Dim blnIsError
Dim strMsg
Dim objFSO
Dim objWSHShell
Dim objWSHShellApp
Dim objWMIService
Dim objEventSink
Dim strScriptFullName
Dim strScriptName
Dim strScriptRoot
Dim strScriptPath
Dim strScriptAppDrive
Dim dicArguments
Dim intWaitCounter
Dim intMaxTime
Dim blnProcessTerminated
Const intFSOForReading = 1
Const intFSOForWriting = 2
Const intFSOForAppending = 8
Const intFSOTristateFalse = 0
Const strNameSeparator = "|"
Const strProcessToStart = "SETUP.EXE"
Const strProcessToWatch = "JAVAW.EXE"
'Const strProcessToStart = "NOTEPAD.EXE"
'Const strProcessToWatch = "WORDPAD.EXE"
Call Main
Call CleanUp
Sub Main
Dim blnMainResult
Dim strPrimaryProcess
Dim strPrimaryProcessPath
Dim strSecondaryProcess
Dim lngProcessID
intMaxTime = 900 '// 15 minutes!
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objWSHShell = CreateObject("Wscript.Shell")
Set objWSHShellApp = CreateObject("Shell.Application")
Set dicArguments = CreateObject("Scripting.Dictionary")
Set objWMIService = GetObject("WINMGMTS:{impersonationLevel=impersonate,(Security)}!\\.\ROOT\CIMV2")
dicArguments.CompareMode = vbTextcompare '// Ignore case in command-line arguments
'//------------------------------------------------------------------------------------------------------------//
'// Set some variables for script usage
'//------------------------------------------------------------------------------------------------------------//
With objFSO
strScriptFullName = WScript.ScriptFullName
strScriptName = WScript.ScriptName
strScriptRoot = .GetFile(strScriptFullName).ParentFolder.ParentFolder
strScriptPath = .GetFile(strScriptFullName).ParentFolder
strScriptAppDrive = .GetFile(strScriptFullName).Drive
End With
'//------------------------------------------------------------------------------------------------------------//
'// Force use of CScript
'//------------------------------------------------------------------------------------------------------------//
Call ForceCScriptExecution(True)
blnIsCustomAction = False
On Error Resume Next
If IsObject(Session) Then
'// We may have arrived here because error-trapping is off
If Err.Number = 0 Then
blnIsCustomAction = True
End If
End If
On Error Goto 0
'// Get the folder you want to process and the target folder
If WScript.Arguments.Count < 2 Then
strMsg = "the name of the process you want to "
Select Case WScript.Arguments.Count
Case 0
strMsg = strMsg & "launch"
strPrimaryProcess = InputBox("Enter " & strMsg, "Process Name", strProcessToStart)
If Len(strPrimaryProcess) = 0 Then
blnIsError = True
strMsg = "You must specify " & strMsg
Call Say(strMsg, blnIsError, blnIsCustomAction)
Exit Sub
End If
strMsg = strMsg & "monitor"
strSecondaryProcess = InputBox("Enter " & strMsg, "Process Name", strProcessToWatch)
If Len(strPrimaryProcess) = 0 Then
blnIsError = True
strMsg = "You must specify " & strMsg
Call Say(strMsg, blnIsError, blnIsCustomAction)
Exit Sub
End If
Case 1
strMsg = strMsg & "monitor"
strSecondaryProcess = InputBox("Enter " & strMsg, "Process Name", strProcessToWatch)
If Len(strPrimaryProcess) = 0 Then
blnIsError = True
strMsg = "You must specify " & strMsg
Call Say(strMsg, blnIsError, blnIsCustomAction)
Exit Sub
End If
Case Else
strMsg = strMsg & "monitor"
strSecondaryProcess = InputBox("Enter " & strMsg, "Process Name", strProcessToWatch)
If Len(strPrimaryProcess) = 0 Then
blnIsError = True
strMsg = "You must specify " & strMsg
Call Say(strMsg, blnIsError, blnIsCustomAction)
Exit Sub
End If
End Select
Else
strPrimaryProcess = WScript.Arguments(0)
strSecondaryProcess = WScript.Arguments(1)
End If
'// Create the Event Notification sink
Set objEventSink = CreateObject("WbemScripting.SWbemSink")
WScript.ConnectObject objEventSink,"EVENTSINK_"
'// If the Primary Process name contains a backslash, then we need to parse the path.
'// If it doesn't, we can use the script's path
intIndex = InStrRev(strPrimaryProcess, "\")
If intIndex > 0 Then
strPrimaryProcessPath = Mid(strPrimaryProcess, 1, intIndex - 1)
strPrimaryProcess = Mid(strPrimaryProcess, intIndex+1, Len(strPrimaryProcess) - intIndex)
Else
strPrimaryProcessPath = strScriptPath
End If
blnMainResult = ProcessLaunch(strPrimaryProcess, strPrimaryProcessPath)
If Not blnMainResult Then
'// Failed to start process
Exit Sub
End If
'// Wait for a short delay, find the secondary process and get its process ID, ready to watch that process
Call Sleep(10)
blnMainResult = FindProcess(".", strSecondaryProcess, lngProcessID)
If Not blnMainResult Then
'// Failed to find secondary process
Exit Sub
End If
Call WatchProcess(lngProcessID)
Do While blnProcessTerminated = False
intWaitCounter = intWaitCounter + 1
Wscript.Sleep(1000)
strMsg = "Waiting..." & intWaitCounter & ", " & intMaxTime
Call Say(strMsg, blnIsError, blnIsCustomAction)
If intWaitCounter > intMaxTime Then
blnIsError = True
strMsg = String(3, vbCRLF) & "Process ID:" & lngProcessID & " timed out at " & Now()
Call Say(strMsg, blnIsError, blnIsCustomAction)
blnMainResult = KillProcessByID(lngProcessID)
'blnMainResult = KillProcessByName(strSecondaryProcess)
End If
Loop
End Sub
Sub ForceCScriptExecution(ByVal blnQuoteArguments)
Dim objShellRun
Dim strArgument
Dim strArguments
Dim strCmdLine
Dim intIndex
'// If running in CScript, do nothing
If UCase(Right(WScript.FullName, 11)) = "CSCRIPT.EXE" Then
Exit Sub
End If
If WScript.Arguments.Count > 0 Then
strArguments = ""
'For Each strArgument In WScript.Arguments
' If Len(strArguments) = 0 Then
' strArguments = strArgument
' Else
' strArguments = strArguments & " " & strArgument
' End If
'Next
For intIndex = 0 To (WScript.Arguments.Count - 1)
If Len(strArguments) = 0 Then
strArguments = WScript.Arguments(intIndex)
Else
strArguments = strArguments & " " & WScript.Arguments(intIndex)
End If
Next
If blnQuoteArguments Then
strArguments = Chr(34) & strArguments & Chr(34)
End If
End If
'// If running in WScript, execute the script using CScript
'// and then quit this script
If UCase(Right(WScript.FullName, 11)) = "WSCRIPT.EXE" Then
Set objShellRun = CreateObject("WScript.Shell")
'objShellRun.Run "CSCRIPT.EXE """ & WScript.ScriptFullName & """", 1, False
strCmdLine = "CSCRIPT.EXE "
If InStr(WScript.ScriptFullName, " ") > 0 Then
strCmdLine = strCmdLine & Chr(34)
End If
strCmdLine = strCmdLine & WScript.ScriptFullName
If InStr(WScript.ScriptFullName, " ") > 0 Then
strCmdLine = strCmdLine & Chr(34)
End If
If Len(strArguments) > 0 Then
strCmdLine = strCmdLine & " "
strCmdLine = strCmdLine & strArguments
End If
objShellRun.Run strCmdLine, 1, False
Set objShellRun = Nothing
WScript.Quit
End If
'// If script engine is anything else, quit with an error
WScript.Echo "Unknown scripting engine."
WScript.Quit
End Sub
Function ProcessLaunch(ByVal strProcessName, ByVal strProcessPath)
Dim objProcess
Dim objStartup
Dim objConfig
Dim lngReturn
Dim lngID
Const intSW_HIDE = 0 '// Hides the window and activates another window.
Const intSW_NORMAL = 1 '// Activates and displays a window.
'// If the window is minimised or maximised, the system restores it to the original size and position.
'// An application specifies this flag when displaying the window for the first time.
Const intSW_SHOWMINIMIZED = 2 '// Activates the window, and displays it as a minimised window.
Const intSW_SHOWMAXIMIZED = 3 '// Activates the window, and displays it as a maximised window.
Const intSW_SHOWNOACTIVATE = 4 '// Displays a window in its most recent size and position.
'// This value is similar to SW_SHOWNORMAL, except that the window is not activated.
Const intSW_SHOW = 5 '// Activates the window, and displays it at the current size and position.
Const intSW_MINIMIZE = 6 '// Minimises the specified window, and activates the next top level window in the Z order.
Const intSW_SHOWMINNOACTIVE = 7 '// Displays the window as a minimised window. This value is similar to SW_SHOWMINIMZED,
'// except that the window is not activated.
Const intSW_SHOWNA = 8 '// Displays the window at the current size and position. This value is similar to SW_SHOW,
'// except that the window is not activated.
Const intSW_RESTORE = 9 '// Activates and displays the window. If the window is minimised or maximised, the system
'// restores it to the=original size and position. An application specifies this flag when
'// restoring a minimised window.
Const intSW_SHOWDEFAULT = 10 '// Sets the show state based on the SW_ value that is specified in the STARTUPINFO structure
'// passed to the CreateProcess function by the program that starts the application.
Const intSW_FORCEMINIMIZE = 11 '// Windows Server 2003, Windows 2000, and Windows XP:
'// Minimises a window, even when the thread that owns the window is hung.
'// Only use this flag when minimising windows from a different thread.
ProcessLaunch = False
Set objStartup = objWMIService.Get("Win32_ProcessStartup")
Set objConfig = objStartup.SpawnInstance_
objConfig.ShowWindow = intSW_NORMAL
Set objProcess = objWMIService.Get("Win32_Process")
'Err.Clear
lngReturn = objProcess.Create(strProcessName, strProcessPath, objConfig, lngID)
If lngReturn = 0 Then
blnIsError = False
strMsg = String(3, vbCRLF) & "Process " & strProcessName & ", ID:" & lngID & ", started at " & Now()
Call Say(strMsg, blnIsError, blnIsCustomAction)
Else
blnIsError = True
strMsg = "Failed to launch " & strProcessName & vbCRLF
strMsg = strMsg & "Error " & lngReturn & ":"
Select Case lngReturn
Case 2
strMsg = strMsg & "Access denied."
Case 3
strMsg = strMsg & "Insufficient privilege."
Case 8
strMsg = strMsg & "Unknown failure."
Case 9
strMsg = strMsg & "Path not found."
Case 21
strMsg = strMsg & "Invalid parameter."
End Select
Call Say(strMsg, blnIsError, blnIsCustomAction)
Exit Function
End If
blnProcessTerminated = False
intWaitCounter = 0
ProcessLaunch = True
End Function
Function KillProcessByName(ByVal strName)
Dim strQuery
Dim objProcess
Dim colProcess
KillProcessByName = False
strQuery = ""
strQuery = strQuery & "SELECT "
strQuery = strQuery & "* "
strQuery = strQuery & "FROM "
strQuery = strQuery & "Win32_Process "
strQuery = strQuery & "WHERE "
strQuery = strQuery & "NAME='"
strQuery = strQuery & strName
strQuery = strQuery & "'"
On Error Resume Next
Set colProcess = objWMIService.ExecQuery(strQuery)
If Err.Number = 0 Then
If colProcess.Count <> 0 Then
For Each objProcess In colProcess
objProcess.Terminate()
If Err.Number = 0 Then
blnIsError = False
strMsg = String(3, vbCRLF) & "Process ID:" & lngID & " terminated at " & Now()
objEventSink.Cancel()
blnProcessTerminated = True
KillProcessByName = True
Else
blnIsError = True
strMsg = String(3, vbCRLF) & "Failed to terminate process ID:" & lngID
End If
Call Say(strMsg, blnIsError, blnIsCustomAction)
Next
End If
End If
On Error Goto 0
End Function
Function KillProcessByID(ByVal lngID)
Dim strQuery
Dim objProcess
Dim colProcess
KillProcessByID = False
strQuery = ""
strQuery = strQuery & "SELECT "
strQuery = strQuery & "* "
strQuery = strQuery & "FROM "
strQuery = strQuery & "Win32_Process "
strQuery = strQuery & "WHERE "
strQuery = strQuery & "ProcessID="
strQuery = strQuery & lngID
On Error Resume Next
Set colProcess = objWMIService.ExecQuery(strQuery)
If Err.Number = 0 Then
If colProcess.Count <> 0 Then
For Each objProcess In colProcess
objProcess.Terminate()
If Err.Number = 0 Then
blnIsError = False
strMsg = String(3, vbCRLF) & "Process ID:" & lngID & " terminated at " & Now()
objEventSink.Cancel()
blnProcessTerminated = True
KillProcessByID = True
Else
blnIsError = True
strMsg = String(3, vbCRLF) & "Failed to terminate process ID:" & lngID
End If
Call Say(strMsg, blnIsError, blnIsCustomAction)
Next
End If
End If
On Error Goto 0
End Function
Function FindProcess(ByVal strMachine, ByVal strProcessName, ByRef lngID)
Dim objProcess
Dim colProcess
Dim strName
Dim lngProcID
FindProcess = False
Set colProcess = objWMIService.ExecQuery ("Select * from Win32_Process")
For Each objProcess in colProcess
strName = objProcess.Name
lngProcID = objProcess.ProcessID
If UCase(strName) = UCase(strProcessName) Then
Exit For
End If
Next
If IsEmpty(lngProcID) Then
strMsg = ""
strMsg = strMsg & "Cannot find process '" & strProcessName & "'"
Else
strMsg = ""
strMsg = strMsg & "Process to watch '" & strProcessName & "' has ID: " & lngProcID
FindProcess = True
lngID = lngProcID
End If
Call Say(strMsg, blnIsError, blnIsCustomAction)
Set colProcess = Nothing
End Function
Sub WatchProcess(ByVal lngID)
Dim strQuery
strQuery = ""
strQuery = strQuery & "SELECT "
strQuery = strQuery & "* "
strQuery = strQuery & "FROM "
strQuery = strQuery & "__InstanceOperationEvent "
strQuery = strQuery & "WITHIN 1 "
strQuery = strQuery & "WHERE "
strQuery = strQuery & "TargetInstance "
strQuery = strQuery & "ISA "
strQuery = strQuery & "'Win32_Process' "
strQuery = strQuery & "AND "
strQuery = strQuery & "TargetInstance.ProcessID='"
strQuery = strQuery & lngID & "'"
objWMIService.ExecNotificationQueryAsync objEventSink, strQuery
strMsg = ""
strMsg = strMsg & "Setting watch on process ID: " & lngID
Call Say(strMsg, blnIsError, blnIsCustomAction)
End Sub
Sub EVENTSINK_OnObjectReady(ByVal objInstance, ByVal objAsyncContext)
If objInstance.Path_.Class = "__InstanceDeletionEvent" Then
blnIsError = False
strMsg = String(3, vbCRLF) & "Process ID:" & objInstance.TargetInstance.ProcessID & " completed at " & Now()
Call Say(strMsg, blnIsError, blnIsCustomAction)
objEventSink.Cancel()
blnProcessTerminated = True
End If
End Sub
Sub EVENTSINK_OnCompleted(ByVal objInstance, ByVal objAsyncContext)
blnIsError = False
strMsg = "ExecQueryAsync completed"
Call Say(strMsg, blnIsError, blnIsCustomAction)
blnProcessTerminated = True
End Sub
Sub Say(ByVal strMsgText, ByVal blnError, ByVal blnCustomAction)
Dim intMSILogMsgType
Dim intEventLogMsgType
Dim objMSIRecord
Const intLogEventSuccess = 0
Const intLogEventError = 1
Const intLogEventWarning = 2
Const intLogEventInformation = 4
Const intLogEventAuditSuccess = 8
Const intLogEventAuditFailure = 16
Const msiMessageTypeFatalExit = &H00000000 '// Premature termination, possibly fatal out of memory.
Const msiMessageTypeError = &H01000000 '// Formatted error message, [1] is message number in Error table.
Const msiMessageTypeWarning = &H02000000 '// Formatted warning message, [1] is message number in Error table.
Const msiMessageTypeUser = &H03000000 '// User request message, [1] is message number in Error table.
Const msiMessageTypeInfo = &H04000000 '// Informative message for log, not to be displayed.
Const msiMessageTypeFilesInUse = &H05000000 '// List of files in use that need to be replaced.
Const msiMessageTypeResolveSource = &H06000000 '// Request to determine a valid source location.
Const msiMessageTypeOutOfDiskSpace = &H07000000 '// Insufficient disk space message.
Const msiMessageTypeActionStart = &H08000000 '// Start of action,
'// [1] action name,
'// [2] description,
'// [3] template for ACTIONDATA messages.
Const msiMessageTypeActionData = &H09000000 '// Action data. Record fields correspond to the template of ACTIONSTART message.
Const msiMessageTypeProgress = &H0A000000 '// Progress bar information. See the description of record fields below.
Const msiMessageTypeCommonData = &H0B000000 '// To enable the Cancel button set [1] to 2 and [2] to 1.
'// To disable the Cancel button set [1] to 2 and [2] to 0
If blnError Then
intMSILogMsgType = msiMessageTypeError
intEventLogMsgType = intLogEventError
Else
intMSILogMsgType = msiMessageTypeInfo
intEventLogMsgType = intLogEventSuccess
End If
If blnCustomAction Then
Set objMSIRecord = Session.Installer.CreateRecord(0)
objMSIRecord.StringData(0) = strMsgText
Session.Message intMSILogMsgType, objMSIRecord
Set objMSIRecord = Nothing
Else
'// Make an entry in Event Log
objWSHShell.LogEvent intEventLogMsgType, strMsg
WScript.Echo strMsgText
End If
End Sub
Sub Sleep(ByVal intSleepPeriod)
'// Timer returns the number of seconds that have elapsed since midnight.
Dim intStartTime
Dim intEndTime
Dim intCurrentTime
On Error Resume Next
intStartTime = Timer
intEndTime = intStartTime + intSleepPeriod
Do While Timer <= intEndTime
Loop
On Error Goto 0
End Sub
Sub CleanUp
Set objWMIService = Nothing
Set objFSO = Nothing
Set objWSHShellApp = Nothing
Set objWSHShell = Nothing
Set dicArguments = Nothing
End Sub
Posted by:
anonymous_9363
14 years ago
Posted by:
Lee_555
14 years ago
Posted by:
jcarri06
14 years ago
I'm not sure whether the MSI itself offers this kind of functionality, but if you're willing to script a little more logic, you could change your custom action to call a script that:
1. Launches the uninstall.exe as you already have
2. Builds a check point while loop that does "while so and so is running, wait 1 second"
This will keep your script engaged while the uninstall finishes whatever it does and when the process ends, it will quit and continue with the MSI actions.
- Jay
EDIT: just in case, "so and so" is whatever the name of the child process that uninstall.exe calls :)
1. Launches the uninstall.exe as you already have
2. Builds a check point while loop that does "while so and so is running, wait 1 second"
This will keep your script engaged while the uninstall finishes whatever it does and when the process ends, it will quit and continue with the MSI actions.
- Jay
EDIT: just in case, "so and so" is whatever the name of the child process that uninstall.exe calls :)
Posted by:
jcarri06
14 years ago
K..not doing much else right now, so here you go:
I'm not a big VBscripter so all your experts out there...be nice :) lol.
- Jay
Dim objSysInfo
Dim Process, strObject, SOANDSOPROCESS
Dim isProcessrunning
Set objSysInfo = CreateObject("winNTSystemInfo")
strObject = "winmgmts://" & objSysInfo.ComputerName
SOANDSOPROCESS = "WHATEVER.EXE"
IsProcessRunning = true
Do While isProcessRunning = true
isProcessRunning = false
For Each Process in GetObject( strObject ).InstancesOf( "win32_process" )
If UCase( Process.name ) = UCase( SOANDSOPROCESS ) Then
IsProcessRunning = True
End If
Next
WScript.Sleep(1000)
Loop
I'm not a big VBscripter so all your experts out there...be nice :) lol.
- Jay
Posted by:
Lee_555
14 years ago
Thanks Guys !!
Its resolved now....I have added following Custom action in Msi to check for files till it gets uninstalled and then executing removing of Application folder.
So until "uninstall.exe" doesn't uninstall all files, following Custom exection will be in loop.
sFlag="False"
Set fso = CreateObject("Scripting.FileSystemObject")
Do Until SFlag = "True"
If NOT fso.FileExists("C:\Program Files\Common Files\Juniper Networks\Tunnel Manager\Uninstall.exe") AND _
NOT fso.FileExists("C:\Program Files\Common Files\Juniper Networks\JSCDT\jnprShare.dll") AND _
NOT fso.FileExists("C:\Program Files\Common Files\Juniper Networks\TNC Client\uninstall.exe") AND _
NOT fso.FileExists("C:\Program Files\Common Files\Juniper Networks\JUNS\Uninstall.exe") AND _
NOT fso.FileExists("C:\Program Files\Common Files\Juniper Networks\JNPRNA\nsStatsDump.exe") AND _
NOT fso.FileExists("C:\Program Files\Juniper Networks\Odyssey Access Client\uninst.exe") AND Then
strFolder = oWshShell.ExpandEnvironmentStrings("%ProgramFiles%") & "\Juniper Networks\Odyssey Access Client"
If (objFSO.FolderExists(strFolder)) Then
objFSO.DeleteFolder(strFolder),true
End If
Thanks again for giving me ideas.....
Its resolved now....I have added following Custom action in Msi to check for files till it gets uninstalled and then executing removing of Application folder.
So until "uninstall.exe" doesn't uninstall all files, following Custom exection will be in loop.
sFlag="False"
Set fso = CreateObject("Scripting.FileSystemObject")
Do Until SFlag = "True"
If NOT fso.FileExists("C:\Program Files\Common Files\Juniper Networks\Tunnel Manager\Uninstall.exe") AND _
NOT fso.FileExists("C:\Program Files\Common Files\Juniper Networks\JSCDT\jnprShare.dll") AND _
NOT fso.FileExists("C:\Program Files\Common Files\Juniper Networks\TNC Client\uninstall.exe") AND _
NOT fso.FileExists("C:\Program Files\Common Files\Juniper Networks\JUNS\Uninstall.exe") AND _
NOT fso.FileExists("C:\Program Files\Common Files\Juniper Networks\JNPRNA\nsStatsDump.exe") AND _
NOT fso.FileExists("C:\Program Files\Juniper Networks\Odyssey Access Client\uninst.exe") AND Then
strFolder = oWshShell.ExpandEnvironmentStrings("%ProgramFiles%") & "\Juniper Networks\Odyssey Access Client"
If (objFSO.FolderExists(strFolder)) Then
objFSO.DeleteFolder(strFolder),true
End If
Posted by:
anonymous_9363
14 years ago
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.