Show-ADTInstallationPrompt when using silent mode (Cisco Secure Client)

Hi there,

in Version 3.x of the PSADT there was a workaround to show the Show-InstallationWelcome even when the app was deployed in silent mode.

This was very useful when the application was deployed via Intune and needed to be installed as System and the user needed to be informed that one of the applications is using this program (VPN, Java etc.)

I asked this question 3 years ago but maybe this has implemented in v4. (forum thread)

Did anyone know how to realize with v4 of the Toolkit?

Thanks
_shorty

I am not sure what you are asking for here.
Apps deployed in Silent mode are not the same as PSADT being Silent, as you can customise the Toolkit as verbose or silent as you like while still installing the app silently.
I have a hunch you might be referring to using ServiceUI.exe to bring the PSADT dialogs shown in the SYSTEM context, through to the user context - This is common practice when deploying System apps via Intune. (Although the future version 4.1.0 of PSADT aims to get rid of this ServiceUI requirement)
Have you had a read of the Show-ADTInstallationWelcome reference page?

A workaround for what I think you are trying to achieve could be to put an if statement around your code that detects if any of the apps are running before you call the Show-ADTInstallationWelcome function
Here is an example I use for Firefox to do something similar - If the firefox process is / was running before hand, the Show-ADTInstallationWelcome dialog and the Show-ADTInstallationProgress will ā€˜only’ show in this scenario, if firefox is not running, the Show-ADTInstallationWelcome dialog won’t be displayed nor will the Show-ADTInstallationProgress dialog i.e. install appears silent:

if (Get-Process 'Firefox' -ErrorAction SilentlyContinue) {
            #Process is running
            ## Show Welcome Message, close any defined apps if required, allow up to 3 deferrals, verify there is enough disk space to complete the install, and persist the prompt
            # 'Default' 3 Deferal Install
            Show-ADTInstallationWelcome -CloseProcesses 'Firefox=Mozilla Firefox' -NoMinimizeWindows $false -AllowDeferCloseProcesses -DeferTimes 3 -CheckDiskSpace -PersistPrompt -NotTopMost $true
            ## Show Progress Message (with the default message)
            Show-ADTInstallationProgress
        } else {
            #Process is not running
            ## Show Welcome Message, close any defined apps if required, allow up to 3 deferrals, verify there is enough disk space to complete the install, and persist the prompt
            # 'Default' 3 Deferal Install
            Show-ADTInstallationWelcome -CloseProcesses 'Firefox=Mozilla Firefox' -NoMinimizeWindows $false -AllowDeferCloseProcesses -DeferTimes 3 -CheckDiskSpace -PersistPrompt -NotTopMost $true
        }

N.B. I’m sure there are simpler / tidier ways to achieve this, but it works for me

2 Likes

I’m trying to do something like this and the Show-ADTInstallationWelcome keeps repeating even after processes have ended. I just need the user to acknowledge their VPN session if running will be closed before the installation runs there are other commands killings processes and services before the installation continues.

# VPN Check Script
$VpnCheck = $true  # Example value, replace with actual parameter
$deployAppScriptFriendlyName = "DeployAppScript"  # Example value, replace with actual parameter

# Global VPN status check
$vpnRunning = $false
if ($VpnCheck) {
    try {
        $vpnRunning = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter 'Description Like "%Cisco AnyConnect%"' | select -ExpandProperty "IPEnabled"
    } catch {
        $vpnRunning = $false
    }
}


If ($vpnRunning) {

Show-ADTInstallationWelcome -CloseProcesses @{ Name = 'vpnui'; Description = 'Cisco VPN' }, @{ Name = 'csc_ui'; Description = 'Cisco VPN' }, @{ Name = 'cscm'; Description = 'Cisco' }, @{ Name = 'vpnagent'; Description = 'Cisco' } -AllowDeferCloseProcesses -DeferTimes 3 -CheckDiskSpace -PersistPrompt
Show-InstallationProgress

}

Wow!
That looks so similar to the code I use for detecting if our Cisco Secure Client (AnyConnect) VPN is connected.
Let me dig out my code later, and I’ll explain (I did the VPN check as a function that could be called within the script)

1 Like

My script uses PSADT 3.10.1 so it is a little bit different than v4.0.x. but the logic is still roughly the same, with v3.x I made customisations to the AppDeployToolkitConfig.xml to customise the Messaging showing in the Show-InstallationWelcome dialog

Here is my function (TBH I prefer the idea of yours as it determines if the VPN is connected by expanding the ā€œIPEnabledā€ item to determine if it’s connected (or not) where as mine checks if it has a valid network address allocated - although both will work, the only change I’d make to yours is use Get-CIMInstance instead of Get-WMIObject as there are security issues with WMI that Microsoft have now blocked in ā€˜modern’ PowerShell Core (So you can’t use Get-WMIObject calls in modern Powershell)
For my method to work, you just need to update your network range (or ranges). The reason I like your route means the network range is unimportant.

function Get-VPNStatus {
    [CmdletBinding()]
    param ()
    $VPNAdapters = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -f:"Description like '%Cisco AnyConnect%'"
    [bool]$vpnCheck = $false

    foreach ($VPNAdapter in $VPNAdapters) {
        Write-Log -Message "   VPN Adapter with Service Name $($($VPNAdapter).ServiceName) detected"
        $IPAddresses = $VPNAdapter.IPAddress
        If ((($IPAddresses) -like "192.168.50.*") -or (($IPAddresses) -like "192.168.54.*")) { 
            Write-Log -Message "     WARNING: Device appears to be connected to the User VPN, Will retry later, Pausing for 2 minutes" -Severity 2
            $vpnCheck = $true
            break
            #Start-Sleep 120
            #exit 1618
        } Else {
            Write-Log -Message "     INFORMATION: Device appears not to be connected to the User VPN, can continue"
            $vpnCheck = $false
            break
        }
    }
    return $vpnCheck
  }

Then during the Install (or Uninstall) phase of the script I can call the function to check if the VPN is in use (Connected)

$VPNRunningInitially = $false
    # Determine initial status of VPN, in order to decide if messaging is required
    If (Get-VPNStatus) {
        $VPNRunningInitially = $true
    }

With the Cisco Secure Client you do not need to close (or stop) any apps, so you don’t ā€˜need’ to close any apps as you are doing (TBH it may not work for some of the apps / components due to the way they are loaded during the kernel) what we know (from experience) if you use the Network Access Module you do need to trigger a restart once NAM has installed (or upgraded), but you can silence this in the MSI command line and then get PSADT to prompt the user at the end to restart (as we did before we got rid of NAM and moved to use the native Microsoft 802.1x control with the Cisco VPN).
This shows you our v3.10.1 version of what you could do

    If ($deploymentType -ine 'Uninstall' -and $deploymentType -ine 'Repair') {
        ##*===============================================
        ##* PRE-INSTALLATION
        ##*===============================================
        [String]$installPhase = 'Pre-Installation'

        $DefaultMessage = "Installing $($appVendor) $($appName) v$($appVersion).`n`n"

        If ($VPNRunningInitially) {
            # Show Deferal message only if VPN was connected when install lands
            ## Show Welcome Message, close Internet Explorer if required, allow up to 3 deferrals, verify there is enough disk space to complete the install, and persist the prompt
            Show-InstallationWelcome -MinimizeWindows $false -AllowDefer -DeferTimes 3 -CheckDiskSpace -PersistPrompt -TopMost $true

            ## Show Progress Message (with the default message)
            Show-InstallationProgress -StatusMessage "$($DefaultMessage)Please Wait...`n`n`n"
            Start-Sleep -Seconds 10
        }

        ## <Perform Pre-Installation tasks here>
	    #'PreInstallVariable'

        ##*===============================================
        ##* INSTALLATION
        ##*===============================================
        [String]$installPhase = 'Installation'

        ## Handle Zero-Config MSI Installations
        If ($useDefaultMsi) {
            [Hashtable]$ExecuteDefaultMSISplat = @{ Action = 'Install'; Path = $defaultMsiFile }; If ($defaultMstFile) {
                $ExecuteDefaultMSISplat.Add('Transform', $defaultMstFile)
            }
            Execute-MSI @ExecuteDefaultMSISplat; If ($defaultMspFiles) {
                $defaultMspFiles | ForEach-Object { Execute-MSI -Action 'Patch' -Path $_ }
            }
        }

        ## <Perform Installation tasks here>
	    Write-Log -Message  "====================================================== "
	    Write-Log -Message  "$($appVendor) $($appName) installation PowerShell script "
	    Write-Log -Message  "====================================================== "
	    #  we want to make sure we only proceed if the previous MSI installed correctly.
	    #
	    #  So we need to get and inspect the Exit Code to see if it worked.  This is the most elegant construct:
	    #   $Result = (Start-Process -FilePath "msiexec.exe" -ArgumentList "<<whatever>>" -Wait -Passthru).ExitCode

	    Write-Log -Message "============================================= "
	    Write-Log -Message "Installing $($appVendor) $($appName) components "
	    Write-Log -Message "============================================= "
	    Write-Log -Message "$($appVendor) $($appName) version $($appVersion)"

	    If ($VPNRunningInitially) {
            # Exit with Retry code (1618) if the VPN is up
            Write-Log -Message " - Searching for AnyConnect VPN Adapters..."
            Show-InstallationProgress -StatusMessage "$($DefaultMessage)Checking if VPN is connected...`n`n`n"
            Start-Sleep -Seconds 2

            While (Get-VPNStatus) {
                # Warn that VPN needs to be disconnected
                Show-InstallationProgress -StatusMessage "WARNING: The VPN is connected`nPlease close App 1, App 2, App 3, App 4 and then disconnect the VPN so this upgrade can continue"
            }

            Write-Log -Message "   PROCEEDING: User VPN appears to be disconnected"
            Show-InstallationProgress -StatusMessage "$($DefaultMessage)VPN is not connected...`nProceeding with Install`n`n"
            Start-Sleep -Seconds 2
            
            # Install the Cisco Secure Client
            Show-InstallationProgress -StatusMessage "$($DefaultMessage)Installing the Core/VPN package...`n`n`n"
            Start-Sleep -Seconds 2
	    }
        Write-Log -Message " - Installing the Core/VPN package..."
        if (!(Test-Path -Path "$($dirFiles)\$($CoreVPNmsiPath)")) {
			Write-Log -Message "   WARNING: `""$($dirFiles)\$($CoreVPNmsiPath)"`" does not exist" -Severity 2
		} else {
	        $ArgList = "/norestart /quiet"
            [psobject]$Result = (Execute-MSI -Action Install -Path "$($dirFiles)\$($CoreVPNmsiPath)" -Parameters $($ArgList) -ContinueOnError $False -LogName "Cisco-SecureClient-core-vpn_MSI" -Passthru).ExitCode

            if (! ( ($Result -eq 0) -or ($Result -eq 1707) -or ($Result -eq 3010) -or ($Result -eq 1641) -or ($Result -eq 1638) ) ) {
	            Write-Log -Message "   There was an error installing the Core/VPN package : $Result" -Severity 3
	            Write-Log -Message "   Exiting..." -Severity 3
	            Write-Log -Message $Result
	            exit $Result
	        }
	    }
        If ($VPNRunningInitially) {
            Show-InstallationProgress -StatusMessage "$($DefaultMessage)Installing the Core/VPN package...Done!`n`n`n"
            Start-Sleep -Seconds 2
        }    
        Write-Log -Message "   OK"
        If ($VPNRunningInitially) {
            Show-InstallationProgress -StatusMessage "$($DefaultMessage)Installing the Core/VPN package...Done!`nInstalling the DaRT package...`n`n"
            Start-Sleep -Seconds 2
        }
        Write-Log -Message " - Installing the DaRT package..."
	    if (!(Test-Path -Path "$($dirFiles)\$($DaRTmsiPath)")) {
			Write-Log -Message "   WARNING: `""$($dirFiles)\$($DaRTmsiPath)"`" does not exist" -Severity 2
		} else {
            $ArgList = "/norestart /quiet"
            [psobject]$Result = (Execute-MSI -Action Install -Path "$($dirFiles)\$($DaRTmsiPath)" -Parameters $($ArgList) -ContinueOnError $False -LogName "Cisco-SecureClient-DaRT_MSI" -Passthru).ExitCode

            if (! ( ($Result -eq 0) -or ($Result -eq 1707) -or ($Result -eq 3010) -or ($Result -eq 1641) -or ($Result -eq 1638) ) ) {
                Write-Log -Message "   There was an error installing the DART package : $Result" -Severity 3
                Write-Log -Message "   Exiting..." -Severity 3
                Write-Log -Message $Result
                exit $Result
            }
        }
        If ($VPNRunningInitially) {
            Show-InstallationProgress -StatusMessage "$($DefaultMessage)Installing the Core/VPN package...Done!`nInstalling the DaRT package...Done!`n`n"
            Start-Sleep -Seconds 2
        }
        Write-Log -Message "   OK"
        If ($VPNRunningInitially) {
            Start-Sleep -Seconds 2

            Show-InstallationProgress -StatusMessage "$($DefaultMessage)Transferring configuration files...`n`n`n"
            Start-Sleep -Seconds 2
        }
        Write-Log -Message " - Copying in configuration files..."
		# Copy VPN config to 'C:\ProgramData\Cisco\Cisco Secure Client\VPN\Profile\'
	    $Source = $($VPNConfigFile)
	    $Target = "$($env:ProgramData)\Cisco\Cisco Secure Client\VPN\Profile"

        If ($VPNRunningInitially) {
            Show-InstallationProgress -StatusMessage "$($DefaultMessage)Transferring configuration files...`nVPN Config...`n`n"
            Start-Sleep -Seconds 2
        }
	    if (!(Test-Path -Path "$($dirFiles)\$($Source)")) {
			Write-Log -Message "   WARNING: VPN Config File `"$($Source)`" does not exist in `"$($dirFiles)\`"" -Severity 2
		} else {
			if (Test-Path -Path "$($Target)") {
				Write-Log -Message "   Copying VPN profile to $($Target)\$($Source)..."
				Copy-Item "$($dirFiles)\$($Source)" -Destination "$($Target)" -Force -Verbose | Write-Log
			} else {
				Write-Log -Message "   WARNING: VPN profile target folder $($Target) does not exist" -Severity 2
			}
		}
        If ($VPNRunningInitially) {
            Show-InstallationProgress -StatusMessage "$($DefaultMessage)Transferring configuration files...`nVPN Config...Done!`n`n"
            Start-Sleep -Seconds 2

            Show-InstallationProgress -StatusMessage "$($DefaultMessage)Transferring configuration files...`nVPN Config...Done!`nManagement Tunnel Config...`n"
            Start-Sleep -Seconds 2
        }
	    # Copy management tunnel config to 'C:\ProgramData\Cisco\Cisco Secure Client\VPN\Profile\MgmtTun\'
	    $Source = $($MgmtTunnelFile)
	    $Target = "$($env:ProgramData)\Cisco\Cisco Secure Client\VPN\Profile\MgmtTun"

	    if (!(Test-Path -Path "$($dirFiles)\$($Source)")) {
			Write-Log -Message "   WARNING: Management Tunnel Config File `"$($Source)`" does not exist in `"$($dirFiles)\`"" -Severity 2
			} else {
			if (Test-Path -Path "$($Target)") {
				Write-Log -Message "   Copying MgmtTun profile to $($Target)\$($Source)..."
				Copy-Item "$($dirFiles)\$($Source)" -Destination "$($Target)" -Force -Verbose | Write-Log
			} else {
				Write-Log -Message "   WARNING: MgmtTun target folder $($Target) does not exist" -Severity 2
			}
		}
        If ($VPNRunningInitially) {
            Show-InstallationProgress -StatusMessage "$($DefaultMessage)Transferring configuration files...`nVPN Config...Done!`nManagement Tunnel Config...Done!`n"
            Start-Sleep -Seconds 10

            Show-InstallationProgress -StatusMessage "$($DefaultMessage)Transferring configuration files...Done!`n`n`n"
            Start-Sleep -Seconds 2
        }
	    Write-Log -Message "   Done."

	    Write-Log -Message "Result: $($Result)"
	    #endregion

        ##*===============================================
        ##* POST-INSTALLATION
        ##*===============================================
        [String]$installPhase = 'Post-Installation'

        ## <Perform Post-Installation tasks here>
	
        ## Display a message at the end of the install
        If (-not $useDefaultMsi) {
            # Show-InstallationRestartPrompt -Countdownseconds 305 -CountdownNoHideSeconds 60
        }
    }
 

In Summary what my script does is:

  • Check if the VPN is connected initially
    • If it is, then notify the user we are deploying the software with a Warning they will need to close any of the business apps our users require the VPN for before clicking continue (or Defer if it’s not convenient)
  • Commence the install, if the VPN is found to still be connected, again prompt them to close the business apps and disconnect the VPN before the install will proceed (in the While (Get-VPNStatus) loop
  • Installs the Core/VPN package (with /norestart / quiet Arguments)
  • Installs the DaRT package (with /norestart / quiet Arguments)
  • Copy in VPN Profile
  • Copy in Management Tunnel Profile

Without NAM there is no requirement to restart the machine, but if using NAM, you would need to include a final restart prompt (Which I’d recommend you alert users of this requirement at the start)

Unsure if this really answers your actual question, but hope my solution goes some way to assist?

EDIT: Just realised, you need to include the definition for a couple of variables I have called.
Add these in the ##* VARIABLE DECLARATION section:

    # Installers
    [String]$CoreVPNmsiPath = "cisco-secure-client-win-$($appVersion)-core-vpn-predeploy-k9.msi"
    [String]$DaRTmsiPath = "cisco-secure-client-win-$($appVersion)-dart-predeploy-k9.msi"

    # Configuration Files
    [String]$VPNConfigFile = "dfac_vpn_off.xml"
    [String]$MgmtTunnelFile = "VpnMgmtTunProfile.xml"
    #
1 Like

Just re-read you original question…
I think if you change this:

To this:

While ($vpnRunning) {

Show-ADTInstallationWelcome -CloseProcesses @{ Name = 'vpnui'; Description = 'Cisco VPN' }, @{ Name = 'csc_ui'; Description = 'Cisco VPN' }, @{ Name = 'cscm'; Description = 'Cisco' }, @{ Name = 'vpnagent'; Description = 'Cisco' } -AllowDeferCloseProcesses -DeferTimes 3 -CheckDiskSpace -PersistPrompt
}

Show-InstallationProgress

You should find you don’t get the prompt re-appearing (as the VPN ā€˜should’ have disconnected because you have hopefully closed the process that the VPN ran on, and the While loop keeps checking for a new result, where as the If relies on a one time check - so the result stays the same)

2 Likes

What a wealth of information, Scott! I’m going to give this a shot this afternoon to see if it resolved my issue. Everything seems to be working well because if there is no VPN connection the software installs perfectly fine. You are right about cim vs wmi. Thanks for the code review! I really appreciate it!

1 Like