PowerShell Ağ İzleyicisi


Umarım Iron Scripter web sitesinde yayınlanan senaryo yazma zorluklarını denemişsinizdir. Zorluklar, bireylerin PowerShell komut dosyası yazma becerilerini geliştirmek için kendi başlarına yapmaları için tasarlanmıştır. Birkaç hafta önce, PowerShell ve Write-Progress cmdlet'ini kullanarak bir ağ izleme aracı oluşturmaya yönelik bir meydan okuma yayınlandı. Challenge hakkındaki notlarımı ve bulduğum bazı kodları paylaşmayı düşündüm.

Orta Seviye Mücadelesi

İlk adım Get-Counter için gerekli performans sayaçlarını belirlemekti.

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

Bunlarla verileri almak için Get-Counter'ı kullanabilirim.

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}}

Sayaç örneği özelliğinden değerleri ayrıştırıyorum.

Bunu bir adım daha ileri taşımak istersem, çıktıyı özel bir nesne olarak tanımlayabilir ve ekranı temizlemek için ps1xml formatında bir dosya oluşturabilirim.

Gelişmiş

İleri düzey zorluk, Write-Progress'i kullanarak görsel bir araç oluşturmaktı. Cmdlet, aynı pencerede birden fazla ilerleme çubuğuna sahip olmanızı sağlar. Onlara bir kimlik numarasıyla başvurabilirsiniz. Bu, sayaçları bölmem gerektiği anlamına geliyordu.

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

}

Bir diğer bonus unsuru da veriyi Kbps olarak biçimlendirmekti. Bildiğim kadarıyla byte değerini 0,008 ile çarparsam istediğimi elde ederim. Ayrıca ilerleme çubuğunun uzunluğunu da hesaba katmak zorunda kaldım çünkü bariz bir şekilde 100'ün üzerine çıkamıyor. Bu nedenle görüntü görecelidir ve gerçek bir grafik değildir.

Bunu test ederken, Windows PowerShell'deki Yazma İlerlemesi'nin tam olarak aklımda olanı üretmeyen bir ekran hatasına sahip olduğunu gördüm. Ancak PowerShell 7'de gayet iyi çalışıyor.

Get-NetworkPerformance

Bunların hepsini bir PowerShell işlevinde bir araya getirdim.

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)"
}

İşlev esneklik ve kullanım kolaylığı sunar.

Hatta bu zorluğu çözerken birkaç yeni şey öğrendim, asıl mesele de bu. Umarım zorluklara karşı şansınızı denersiniz. Her beceri düzeyi için testler vardır. İyi şanlar.

İlgili makaleler