Question boucle

Plus d'informations
il y a 1 an 5 mois #32783 par Laurent
boucle a été créé 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 !
 

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 1 an 5 mois #32784 par Laurent Dardenne
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 :
$network = "192.168.0."
$Liste=1..254|ForEach-Object % { [PSCustomObject]@{IP=$network$ip;Succes=$false} }
#A adapter
$Liste|% {if (test -eq ok){$_.IP=$true}}
Ensuite tu filtres le résultat selon tes besoins et avec Select-object tu prend les propriétés qui t'intéressent.

Tutoriels PowerShell
Les utilisateur(s) suivant ont remercié: Laurent

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 1 an 5 mois #32785 par Laurent
Réponse de Laurent sur le sujet boucle
Merci pour ce retour ! ça va me permettre de m'amuser un peu et de faire avancer ce petit exercice que je me suis donné ^^'
c'est effectivement une écriture à laquelle je ne suis pas encore trop coutumier.
Je poursuis !

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 1 an 4 mois #32899 par ericlm128
Réponse de ericlm128 sur le sujet boucle
Petite erreur ici
ForEach-Object %

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 1 an 4 mois - il y a 1 an 3 mois #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]$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)"
        }
    }
}
[/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]$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)"
        }
    }
}
[/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]$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"
[/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]<#
    .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"
[/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.
Dernière édition: il y a 1 an 3 mois par Christophe MELIN.

Connexion ou Créer un compte pour participer à la conversation.

Temps de génération de la page : 0.073 secondes
Propulsé par Kunena