Souvent quand on fait un audit d’un environnement nous avons besoin d’avoir les informations, combien d’utilisateurs utilisent une application serveur, par exemple dans une session Remote desktop ou Citrix. Selon la version du système de publication utilisé, bureau ou application les outils sont différents. Là je vous propose une fonction universelle qui vous permettra d’avoir une remontée sur tout système. Dans cette fonction nous aurons en entrée ordinateur requeté et application, puis en sortie ordinateur, application, utilisateur, mémoire utilisé, à quelle heure l’application à démarrer, l’heure de la requête et le chemin où se trouve l’application.
Dans un premier temps nous allons utiliser le WMI avec la classe Win32_Process
Exemple sur un processus :
Get-WmiObject -ComputerName localhost -class Win32_Process
Et toute suite nous avons des paramètres qui nous intéressent :
- Name : pour le nom de l’application, pour cibler l’application il faudra utiliser le paramètre –query de la manière suivante :
Select * la classe Wmi ciblé
Where : La propriété ciblée ici name, puis égale à la valeur recherchée
Get-WmiObject -ComputerName $server ` -Query "Select * from Win32_Process where name = 'powershell.exe'"
- Path : Pour savoir depuis ou l’application s’exécute
- CreationDate : C’est la date de la création du processus, par contre il y aura un travail de remise en forme pour que ça soit plus compréhensible.
Pour ce faire on applique la méthode .ConvertToDateTime :
Get-WmiObject -ComputerName $server ` -Query "Select * from Win32_Process where name = 'powershell.exe'" ` | select Name,Path,` @{name='StartTime';expression={$_.ConvertToDateTime($_.CreationDate)}}
- WorkingSetSize : il nous sera peut être intéressant de remonter la consommation mémoire des applications à analyser. Ce paramètre est en en octet, exemple ci-dessous pour powershell_ise.exe
- pour finir qui a exécuté l’applicatif, nous ne l’aurons pas dans les propriétés directement. Pour ça nous allons regarder les méthodes qui s’appliquent à la classe avec un get-member :
Get-WmiObject -ComputerName $server -class Win32_Process | Get-Member
Là nous récupérons la méthode GetOwner ce qui nous donne le résultat suivant une fois appliquée :
(Get-WmiObject -ComputerName $server -class Win32_Process).GetOwner()
Là nous récupérons la méthode GetOwner ce qui nous donne le résultat suivant une fois appliquée :
(Get-WmiObject -ComputerName $server -class Win32_Process).GetOwner()
Ce n’est pas mal, nous pouvons voir les résultats une fois en forme :
Get-WmiObject -ComputerName $server -class Win32_Process ` | where {$_.path -ne $null}` | select Name,@{Label='Owner';Expression={$_.GetOwner().User}}, WorkingSetSize,` @{name='StartTime';expression={$_.ConvertToDateTime($_.CreationDate)}},` Path ` | Format-Table
Maintenant il nous reste plus qu’à mettre en forme notre script :
#variable $servers = "127.0.0.1","localhost","localh" $application = 'powershell.exe' #create table $result =@() $n = 1 foreach ($server in $servers){ #Test of connectivity try { $connection = Test-Connection -computername $Server -Count 1 -ErrorAction stop } catch [System.Net.NetworkInformation.PingException] { Write-Host "$Server offline" $connection = $False } if($connection -ne $false) { try { $results = Get-WmiObject -ComputerName $server ` -Query "Select * from Win32_Process where name = '$application'" ` | select PSComputerName,Name,@{Label='Owner';Expression={$_.GetOwner().User}}, WorkingSetSize,` @{name='StartTime';expression={$_.ConvertToDateTime($_.CreationDate)}},` Path -ErrorAction Stop write-host "test",$server } #test if remote access is ok catch [System.UnauthorizedAccessException] { write-host "$server Not access" $QueryWMITest = $False } } $QueryTime = Get-Date -format g #Query WMI Win32_Process #Processing result Foreach($fresult in $results) { $object = New-Object Psobject $object | Add-Member -Name "Server" -membertype Noteproperty -Value $null $object | Add-Member -Name "Application" -membertype Noteproperty -Value $null $object | Add-Member -Name "Memory" -membertype Noteproperty -Value $null $object | Add-Member -Name "Owner" -membertype Noteproperty -Value $null $object | Add-Member -Name "StartTime" -membertype Noteproperty -Value $null $object | Add-Member -Name "QueryTime" -membertype Noteproperty -Value $null $object | Add-Member -Name "Path" -membertype Noteproperty -Value $null $object.Server = $fresult.PSComputerName $object.Application = $fresult.Name $object.Owner = $fresult.Owner $object.Memory = ($fresult.WorkingSetSize) $object.StartTime = $fresult.StartTime $object.QueryTime = $QueryTime $object.Path = $fresult.Path $result += $object } $results = $null } $result |ft -AutoSize
Voici un exemple avec les cibles suivantes:
$servers = "127.0.0.1","localhost","localh" $application = 'powershell.exe'
Nous avons maintenant nos deux paramètres pour une future fonction $server et$application. J’ai rajouté la date du query avec un
J’ai créé aussi un objet : $object il nous sert à la mise en forme du résultat, lors de la boucle de traitement pour le $results puis elle est réinjectée dans $result
Voilà maintenant notre fonction :
<# .Synopsis Query application by user .DESCRIPTION Query application by user, Memory, Path .EXAMPLE Query-app -ComputerName 'localhost' -Application 'powershell.exe' #> function Query-app { Param ( # Name of computer query $ComputerName, # Name of application $Application ) Begin { } Process { $result =@() try { $connection = Test-Connection -computername $ComputerName -Count 1 -ErrorAction stop } catch [System.Net.NetworkInformation.PingException] { Write-Host "$ComputerName offline" $connection = $False } if($connection -ne $false) { try { $results = Get-WmiObject -ComputerName $ComputerName ` -Query "Select * from Win32_Process where name = '$application'" ` | select PSComputerName,Name,@{Label='Owner';Expression={$_.GetOwner().User}}, WorkingSetSize,` @{name='StartTime';expression={$_.ConvertToDateTime($_.CreationDate)}},` Path -ErrorAction Stop } #test if remote access is ok catch [System.UnauthorizedAccessException] { write-host "$ComputerName Not access" $QueryWMITest = $False } } $QueryTime = Get-Date -format g #Processing result Foreach($fresult in $results) { $object = New-Object Psobject $object | Add-Member -Name "ComputerName" -membertype Noteproperty -Value $null $object | Add-Member -Name "Application" -membertype Noteproperty -Value $null $object | Add-Member -Name "Memory" -membertype Noteproperty -Value $null $object | Add-Member -Name "Owner" -membertype Noteproperty -Value $null $object | Add-Member -Name "StartTime" -membertype Noteproperty -Value $null $object | Add-Member -Name "QueryTime" -membertype Noteproperty -Value $null $object | Add-Member -Name "Path" -membertype Noteproperty -Value $null $object.ComputerName = $fresult.PSComputerName $object.Application = $fresult.Name $object.Owner = $fresult.Owner $object.Memory = ($fresult.WorkingSetSize) $object.StartTime = $fresult.StartTime $object.QueryTime = $QueryTime $object.Path = $fresult.Path $result += $object } return $result } End { } }
Voici un exemple :