highend01
Goto Top

VBscript - WMI - ServerAddress + ConnectionStatus (Windows 7)

Hi zusammen,

ich kann "ServerAddress" + "ConnectionStatus" für eine VPN-Verbindung allein durch ihren Namen (z.B. "Work VPN") unter Windows 8+
problemlos bekommen, in dem ich den Namespace "root\Microsoft\Windows\RemoteAccess\Client" und die Klasse "PS_VpnConnection" benutze.

Der query sieht dann so aus:
SELECT * FROM PS_VpnConnection WHERE Name = "Work VPN"

objItem.ServerAddress + objItem.ConnectionStatus
liefern dann die benötigten Werte.

Mein Problem ist: Unter Windows 7 gibt es diesen Namespace leider nicht, er wurde erst mit Windows 8 eingeführt...

Kann mir jemand sagen, wie ich mit den Namespaces unter Windows 7 an die beiden Werte komme, wenn nur der
Name der VPN-Verbindung "vorhanden" ist?

Danke sehr!

Content-ID: 312404

Url: https://administrator.de/contentid/312404

Ausgedruckt am: 16.11.2024 um 05:11 Uhr

129813
129813 12.08.2016 um 12:11:11 Uhr
Goto Top
Hi,
you can use powershell and the DotRAS Library DLL
$conn_name = 'Work VPN'  
Add-Type -Path "D:\DotRas.dll"  
$conn = [DotRas.RasConnection]::GetActiveConnections() | ?{$_.EntryName -eq $conn_name}
$conn.GetConnectionStatus()
Output:
ConnectionState    : Connected
ErrorCode          : 0
ErrorMessage       : 
Device             : DotRas.RasDevice
PhoneNumber        : 192.168.234.11
LocalEndPoint      : 
RemoteEndPoint     : 192.168.234.11
ConnectionSubState : None
Regards
colinardo
colinardo 12.08.2016 aktualisiert um 13:20:50 Uhr
Goto Top
@129813 : Wenn man möchte kann man es auch ohne DLL in Powershell machen, ist zwar etwas mehr Code aber dafür ohne Abhängigkeit:
$connectionname = 'Work VPN'  

Add-Type -TypeDefinition @'  
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace VPN
{
    public class RAS
    {
        private int rasConnectionsAmount;

        const int MAX_PATH = 260;
        const int RAS_MaxDeviceType = 16;
        const int RAS_MaxPhoneNumber = 128;
        const int RAS_MaxEntryName = 256;
        const int RAS_MaxDeviceName = 128;

        [DllImport("rasapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]  
        private static extern int RasEnumConnections([In, Out] RASCONN lprasconn, ref int lpcb,ref int lpcConnections);

        [DllImport("RASAPI32", SetLastError = true, CharSet = CharSet.Auto)]  
        static extern int RasGetConnectStatus(IntPtr hrasconn, ref RASCONNSTATUS lprasconnstatus);


        public enum RASTUNNELENDPOINTTYPE
        {
            Unknown = 0,
            IPv4 = 1,
            IPv6 = 2
        }

        public enum RasConnectionSubState
        {
            Dormant = 1,
            None = 0,
            Reconnected = 0x2000,
            Reconnecting = 2
        }

        [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
        public struct RASCONN
        {
            public int dwSize;
            public IntPtr hrasconn;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxEntryName + 1)]
            public string szEntryName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxDeviceType + 1)]
            public string szDeviceType;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxDeviceName + 1)]
            public string szDeviceName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
            public string szPhonebook;
            public int dwSubEntry;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct RASTUNNELENDPOINT
        {
            public RASTUNNELENDPOINTTYPE dwType;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)]
            public byte addr;
        }
        
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct RASCONNSTATUS
        {
            public int dwSize;
            public int rasconnstate;
            public int dwError;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxDeviceType + 1)]
            public string szDeviceType;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxDeviceName + 1)]
            public string szDeviceName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxPhoneNumber + 1)]
            public string szPhoneNumber;
            public RASTUNNELENDPOINT localEndPoint;
            public RASTUNNELENDPOINT remoteEndPoint;
            public RasConnectionSubState connectionSubState;
        }
    

        public RASCONN GetRasConnections()
        {
            int rasEnumReturn;
            RASCONN rasconnStructs = new RASCONN[256];
            rasconnStructs.Initialize();
            rasconnStructs.dwSize = Marshal.SizeOf(typeof(RASCONN));
            int sizeOfRasconnStruct = rasconnStructs.dwSize * rasconnStructs.Length;
            rasEnumReturn = RasEnumConnections(rasconnStructs, ref sizeOfRasconnStruct, ref rasConnectionsAmount);
            if (rasEnumReturn != 0) {
                throw new Win32Exception(rasEnumReturn);
            }
            return rasconnStructs;
        }

        public RASCONNSTATUS GetConnectionStatus(IntPtr conn)
        {
            RASCONNSTATUS rasConnStatus = new RASCONNSTATUS();
            rasConnStatus.dwSize = Marshal.SizeOf(typeof(RASCONNSTATUS));
            int statusResult = RasGetConnectStatus(conn, ref rasConnStatus);
            if (statusResult != 0) throw new Win32Exception(statusResult);
            return rasConnStatus;
        }
    }
}
'@  

$vpn = New-Object VPN.RAS
$conn = $vpn.GetRasConnections() | ?{$_.hrasconn -ne 0 -and $_.szEntryName -eq $connectionname}
if ($conn){
    $state = $vpn.GetConnectionStatus($conn.hrasconn)
    if ($state.rasconnstate -band 0x2000){
        "$connectionname is Connected to $(([ipaddress][byte[]]$state.remoteEndPoint.addr[0..3]).IPAddressToString)"  
    }
    
}else{
    "$connectionname is not connected"  
}

@Highend01 : Eine WMI Klasse für den Status von RAS Verbindungen ist mir für Windows 7 nicht bekannt, so eine gibt es dort nicht (außer für VPN Statistiken, übertragene Pakete etc.). Da wirst du wie hier eine zweite Skriptsprache anwenden müssen (Powershell lässt sich auch über VBS aufrufen wenn man will) oder man schreibt sich eine EXE die die gewünschten Infos zurück gibt.

Grüße Uwe
Highend01
Highend01 12.08.2016 um 13:30:23 Uhr
Goto Top
Danke sehr, highload!

Leider ist auf einigen Rechnern die ExecutionPolicy für Powershell sehr restriktiv, so dass ich mich nicht drauf verlassen kann / will, dass Powershell dafür eingesetzt werden kann :/

Eine (einfache) Lösung für VBscript ist nicht zufällig in Sicht? face-smile

Lg,
Highend
Highend01
Highend01 12.08.2016 um 13:38:16 Uhr
Goto Top
Hi Uwe,

em... Wow! Ich hätte noch die Möglichkeit, das Ganze in AutohotKey umzusetzen, aber Strukturen, Pointer, etc. kommen mir immer wie ein Buch mit 7 Siegeln vor...

Naja, eher eines mit 8^^

Im AutoHotkey Forum gab es mal für die rasapi32.dll einen thread und ein script, wie man RasEnumEntriesW umsetzt.

Leider fehlt es mir an dem nötigen Know-How, das mit GetConnectionStatus() ebenfalls zu machen...

Das hier ist das script:

DllCall( "LoadLibrary", "Str", "Rasapi32.dll" )  

MsgBox % RAS_EnumAll()

return


RAS_EnumAll() {
Static ERROR_BUFFER_TOO_SMALL :=  603
     , ERROR_INVALID_SIZE     :=  632
     , SizeOf_RASENTRYNAME    :=  520  
 
Local TSz, RASENTRYNAME, pRASENTRYNAME, EC := 0, CC := 0, PBEntry, PBEntries := "`n", RASCONN, pRASCONN    
 
  TSz := SizeOf_RASENTRYNAME  
  VarSetCapacity( RASENTRYNAME, TSz, 0 )         
  NumPut( SizeOf_RASENTRYNAME, RASENTRYNAME )
 
  Error := DllCall( "Rasapi32\RasEnumEntriesW", "Int",0, "Int",0, "Ptr",&RASENTRYNAME, "PtrP",TSz, "PtrP",EC )  
 
  If ( Error = ERROR_BUFFER_TOO_SMALL ) 
      VarSetCapacity( RASENTRYNAME, TSz, 0 ) 
    , NumPut( SizeOf_RASENTRYNAME, RASENTRYNAME )
    , DllCall( "Rasapi32\RasEnumEntriesW", "Int",0, "Int",0, "Ptr",&RASENTRYNAME, "PtrP",TSz, "PtrP",EC )  
 
  Loop %EC% 
  { 
     PBEntry := StrGet(&RASENTRYNAME + (SizeOf_RASENTRYNAME * (A_Index - 1)) + 4, "UTF-16" )  
     PBEntries .=  A_Index .  "|" PBEntry "`n"  
  }
  StringTrimRight, PBEntries, PBEntries, 1
 
Return Trim( PBEntries , "`n" )  
}  

Es funktioniert unter Windows 7 (x86/x64) bis hoch zu Windows 10 einwandfrei, enthält aber eben nur die Variante, alle RAS Verbindungen auszulesen und nicht, den Status einer bestimmten Verbindung abzufragen.
129813
129813 12.08.2016 aktualisiert um 13:40:07 Uhr
Goto Top
VBS does not support loading WIN32-Code (VBA instead does) so the possibility is very limited.

Take the c# code from colinardo an compile yourself an exe face-wink
colinardo
colinardo 12.08.2016 um 13:52:30 Uhr
Goto Top
Die Umsetzung in AutoIt müsste ich mir erst noch mal ansehen. Mit C# könnte ich dir aber eine EXE kompilieren, bzw. das könntest du auch selbst wenn ich dir den Powershell-Code zum kompilieren schicke.
Highend01
Highend01 12.08.2016 um 14:04:13 Uhr
Goto Top
AutoHotkey, nicht AutoIt face-smile

Wäre aber total toll, wenn du dir das mal anschauen kannst.

Eine externe .exe wäre eine Möglichkeit, das Kompilieren würde ich auch hinbekommen. Allerdings wäre das suboptimal, da ich dann eine Form der Kommunikation / des Auslesens benötige, was die .exe dann an Informationen auswirft. Im Regelfall (und am einfachsten) dann entweder über die Zwischenablage oder das Abspeichern in einer Datei. IPC als Kommunikationsmöglichkeit lass ich mal außen vor^^ Per DllCall wäre (zumindest für mich) am einfachsten, dann hab ich die Informationen direkt in einer Variable, die sich leicht parsen lässt face-smile

Ich fang gerade (mal wieder) an, mir Tutorials für DllCall in AutohotKey anzusehen...
colinardo
Lösung colinardo 12.08.2016 aktualisiert um 15:11:45 Uhr
Goto Top
AutoHotKey verwende ich leider nicht.

Die Ausgabe der Consolen-EXE kannst du ja mit C# unten einfach an deine Bedürfnisse anpassen. ExitCodes geben dir einen Hinweis ob die Verbindung läuft oder nicht etc.

Hier mal auf die Schnelle die C# Konsolenanwendung, via Powershell-Kompilierung, gibt eine get-status.exe im aktuellen Verzeichnis aus von dem du das Skript aufrufst.

Die Exe rufst du dann mit dem Verbindungsnamen als ersten Parameter auf:
get-status.exe "Work VPN"
Ausgabe
Status:Connected
Endpoint:192.168.1.95
ExitCode: 0 = Connected
ExitCode: 1 = Disconnected
ExitCode: 255 = anderer Fehler

Viel Erfolg, mehr Code gibt's hier von meiner Seite nicht mehr kostenlos face-wink

$code = @'  
using System;
using System.Net;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace get_ras_status {
    class Program {
        static void Main(string args) {
            if (args.Length == 1) {
                try {
                    RAS r = new RAS();
                    RAS.RASCONNSTATUS conn = r.GetConnectionStatusByName(args);
                    if (conn.rasconnstate == 0x2000) {
                        byte ip_arr = new byte[4];
                        Array.Copy(conn.remoteEndPoint.addr, ip_arr, 4);
                        IPAddress remote_endpoint = new IPAddress(ip_arr);
                        Console.WriteLine(@"Status:Connected" + Environment.NewLine + "Endpoint:" + remote_endpoint.ToString());  
                        ExitProg(0);
                    } else {
                        ExitProg(1,@"Status:Disconnected");  
                    }
                } catch (SystemException ex){
                    ExitProg(255,@"Unbekannter Fehler: " + ex.Message);  
                }
            } else {
                ExitProg(255,@"Parameterfehler: Bitte den Namen der VPN-Verbindung als einzigen Parameter angeben!");  
            }
        }
        static void ExitProg(int exitcode, string message = "") {  
            if (message != "") {  
                if (exitcode > 1) {
                    Console.Error.WriteLine(message);
                } else {
                    Console.WriteLine(message);
                }
            }
            Environment.Exit(exitcode);
        }
    }
}

public class RAS {
    private int rasConnectionsAmount;

    const int MAX_PATH = 260;
    const int RAS_MaxDeviceType = 16;
    const int RAS_MaxPhoneNumber = 128;
    const int RAS_MaxEntryName = 256;
    const int RAS_MaxDeviceName = 128;

    [DllImport("rasapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]  
    private static extern int RasEnumConnections([In, Out] RASCONN lprasconn, ref int lpcb, ref int lpcConnections);

    [DllImport("RASAPI32", SetLastError = true, CharSet = CharSet.Auto)]  
    static extern int RasGetConnectStatus(IntPtr hrasconn, ref RASCONNSTATUS lprasconnstatus);


    public enum RASTUNNELENDPOINTTYPE {
        Unknown = 0,
        IPv4 = 1,
        IPv6 = 2
    }

    public enum RasConnectionSubState {
        Dormant = 1,
        None = 0,
        Reconnected = 0x2000,
        Reconnecting = 2
    }

    [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
    public struct RASCONN {
        public int dwSize;
        public IntPtr hrasconn;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxEntryName + 1)]
        public string szEntryName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxDeviceType + 1)]
        public string szDeviceType;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxDeviceName + 1)]
        public string szDeviceName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
        public string szPhonebook;
        public int dwSubEntry;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct RASTUNNELENDPOINT {
        public RASTUNNELENDPOINTTYPE dwType;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)]
        public byte addr;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct RASCONNSTATUS {
        public int dwSize;
        public int rasconnstate;
        public int dwError;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxDeviceType + 1)]
        public string szDeviceType;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxDeviceName + 1)]
        public string szDeviceName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxPhoneNumber + 1)]
        public string szPhoneNumber;
        public RASTUNNELENDPOINT localEndPoint;
        public RASTUNNELENDPOINT remoteEndPoint;
        public RasConnectionSubState connectionSubState;
    }


    public RASCONN GetRasConnections() {
        int rasEnumReturn;
        RASCONN rasconnStructs = new RASCONN[256];
        rasconnStructs.Initialize();
        rasconnStructs.dwSize = Marshal.SizeOf(typeof(RASCONN));
        int sizeOfRasconnStruct = rasconnStructs.dwSize * rasconnStructs.Length;
        rasEnumReturn = RasEnumConnections(rasconnStructs, ref sizeOfRasconnStruct, ref rasConnectionsAmount);
        if (rasEnumReturn != 0) {
            throw new Win32Exception(rasEnumReturn);
        }
        return rasconnStructs;
    }

    public RASCONNSTATUS GetConnectionStatusByName(string connectionName) {
        RASCONNSTATUS rasConnStatus = new RASCONNSTATUS();
        rasConnStatus.dwSize = Marshal.SizeOf(typeof(RASCONNSTATUS));
        RASCONN connections = GetRasConnections();
        for (int i = 0; i < connections.Length; i++) {
            int statusResult = RasGetConnectStatus(connections[i].hrasconn, ref rasConnStatus);
            //if (statusResult != 0) throw new Win32Exception(statusResult);
            if (connections[i].szEntryName.ToLower() == connectionName.ToLower()) {
                return rasConnStatus;
            }
        }
        return (new RASCONNSTATUS());
    }
}
'@  
Add-Type -TypeDefinition $code -OutputAssembly "get-status.exe" -OutputType ConsoleApplication -Language CSharp  
Grüße Uwe
Highend01
Highend01 12.08.2016 um 15:21:12 Uhr
Goto Top
Herzlichen Dank, Uwe!

Mir war nicht mal bekannt, dass Powershell C# Code kompilieren kann oO

Dann werde ich den Output der .exe Datei parsen, wenn der Returncode 1 ist...


mehr Code gibt's hier von meiner Seite nicht mehr kostenlos

Das ist nur fair face-smile

Ein schönes Wochenende und vielen dank noch mal,
Highend
colinardo
colinardo 12.08.2016 aktualisiert um 15:23:52 Uhr
Goto Top
Zitat von @Highend01:
Ein schönes Wochenende und vielen dank noch mal,
Keine Ursache, wünsch ich dir ebenfalls.

Grüße Uwe