Skip to content

Instantly share code, notes, and snippets.

@jhorsman
Created January 6, 2015 10:11
Show Gist options
  • Star 45 You must be signed in to star a gist
  • Fork 15 You must be signed in to fork a gist
  • Save jhorsman/88321511ce4f416c0605 to your computer and use it in GitHub Desktop.
Save jhorsman/88321511ce4f416c0605 to your computer and use it in GitHub Desktop.
PowerShell to automate VPN connection with Cisco AnyConnect Secure Mobility Client
# Usage: & '.\Cisco_Anyconnect.ps1' [-Server <server name or ip>] [-Group <group>] [-User <user>] [-Password <password>]
#Source www.cze.cz
#This script is tested with "Cisco AnyConnect Secure Mobility Client version 3.1.00495"
# Usage: & '.\Cisco_Anyconnect.ps1' [-Server <server name or ip>] [-Group <group>] [-User <user>] [-Password <password>]
#Please change following variables
#IP address or host name of cisco vpn, Username, Group and Password as parameters
param (
[string]$Server = $( Read-Host "Input server, please" ),
[string]$Group = $( Read-Host "Input group, please" ),
[string]$User = $( Read-Host "Input username, please" ),
[string]$Password = $( Read-Host -assecurestring "Input password, please" )
)
#Please check if file exists on following paths
[string]$vpncliAbsolutePath = 'C:\Program Files (x86)\Cisco\Cisco AnyConnect Secure Mobility Client\vpncli.exe'
[string]$vpnuiAbsolutePath = 'C:\Program Files (x86)\Cisco\Cisco AnyConnect Secure Mobility Client\vpnui.exe'
#****************************************************************************
#**** Please do not modify code below unless you know what you are doing ****
#****************************************************************************
Add-Type -AssemblyName System.Windows.Forms -ErrorAction Stop
#Set foreground window function
#This function is called in VPNConnect
Add-Type @'
using System;
using System.Runtime.InteropServices;
public class Win {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
}
'@ -ErrorAction Stop
#quickly start VPN
#This function is called later in the code
Function VPNConnect()
{
Start-Process -WindowStyle Minimized -FilePath $vpncliAbsolutePath -ArgumentList "connect $Server"
$counter = 0; $h = 0;
while($counter++ -lt 1000 -and $h -eq 0)
{
sleep -m 10
$h = (Get-Process vpncli).MainWindowHandle
}
#if it takes more than 10 seconds then display message
if($h -eq 0){echo "Could not start VPNUI it takes too long."}
else{[void] [Win]::SetForegroundWindow($h)}
}
#Terminate all vpnui processes.
Get-Process | ForEach-Object {if($_.ProcessName.ToLower() -eq "vpnui")
{$Id = $_.Id; Stop-Process $Id; echo "Process vpnui with id: $Id was stopped"}}
#Terminate all vpncli processes.
Get-Process | ForEach-Object {if($_.ProcessName.ToLower() -eq "vpncli")
{$Id = $_.Id; Stop-Process $Id; echo "Process vpncli with id: $Id was stopped"}}
#Disconnect from VPN
echo "Trying to terminate remaining vpn connections"
Start-Process -WindowStyle Minimized -FilePath $vpncliAbsolutePath -ArgumentList 'disconnect' -wait
#Connect to VPN
echo "Connecting to VPN address '$Server' as user '$User'."
VPNConnect
#Write login and password
[System.Windows.Forms.SendKeys]::SendWait("$Group{Enter}")
[System.Windows.Forms.SendKeys]::SendWait("$User{Enter}")
[System.Windows.Forms.SendKeys]::SendWait("$Password{Enter}")
#Start vpnui
Start-Process -WindowStyle Minimized -FilePath $vpnuiAbsolutePath
#Wait for keydown
#echo "Press any key to continue ..."
#try{$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")}catch{}
@pop0ff
Copy link

pop0ff commented Apr 1, 2016

Hi Jan,

First. Nice and useful gist! I have one question, do you know maybe how to modify your script to transfer second password into it (we are using two-factor authentication and it need to enter OTP in this field)? Our login form looks following:
cisco anyconnect

I've tried this following but without success:

#IP address or host name of cisco vpn, Username, Group and Password as parameters
param (
  [string]$Server = $( Read-Host "Input server, please" ),
  [string]$Group = $( Read-Host "Input group, please" ),
  [string]$User = $( Read-Host "Input username, please" ),
  [string]$Password = $( Read-Host -assecurestring "Input password, please" ),
  [string]$Second = $( Read-Host -assecurestring "Input second password, please" )
)
#Write login and password
[System.Windows.Forms.SendKeys]::SendWait("$Group{Enter}")
[System.Windows.Forms.SendKeys]::SendWait("$User{Enter}")
[System.Windows.Forms.SendKeys]::SendWait("$Password{Enter}")
[System.Windows.Forms.SendKeys]::SendWait("$Second{Enter}")

Thanks in advance!

@Bootscreen
Copy link

Nice Script, but can you tell me, what i must configure to have local lan access? when i use the gui it works fine, when i use this script or the cli it doesn't work

@divyang-patel
Copy link

I also want to know how to extend this particular script to input second password in-case we have 2-factor authentication.

@drewdowling
Copy link

Great script, you saved me hours. Thanks.

@nicolaibaralmueller
Copy link

Great script! Works

@janostl
Copy link

janostl commented Jan 5, 2018

Great script. Works fine as long as I have one (1) Cisco Anyconnect profile stored.
But when you have many profiles at same client (and want to use them via shortcuts using this script) it gets stuck.

Then it only work if the FIRST entry in the list is passed as parameters, not for the 2nd or higher entry.

So how to modify the script when there are multiple connection entries at the same client ????

2018-01-05 15-55-15

@hubertsvk
Copy link

hi,
i have problem with this script ... i have three profiles and when i can connect to specific profile

PS C:\Users\XXX\Documents> .\Cisco_Anyconnect.ps1 'a.b.com' '' 'a.b'
Process vpnui with id: 18412 was stopped
Process vpncli with id: 7840 was stopped
Trying to terminate remaining vpn connections
Connecting to VPN address 'a.b.com' as user 'a.b'.

and script stopt and then shows me anyconnect dialog with button connect ....

...and the second "problem" is how store username and password in secure way .... i try with this, but without success
$Path = "$home\Desktop\multipass.xml"
[PSCustomObject]@{
User3 = Get-Credential -Message domain\a.b
} | Export-Clixml -Path $Path

$multipass = Import-Clixml -Path $Path

can you help me?

@RamanaReddyV
Copy link

Hi

check the below link may be useful. if any problems while setup please let me know.
https://www.codeproject.com/Tips/1250398/Login-VPN-through-Cisco-AnyConnect-Secure-Mobility

@jakawell
Copy link

Love this script. Just sharing something that I did to automate import of a one-time password (a la, Google Authenticator, etc.). First, I installed this great open-source Python TOTP/HOTP CLI: https://github.com/JeNeSuisPasDave/authenticator
Once you setup your OTP account in that, you can get the latest OTP in your Powershell script like this:

$AuthResult = "foo" | authenticator generate --refresh "once" | Out-String
$AuthResult -match '([0-9]{6})'
$AuthCode = $matches[0]

Just update the authenticator password (foo, above) and update the regex to match the number of digits in your OTP (I used a typical 6 digit code above).

@UsamaWaheed
Copy link

$AuthResult = "foo" | authenticator generate --refresh "once" | Out-String
$AuthResult -match '([0-9]{6})'
$AuthCode = $matches[0]

I tried that but I get an error saying, authenticator command is unknown. If I open CLI and type authenticator generate it works perfectly fine.

authenticator : The term 'authenticator' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the 
spelling of the name, or if a path was included, verify that the path is correct and try again.
At C:\Users\testuser\Desktop\Mode Selector.ps1:218 char:25
+ $AuthResult = "abcde" | authenticator generate --refresh "once" | Out ...
+                         ~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (authenticator:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
 
False

The code that I added is exactly what u did

$AuthResult = "abcde" | authenticator generate --refresh "once" | Out-String
$AuthResult -match '([0-9]{6})'
$AuthCode = $matches[0]

@Shikha1912
Copy link

Is there anyway, if we can hide the command line window rather than minimize?

@dlwiii
Copy link

dlwiii commented Mar 27, 2021

This works great from the command line. But I added this as a windows scheduled task which runs "powershell" and it does not seem to work. Any idea why this would not work as a scheduled task?

@FPl47h
Copy link

FPl47h commented Jul 20, 2021

I had the same problem. I was able to fix it by starting the task as admin.
In the new Jabber version 4.10.01075 I suddenly had problems entering the password. Adjusted line 71 without the wait-operator [System.Windows.Forms.SendKeys] :: Send("$ User {Enter}")

@vensondiana
Copy link

Hi,

This was nice and working. Also, we have a banner to accept on dual authentication. Is there a way on how to auto-accept also the banner?

@uluvdj
Copy link

uluvdj commented Sep 21, 2021

Hi,

This was nice and working. Also, we have a banner to accept on dual authentication. Is there a way on how to auto-accept also the banner?

Hi, You may have figured this out by now but, what i did to get this to work was after the section that sends the keys to application, i added:

Sleep 20
[System.Windows.Forms.SendKeys]::SendWait(‘y~’)

@ommcodes
Copy link

Love this script. Just sharing something that I did to automate import of a one-time password (a la, Google Authenticator, etc.). First, I installed this great open-source Python TOTP/HOTP CLI: https://github.com/JeNeSuisPasDave/authenticator Once you setup your OTP account in that, you can get the latest OTP in your Powershell script like this:

$AuthResult = "foo" | authenticator generate --refresh "once" | Out-String
$AuthResult -match '([0-9]{6})'
$AuthCode = $matches[0]

Just update the authenticator password (foo, above) and update the regex to match the number of digits in your OTP (I used a typical 6 digit code above).

Hi, Did you achieved getting TOPT from Microsoft Authenticator based on the script in the link you provided ?

@mattcargile
Copy link

Ever try to automate a M365 login prompt with MFA? We recently switched to it and I really miss my script. I've considered some robo-hack but haven't gotten to it yet. It would be cool if one could hook in with a powershell module like MSAL.PS.

@brianhauge
Copy link

@mattcargile

Ever try to automate a M365 login prompt with MFA? We recently switched to it and I really miss my script. I've considered some robo-hack but haven't gotten to it yet. It would be cool if one could hook in with a powershell module like MSAL.PS.

I've added and extra parameters to by able to wait for a 2FA. Add the following after inputs of username and password:

if($Sms -eq 'yes') {
		do { 
            sleep -s 2
        } while (
            -not ( $Host.UI.RawUI.KeyAvailable -and ($Host.UI.RawUI.ReadKey("IncludeKeyUp,NoEcho").VirtualKeyCode -eq 13 ) ) 
       )
}

@brianhauge
Copy link

brianhauge commented Oct 3, 2023

I have a problem. After the latest Windows 11 Update, It's not possible to send @ as part of the parameters any longer, when using [System.Windows.Forms.SendKeys]::SendWait. Anyone knows a way around this?

Found out it is because I'm using a danish keyboard. Switching to en-US:

Set-WinUserLanguageList -Force 'en-US'
[System.Windows.Forms.SendKeys]::SendWait("$user{Enter}")
Set-WinUserLanguageList -Force 'da-DK'

@mattcargile
Copy link

Thanks @brianhauge . I might look into that. It still seems like I need AutoIT or AutohotKey to really maximize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment