WSH Shell : Afficher les URL d`une machine distante
Transcription
WSH Shell : Afficher les URL d`une machine distante
glsft.free.fr WSH Shell : Afficher les URL d'une machine distante Soumis par Gilles LAURENT 26-08-2008 WSH Shell : Afficher les URL des instances Internet Explorer en cours d'exécution sur une machine distante Une question d'un usager sur le Forum Scripting (Fr) était de savoir s'il était possible de déterminer par script les URL des instances Internet Explorer en cours d'exécution sur une machine distante. J'ai tout d'abord pensé, à tord, que le simple fait d'utiliser l'outil PSExec de Windows Sysinternals pour exécuter un script VBScript distant suffirait pour accomplir cette tâche en s'inspirant du précédent article WSH Shell : Afficher les URL. Et bien NON ! Pour la bonne et simple raison que l'outil PSExec n'est pas en mesure d'exécuter à distance un outil ou un script au sein d'une session utilisateur connecté sur une machine distante. Cela n'est pas grave car il y a quelques temps maintenant, j'avais developpé l'outil RunAsLoggedOnUser permettant de réaliser cette tâche (Vous pouvez retrouver l'article concernant cet outil en suivant ce lien). J'ai donc rapidement maquetté une solution, ce qui m'a conduit à mettre à jour l'outil RunAsLoggedOnUser pour, entre autre, ajouter le support de la redirection des flux puis à créer un module externe compatible avec la console WSH Shell. C'est cette solution que je vous présente ici et qui se compose de l'outillage et pré requis suivants : 1- Sur la machine d'administration : - De la classe VBScript _wshRemoteIExplore.inc (module externe WSH Shell) Ce module est à déposer dans le sous-dossier Include de la console WSH Shell - De l'outil PSExec de Windows Sysinternals - De l'outil RunAsLoggedOnUser de moi-même ;-) Il est absolument nécessaire d'utiliser la version supérieure ou égale à la v1.0.0.3 - Du composant COM DynaWrap (version étendue obligatoire) Ce composant a besoin d'être inscrit dans le registre via la commande regsvr32 sur la machine d'administration. Il est à noter que cette opération est automatiquement réalisée depuis la version v1.0.0.9 du setup WSH Shell si le composant DynaWrap - DynaCall Wrapper a été sélectionné dans la liste des composants additionnels à installer) Note : Le composant COM DynaWrap est utilisé pour invoquer les API Win32 suivantes : - NetApiBufferFree - NetWkstaGetInfo - PathFindOnPathW 2- Sur la machine distante : - Du script VBScript IExplore.vbs (à installer par défaut à la racine de la partition C:\) La propriété RemoteScriptFolder de la classe wshRemoteIExplore permet de modifier ce chemin par défaut. Ce script pourra, par exemple, être installé dans le dossier partagé netlogon d'un contrôleur de domaine pour les postes membres d'un domaine. Dans ce cas, il faudra utiliser la syntaxe d'expansion retardée des variables d'environnement compatible avec l'outil RunAsLoggedOnUser, c'est à dire : WSH D:\Test> oRemoteIE.RemoteScriptFolder="{logonserver}\netlogon" - Du composant COM DynaWrap (version étendue obligatoire) Il est facilement possible de s'affranchir de ce pré requis si uniquement les URL doivent être affichées. Le script IExplore.vbs devra dans ce cas être adapté en conséquence Note : Le composant COM Dynawrap est utilisé pour invoquer l'API Win32 suivante : - GetWindowThreadProcessId Important : Comme le soulignait à juste titre Jacques Barathon [MS] dans ce fil de discussion, j'attire également votre attention sur le risque d'illégalité de l'utilisation de cette solution si les utilisateurs finaux ne sont pas prévenus que leur navigation Internet est susceptible d'être surveillée. Cette solution (scripts VBScript ainsi que les outils personnels développés qui l'accompagne) est destinée à un usage à but purement éducatif et non à un usage dans le cadre d'une utilisation illégale. Bon, le décor étant maintenant planté, il est temps de démarrer une console WSH Shell pour tester ce nouveau module externe ! Les commentaires se font au fil de l'eau en ligne de commandes dans la console.Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. Tous droits réservés. _ _ _ ___ _ _ ___ _ _ _ | | | |/ __>| | | / __>| |_ ___ | || | | | | |\__ \| | \__ \| . |/ ._>| || | |__/_/ <___/|_|_| <___/|_|_|\___.|_||_| http://glsft.free.fr Propulsé par Joomla! Généré: 16 February, 2017, 19:51 glsft.free.fr Windows Script Host (WSH) Shell v1.0.0.9 starting ... Registering components ... Loading external modules ... Loading _wshAdsi.inc ... Loading _wshCalendar.inc ... Loading _wshCodeSyntaxing.inc ... Loading _wshComputerToolbox.inc ... Loading _wshCultures.inc ... Loading _wshFtp.inc ... Loading _wshIExplore.inc ... Loading _wshIni.inc ... Loading _wshModuleManager.inc ... Loading _wshRemoteIExplore.inc ... Loading _wshTaskView.inc ... Loading _wshWmi.inc ... Loading profiles ... Loading D:\Users\Dev\Copyright\WSH\Release\WSHShell_Profile.inc ... Loading D:\Documents and Settings\Gilles\Mes documents\WSH Shell\WSHShell_P... Welcome ... It's 25/08/2008 18:46:48 and WSH Shell is up ! Ready. WSH D:\Test> ' notre nouveau module est bien présent dans la liste des modules WSH D:\Test> ' automatiquement chargés. Il ne reste plus, comme d'habitude, à WSH D:\Test> ' créer une instance pour en bénéficier WSH D:\Test> Set oRemoteIE=New wshRemoteIExplore WSH D:\Test> WSH D:\Test> ' détermination des membres (méthodes et propriétés) WSH D:\Test> gm(oRemoteIE) Category Name -------- ---Function CheckPrerequisites () Function GetRemoteIERunningInstances (strComputer) Function IsUserLoggedIn (strComputer) Property OptionalToolsFolder Property RemoteScriptFolder Property Verbose Property Version WSH D:\Test> ' la méthode "CheckPrerequisites ()" permet de vérifier que les WSH D:\Test> ' pré requis sont bien présent dans un dossier référencé par la WSH D:\Test> ' variable d'environnement Path ou alors dans le dossier pointé WSH D:\Test> ' par la propriété OptionalToolsFolder WSH D:\Test> ' les pré requis sont les deux outils suivants : WSH D:\Test> ' - PsExec de Windows Sysinternals WSH D:\Test> ' - RunAsLoggedOnUser >= 1.0.0.3 disponible sur mon site WSH D:\Test> WSH D:\Test> ' vérification des pré requis WSH D:\Test> echo CStr (oRemoteIE.CheckPrerequisites ()) Checking prerequisites ... PSExec.exe : Faux RunAsLoggedOnUser.exe : Faux Operation completed successfully Faux WSH D:\Test> ' les deux outils ne sont pas installés ou non présents dans l'un WSH D:\Test> ' des dossiers référencé par la variable d'environnement Path WSH D:\Test> ' en fait, j'ai installé ces deux outils dans le dossier "D:\Test" WSH D:\Test> oRemoteIE.OptionalToolsFolder = "D:\Test" http://glsft.free.fr Propulsé par Joomla! Généré: 16 February, 2017, 19:51 glsft.free.fr Checking Tools Folder ... Tools folder exists on this machine : D:\TEST Operation completed successfully WSH D:\Test> ' ok, le dossier spécifié existe bien sur ma machine locale WSH D:\Test> ' nouvelle vérification des pré requis WSH D:\Test> echo CStr (oRemoteIE.CheckPrerequisites ()) Checking prerequisites ... PSExec.exe : Vrai RunAsLoggedOnUser.exe : Vrai Operation completed successfully Vrai WSH D:\Test> ' tout semble en ordre au niveau de l'outillage nécessaire WSH D:\Test> ' une autre étape consiste à s'assurer qu'un utilisateur est bien WSH D:\Test> ' connecté sur la machine distante WSH D:\Test> ' pour cela il suffit d'utiliser la méthode "IsUserLoggedIn" en WSH D:\Test> ' spécifiant comme paramètre le nom NetBIOS ou DNS de la machine WSH D:\Test> ' distante WSH D:\Test> echo CStr (oRemoteIE.IsUserLoggedIn ("\\homem500")) Trying to connect to \\HOMEM500 ... Number of logged on users (including service accounts) : 2 At least on user is logged in to \\HOMEM500 Operation completed successfully Vrai WSH D:\Test> ' au moins un utilisateur semble être connecté sur la machine WSH D:\Test> ' distance HOMEM500 WSH D:\Test> ' Note: Les comptes de service sont également comptabilisés ! WSH D:\Test> WSH D:\Test> ' le script VBScript distant doit être présent dans un dossier WSH D:\Test> ' de la machine distante. Ce script VBScript porte le nom : WSH D:\Test> ' IExplore.vbs. Par défaut, il doit être présent à la racine de WSH D:\Test> ' la partition C:\. Ce dossier par défaut peut être modifié via WSH D:\Test> ' la propriété "RemoteScriptFolder" WSH D:\Test> ' affichage du dossier distant défini par défaut WSH D:\Test> echo oRemoteIE.RemoteScriptFolder C:\ WSH D:\Test> ' lecture des URL Internet Explorer (ici la version IE7) WSH D:\Test> ' - deux onglets dans une instance IE7 WSH D:\Test> ' - un seul onglet dans une autre instance IE7 WSH D:\Test> arrURL=oRemoteIE.GetRemoteIERunningInstances ("\\homem500") Checking prerequisites ... PSExec.exe : Vrai RunAsLoggedOnUser.exe : Vrai Operation completed successfully Creating temporary file ... Running remote command ... Checking result ... Reading remote URL ... Operation completed successfully WSH D:\Test> ' Tout est "successfully" ;-) WSH D:\Test> ' combien d'URL utilise l'utilisateur sur la machine distante ? WSH D:\Test> echo UBound (arrURL) 3 WSH D:\Test> ' l'utilisateur connecté sur la machine distante HOMEM500 utilise WSH D:\Test> ' actuellement trois URL WSH D:\Test> ' mais quelles sont ces URL consultées ? WSH D:\Test> ' affichage formaté des instances IE WSH D:\Test> ft arrURL,"Id","","*" Id Name URL -- -----2568 iexplore.exe http://glsft.free.fr/ 3512 iexplore.exe http://fr.msn.com/ 3512 iexplore.exe http://www.google.fr/ WSH D:\Test> ' Enjoy ! http://glsft.free.fr Propulsé par Joomla! Généré: 16 February, 2017, 19:51 glsft.free.fr Tip_1 : Fixer la propriété Verbose à False désactive le mode verbeux ;-) Vous trouverez ci-dessous le listing du module externe _wshRemoteIExplore.inc de la console WSH Shell ainsi que le listing du script VBScript IExplore.vbs à déposer celui-ci sur la machine distante. Listing 1 : _wshRemoteIExplore.inc -' - ' Windows Script Host (WSH) Shell - ' (c) 2008 Gilles LAURENT - ' wshRemoteIExplore Class v1.0.0.1 -' - Option Explicit - ' spécification des objets COM requis pour exécuter ce module externe - ' un message d'erreur s'affichera lors du chargement du module externe - ' si les pré requis ne sont pas vérifiés et la classe ne sera pas chargée - ' en mémoire donc ne pourra être instanciée - shell.Require "DynamicWrapper" - Class WSHRemoteIExplore - ' ========================= - ' == PRIVATE PROPERTIES - ' ========================= - Private m_oFs, m_oRe, m_oDyn, m_oSh - Private m_strToolsFolder, m_strScriptFolder, m_strRALUPath, m_strPSEPath - Private m_dwToolsPtr - Private m_bVerbose - ' ========================= - ' == PUBLIC PROPERTIES - ' ========================= - Public Property Get OptionalToolsFolder () OptionalToolsFolder = m_strToolsFolder - End Property - Public Property Let OptionalToolsFolder (strToolsFolder) ' déclaration des variables Dim oFolder If Not IsNull (strToolsFolder) Then ' vérification de l'existance du dossier contenant les outils PrintMessage "Checking Tools Folder ..." & Chr (2) Set oFolder = m_oFs.GetFolder (strToolsFolder) ' le dossier existe ' lecture du chemin court m_strToolsFolder = oFolder.ShortPath PrintMessage "Tools folder exists on this machine : " & UCase (m_strToolsFolder) & Chr (2) ' libération de l'objet Set oFolder = Nothing Else ' le dossier n'est pas spécifié m_strToolsFolder = Null End If ' détermination de l'adresse de la chaine de caractères m_dwToolsPtr = m_oDyn.GetBSTRAddr (m_strToolsFolder) ' traitement achevé avec succès PrintMessage "Operation completed successfully" & Chr (2) - End Property - Public Property Get RemoteScriptFolder () RemoteScriptFolder = m_strScriptFolder - End Property - Public Property Let RemoteScriptFolder (strScriptFolder) PrintMessage "Remote script folder set to " & UCase (strScriptFolder) & Chr (2) m_strScriptFolder = strScriptFolder ' traitement achevé avec succès PrintMessage "Operation completed successfully" & Chr (2) http://glsft.free.fr Propulsé par Joomla! Généré: 16 February, 2017, 19:51 glsft.free.fr - End Property Public Property Get Verbose () Verbose = m_bVerbose End Property Public Property Let Verbose (bValue) m_bVerbose = CBool (bValue) End Property Public Property Get Version () m_oRe.Pattern="\r\n\'.+?[vV]((\d+\.?){3}(\.\d+)?)\r\n" Version = m_oRe.Execute (m_oFs.OpenTextFile (shell.Path & "\Include\_" & TypeName (Me) & ".inc", 1, False).ReadAll ())( Matches (0) - End Property - ' ========================= - ' == PRIVATE MEMBERS - ' ========================= - Private Sub Class_Initialize () ' initialisation des objets Set m_oDyn = CreateObject ("DynamicWrapper") Set m_oFs = CreateObject ("Scripting.FileSystemObject") Set m_oSh = CreateObject ("WScript.Shell") Set m_oRe = New RegExp ' initialisation des variables m_bVerbose = True m_strToolsFolder = Null m_strScriptFolder = "C:\" m_dwToolsPtr = m_oDyn.GetBSTRAddr (m_strToolsFolder) ' déclaration des API Win32 (prototypes) m_oDyn.Register "shlwapi.dll", "PathFindOnPathW", "f=s", "r=b", "i=ll" m_oDyn.Register "netapi32.dll", "NetApiBufferFree", "f=s", "r=l", "i=l" m_oDyn.Register "netapi32.dll", "NetWkstaGetInfo", "f=s", "r=l","i=lll" ' définition des propriétés de l'expression régulière m_oRe.IgnoreCase = True m_oRe.Multiline = False m_oRe.Global = True - End Sub - Private Sub Class_Terminate () ' libération des objets Set m_oRe = Nothing Set m_oSh = Nothing Set m_oFs = Nothing Set m_oDyn = Nothing - End Sub - Private Sub PrintMessage (str) ' le message s'affiche uniquement en mode verbeux If Verbose Then WScript.Echo str - End Sub - ' ========================= - ' == PUBLIC MEMBERS - ' ========================= - Public Function CheckPrerequisites () ' déclaration des variables Dim bRet(1) Dim strFileName ' vérification de la présence des pré requis PrintMessage "Checking prerequisites ..." & Chr (2) strFileName=Left("PSExec.exe" & String(260,0), 260) bRet(0) = m_oDyn.PathFindOnPathW (m_oDyn.GetBSTRAddr(strFileName), m_oDyn.GetVariantAddr (m_dwToolsPtr)) PrintMessage "PSExec.exe : " & CStr (bRet(0)) & Chr (2) ' sauvegarde du chemin complet de l'outil PSExec.exe m_strPSEPath = Left(strFileName, InStr(strFileName, Chr(0)) - 1) strFileName=Left("RunAsLoggedOnUser.exe" & String(260,0), 260) bRet(1) = m_oDyn.PathFindOnPathW (m_oDyn.GetBSTRAddr(strFileName), m_oDyn.GetVariantAddr (m_dwToolsPtr)) PrintMessage "RunAsLoggedOnUser.exe : " & CStr (bRet(1)) & Chr (2) http://glsft.free.fr Propulsé par Joomla! Généré: 16 February, 2017, 19:51 glsft.free.fr ' sauvegarde du chemin complet de l'outil RunAsLoggedOnUser.exe m_strRALUPath = Left(strFileName, InStr(strFileName, Chr(0)) - 1) ' traitement achevé avec succès PrintMessage "Operation completed successfully" & Chr (2) ' retour du résultat de l'opération CheckPrerequisites = bRet(0) And bRet(1) - End Function - Public Function GetRemoteIERunningInstances (strComputer) ' déclaration des variables Dim strTempFileName, strCmd Dim arrContent ' vérification de la présence des pré requis If CheckPrerequisites () = True Then ' création d'un fichier temporaire PrintMessage "Creating temporary file ..." & Chr (2) strTempFileName = m_oFs.GetSpecialFolder (2) & "\" & m_oFs.GetTempName () ' préparation de la commande strCmd = "%COMSPEC% /c " & m_strPSEPath & " " & strComputer & " -accepteula -s -c " & m_strRALUPath & " -hide cmd " & Chr(34) & "cscript.exe //nologo " & m_strScriptFolder & "\IExplore.vbs" & Chr(34) & "2>nul >" & strTempFileName ' exécution de la commande distante ' la méthode Exec ne semble pas fonctionner avec l'outil psexec :-( PrintMessage "Running remote command ..." & Chr (2) m_oSh.Run strCmd, 0, True ' vérification du résultat de l'opération PrintMessage "Checking result ..." & Chr(2) ' le fichier peut être vide sur la machine distante est inaccessible ' il est donc nécessaire de gérer les erreurs On Error Resume Next arrContent = Shell.GetFileContent (strTempFileName) On Error Goto 0 ' le fichier ne doit pas être vide ! If IsArray (arrContent) Then ' vérification de la présence du header If arrContent(0) = "Id,Name,URL" Then ' lecture des url PrintMessage "Reading remote URL ..." & Chr (2) GetRemoteIERunningInstances = Shell.StringToArray (Replace (Shell.ArrayToString (arrContent), ",", Shell.strTable ) ' traitement achevé avec succès PrintMessage "Operation completed successfully" & Chr (2) Else ' une erreur est survenue WScript.Echo ":: An error occurred" & Chr (1) & " :: Remote process failed to execute" End If Else ' une erreur est survenue WScript.Echo ":: An error occurred" & Chr (1) & " :: Temporary file is empty !" End If ' suppression du fichier temporaire If m_oFs.FileExists (strTempFileName) Then m_oFs.DeleteFile strTempFileName, True Else ' les pré requis ne sont pas vérifiés ' Impossible d'exécuter l'opération requise Err.Raise 17 End If - End Function - Public Function IsUserLoggedIn (strComputer) ' déclaration des variables Dim bUserLoggedIn: bUserLoggedIn = False Dim lRet, lBufferAddr, lBufferPtr, lNbLoggedOnUsers ' récupération des informations de niveau 102 ' la structure WKSTA_INFO_102 est allouée par le système PrintMessage "Trying to connect to " & UCase (strComputer) & " ..." & Chr (2) lRet = m_oDyn.NetWkstaGetInfo (m_oDyn.GetBSTRAddr (strComputer), 102, m_oDyn.GetVariantAddr (lBufferAddr)) http://glsft.free.fr Propulsé par Joomla! Généré: 16 February, 2017, 19:51 glsft.free.fr ' vérification du résultat de l'opération If lRet = 0 Then ' l'opération a réussi ' récupération du pointeur sur la structure WKSTA_INFO_102 (LPBYTE *) lBufferPtr = m_oDyn.GetMemInBSTRAddr(m_oDyn.GetVariantAddr (lBufferAddr), 0, 4) ' détermination du nombre d'utilisateur connecté sur la machine distante lNbLoggedOnUsers = m_oDyn.GetMemInBSTRAddr (lBufferPtr, 24, 4) PrintMessage "Number of logged on users (including service accounts) : " & lNbLoggedOnUsers & Chr (2) ' évaluation du nombre d'utilisateur connecté If lNbLoggedOnUsers > 0 Then ' au moins un utilisateur est connecté sur la machine distante PrintMessage "At least on user is logged in to " & UCase (strComputer) & Chr (2) bUserLoggedIn = True Else ' aucun utilisateur connecté sur la machine distante PrintMessage "No user is logged in to " & UCase (strComputerName) End If ' libération du buffer alloué par le système m_oDyn.NetApiBufferFree (lBufferAddr) Else ' une erreur est survenue WScript.Echo ":: An error occurred (" & lRet & ")" & Chr (1) & " :: " & m_oDyn.FormatMessage (lRet) End If ' traitement achevé avec succès PrintMessage "Operation completed successfully" & Chr (2) ' retour du résultat de l'opération IsUserLoggedIn = bUserLoggedIn - End Function - End Class Listing 2 : IExplore.vbs - Option Explicit - ' déclaration des variables - Dim oDyn, oApp, oWindow, oProc - Dim dwPid: dwPid=CLng(0) - ' initialisation des objets - Set oDyn=CreateObject("DynamicWrapper") - Set oApp=CreateObject("Shell.Application") - ' déclaration des API Win32 (prototypes) - oDyn.Register "User32.dll", "GetWindowThreadProcessId", "f=s", "r=l", "i=hl" - ' écriture du header dans le flux stdout - WScript.Echo "Id,Name,URL" - ' énumération des instances Explorer et Internet Explorer - For Each oWindow In oApp.windows - ' détermination du pid du processus - oDyn.GetWindowThreadProcessId oWindow.HWND, oDyn.GetVariantAddr(dwPid) - ' détermination du nom du processus - Set oProc = GetObject("winmgmts:/root/cimv2:Win32_Process.Handle='" & dwPid & "'") - ' écriture des informations dans le flux stdout - WScript.Echo oProc.ProcessId & "," & oProc.Name & "," & oWindow.LocationURL - Next http://glsft.free.fr Propulsé par Joomla! Généré: 16 February, 2017, 19:51