Comment tester si des ports sont ouverts en PowerShell

J’ai récemment eu besoin d’effectuer en volume des tests de ports pour vérifier si ces derniers étaient ouverts ou non au sein d’une infrastructure.

Jusqu’à présent, j’avais toujours résolu ce type de questions en effectuant mes tests Telnet à la main en installant sur mon Windows Server le client Telnet. Mais cela peut vite devenir un peu ennuyeux lorsque vous devez tester un grand nombre de ports (et sur plusieurs serveurs).

Contexte

Je vous propose de partager un court script PowerShell qui m’a permis de répondre à ce besoin et que j’utilise régulièrement depuis.

Mon contexte est le suivant : je dispose de plusieurs scénarios qui comportent chacun une série spécifique de ports à tester. Je souhaite donc exécuter un scénario en particulier en fonction du serveur sur lequel je suis connecté. Idéalement, je ne souhaite pas modifier le script si jamais un port doit être changé/supprimé ou ajouté.

Mon script sera composé de 2 fichiers : 1 fichier CSV qui contiendra les différents scénarios de tests et 1 script PowerShell que je pourrais appeler en fonction de mon besoin et qui utilisera en entrée le fichier CSV. Je souhaite également pouvoir tester des ports dont le protocole sera TCP ou UDP (et le script doit pouvoir gérer ça tout seul). Pas besoin de gérer d’autres protocoles dans mon cas de figure.

Comme d’habitude, je vous partage tous les fichiers à la fin de l’article pour que vous puissiez tester de votre côté si besoin. Libre à vous de copier/adapter le tout en fonction de vos besoins.

Fichier CSV

De mon côté, je suis parti sur un fichier CSV avec le contenu suivant – TestPortsOpened.csv :

scenario,name,port,protocol
scenario1,http,80,TCP
scenario1,proxy,8080,TCP
scenario1,https web,443,TCP
scenario2,ssh,22,TCP
scenario2,ssh_2222,2222,TCP
scenario2,rdp,3389,TCP
scenario2,udp_161,161,UDP
scenario2,udp_162,162,UDP

Donc avec cet exemple si je choisi d’exécuter le test correspondant au scénario 1, le script va tester les ports 80/TCP, 8080/TCP, 443/TCP.

Si je test le scénario 2, les ports testés seront les suivants 22/TCP, 2222/TCP3389/TCP, 161/UDP, 162/UDP.

Script PowerShell

La première partie du script TestPortsOpened.csv commencera avec les éléments suivants :

############################################################
# Objective: Check port requirements automatically
############################################################
param(
[Parameter(Mandatory=$true)]
[string]$scenario,
[Parameter(Mandatory=$true)]
[string]$target
)

# Variables
$MyFolder = (Get-Location).Path
$ConfigFile = $MyFolder + "\" + ($MyInvocation.MyCommand).Name.Replace(".ps1", ".csv")

# We read the configuration of the XML variable for the test to process
$data = Import-Csv $ConfigFile
$data = $data | Where-Object { $_.scenario -eq $scenario }

Ce script fonctionnera avec 2 paramètres : le nom du scénario à tester ainsi que l’adresse cible que l’on souhaite tester.

Les premières variables vont nous permettre successivement récupérer le dossier d’exécution du script, trouver automatiquement le fichier CSV correspondant dans le dossier et finalement notre variable $data importera notre fichier CSV pour ne garder que le scénario et les ports correspondants à tester.

foreach ($item in $data)
{
# Limit the outputs when the connection will fail
$ErrorActionPreference = 'SilentlyContinue'

# Force clearing the variable
$connect = $null

# Protocol UDP
if ($item.protocol -eq "UDP")
{
$connection = New-Object -TypeName System.Net.Sockets.UdpClient -ArgumentList $target,$($item.port)
}

# Protocol TCP (all others cases)
else
{
$connection = New-Object -TypeName System.Net.Sockets.TcpClient -ArgumentList $target,$($item.port)
}

# If connection has been successfully established
if ($connection.Connected)
{
# Displaying the result
Write-Host "Test executed on $($item.port) ($($item.protocol)) from localhost to $($target): " -NoNewline
Write-Host "SUCCESS" -ForegroundColor Green
}

# If the connection has timedout and can't be established
else
{
# Displaying the result
Write-Host "Test executed on $($item.port) ($($item.protocol)) from localhost to $($target): " -NoNewline
Write-Host "FAILED" -ForegroundColor Red
}
# Closing connection
$connection.Close()
}

Pour chaque scénario, nous avons donc plusieurs ports à tester. Dans la variable $data nous avons récupéré la liste des ports à tester pour un scénario donné.

Pour chaque ligne, nous avons donc 1 port à tester avec le numéro, un nom/description (dont nous ne faisons rien) et le protocole.

Cette boucle foreach va nous permettre pour un port donné de :

  • Tester s’il s’agit d’un port UDP ou TCP et en fonction du protocole on établit une nouvelle connexion de type System.Net.Sockets.UdpClient dans le cas d’un port UDP ou System.Net.Sockets.TcpClient pour le protocole TCP ;
  • Si nous parvenons à établir la connexion avec succès  dans ce cas nous affichons un message de succès avec une coloration verte et la mention “SUCCESS” ;
  • En revanche, sinon nous ne parvenons pas à établir la connexion dans ce cas le message se terminera de la mention “FAILED” en rouge ;
  • Une fois terminé, on clos la connexion proprement. 🙂

Exemples d’exécution

Bien entendu, pour pouvoir effectuer un test probant, réalisez votre test sur un serveur ou quelque-chose dont vous maîtrisez la configuration réseau.

Pour télécharger l’intégralité du script ainsi qu’un exemple de fichier CSV suivez lien: TestPortsOpened. 

Testé sous Windows Server 2012 R2, 2016 (avec les versions PowerShell intégrées par défaut à ces versions d’OS).