Requête Echo ICMP en VBScript avec les API Win32 WinSock et le composant DynaWrap Dans le but de mettre à l'épreuve ma version étendue du composant COM DynaWrap, j'ai souhaité me lancer dans la manipulation des API Win32 Winsock en écrivant un script VBScript qui reproduit le plus fidèlement possible le fonctionnement du célèbre outil de diagnostique Ping.exe. Rien de bien transcendant dans tout cela néanmoins les API Winsock utilisant principalement des pointeurs et des structures, c'était l'occasion de vérifier la stabilité et la complétude des nouvelles méthodes offertes par ce composant. Note: Dans le cadre de ce projet, le composant COM DynaWrap est utilisé pour invoquer les API Win32 suivantes : 1- Librairie dynamique ws2_32.dll - WSAStartup
- WSACleanup
- inet_addr
- inet_ntoa
- gethostbyname
2- Librairie dynamique icmp.dll (Windows 2000) ou iphlpapi.dll (Windows XP+) - IcmpSendEcho
- IcmpCreateFile
- IcmpCloseHandle
- GetIpErrorString ( Windows XP+ uniquement )
Historique: Version 1.0 - 20080715 - Première Release Publique Plateformes supportées: Windows 2000+ Pré requis: Winsock 2.0 Listing 1 : VBSPing.vbs | - Option Explicit
- ' déclaration des constantes DynaWrap
- Const dw_BSTR=0
- Const dw_BYTE=1
- Const dw_DOUBLE=8
- Const dw_INT=2
- Const dw_LONG=4
- ' déclaration des constantes internes
- Const TIMEOUT=1000
- Const PINGCOUNT=4
- ' déclaration des variables
- Dim oDyn, oRe
- Dim sWSAData, sHostToReach, sIpAddr, sReplyBuffer, sError
- Dim dwIpAddr, dwReplyBufferAddr, dwHostentAddr
- Dim lRet, lErrorSize
- Dim bIsIpErrorStringSupported
- Dim nPingCount
- Dim hIcmpFile
- Dim nTimeout: nTimeout=TIMEOUT
- Dim nPingCountRequired: nPingCountRequired=PINGCOUNT
- Dim nPingCountReceived: nPingCountReceived=0
- Dim nMinTimeResponseReceived: nMinTimeResponseReceived=nTimeout
- Dim nMaxTimeResponseReceived: nMaxTimeResponseReceived=0
- Dim nTimeResponseReceived: nTimeResponseReceived=0
- Dim nTotalTimeResponseReceived: nTotalTimeResponseReceived=0
- ' initialisation des objets
- Set oDyn=CreateObject("DynamicWrapper")
- Set oRe=New RegExp: oRe.Pattern="^(\d+\.){3}\d+$"
- ' déclaration dynamique des API Win32 utilisées
- oDyn.Register "ws2_32.dll", "WSAStartup", "r=l","i=ll"
- oDyn.Register "ws2_32.dll", "WSACleanup", "r=l"
- oDyn.Register "ws2_32.dll", "inet_addr", "r=l", "i=s"
- oDyn.Register "ws2_32.dll", "inet_ntoa", "r=l", "i=l"
- oDyn.Register "ws2_32.dll", "gethostbyname", "r=l", "i=s"
- ' gestion des erreurs
- ' les API sont disponibles dans des librairies différentes
- ' selon le système d'exploitation (Windows 2000 et Windows XP+)
- On Error Resume Next
- ' tentative de déclaration dynamique pour Windows XP et supérieur
- oDyn.Register "iphlpapi.dll", "IcmpSendEcho", "r=l", "i=llslllll"
- ' vérification de la disponibilité de la fonction exportée
- If Err.Number Then
- ' la plateforme est Windows 2000 (librairie icmp.dll)
- oDyn.Register "icmp.dll", "IcmpSendEcho", "r=l", "i=llslllll"
- oDyn.Register "icmp.dll", "IcmpCreateFile", "r=h"
- oDyn.Register "icmp.dll", "IcmpCloseHandle", "r=b", "i=l"
- ' l'API GetIpErrorString n'est pas supportée
- bIsIpErrorStringSupported=False
- Else
- ' la plateforme est Windows XP ou supérieur (librairie iphlpapi.dll)
- oDyn.Register "iphlpapi.dll", "GetIpErrorString", "r=l", "i=lll"
- oDyn.Register "iphlpapi.dll", "IcmpCreateFile", "r=h"
- oDyn.Register "iphlpapi.dll", "IcmpCloseHandle", "r=b", "i=l"
- ' l'API GetIpErrorString est supportée
- bIsIpErrorStringSupported=True
- End If
- ' fin de la gestion des erreurs
- On Error Goto 0
- ' initialisation des API Winsock (au moins Winsock v2.0)
- sWSAData=String(200, Chr(0))
- lRet=odyn.WSAStartup(&h0002, oDyn.GetBSTRAddr(sWSAData))
- ' vérification de la disponibilité des API Winsock
- If lRet<>0 Then
- ' une erreur est survenue
- WScript.Echo oDyn.FormatMessage(lRet)
- ' libération des ressources et fin de traitement
- oDyn.WSACleanup()
- WScript.Quit()
- End If
- ' lecture de l'argument (adresse IP ou nom de hôte)
- sHostToReach=WScript.Arguments(0)
- ' détermination du type d'argument
- ' addresse IP ou nom de hôte
- If oRe.Test(sHostToReach) Then
- ' l'argument est une adresse IP
- sIpAddr=sHostToReach
- ' détermination de l'adresse réseau
- dwIpAddr=oDyn.inet_addr(oDyn.GetBSTRAddr(sHostToReach))
- Else
- ' l'argument est un nom de hôte
- ' il est nécessaire de résoudre le nom de hôte via DNS, WINS, ...
- dwHostentAddr=oDyn.gethostbyname(oDyn.GetBSTRAddr(sHostToReach))
- ' vérification du résultat de l'opération
- If dwHostentAddr=0 Then
- ' une erreur est survenue
- ' affichage du message d'erreur
- WScript.Echo oDyn.FormatMessage(oDyn.GetLastError())
- ' libération des ressources et fin de traitement
- oDyn.WSACleanup()
- WScript.Quit()
- End If
- ' lecture du nom de hôte réel
- ' celui transmis comme argument peut être un alias
- sHostToReach=odyn.GetMemInBSTRAddr( _
- oDyn.GetMemInBSTRAddr( _
- dwHostentAddr, 0, dw_LONG _
- ), 0, dw_BSTR _
- )
- ' lecture de l'adresse réseau
- dwIpAddr=odyn.GetMemInBSTRAddr( _
- oDyn.GetMemInBSTRAddr( _
- oDyn.GetMemInBSTRAddr( _
- dwHostentAddr, 12, dw_LONG _
- ), 0, dw_LONG _
- ), 0, dw_LONG _
- )
- ' lecture de l'adresse IP au format texte
- sIpAddr=oDyn.GetMemInBSTRAddr(oDyn.inet_ntoa(dwIpAddr), 0, dw_BSTR)
- End If
- ' tout semble en ordre
- ' ouverture du handle Echo ICMP IPv4
- hIcmpFile=oDyn.IcmpCreateFile()
- ' initialisation de la structure nécessaire au ping et récupération
- ' de son adresse. Les données transmises ont une taille de 32 octets
- sReplyBuffer=String(28/2+32/2, Chr(0))
- dwReplyBufferAddr=oDyn.GetBSTRAddr(sReplyBuffer)
- ' affichage du header
- WScript.Stdout.Write "Envoi d'une requête 'ping' sur " & sHostToReach & " "
- If sIpAddr<>sHostToReach Then WScript.Stdout.Write "[" & sIpAddr & "] "
- WScript.Echo "avec 32 octets de données :"
- WScript.Echo
- ' Compteur du nombre de requête Echo ICMP IPv4 (timeout=1s)
- For nPingCount=1 to nPingCountRequired
- ' envoi d'un Echo ICMP
- lRet=oDyn.IcmpSendEcho( _
- hIcmpFile, _
- dwIpAddr, _
- "01234567890123456789012345678901", _
- 32, _
- 0, _
- dwReplyBufferAddr, _
- Lenb(sReplyBuffer), _
- nTimeout _
- )
- ' vérification du résultat de l'opération
- If lRet=0 Then
- ' une erreur est survenue
- ' si l'API GetIpErrorString est supportée alors détermination du message d'erreur
- If bIsIpErrorStringSupported=True Then
- ' allocation du buffer et détermination du message d'erreur
- sError=String(256/2, Chr(0))
- lErrorSize=Lenb(sError)
- oDyn.GetIpErrorString oDyn.GetLastError(), oDyn.GetBSTRAddr(sError), oDyn.GetVariantAddr(lErrorSize)
- Else
- ' l'API GetIpErrorString n'est pas supportée
- ' seul le code d'erreur sera affiché
- ' les messages associés sont disponibles sur le site MSDN
- ' http://msdn.microsoft.com/en-us/library/aa366053(VS.85).aspx
- sError="Une erreur est survenue : [" & oDyn.GetLastError() & "]"
- End If
- ' affichage du message d'erreur
- Wscript.Echo sError
- Else
- ' le requête Echo ICMP a réussi
- nPingCountReceived=nPingCountReceived+1
- ' lecture du temps de réponse de la requête
- nTimeResponseReceived=oDyn.GetMemInBSTRAddr(dwReplyBufferAddr,8,dw_LONG)
- ' incrémentation du temps de réponse total
- nTotalTimeResponseReceived=nTotalTimeResponseReceived+nTimeResponseReceived
- ' affichage des informations
- WScript.Stdout.Write _
- "Réponse de " & oDyn.GetMemInBSTRAddr( _
- oDyn.inet_ntoa( _
- oDyn.GetMemInBSTRAddr( _
- dwReplyBufferAddr, 0, dw_LONG _
- ) _
- ), 0, dw_BSTR _
- ) & " : " & _
- "octets=" & oDyn.GetMemInBSTRAddr(dwReplyBufferAddr, 12, dw_BYTE) & " "
- If nTimeResponseReceived=0 Then WScript.Stdout.Write "temps<1ms "
- If nTimeResponseReceived>0 Then WScript.Stdout.Write "temps=" & nTimeResponseReceived & " ms "
- WScript.Echo "TTL=" & oDyn.GetMemInBSTRAddr(dwReplyBufferAddr, 20, dw_BYTE)
- ' sauvegarde des temps de réponses mini et maxi
- If nTimeResponseReceived > nMaxTimeResponseReceived Then nMaxTimeResponseReceived = nTimeResponseReceived
- If nTimeResponseReceived < nMinTimeResponseReceived Then nMinTimeResponseReceived = nTimeResponseReceived
- End If
- ' temporisation d'une seconde avant la nouvelle requête
- If nPingCount<>nPingCountRequired Then WScript.Sleep(1000)
- Next
- ' affichage des statistiques
- WScript.Echo
- WScript.Echo "Statistiques Ping pour " & sIpAddr & ":"
- WScript.Echo " Paquets : envoyés = " & nPingCountRequired & ", reçus = " & nPingCountReceived & ", perdus = " & nPingCountRequired - nPingCountReceived & " (perte " & 100-(nPingCountReceived*100 / nPingCountRequired) & "%)"
- ' affichage des statistiques supplémentaires si au moins une réponse a été reçue
- If nPingCountReceived Then
- WScript.Echo "Durée approximative des boucles en millisecondes :"
- WScript.Echo " Minimum = " & nMinTimeResponseReceived & "ms , Maximun = " & nMaxTimeResponseReceived & "ms , Moyenne = " & Fix(nTotalTimeResponseReceived / nPingCountRequired) & "ms"
- End If
- ' libération des ressources
- oDyn.IcmpCloseHandle hIcmpFile
- oDyn.WSACleanup()
|
L'utilisation de ce script est très simple. Il suffit de transmettre en argument l'adresse IPv4 ou le nom de hôte sur lequel envoyer une requête Echo ICMP. Ci-dessous un exemple d'utilisation réalisé sous Windows XP Service Pack 2 avec la console WSH Shell :
WSH D:\Test> ' ping sur un nom de hôte
WSH D:\Test> @cscript VBSPing.vbs www.google.com
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. Tous droits réservés.
Envoi d'une requête 'ping' sur www.l.google.com [209.85.135.103] avec 32 octets
de données :
Réponse de 209.85.135.103 : octets=32 temps=61 ms TTL=242
Réponse de 209.85.135.103 : octets=32 temps=61 ms TTL=242
Réponse de 209.85.135.103 : octets=32 temps=70 ms TTL=242
Réponse de 209.85.135.103 : octets=32 temps=59 ms TTL=242
Statistiques Ping pour 209.85.135.103:
Paquets : envoyés = 4, reçus = 4, perdus = 0 (perte 0%)
Durée approximative des boucles en millisecondes :
Minimum = 59ms , Maximun = 70ms , Moyenne = 62ms
WSH D:\Test> ' ping sur une adresse IP V4
WSH D:\Test> @cscript VBSPing.vbs 195.8.214.142
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. Tous droits réservés.
Envoi d'une requête 'ping' sur 195.8.214.142 avec 32 octets de données :
Réponse de 195.8.214.142 : octets=32 temps=45 ms TTL=58
Réponse de 195.8.214.142 : octets=32 temps=43 ms TTL=58
Réponse de 195.8.214.142 : octets=32 temps=45 ms TTL=58
Réponse de 195.8.214.142 : octets=32 temps=43 ms TTL=58
Statistiques Ping pour 195.8.214.142:
Paquets : envoyés = 4, reçus = 4, perdus = 0 (perte 0%)
Durée approximative des boucles en millisecondes :
Minimum = 43ms , Maximun = 45ms , Moyenne = 44ms
WSH D:\Test> ' ping sur une adresse IP refusant les requêtes Echo entrantes
WSH D:\Test> @cscript VBSPing.vbs 192.168.0.1
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. Tous droits réservés.
Envoi d'une requête 'ping' sur 192.168.0.1 avec 32 octets de données :
Délai d'attente de la demande dépassé.
Délai d'attente de la demande dépassé.
Délai d'attente de la demande dépassé.
Délai d'attente de la demande dépassé.
Statistiques Ping pour 192.168.0.1:
Paquets : envoyés = 4, reçus = 0, perdus = 4 (perte 100%)
WSH D:\Test> ' Ping sur un nom de hôte non résolu
WSH D:\Test> @cscript VBSPing.vbs www.domain.invalid.fr
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. Tous droits réservés.
Le nom demandé est valide et a été trouvé dans la base de données, mais il ne di
spose pas des données associées recherchées.
Téléchargement: Guide PDF : - Archive : VBSPing.zip
|