Telemetri PowerShell İstemi İşlevim


Bu PowerShell istemi işlevlerini oluşturmaktan keyif aldım. Performans kritik olduğundan beni verimli kod oluşturmaya zorladı. Örneğin, belirli sınıflardan seçilmiş özellikleri almak için Get-CimInstance kullanıyorum. Hangi özelliklere ihtiyacım olduğunu önceden bildiğim için Get-Ciminstance'a yalnızca bu mülkleri alıp iade etmesini söyleyebilirim. Bugünkü versiyonda bu çok önemli. Bu "telemetri" istemi, önceki yinelemelerdeki bir dizi özelliği, birkaç kritik sunucunun durumunun daha kapsamlı bir anlık görüntüsünde birleştirir.

Bu istem işlevi aynı zamanda az sayıda uzak sunucudan sistem bilgilerini almak için çalışma alanına ve senkronize karma tablosuna da dayanır. Listeyi anında değiştirebilirsiniz. Konsol ekranınızı genişletmediğiniz veya işlevi değiştirmediğiniz sürece bunu minimumda tutmanızı öneririm. Bu arada, varsayılan C:\Scripts\watch.txt dosyası bulunamazsa istem varsayılan olarak localhost'a yönlendirilir. Bir listenin mevcut olduğunu ve tüm sunucuların çalışır durumda olduğunu varsayarsak, aşağıdaki gibi bir istem bekleyebilirsiniz:

Gördüğünüz gibi bazı renk kodları var. İstemi çözmenize yardımcı olmak için bazı değerlerin önünde bazı grafik öğeleri kullanıyorum. Elbette dilediğiniz gibi değişiklik yapmaktan çekinmeyin.

İşlev ayrıca bir sunucunun çevrimdışı olup olmadığını da dikkate alır.

Sunucu geri geldiğinde her şey geri yüklenir.

Bu fonksiyonun kodu diğerleriyle birlikte Github'dadır.

TelemetryPrompt.ps1:

#requires -version 5.1
#this requires a windows platform

Function prompt {

    $charHash = @{
        Up   = 0x25b2 -as [char]
        Down = 0x25bc -as [char]
    }

    Try {
        #verify there is a global hashtable variable
        Get-Variable -Name rsHash -Scope global -ErrorAction Stop | Out-Null
    }
    Catch {
        #create the runspace and synchronized hashtable
        $global:rsHash = [hashtable]::Synchronized(@{Computername = $env:computername; results = ""; date = (Get-Date); computers = @()})
        $newRunspace = [runspacefactory]::CreateRunspace()
        #set apartment state if available
        if ($newRunspace.ApartmentState) {
            $newRunspace.ApartmentState = "STA"
        }
        $newRunspace.ThreadOptions = "ReuseThread"         
        $newRunspace.Open()
        $newRunspace.SessionStateProxy.SetVariable("rsHash", $rsHash)  

        $pscmd = [PowerShell]::Create().AddScript( {                      

            #define the path to the list of computers
            $script:listPath = "C:\scripts\watch.txt"
            #define scriptblock to run remotely
                $sb = {

                    Try {        
                        $mem = Get-CimInstance -ClassName win32_operatingsystem -Property TotalVisibleMemorySize, FreePhysicalMemory -ErrorAction Stop -OperationTimeoutSec 2
                        $memUsage = ($mem.FreePhysicalMemory / $mem.TotalVisibleMemorySize) * 100 -as [int]
                        $disk = Get-CimInstance -Classname win32_logicaldisk -filter "deviceID = 'c:'" -Property DeviceID, Size, FreeSpace -ErrorAction Stop -OperationTimeoutSec 2
                        $diskFree = ($disk.FreeSpace / $disk.Size) * 100 -as [int]
                        #get a count of all processes except idle and system and subtract 1 for the remote connection
                        $proc = (Get-Process).Where({$_.name -notmatch 'Idle|system'}).count -1
                        $os = Get-CimInstance -ClassName win32_operatingsystem -Property lastbootupTime
                        $isUp = $True
                    }
                    catch {
                        #this will probably never be used
                        $memUsage = 0
                        $diskFree = 0
                        $isUp = $False
                        Processes = 0
                        OS = "" 
                    }
                    [pscustomobject]@{
                        Computername = $env:computername
                        MemoryUsage  = $memUsage
                        DiskFree     = $diskFree
                        Processes    = $proc
                        IsUp         = $IsUp
                        Uptime       = ((Get-Date) - $os.LastBootUpTime).toString("d\.hh\:mm\:ss")
                    }
                } #end scriptblock
                    
                #define a pssession option to speed up connections
                $opt = New-PSSessionOption -OpenTimeout 1000 -MaxConnectionRetryCount 1

                do {
                    #define the list of computers to test
                    #filter out blank lines and trim any spaces to clean up names.
                    #This should be a short list unless you increase the width of your console sessions
                    if (Test-Path -path $script:listPath ) {
                           $computers = Get-Content -Path $script:listpath |
                            Where-Object {$_ -match '\w+' -AND $_ -notmatch "#"} | Foreach-Object {$_.trim()} | Sort-Object
                }
                else {
                    #if path not found default to local computer
                    $computers = $env:computername
                }


                    #make sure there are sessions for all computers in the list
                    $computers | Where-Object {(get-pssession).where( {$_.state -eq 'opened'}).computername -notcontains $_} |
                        ForEach-Object {
                        New-PSSession -ComputerName $_ -SessionOption $opt
                    }
                    #remove broken sessions
                    Get-PSSession | Where-Object {$_.state -eq 'broken'} | Remove-PSSession
                    $results = Invoke-Command -ScriptBlock $sb -HideComputerName  -Session (Get-PSSession) 

                    $global:rsHash.results = $results
                    $global:rsHash.date = Get-Date
                    $global:rshash.computers = $computers
                    #set a sleep interval between tests
                    Start-Sleep -Seconds 10
                } While ($True)
            }) # script
        $pscmd.runspace = $newrunspace
        [void]$psCmd.BeginInvoke()
    } #catch

    #guess at a line length
    $names = ($global:rshash.computers | Measure-Object -Property length -sum).sum
    #account for a : after each name + character + value
    #you may have to tweak this value to get everything to line up
    #and it might depend on whether you are using the console or ISE
    $len = $names + (($global:rshash.computers.count) * 27) + 1
    
    #display local computername and datetime
    $dt= "`n {2} {0} {1} " -f (get-date).toshortdatestring(),(get-date).TolongTimeString(),$env:computername
    Write-host $dt -ForegroundColor black -BackgroundColor gray

    Write-Host "`n$([char]0x250c)" -NoNewline
    Write-Host $(([char]0x2500).ToString() * $len ) -NoNewline
    Write-Host $([char]0x2510) 
    Write-Host " " -NoNewline

    if ($global:rsHash.results) {
    
        #create a hashtable from the results
        $h = $global:rshash.results | Group-Object -Property Computername -AsHashTable -AsString

        #sort the results by computername
        foreach ($item in $global:rshash.computers) {

            if ($h[$item]) {
                $obj = $h[$item]
            }
            else {
                #create a temporary object for computer that is not running but in the list
                $obj = [pscustomobject]@{
                    Computername = $item.ToUpper()
                    Uptime = (New-TimeSpan).toString()
                    DiskFree = "00"
                    MemoryUsage = "00"
                    Processes = "00"
                    IsUp = $false
                }
            }

            if ($obj.DiskFree -le 20) {
                $diskfg = "red"
            }
            elseif ($obj.DiskFree -le 75) {
                $diskfg = "yellow"
            }
            else {
                $diskfg = "green"
            }
            if ($obj.MemoryUsage -le 30) {
                $memfg = "red"
            }
            elseif ($obj.MemoryUsage -le 60) {
                $memfg = "yellow"
            }
            else {
                $memfg = "green"
            }
            
            if ($obj.IsUp) {
                Write-Host " $($charHash.Up)" -ForegroundColor green -NoNewline
                $upfg = "green"
            }
            else {
                Write-Host " $($charHash.down)" -ForegroundColor red -NoNewline
                $upfg = "red"
            }
            
            Write-Host $obj.Uptime -ForegroundColor $upfg -NoNewline
            Write-Host " $($obj.computername) " -NoNewline            
            Write-Host "$([char]0x058d)$($obj.diskfree)%" -NoNewline -ForegroundColor $diskfg
            Write-Host " $([char]0x3bc)$($obj.MemoryUsage)%"-NoNewline -ForegroundColor $memfg 
            Write-Host " p$($obj.Processes)" -NoNewline
            
        } #foreach
    }
    else {
        Write-Host "Working..." -ForegroundColor yellow -NoNewline
    }

    Write-Host " "
    Write-Host $([char]0x2514) -NoNewline
    Write-Host $(([char]0x2500).ToString() * $len ) -NoNewline
    Write-Host $([char]0x2518) 

    "PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) "

}

Hala kodla oynuyorum, bu yüzden biraz farklı çıktılar görebilirsiniz. Aksi takdirde tadını çıkarın ve biraz eğlenin.

İlgili makaleler