Question
boucle
- Laurent
- Auteur du sujet
- Hors Ligne
- Nouveau membre
-
Réduire
Plus d'informations
- Messages : 11
- Remerciements reçus 0
il y a 10 mois 3 semaines #32783
par Laurent
bonjour la communauté,
J'essaye d'apprendre un peu Powershell...la tâche est ardue, je me suis lancé dans les boucles enfin des choses basiques...
J'ai connecté 3 PC à ma box et j'essaye de faire un ping, d'exporter les résultats, de faire des choses propres...
C'est un voeu pieux pour le moment.
Pour le moment, je réussi juste à faire en sorte de toujours implémenter le même fichier.
$network = "192.168.0."
$ip = 1..254
for($ip=0;$ip -lt 255;$ip++)
{
Set-Content -Path C:\Users\Laurent\Desktop\test.txt -Value $network$ip
}
En modifiant set-content par test-netconnection $network$ip mais ça ne me satisfait qu'à peine...
Je préfèrerai exporter les résultats "positifs" dans un fichier et les résultats négatifs dans un second.
une fois, ces petites tâches effectuées...je voudrais m'amuser à tester les ports...
Je sais que je peux voir ceux de ma machine avec une commande simple : Get-NetTCPConnection -State Listen puis préciser avec des numéros de ports.
Comme je suis un peu intrépide et stupide, il me semble qu'on peut aussi faire quelque chose comme Test-NetConnection 192.168.0.254:8080
Ce que je trouve intéressant c'est qu'avec une commande pareil, je pourrai inclure une seconde variable...et ça me permettrait de travailler sur un script un peu plus fous tout en restant dans un domaine légal...le périmètre entre mon ordinateur et ma box.
bref voilà vous savez tout...et si vous avez un conseil je suis preneur !
J'essaye d'apprendre un peu Powershell...la tâche est ardue, je me suis lancé dans les boucles enfin des choses basiques...
J'ai connecté 3 PC à ma box et j'essaye de faire un ping, d'exporter les résultats, de faire des choses propres...
C'est un voeu pieux pour le moment.
Pour le moment, je réussi juste à faire en sorte de toujours implémenter le même fichier.
$network = "192.168.0."
$ip = 1..254
for($ip=0;$ip -lt 255;$ip++)
{
Set-Content -Path C:\Users\Laurent\Desktop\test.txt -Value $network$ip
}
En modifiant set-content par test-netconnection $network$ip mais ça ne me satisfait qu'à peine...
Je préfèrerai exporter les résultats "positifs" dans un fichier et les résultats négatifs dans un second.
une fois, ces petites tâches effectuées...je voudrais m'amuser à tester les ports...
Je sais que je peux voir ceux de ma machine avec une commande simple : Get-NetTCPConnection -State Listen puis préciser avec des numéros de ports.
Comme je suis un peu intrépide et stupide, il me semble qu'on peut aussi faire quelque chose comme Test-NetConnection 192.168.0.254:8080
Ce que je trouve intéressant c'est qu'avec une commande pareil, je pourrai inclure une seconde variable...et ça me permettrait de travailler sur un script un peu plus fous tout en restant dans un domaine légal...le périmètre entre mon ordinateur et ma box.
bref voilà vous savez tout...et si vous avez un conseil je suis preneur !
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Hors Ligne
- Modérateur
-
Réduire
Plus d'informations
- Messages : 6294
- Remerciements reçus 67
il y a 10 mois 3 semaines #32784
par Laurent Dardenne
Tutoriels PowerShell
Réponse de Laurent Dardenne sur le sujet boucle
Salut,
pour ceci :
>>Je préfèrerai exporter les résultats "positifs" dans un fichier et les résultats négatifs dans un second.
tu peux aussi construire un psobject avec des propriétés supplémentaires :Ensuite tu filtres le résultat selon tes besoins et avec Select-object tu prend les propriétés qui t'intéressent.
pour ceci :
>>Je préfèrerai exporter les résultats "positifs" dans un fichier et les résultats négatifs dans un second.
tu peux aussi construire un psobject avec des propriétés supplémentaires :
$network = "192.168.0."
$Liste=1..254|ForEach-Object % { [PSCustomObject]@{IP=$network$ip;Succes=$false} }
#A adapter
$Liste|% {if (test -eq ok){$_.IP=$true}}
Tutoriels PowerShell
Les utilisateur(s) suivant ont remercié: Laurent
Connexion ou Créer un compte pour participer à la conversation.
- Laurent
- Auteur du sujet
- Hors Ligne
- Nouveau membre
-
Réduire
Plus d'informations
- Messages : 11
- Remerciements reçus 0
il y a 10 mois 3 semaines #32785
par Laurent
Connexion ou Créer un compte pour participer à la conversation.
- ericlm128
- Hors Ligne
- Membre elite
-
Réduire
Plus d'informations
- Messages : 169
- Remerciements reçus 35
- Christophe MELIN
- Hors Ligne
- Nouveau membre
-
Réduire
Plus d'informations
- Messages : 16
- Remerciements reçus 1
il y a 9 mois 3 jours - il y a 9 mois 1 jour #32906
par Christophe MELIN
Réponse de Christophe MELIN sur le sujet boucle
% est un alias de la commande foreach-object. Il faut donc supprimer un des deux termes. Personnellement, je n'aime pas les alias %(foreach-object) et ? (where-object). Je préfère utiliser les cmdlet par leur nom explicit car cela facilite la lecture d'un code. Pour ton exercice, je me suis livré à quelques tests.
Exemple n°1[/code][/code]
Le problème avec ce code est que les actions ont totalement séquentielles. J'ai utilisé un objet de type StopWatch qui sert un peu de de chronomêtre. En gros le test d'un port sur une adresse IP prend environ 2 secondes donc le simple test de tous les port sur l'adresse IP d'une machine allumée var prendre 65535 * 2 / 86400 soit 1j 12h 24m. Comme cela représente un temps inacceptable, j'ai essayé un deuxième code avec des objets réseau de plus bas niveau.
Exemple n°2[/code][/code]
Globalement, le problème ne change pas. Les durées sont du même ordre de grandeur. Il fallait s'orienter vers une autre solution. J'ai donc regardé une méthode qui travaille de manière asynchrone.
Exemple n°3[/code][/code]
Dans cet exemple, je n'ai pas encore pu imbriquer le test des ports mais sur 254 possibilités, j'ai pu pinguer avec succès 180 serveurs en moins de 5 secondes alors que dans les exemples 1 et 2, il fallait environ 1.5 secondes par serveur soit environ 6 minutes 20 secondes
Dernier exercice de style (mais j'ai repris une fonction trouvée sur GitHub pour le multithreading). Il s'agit de scanner une étendue de ports sur une seule adresse ip. Exemple n°4[/code]
Dans cette exemple, on scanne les ports de 1 à 65535 pour l'adresse 192.168.1.xx (à mettre à jour bien sûr) en autorisant 1024 threads simultanées.
Avec toutes ces briques, voilà de quoi se faire un scanneur de port qui ne va pas tourner pendant des jours.
Exemple n°1
[code][code]$network = "192.168.1"
$IPRange = 1..254
$PortRange = 1..65535
$stopwatch = [system.diagnostics.stopwatch]::StartNew()
foreach( $i in $IPRange ) {
$ip = "$network.$i"
if ( -not (test-connection $ip -Count 1 -Quiet) ) {
write-host ". $ip;poste non joignable;$($stopwatch.elapsed.Totalmilliseconds)"
continue # passe directement à l'ip suivante
}
foreach ( $port in $PortRange ) {
if ( (test-netconnection -computername $ip -Port $port -WarningAction Silentlycontinue -InformationLevel quiet) ) {
write-host ". $ip;$port;opérationnel;$($stopwatch.elapsed.Totalmilliseconds)"
} else {
write-host ". $ip;$port;bloqué;$($stopwatch.elapsed.Totalmilliseconds)"
}
}
}
Le problème avec ce code est que les actions ont totalement séquentielles. J'ai utilisé un objet de type StopWatch qui sert un peu de de chronomêtre. En gros le test d'un port sur une adresse IP prend environ 2 secondes donc le simple test de tous les port sur l'adresse IP d'une machine allumée var prendre 65535 * 2 / 86400 soit 1j 12h 24m. Comme cela représente un temps inacceptable, j'ai essayé un deuxième code avec des objets réseau de plus bas niveau.
Exemple n°2
[code][code]$network = "192.168.1"
$IPRange = 1..254
$PortRange = 1..65535
$ping = new-object System.Net.NetworkInformation.Ping
$tcpclient = New-Object Net.Sockets.TcpClient
$stopwatch = [system.diagnostics.stopwatch]::StartNew()
foreach( $i in $IPRange ) {
$ip = "$network.$i"
$result = $ping.send($ip)
if ( $result.status -ne "success" ) {
write-host ". $ip;erreur : $($result.status);$($stopwatch.elapsed.Totalmilliseconds)"
continue
}
foreach ( $port in $PortRange ) {
try {
$tcpclient.connect( $ip, $port )
if ($tcpclient.connected) {
write-host ". $ip;$port;opérationnel;$($stopwatch.elapsed.Totalmilliseconds)"
$tcpclient.close()
}
} catch {
write-host ". $ip;$port;bloqué;$($stopwatch.elapsed.Totalmilliseconds)"
}
}
}
Globalement, le problème ne change pas. Les durées sont du même ordre de grandeur. Il fallait s'orienter vers une autre solution. J'ai donc regardé une méthode qui travaille de manière asynchrone.
Exemple n°3
[code][code]$network = "192.168.1"
$IPRange = 1..254
$IPs = $IPRange | ForEach { "$network.$_" }
$stopwatch = [system.diagnostics.stopwatch]::StartNew()
#-- crée un système de thread pour réaliser des ping asynchrones --
$Task = foreach( $ip in $IPs ) { (New-Object System.Net.NetworkInformation.Ping).SendPingAsync($ip) }
#-- attend que tous les threads soient terminées --
[Threading.Tasks.Task]::WaitAll($Task)
#-- récupère juste la liste des postes qui ont répondu au ping --
$Task.result | where { $_.status -eq "success" } | ft -auto *
write-host "> terminé en $($stopwatch.elapsed.TotalMilliSeconds) ms"
Dans cet exemple, je n'ai pas encore pu imbriquer le test des ports mais sur 254 possibilités, j'ai pu pinguer avec succès 180 serveurs en moins de 5 secondes alors que dans les exemples 1 et 2, il fallait environ 1.5 secondes par serveur soit environ 6 minutes 20 secondes
Dernier exercice de style (mais j'ai repris une fonction trouvée sur GitHub pour le multithreading). Il s'agit de scanner une étendue de ports sur une seule adresse ip. Exemple n°4
[code]<#
.SYNOPSIS
Powerful asynchronus IPv4 Port Scanner
.DESCRIPTION
This powerful asynchronus IPv4 Port Scanner allows you to scan every Port-Range you want (500 to 2600 would work). Only TCP-Ports are scanned.
The result will contain the Port number, Protocol and the Status.
.LINK
https://github.com/BornToBeRoot/PowerShell_IPv4PortScanner/blob/master/README.md
#>
function IPv4PortScan {
param(
[Parameter(
Position = 0,
Mandatory = $true,
HelpMessage = 'ComputerName or IPv4-Address of the device which you want to scan')]
[String]$ComputerName,
[Parameter(
Position = 1,
HelpMessage = 'First port which should be scanned (Default=1)')]
[ValidateRange(1, 65535)]
[Int32]$StartPort = 1,
[Parameter(
Position = 2,
HelpMessage = 'Last port which should be scanned (Default=65535)')]
[ValidateRange(1, 65535)]
[ValidateScript({
if ($_ -lt $StartPort) {
throw "Invalid Port-Range!"
}
else {
return $true
}
})]
[Int32]$EndPort = 65535,
[Parameter(
Position = 3,
HelpMessage = 'Maximum number of threads at the same time (Default=512)')]
[Int32]$Threads = 512
)
Process {
$PortsToScan = ($EndPort - $StartPort)
Write-Verbose -Message "Scanning range from $StartPort to $EndPort ($PortsToScan Ports)"
Write-Verbose -Message "Running with max $Threads threads"
# Check if ComputerName is already an IPv4-Address, if not... try to resolve it
if ([bool]($ComputerName -as [IPAddress])) {
$IPv4Address = $ComputerName
} else {
$IPv4Address = [String]::Empty
# Get IP from Hostname (IPv4 only)
try {
$AddressList = @(([System.Net.Dns]::GetHostEntry($ComputerName)).AddressList)
foreach ($Address in $AddressList) {
if ($Address.AddressFamily -eq "InterNetwork") {
$IPv4Address = $Address.IPAddressToString
break
}
}
} catch { } # Can't get IPAddressList
if ([String]::IsNullOrEmpty($IPv4Address)) {
throw "Could not get IPv4-Address for $ComputerName. (Try to enter an IPv4-Address instead of the Hostname)"
}
}
# Scriptblock --> will run in runspaces (threads)...
[System.Management.Automation.ScriptBlock]$ScriptBlock = {
Param(
$IPv4Address,
$Port
)
try {
$Socket = New-Object System.Net.Sockets.TcpClient($IPv4Address, $Port)
if ($Socket.Connected) {
$Socket.Close()
[pscustomobject] @{
Port = $Port
Protocol = "tcp"
Status = "Open"
}
}
} catch { }
}
Write-Verbose -Message "Setting up RunspacePool..."
# Create RunspacePool and Jobs
$RunspacePool = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspacePool(1, $Threads, $Host)
$RunspacePool.Open()
[System.Collections.ArrayList]$Jobs = @()
Write-Verbose -Message "Setting up Jobs..."
# Set up job for each port...
Write-Progress -Activity "Creating scan jobs..." -Id 1 -Status "Current Port: 0" -PercentComplete (0)
$i = 0
$oldpercent = 0
foreach ($Port in $StartPort..$EndPort) {
$i++
$ScriptParams = @{
IPv4Address = $IPv4Address
Port = $Port
}
# Catch when trying to divide through zero
try {
[int]$Progress_Percent = ($i / $PortsToScan) * 100
} catch {
[int]$Progress_Percent = 100
}
if ( ($oldpercent -ne $progress_percent) ) {
Write-Progress -Activity "Creating scan jobs..." -Id 1 -Status "Current Port: $Port" -PercentComplete ($Progress_Percent)
$oldpercent = $progress_percent
}
# Create mew job
$Job = [System.Management.Automation.PowerShell]::Create().AddScript($ScriptBlock).AddParameters($ScriptParams)
$Job.RunspacePool = $RunspacePool
$JobObj = [pscustomobject] @{
RunNum = $i
Pipe = $Job
Result = $Job.BeginInvoke()
}
# Add job to collection
[void]$Jobs.Add($JobObj)
}
Write-Verbose -Message "Waiting for jobs to complete & starting to process results..."
# Total jobs to calculate percent complete, because jobs are removed after they are processed
$Jobs_Total = $Jobs.Count
# Process results, while waiting for other jobs
Do {
# Get all jobs, which are completed
$Jobs_ToProcess = $Jobs | Where-Object -FilterScript { $_.Result.IsCompleted }
# If no jobs finished yet, wait random between 300 and 480 ms (by step of 60ms) and try again
if ($null -eq $Jobs_ToProcess) {
Start-Sleep -Milliseconds ( (get-random -minimum 5 -maximum 8)*60 )
continue
}
# Get jobs, which are not complete yet
$Jobs_Remaining = $Jobs.count - $Jobs_ToProcess.count
# Catch when trying to divide through zero
try {
$Progress_Percent = 100 - (($Jobs_Remaining / $Jobs_Total) * 100)
} catch {
$Progress_Percent = 100
}
Write-Progress -Activity "Waiting for jobs to complete... ($($Threads - $($RunspacePool.GetAvailableRunspaces())) of $Threads threads running)" -Id 1 -PercentComplete $Progress_Percent -Status "$Jobs_Remaining remaining..."
# Processing completed jobs
foreach ($Job in $Jobs_ToProcess) {
# Get the result...
$Job_Result = $Job.Pipe.EndInvoke($Job.Result)
$Job.Pipe.Dispose()
# Remove job from collection
$Jobs.Remove($Job)
# Check if result is null --> if not, return it
if ($Job_Result.Status) { $Job_Result }
}
} While ($Jobs.Count -gt 0)
Write-Verbose -Message "Closing RunspacePool and free resources..."
# Close the RunspacePool and free resources
$RunspacePool.Close()
$RunspacePool.Dispose()
Write-Verbose -Message "Scan for $computername finished at $(Get-Date)"
}
}
$ip = "192.168.1.xx"
$stopwatch = [system.diagnostics.stopwatch]::StartNew()
$arrResults = IPv4PortScan -computername $ip -startport 1 -endport 65535 -threads 1024
$arrResults | ft -auto
write-host "> $($arrResults.count) ports ouverts trouvés en $($stopwatch.elapsed.TotalMilliSeconds) ms"
Dans cette exemple, on scanne les ports de 1 à 65535 pour l'adresse 192.168.1.xx (à mettre à jour bien sûr) en autorisant 1024 threads simultanées.
Avec toutes ces briques, voilà de quoi se faire un scanneur de port qui ne va pas tourner pendant des jours.
Dernière édition: il y a 9 mois 1 jour par Christophe MELIN.
Connexion ou Créer un compte pour participer à la conversation.
Temps de génération de la page : 0.054 secondes
- Vous êtes ici :
-
Accueil
-
forum
-
PowerShell
-
Entraide pour les débutants
- boucle