ค้นหาเว็บไซต์

เพิ่มพรอมต์ของฉันให้สูงสุดใน PowerShell Core


เมื่อวานฉันเขียนเกี่ยวกับความตั้งใจของฉันที่จะทำให้ PowerShell Core ที่ทำงานบน Windows 10 เป็น "ไดรเวอร์รายวัน" ของฉัน ฉันยังได้เขียนเมื่อเร็ว ๆ นี้เกี่ยวกับการใช้ฟังก์ชันพรอมต์ PowerShell เพื่อให้ข้อมูลที่หลากหลาย ดังนั้นฉันจึงตัดสินใจรวมทั้งสองอย่างเข้าด้วยกัน พร้อมผสมผสานฟังก์ชันบางอย่างจากเครื่องมือ PowerShell อื่น ๆ ของฉัน เพื่อสร้างคอนโซล PowerShell ที่มีทุกสิ่งอยู่แค่เพียงปลายนิ้วของฉัน ฉันจะแนะนำคุณตลอดขั้นตอนการทำซ้ำข้อความแจ้ง แม้ว่าคุณอาจเลือกที่จะข้ามคุณสมบัติบางอย่างก็ตาม ในระหว่างนี้ ฉันจะชี้ให้เห็นว่าคุณจะต้องติดตั้งโมดูลใดบ้างจาก PowerShell Gallery โปรเจ็กต์เหล่านี้ทั้งหมดอยู่บน GitHub ดังนั้นคุณสามารถตรวจสอบก่อนทำการติดตั้ง โค้ดสำหรับฟังก์ชันพรอมต์ PowerShell ของฉันมีความซับซ้อน และหากคุณต้องการปรับแต่ง คุณจะต้องมีประสบการณ์ในการเขียนสคริปต์ PowerShell บ้าง หรือบางทีคุณอาจต้องการทำซ้ำประสบการณ์ของฉัน ไม่ว่าในกรณีใดเรามาเจาะลึกกัน

PowerShell รายวันของฉัน

ก่อนที่ฉันจะทำตามขั้นตอนต่างๆ ฉันคิดว่าคุณอาจต้องการเห็นผลิตภัณฑ์สำเร็จรูป

จอแสดงผลจะแสดงชื่อคอมพิวเตอร์พร้อมวันที่และเวลาปัจจุบัน รายการกิจกรรมที่กำลังจะเกิดขึ้น ปฏิทินพร้อมวันกิจกรรมที่ไฮไลต์ และข้อมูลระบบบางส่วน: เวลาทำงาน เปอร์เซ็นต์พื้นที่ว่างบน C: เปอร์เซ็นต์หน่วยความจำว่าง และจำนวนกระบวนการที่กำลังทำงานอยู่ทั้งหมด ฉันควรชี้ให้เห็นว่าพรอมต์ที่เสร็จแล้วจะทำงานบน Windows PowerShell ด้วย ฉันเพิ่งจะใช้มันกับ PowerShell Core ยังสนใจอยู่ไหม? คุณจะต้องตั้งค่าเครื่องมือเพิ่มเติมบางอย่าง

มายทิคเคิล

ฉันมีโมดูลที่ใช้ติดตามกิจกรรมที่กำลังจะเกิดขึ้น เช่น โทรศัพท์ การประชุม หรือรายการอื่นๆ ที่ฉันต้องการให้แน่ใจว่าจะไม่ลืม โมดูลนี้มีระบบตัวกระตุ้นเพื่อช่วยให้ฉันจดจำ คุณสามารถอ่านทั้งหมดได้บนพื้นที่เก็บข้อมูล GitHub โมดูลนี้จะต้องมีแบ็กเอนด์ SQL Server บางประเภท ฉันขอแนะนำให้คุณติดตั้ง SQL Server Express รุ่นฟรี ติดตั้งโดยใช้การตั้งค่าเริ่มต้นเพื่อให้ชื่ออินสแตนซ์เป็น SQLExpress นั่นคือเส้นทางที่มีความต้านทานน้อยที่สุดในการใช้โมดูลนี้ หรืออ่านวิธีใช้โดยละเอียดเพื่อดูวิธีปรับแต่ง ใช้คำสั่ง c: เพื่อตั้งค่า

จากนั้นคุณสามารถใช้ Add-TickleEvent เพื่อกำหนดการเตือนความจำบางอย่างได้ ฟังก์ชั่นพร้อมท์ของฉันจะแสดงเหตุการณ์ที่ครบกำหนดในอีก 10 วันข้างหน้า รายการที่ครบกำหนดภายในหนึ่งวันหรือน้อยกว่านั้นจะแสดงเป็นสีแดง หากถึงกำหนดภายใน 48 ชั่วโมง จะแสดงเป็นสีเหลือง มิฉะนั้นการแจ้งเตือนจะแสดงเป็นสีเขียว กิจกรรมที่ครบกำหนดในอีก 30 วันข้างหน้าจะถูกใช้เพื่อเติมปฏิทิน

PSปฏิทิน

ถัดไป คุณจะต้องใช้โมดูล PSCalendar ของฉัน อย่างน้อยเวอร์ชัน 1.5.0 คำสั่ง Show-Calendar จะถูกใช้ภายในฟังก์ชันเพื่อแสดงเดือนที่มีสี เหตุการณ์จั๊กจี้ในอีก 30 วันข้างหน้าจะถูกใช้เป็นวันที่เน้นสำหรับปฏิทิน แน่นอนว่าโมดูลมีคำสั่งปฏิทินอื่นๆ ที่คุณอาจต้องการใช้

การปรับแต่งหน้าต่าง PowerShell Core

ฉันจะถือว่าคุณได้ดาวน์โหลดและติดตั้ง PowerShell Core บนเดสก์ท็อป Windows ของคุณแล้ว คุณสามารถใช้โมดูล PSReleaseTools ของฉันเพื่อทำให้กระบวนการนี้ง่ายขึ้น

get-psreleaseasset -Family Windows -Only64Bit | where format -eq msi | 
Save-PSReleaseAsset -Path C:\PS6 -Passthru | foreach { invoke-item $_.fullname}

เมื่อติดตั้งแล้ว ให้เปิด PowerShell Core ฉันมักจะเรียกใช้งานในเซสชันที่มีการยกระดับเสมอ แต่ฉันทำงานที่บ้านและไม่มีเครือข่ายการผลิตที่สำคัญที่ต้องกังวล ฉันแก้ไขหน้าต่างเพื่อเพิ่มขนาดตัวอักษร (24) แบบอักษร (Consolas) ขนาดหน้าต่าง/บัฟเฟอร์ (120×35) และตั้งค่าความทึบ (75%) ฉันคงรูปแบบสีเริ่มต้นไว้ คุณสามารถตั้งค่าสิ่งเหล่านี้ได้ในการตั้งค่าระบบ

ฟังก์ชั่นพร้อมท์

ชิ้นส่วนสุดท้ายของปริศนาคือฟังก์ชั่นพร้อมท์นั่นเอง ฉันได้ใส่ฟังก์ชั่น prompt ที่สมบูรณ์บน Github แล้ว

dailyprompt.ps1:

#requires -version 5.1

<#
The complete version of the function also requires additional modules
which can be downloaded from the PowerShell Gallery.

https://github.com/jdhitsolutions/PSCalendar
https://github.com/jdhitsolutions/myTickle

If you prefer to
skip some of the features in this function you'll need to remove those lines
and modify the following requires statements.

The function requires a windows platform.
#>

#requires -module PSCalendar
#requires -module myTickle

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 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 {
                    $computers = $env:computername
                 <#
                  23 January 2019
                  This version of the prompt is only querying the local computer so I have
                  commented out code that you would use to get information from remote computers.

                    #define a pssession option to speed up connections.
                    $opt = New-PSSessionOption -OpenTimeout 1000 -MaxConnectionRetryCount 1
                     $computers | Where-Object {(get-pssession).where( {$_.state -eq 'opened'}).computername -notcontains $_} |
                        ForEach-Object {
                        #make sure there are sessions for all computers in the list
                        New-PSSession -ComputerName $_ -SessionOption $opt
                    }
                    #remove broken sessions
                    Get-PSSession | Where-Object {$_.state -eq 'broken'} | Remove-PSSession
                    #>

                    $global:rsHash.date = Get-Date
                    $global:rshash.computers = $computers

                    #uncomment the other parameters if querying remote computers
                    $results = Invoke-Command -ScriptBlock $sb #-HideComputerName  -Session (Get-PSSession)
                    #set a sleep interval between tests
                    $global:rsHash.results = $results
                    Start-Sleep -Seconds 10
                } While ($True)
            }) # script
            }) # script
        $pscmd.runspace = $newrunspace
        [void]$psCmd.BeginInvoke()
    } #catch

    #guess at a line length
    #Note that this code is copied from other prompts that were displaying information
    #from multiple computers. This version is only querying the local host but I'm
    #leaving this since it doesn't break anything and you may want to go back to a version
    #that queries other computers.
    $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) * 20) + 1

    ######### PSCALENDAR CODE  #########
    #display calendar
    #check if y is greater than 3
    if ($host.ui.RawUI.CursorPosition.y -le 10) {
        $Y = $host.ui.RawUI.CursorPosition.Y
    }
    else {
        $Y = $host.ui.RawUI.CursorPosition.Y - 3
    }
    $X = 75

    Show-Calendar -position ([System.Management.Automation.Host.Coordinates]::new($X, $Y))
    ######### PSCALENDAR CODE  #########

    #display local computername and datetime
    $dt = "{2} {0} {1} " -f (Get-Date).toshortdatestring(), (Get-Date).TolongTimeString(), $env:computername
    Write-Host "`n " -NoNewline
    Write-Host $dt -ForegroundColor black -BackgroundColor gray

    ######### TICKLE CODE  #########
    #get tickle events
    $tickle = Get-TickleEvent -days 10
    if ($tickle) {
        #get length of longest event for padding purposes
        $evtlen = ($tickle | sort-object {$_.event.length} -Descending)[0].event.length
        foreach ($item in $tickle) {
            #date time is formatted for North America
            $evtString = " {0} {1:MM/dd/yyyy hh:mm:ss} [{2}]" -f $item.event.padright($evtlen), $item.date, $item.countdown.tostring("dd\.hh\:mm\:ss")
            if ($item.countdown.totalhours -le 24) {
                $fg = "red"
            }
            elseif ($item.countdown.TotalHours -le 48) {
                $fg = "yellow"
            }
            else {
                $fg = "green"
            }
            Write-Host $evtString -ForegroundColor $fg
        }
    }
    ######### TICKLE CODE  #########

    Write-Host "$([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 " $([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)) "

}

ดาวน์โหลดสำเนาและแก้ไขตามที่คุณต้องการ ฉันได้พยายามแทรกความคิดเห็นเพื่อช่วยคุณลบฟีเจอร์ที่คุณอาจไม่ต้องการใช้ หากต้องการโหลดการแก้ไขพร้อมท์โดยอัตโนมัติหรือสร้างสคริปต์โปรไฟล์สำหรับผู้ใช้ปัจจุบัน โฮสต์ปัจจุบันและแหล่งที่มาของจุด เส้นทางของฟังก์ชันพร้อมท์ หากต้องการทำซ้ำสิ่งที่ฉันทำอยู่อย่างสมบูรณ์ คุณอาจต้องการเพิ่มความกระจ่างอีกเล็กน้อย

import-module myTickle
import-module PSCalendar

$PSDefaultParameterValues.Add("Get-Calendar:Highlightdate", (Get-TickleEvent -days 30).date.toshortdatestring())
$PSDefaultParameterValues.Add("Show-Calendar:Highlightdate", (Get-TickleEvent -days 30).date.toshortdatestring())
. c:\scripts\dailyprompt.ps1

function Test-IsAdministrator {  
    $user = [Security.Principal.WindowsIdentity]::GetCurrent();
    (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)  
}


if (Test-IsAdministrator) {
    $n = "Administrator"
}
else {
    $n = "Non-Admin"
}
[console]::Title = "$($n): PowerShell $($psversiontable.psedition) $(([regex]"\d+\.\d+.\d+").match($psversiontable.psversion).value)"

Set-Location C:\

เพื่อให้สิ่งต่าง ๆ ง่ายขึ้น ฉันกำลังตั้งค่าพารามิเตอร์เริ่มต้นเพื่อให้ปฏิทินเป็นค่าเริ่มต้นในการเน้นเหตุการณ์จั๊กจี้ของฉัน ฉันยังมีโค้ดบางส่วนที่ใช้ตั้งค่าแถบชื่อเรื่องของหน้าต่างด้วย หากทุกอย่างเป็นไปด้วยดี เมื่อฉันเริ่ม PowerShell Core ฉันควรจะเห็นจอแสดงผลของฉัน แม้ว่าฉันควรจะชี้ให้เห็นว่าในการโหลดครั้งแรกจะมีงานพื้นหลังอยู่บ้าง ดังนั้นคุณจะไม่เห็นสถิติประสิทธิภาพเป็นเวลาประมาณหนึ่งนาทีจนกว่าคุณจะกด Enter อีกครั้ง คาดว่าคุณอาจต้องปรับแต่งการตั้งค่าบางอย่าง

PowerShell ชีวิตของคุณ

ฉันยอมรับว่าฉันอาจใช้ความสามารถมากเกินไปเล็กน้อยด้วยการผสาน PowerShell เข้ากับชีวิตของฉัน คุณอาจจะไม่ได้เกือบจะคลั่งไคล้ขนาดนั้น! อย่างไรก็ตาม กระบวนการสร้างทั้งหมดนี้ถือเป็นโอกาสในการเรียนรู้ที่ดี ฉันหวังว่ามันจะเป็นสำหรับคุณ ใช้เวลาศึกษาโมดูลและฟังก์ชันต่างๆ ดูว่าฉันกำลังบูรณาการส่วนต่างๆ อย่างไร ฉันหวังว่าสิ่งนี้จะช่วยให้เข้าใจวิธีการทำงานของ PowerShell ได้ดีขึ้น และวิธีที่คุณสามารถสร้างเครื่องมือของคุณเองเพื่อช่วย PowerShell จัดการชีวิตของคุณ

บทความที่เกี่ยวข้อง