Búsqueda de sitios web

Un monitor de red PowerShell


Espero que hayas estado probando los desafíos de secuencias de comandos que se publican en el sitio web de Iron Scripter. Los desafíos están diseñados para que los individuos los realicen por su cuenta para desarrollar sus habilidades de secuencias de comandos de PowerShell. Hace unas semanas, se publicó un desafío para crear una herramienta de monitoreo de red usando PowerShell y el cmdlet Write-Progress. Pensé en compartir mis notas sobre el desafío y parte del código que se me ocurrió.

Desafío intermedio

El primer paso fue identificar los contadores de rendimiento necesarios para Get-Counter.

$counters = "\Network interface(*ethernet*)\Bytes sent/sec",
"\Network interface(*ethernet*)\Bytes received/sec",
"\Network interface(*ethernet*)\Bytes total/sec"

Con estos, podría usar Get-Counter para recuperar los datos.

Get-Counter -Counter $counters -MaxSamples 10 -SampleInterval 1 -ov d | 
Select-object -ExpandProperty CounterSamples | Select-Object -Property Timestamp,
@{Name="Computername";Expression = {[regex]::Match($_.path, "(?<="\)\w+").Value.toUpper() }},
@{Name = "Counter"; Expression = { ($_.path -split "\\")[-1]}},
@{Name = "Network"; Expression = {$_.instancename}},
@{Name = "Count"; Expression = {$_.cookedValue}}

Estoy analizando valores de la propiedad de muestra del contador.

Si quisiera llevar esto un paso más allá, podría definir la salida como un objeto personalizado y crear un archivo de formato ps1xml para limpiar la pantalla.

Avanzado

El desafío avanzado era crear una herramienta visual usando Write-Progress. El cmdlet le permite tener varias barras de progreso en la misma ventana. Puede hacer referencia a ellos mediante un número de identificación. Esto significó que tuve que dividir los mostradores.

Get-Counter -Counter $counters -MaxSamples 30 -SampleInterval 1  |
ForEach-Object {
    $network = $_.countersamples[0].InstanceName
    $computername = [regex]::Match($_.CounterSamples[0].path, "(?<="\)\w+").Value.toUpper()
    $time = $_.timestamp
    $total = $_.countersamples.where( {$_.path -match "total"})
    $totalKbps = $total.cookedValue*0.008
    if ($totalKbps -gt 100) {
        $totalPct = 100
    }
    else {
        $totalPct = $totalKbps
    }
    $sent = $_.countersamples.where( {$_.path -match "sent"})
    $sentKbps = $sent.cookedValue*0.008
    if ($sentKbps -gt 100) {
        $sentPct = 100
    }
    else {
        $sentPct = $sentKbps
    }
    $rcvd = $_.countersamples.where( {$_.path -match "received"})
    $rcvdKbps = $rcvd.cookedValue*0.008
    if ($rcvdKbps -gt 100) {
        $rcvdPct = 100
    }
    else {
        $rcvdPct = $rcvdKbps
    }
    Write-Progress -Activity "[$time] $computername : $network" -status "Total Kbps $totalKbps" -id 1 -PercentComplete $totalpct
    Write-Progress -Activity " " -status "Send Kbps $sentKbps" -id 2 -PercentComplete $sentpct
    Write-Progress -Activity " " -status "Received Kbs $rcvdKbps" -id 3 -PercentComplete $rcvdpct

}

Otro elemento adicional fue formatear los datos como Kbps. Hasta donde yo sé, si multiplico el valor del byte por 0,008 obtendré lo que quiero. También tuve que tener en cuenta la longitud de la barra de progreso ya que obviamente no puede superar 100. Por lo tanto, la visualización es relativa y no un gráfico real.

Al probar esto, descubrí que Write-Progress en Windows PowerShell parece tener un error de visualización que no produce exactamente lo que tengo en mente. Pero funciona bien en PowerShell 7.

Obtener-NetworkPerformance

Junté todo esto en una función de PowerShell.

Function Get-NetworkPerformance {
    [cmdletbinding(DefaultParameterSetName = "sample")]
    [alias("gnp")]
    Param(
        [Parameter(HelpMessage = "Specify a computer to connect to.")]
        [string]$Computername = $env:computername,
        [Parameter(HelpMessage = "Use the network description from Get-NetAdapter")]
        [string]$NetworkInterface = "*ethernet*",
        [Parameter(ParameterSetName = "continuous")]
        [switch]$Continuous,
        [Parameter(Mandatory, ParameterSetName = "sample")]
        [int64]$MaxSamples,
        [Parameter(Mandatory, ParameterSetName = "sample")]
        [Int32]$SampleInterval,
        [switch]$Passthru
    )

    Write-Verbose "Starting $($MyInvocation.MyCommand)"
    Write-Verbose "Detected parameter set $($pscmdlet.ParameterSetName)"
    Write-Verbose "Validating network interface"
    #updated 12 Oct 2021 to make sure only a single network adapter is selected 
    $c = (Get-NetAdapter -InterfaceDescription $NetworkInterface -CimSession $Computername | Where-Object { $_.status -eq 'up' }).count
    if ($c -gt 1) {
        Throw "You must specify a single network interface."
    }
    Write-Verbose "Verified a single network interface"
    #save the current progressbar setting
    $bg = $host.PrivateData.progressBackgroundColor

    #the networking counters
    $counters = "\Network interface($NetworkInterface)\Bytes sent/sec",
    "\Network interface($NetworkInterface)\Bytes received/sec",
    "\Network interface($NetworkInterface)\Bytes total/sec"

    $PSBoundParameters.Add("counter", $counters)

    if ($PSBoundParameters.ContainsKey("Passthru")) {
        [void]( $PSBoundParameters.Remove("passthru"))
    }

    if ($PSBoundParameters.ContainsKey("NetworkInterface")) {
        [void]( $PSBoundParameters.Remove("NetworkInterface"))
    }
    Write-Verbose "Passing these parameters to Get-Counter:`n $($PSBoundParameters | Out-String)"

    Try {
        Get-Counter @PSBoundParameters -OutVariable pass -ErrorAction Stop |
        ForEach-Object {
            $network = $_.countersamples[0].InstanceName
            $computername = [regex]::Match($_.CounterSamples[0].path, "(?<="\)\w+").Value.toUpper()
            $time = $_.timestamp
            $total = $_.countersamples.where( { $_.path -match "total" })
            $totalKbps = $total.cookedValue * 0.008
            #adjust the progressbar color
            if ($totalKbps -ge 150) {
                $host.PrivateData.progressBackgroundColor = "Red"
            }
            else {
                $host.PrivateData.progressBackgroundColor = $bg
            }
            if ($totalKbps -gt 100) {
                $totalPct = 100
            }
            else {
                $totalPct = $totalKbps
            }
            $sent = $_.countersamples.where( { $_.path -match "sent" })
            $sentKbps = $sent.cookedValue * 0.008
            if ($sentKbps -gt 100) {
                $sentPct = 100
            }
            else {
                $sentPct = $sentKbps
            }
            $rcvd = $_.countersamples.where( { $_.path -match "received" })
            $rcvdKbps = $rcvd.cookedValue * 0.008
            if ($rcvdKbps -gt 100) {
                $rcvdPct = 100
            }
            else {
                $rcvdPct = $rcvdKbps
            }

            Write-Progress -Activity "[$time] $computername : $network" -Status "Total Kbps $totalKbps" -Id 1 -PercentComplete $totalpct
            Write-Progress -Activity " " -Status "Send Kbps $sentKbps" -Id 2 -PercentComplete $sentpct
            Write-Progress -Activity " " -Status "Received Kbs $rcvdKbps" -Id 3 -PercentComplete $rcvdpct
        }
    } #Try
    Catch {
        Write-Warning "Failed to get performance counters. $($_.Exception.message)"
    }

    if ($passthru -AND $pass) {
        Write-Verbose "Passing results to the pipeline"
        $pass
    }

    #restore the progressbar value
    $host.PrivateData.progressBackgroundColor = $bg
    Write-Verbose "Ending $($MyInvocation.MyCommand)"
}

La función ofrece flexibilidad y facilidad de uso.

Incluso aprendí algunas cosas nuevas al resolver este desafío, que es realmente el punto. Espero que pruebes los desafíos. Hay pruebas para cada nivel de habilidad. Buena suerte.

Artículos relacionados