תפריט טופס PowerShell: גישה מהירה לסקריפטים שלך

זה זמן לפרויקט סופשבוע שוב והיום תלמד איך לבנות תפריט טריי מערכת קל משום כך ב-PowerShell, בו תוכל להפעיל בקלות ובמהירות את סקריפטי ה-PowerShell האהובים עליך הכי הרבה. תוכל לראות למטה את התוצאה הסופית.

Launching PowerShell scripts via a system tray menu icon

במאמר זה, תלמד כיצד לבנות תפריט GUI שלך באמצעות PowerShell על ידי פיצול התהליך לשלבים.

דרישות סביבה וידע

לפני שתתעמ淩淩n淩淩d淩淩淩淩淩c淩淩淩淩淩淩淩淩淩淩淩淩淩טש לעממינ淩淩d淩淩淩淩淩淩淩ו淩淩o淩淩淩淩淩ע淩עד:

  • Windows 7 או מאוחר יותר
  • Windows PowerShell 3 או מאוחר יותר – הגרסה האחרונה של .NET Core 3.0 עם PowerShell 7 התצוגה מתאימה לעבודה בחלונות עקב לתמיכה התוווספה לאחרונה ב-WPF וב-WinForm, אך איננה נבדקת.
  • .NET Framework 4.5 או מאוחר יותר
  • A familiarity with Windows Forms (WinForms)  You can, however, due this with WPF too though.

לפרויקט זה, החדשות הטובות הן שאין צורך באמת להיסמך על Visual Studio, PoshGUI, או כל כלי פיתוח UI אחר כי הרכיבים העיקריים של פרויקט זה יתבססו על הרכיבים הבאים:

  • NotifyIcon – זה ייווצג כסמל המערכת הניתן להתאמה אישית בשורת המשתמש.
  • תפריט ההקשר – מכיל כאשר המשתמש ילחץ על התמונה במגש המשימה.
  • פריט תפריט – אובייקטים יחידים לכל אפשרות בתפריט לחיצה ימנית.

פתחו את עורך סקריפט הפוורשל המועדף עליכם ובואו נתחיל!

עבור פרויקט זה תצטרכו לבנות שלוש פונקציות: שתי פונקציות להצגה/הסתרה של המסוף כדי לספק חוויית משתמש נקייה ואחת להוספת פריטים לתפריט המשימה שלכם. פונקציות אלו ישמשו כיסוד לשימוש מאוחר יותר ויקלו על חייכם הרבה יותר, כפי שתלמדו מעט מאוחר יותר במאמר זה.

הצגה/הסתרה של חלון המסוף

מלבד אם נסתר, כאשר אתם מפעילים סקריפט פוורשל, המסוף המוכר של פוורשל יופיע. מאחר ופריטי התפריט בטופס הפוורשל שתיצרו יפעילו סקריפטים, עליכם לוודא שהמסוף לא יופיע. אתם רק רוצים שיבצע.

כאשר סקריפט מופעל, אתם יכולים להחליף את תצוגת חלון המסוף של פוורשל להצגה או לא להצגה באמצעות פעולה מעטה של .NET.

הוסף תחום Window .NET להפעלה הנוכחית. לעשות זאת, יש להשתמש ב-C# כפי שמוצג למטה. שני השיטות שיש לך צורך לטעון להקשר הם GetConsoleWindow ו-ShowWindow. על ידי טעינת אלו DLLs לזכרון, אתה חושף חלקים מסוימים של ה-API, מה שמאפשר לך להשתמש בהם בהקשר של סקריפט PowerShell שלך:

 #טען DLLs להקשר של ישיבת הקונסול הנוכחית
 Add-Type -Name Window -Namespace Console -MemberDefinition '
    [DllImport("Kernel32.dll")]
    public static extern IntPtr GetConsoleWindow();
 
    [DllImport("user32.dll")]
    public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);

צור שתי פונקציות באמצעות הטעינה למעלה באמצעות השימוש בשיטות GetConsoleWindow() ו-ShowWindow() כפי שמוצג למטה.

 function Start-ShowConsole {
    $PSConsole = [Console.Window]::GetConsoleWindow()
    [Console.Window]::ShowWindow($PSConsole, 5)
 }
 
 function Start-HideConsole {
    $PSConsole = [Console.Window]::GetConsoleWindow()
    [Console.Window]::ShowWindow($PSConsole, 0)
 }

עם שתי פונקציות אלו, יש לך כעת אמצע להציג או להסתיר את חלון הקונסול כרצונך.

הערה: אם ברצונך לראות פלט מהסקריפטים שנכנסים דרך התפריט, תוכל להשתמש בPowerShell transcripts או בתכונות הלוג שמבוססות על טקסט אחר. זה מאפשר לך לשמור שליטה בניגוד להפעלת ישיבת ה-PowerShell רק עם הפרמטר WindowStyle כדי להסתיר.

כעת התחל לבנות קוד סקריפט על ידי קריאה ל-Start-HideConsole. כאשר הסקריפט הנקבע בתפריט PowerShell מופעל, זה יוודא שחלון ישיבת ה-PowerShell לא יופיע.

<#
    אתחול של פונקציות ואובייקטים שנטענים לזיכרון
    הצגת סרגל טעינה מבוסס טקסט או כתיבה של Write-Progress למארח
#>
 
Start-HideConsole
 
<#
    קוד להצגת האייקון של הטבלה הראשית / המשימות
    זה ישמור על הקונסול כאן עד שיסגר
#>

יצירת אפשרויות תפריט

עכשיו זה הזמן ליצור את אפשרויות התפריט. לוודא שתוכל ליצור בקלות אפשרויות חדשות מאוחר יותר, יש ליצור פונקציה נוספת הפעם בשם New-MenuItem. כאשר אתה קורא לפונקציה זו, היא תיצור אובייקט MenuItem חדש מ-.NET שתוכל להוסיף אז לתפריט.

כל אפשרות בתפריט תפעיל סקריפט אחר או תיצא מהמשימה. כדי להתאים לפונקציונליות זו, לפונקציה New-MenuItem יש שלוש פרמטרים:

  • Text – התווית שהמשתמש ילחץ עליה
  • MyScriptPath – הנתיב לתסריט PowerShell שיש להריץ
  • ExitOnly – האפשרות לצאת מהמשימה.

יש להוסיף את קטע הפונקציה הבא לתסריט של התפריט.

 function New-MenuItem{
     param(
         [string]
         $Text = "Placeholder Text",
 
         $MyScriptPath,
         
         [switch]
         $ExitOnly = $false
     )

המשיכו לבנות את הפונקציה New-MenuItem, צרו אובייקט MenuItem על ידי הקצאתו למשתנה.

 #אתחול
 $MenuItem = New-Object System.Windows.Forms.MenuItem

לאחר מכן, הקצו את התווית לפריט התפריט.

 # החלת טקסט מועדף
 if($Text) {
 	$MenuItem.Text = $Text
 }

כעת הוסיפו מאפיין מותאם אישית לפריט התפריט בשם MyScriptPath. נתיב זה ייקרא כאשר הפריט יילחץ בתפריט.

 #יישום הגיוס של אירועי לחיצה
 if($MyScriptPath -and !$ExitOnly){
 	$MenuItem | Add-Member -Name MyScriptPath -Value $MyScriptPath -MemberType NoteProperty

הוסף אירוע לחיצה לפריט התפריט שמפעיל את התסריט הרצוי. Start-Process מספק דרך נקייה לעשות זאת בתוך בלוק try/catch כך שתוכל לוודא שכל שגיאות ההפעלה של התסריט (כגון אי התאמת PowerShell או התסריט אינו קיים בנתיב הספק) ייפלו לבלוק התפיסה שלך.

   $MenuItem.Add_Click({
        try{
            $MyScriptPath = $This.MyScriptPath #משמש למציאת נתיב המתאים במהלך אירוע לחיצה
            
            if(Test-Path $MyScriptPath){
                Start-Process -FilePath "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -ArgumentList "-NoProfile -NoLogo -ExecutionPolicy Bypass -File `"$MyScriptPath`"" -ErrorAction Stop
            } else {
                throw "Could not find at path: $MyScriptPath"
            }
        } catch {
          $Text = $This.Text
          [System.Windows.Forms.MessageBox]::Show("Failed to launch $Text`n`n$_") > $null
        }
  })

הוסף את הלוגיקה הנותרת כדי לספק תנאי יציאה למשדר ולאחר מכן החזר את הפריט שנוצר למשתנה אחר בזמן הריצה.

    #ספק דרך ליציאה מהמשדר
    if($ExitOnly -and !$MyScriptPath){
        $MenuItem.Add_Click({
            $Form.Close()
    
            #טפל בתהליכים תלויים
            Stop-Process $PID
        })
    }
 
 	 #החזר את הפריט החדש שלנו
    $MenuItem
 }

כעת אמור לך להיות פונקציית New-MenuItem נוצרה! הפונקציה הסופית צריכה להיראות כך:

 function New-MenuItem{
     param(
         [string]
         $Text = "Placeholder Text",
 
         $MyScriptPath,
         
         [switch]
         $ExitOnly = $false
     )
 
     #אתחול
     $MenuItem = New-Object System.Windows.Forms.MenuItem
 
     #החלק טקסט רצוי
     if($Text){
         $MenuItem.Text = $Text
     }
 
     #החלק לוגיקת לחיצה
     if($MyScriptPath -and !$ExitOnly){
         $MenuItem | Add-Member -Name MyScriptPath -Value $MyScriptPath -MemberType NoteProperty
     }
 
     $MenuItem.Add_Click({
             try{
                 $MyScriptPath = $This.MyScriptPath #משמש למציאת נתיב נכון במהלך לחיצה
             
                 if(Test-Path $MyScriptPath){
                     Start-Process -FilePath "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -ArgumentList "-NoProfile -NoLogo -ExecutionPolicy Bypass -File `"$MyScriptPath`"" -ErrorAction Stop
                 } else {
                     throw "Could not find at path: $MyScriptPath"
                 }
             } catch {
                 $Text = $This.Text
                 [System.Windows.Forms.MessageBox]::Show("Failed to launch $Text`n`n$_") > $null
             }
         })
 
     #ספק דרך לצאת מהמשדר
     if($ExitOnly -and !$MyScriptPath){
         $MenuItem.Add_Click({
                 $Form.Close()
    
                 #טפל בתהליכים תקועים
                 Stop-Process $PID
             })
     }
 
     #החזר את MenuItem החדש שלנו
     $MenuItem
 }

בדיקת הפונקציה New-MenuItem על ידי העתקה והדבקה של הקוד לקונסול PowerShell שלך והפעלת הפונקציה עם ערכי פרמטרים מזוייפים. תראה שאובייקט MenuItem של .NET נוחזר.

 PS51> (New-MenuItem -Text "Test" -MyScriptPath "C:\test.ps1").GetType()
 
 IsPublic IsSerial Name                                     BaseType
 -------- -------- ----                                     --------
 True     False    MenuItem                                 System.Windows.Forms.Menu

יצירת טופס לאשף

רוצה עוד טיפים כמו זה? בדוק את בלוג ה-PowerShell האישי שלי ב: https://nkasco.com/FriendsOfATA

עכשיו שאתה יכול ליצור בקלות פריטי תפריט חדשים, הגיע הזמן ליצור אשף לוח המערכת שיציג את התפריט.

יצירת אובייקט טופס בסיסי כדי להוסיף רכיבים אליו. אין צורך שיהיה משהו מיוחד מדי, מכיוון שהוא יישמר נסתר מהמשתמש הסופי וישמור על הקונסול רציני ברקע גם.

 #יצירת טופס לשמש כקונטיינר לרכיבים שלנו
 $Form = New-Object System.Windows.Forms.Form
 ​
 #הגדרת הטופס שלנו להיות מוסתר
 $Form.BackColor = "Magenta" #התאמת צבע זה למאפיין TransparencyKey לשקיפות של הטופס שלך
 $Form.TransparencyKey = "Magenta"
 $Form.ShowInTaskbar = $false
 $Form.FormBorderStyle = "None"

הבא, צור את האייקון שיפועל בסרגל המשימות. למטה בחרתי להשתמש באייקון PowerShell. בזמן ריצה, הקוד למטה יוצר אייקון בסרגל המשימות. ניתן להתאים אישית את האייקון על פי העדפותיך על ידי הגדרת משתנה SystrayIcon לאייקון הרצוי שלך.

בדוק את תיעוד המחלקה System.Drawing.Icon כדי לראות שיטות אחרות שבהן ניתן לטעון אייקון לזיכרון.

 #אתחול/הגדרת רכיבים נדרשים
 $SystrayLauncher = New-Object System.Windows.Forms.NotifyIcon
 $SystrayIcon = [System.Drawing.Icon]::ExtractAssociatedIcon("C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe")
 $SystrayLauncher.Icon = $SystrayIcon
 $SystrayLauncher.Text = "PowerShell Launcher"
 $SystrayLauncher.Visible = $true

כאשר הסקריפט מורץ, אתה אמור לראות אייקון של PowerShell בסרגל המשימות כפי שניתן לראות למטה.

עכשיו, צור מיכל לפריטי התפריט שלך עם אובייקט ContextMenu חדש וצור את כל פריטי התפריט שלך. לדוגמה, התפריט יכיל שני סקריפטים להרצה ואפשרות ליציאה.

 $ContextMenu = New-Object System.Windows.Forms.ContextMenu
 ​
 $LoggedOnUser = New-MenuItem -Text "Get Logged On User" -MyScriptPath "C:\scripts\GetLoggedOn.ps1"
 $RestartRemoteComputer = New-MenuItem -Text "Restart Remote PC" -MyScriptPath "C:\scripts\restartpc.ps1"
 $ExitLauncher = New-MenuItem -Text "Exit" -ExitOnly

המשך, הוסף את כל פריטי התפריט שנוצרו לתפריט ההקשר. זה יבטיח שכל אפשרות בתפריט יופיע בתפריט ההקשר של הטופס.

 #הוסף פריטי תפריט לתפריט ההקשר
 $ContextMenu.MenuItems.AddRange($LoggedOnUser)
 $ContextMenu.MenuItems.AddRange($RestartRemoteComputer)
 $ContextMenu.MenuItems.AddRange($ExitLauncher)#הוסף רכיבים לטופס שלנו
 $SystrayLauncher.ContextMenu = $ContextMenu

הצג את טופס ההשקה

עכשיו שהטופס הוא מוכן, הדבר האחרון לעשות הוא להציג אותו בזמן שמבטיחים שחלון הפקודות של PowerShell לא יופיע. עשה זאת באמצעות השימוש בStart-HideConsole, הצגת טופס ההשקה ואז הצגת הקונסול שוב עם Start-ShowConsole כדי למנוע תהליך powershell.exe תלוי.

#השקה
Start-HideConsole
$Form.ShowDialog() > $null
Start-ShowConsole

רוצה עוד טיפים כמו אלה? בדקו בבלוג הפושר-שלי בכתובת: https://nkasco.com/FriendsOfATA

הקוד המלא נמצא כאן: https://github.com/nkasco/PSSystrayLauncher

המסקנות שלך

ברכות, סיימת את הפרויקט הזה! במאמר זה למדת:

  1. איך לחשוף רכיבים של ממשק ה- Windows API.
  2. איך לעבוד עם תפריטי הקשר דרך WinForms ולהוסיף פריטי תפריט נוספים.
  3. איך ליצור אייקון בסרגל המשימות בפווֹושֶל.

הפרויקט הזה צריך לתת לך מבוא וניסיון מספיק ליצירת תפריט סיסטרי משלך עבור סקריפטים שלך בפווֹשֶל!

Source:
https://adamtheautomator.com/powershell-form/