Cisco AnyConnect: Powershell für Autologin

Inhaltsverzeichnis

 

1. Vorwort Inhalt

Seit geraumer Zeit schon geht mir der Cisco-Client () auf die Nerven mit seiner gewollten Unfähigkeit, das Benutzerkennwort zu speichern. Nein, ich will wirklich nichts über IT-Sicherheit wissen; der im BIOS eingebaute Keylogger hat mein Paßwort sowieso schon an alle Stellen, die interessiert sind, verteilt. Leider läßt sich der Client nicht per Kommandozeile mit Parametern versehen; es muß ein bißchen tiefer in die Trickkiste gegriffen werden.

2. Originale Vorlage Inhalt

Nach einiger Suche stieß ich in diesem Forum auf einen Vorschlag zur Verwendung der in Windows eingebauten PowerShell. Der originale Code wie folgt:

#Source www.cze.cz
#This script is tested with "Cisco AnyConnect Secure Mobility Client version 3.0.5080"
#Please change following variables

#IP address or host name of cisco vpn
[string]$CiscoVPNHost = "192.168.0.50"
[string]$Login = "LOGIN"
[string]$Password = "PASSWORD"

#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 -FilePath $vpncliAbsolutePath -ArgumentList "connect $CiscoVPNHost"
    $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 -FilePath $vpncliAbsolutePath -ArgumentList 'disconnect' -wait
#Connect to VPN
echo "Connecting to VPN address '$CiscoVPNHost' as user '$Login'."
VPNConnect

#Write login and password
[System.Windows.Forms.SendKeys]::SendWait("$Login{Enter}")
[System.Windows.Forms.SendKeys]::SendWait("$Password{Enter}")

#Start vpnui
start-Process -FilePath $vpnuiAbsolutePath
#Wait for keydown
echo "Press any key to continue ..."
try{$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")}catch{}

Leider hatte er nicht auf Anhieb funktioniert, da inzwischen die Profilauswahl ebenfalls in der Kommandozeile verfügbar ist. Auch hätte ich gerne, daß das Fenster eines Batch Files nach erfolgreichem Verbinden geschlossen wird und nicht auf einen Tastendruck gewartet wird.

3. Verbesserte Lösung Inhalt

Daher ist das Script wie folgt angepaßt; es funktioniert einwandfrei.

#Source www.cze.cz
#This script is tested with "Cisco AnyConnect Secure Mobility Client version 3.0.10057"
[string]$CiscoVPNHost = "$CISCO-HOST"
[string]$Login    = "$LOGIN"
[string]$Password = "$PASSWORD"
[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'

Add-Type -AssemblyName System.Windows.Forms -ErrorAction Stop

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

Function VPNConnect()
{
    Start-Process -FilePath $vpncliAbsolutePath -ArgumentList "connect $CiscoVPNHost"
    $counter = 0; $h = 0;
    while($counter++ -lt 1000 -and $h -eq 0)
    {
        sleep -m 10
        $h = (Get-Process vpncli).MainWindowHandle
    }
    if($h -eq 0){echo "Could not start VPNUI it takes too long."}
    else{[void] [Win]::SetForegroundWindow($h)}
}

Get-Process | ForEach-Object {if($_.ProcessName.ToLower() -eq "vpnui")
{$Id = $_.Id; Stop-Process $Id; echo "Process vpnui with id: $Id was stopped"}}
Get-Process | ForEach-Object {if($_.ProcessName.ToLower() -eq "vpncli")
{$Id = $_.Id; Stop-Process $Id; echo "Process vpncli with id: $Id was stopped"}}

echo "Trying to terminate remaining vpn connections"
start-Process -FilePath $vpncliAbsolutePath -ArgumentList 'disconnect' -wait
echo "Connecting to VPN address '$CiscoVPNHost' as user '$Login'."
VPNConnect

[System.Windows.Forms.SendKeys]::SendWait("{Enter}")
start-sleep 2
[System.Windows.Forms.SendKeys]::SendWait("$Login{Enter}")
start-sleep 2
[System.Windows.Forms.SendKeys]::SendWait("$Password{Enter}")

start-sleep 5
start-Process -FilePath $vpnuiAbsolutePath

4. Anmerkungen Inhalt

Zwei Dinge gilt es zu beachten; beide auch hier erwähnt. Auf jungfräulichen Windows-Installationen ist das Ausführen eigener PowerShell-Scripts nicht gestattet. Außerdem muß, wenn der erste Punkt behoben wurde, das Script mit vollem oder wenigstens relativen Pfad durch „./“ aufgerufen werden.

Happy Connecting…

8 Kommentare zu “Cisco AnyConnect: Powershell für Autologin”

1.   Kommentar von Rizwan
Erstellt am 03. Januar 2014 um 22:16 Uhr.

Hi, i have test you script and it is working very nice. thanks to you, but 2 things are still disturbing,(1) first i am getting a popup message like „Connect not available. Another AnyConnect application is running or the functionality is not requested by this application.“ (2)at the same time powershell shows the successful connection and then it needs to get the cisco acceptance? certificate? by entering „Y“
in the end the connection gets ok/
could you pl help in this regard?
Rizwan
Rizwan.qadeer@gmail.com

2.   Kommentar von McSeven
Erstellt am 04. Januar 2014 um 01:20 Uhr.

Hi,

sorry, the first error has never occurred on my installations and I don’t know how to solve it. On my computers it makes no difference if the previous instance is still running, since the script attempts to close the instance (see line 34).

As for the second issue, I don’t know either, it looks like you need to find the appropriate window (maybe by its title or its process image name) and send a „Y“ to it. I have no idea how to do that with powerscript, sorry.

3.   Kommentar von Marc
Erstellt am 18. Februar 2014 um 12:14 Uhr.

Hey, i have an issue.. we have a Password with some @ and / signgs.. thats generating errors.
Can you help me?

4.   Kommentar von Marc
Erstellt am 18. Februar 2014 um 12:37 Uhr.

Ok.. the problem is not the @.. the problem is a ( in the password

5.   Kommentar von McSeven
Erstellt am 18. Februar 2014 um 18:22 Uhr.

Hi, without source code it’s difficult to give an exact solution. If you compare the password string to a saved one and use the match() function, be aware that it uses regular expressions: http://www.vistax64.com/powershell/199639-comparing-string-contains-parenthesis.html

In this case, you need to escape the parenthesis character by preceeding an escape character (most likely the backslash „\“). Hope that helps.

6.   Kommentar von Marc
Erstellt am 19. Februar 2014 um 11:00 Uhr.

This is about your script… just try it with a $Password like 1245(@ABC

7.   Kommentar von McSeven
Erstellt am 19. Februar 2014 um 11:11 Uhr.

Well, same thing basically. See documentation for ::Send()-Method here.

It states that some characters, such as parenthesis, have special meaning and must be escaped if used as characters. Escaping takes place by enclosing the appropriate character in (curly) braces „{}“. So, your password string „1245(@ABC“ should become „1245{(}@ABC“, if I’m not mistaken.

Unfortunately, I cannot test this, since our company threw all Cisco equipment overboard after NSA stuff.

8.   Kommentar von Marc
Erstellt am 19. Februar 2014 um 11:34 Uhr.

Thank you! that {(} worked 🙂

Einen Kommentar hinterlassen