שלט בבלוקי PowerShell Try Catch כמו מומחה עם דוגמאות

האם אי פעם הפעלת סקריפט או פקודת PowerShell ונתקלת בקיר טקסט צועק – באדום – דומה לזה שמוצג למטה?

Example of errors in PowerShell

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

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

במאמר זה, תלמד על שגיאות ב־PowerShell וכיצד ניתן לתפוס אותן כדי לבצע טיפול בשגיאות באמצעות בלוקי Try Catch ב־PowerShell (ובלוקי finally).

הבנת כיצד שגיאות פועלות ב־PowerShell

לפני שנכנס לטיפול בשגיאות, בוא נכסה כמה רעיונות סביב שגיאות ב־PowerShell. הבנה טובה של השגיאות יכולה להוביל לאסטרטגיות טובות יותר של טיפול בשגיאות.

המשתנה האוטומטי $Error

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

כאשר אתה פותח סשן PowerShell לראשונה, משתנה $Error ריק. אתה יכול לבדוק את זה על ידי קריאה למשתנה $Error.

The $Error variable is empty

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

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

PS> Get-Service xyz
PS> $Error
PS> $Error.Count
The error is added to the $Error variable

כפי שניתן לראות מהפלט לעיל, השגיאה שנוצרה התווספה למשתנה $Error.

המשתנה $Error מכיל אוסף של שגיאות שנוצרו בסשן PowerShell. כל שגיאה ניתן לגשת אליה על ידי קריאה למיקום המערך שלה. השגיאה האחרונה תמיד תהיה באינדקס 0.

לדוגמה, השגיאה האחרונה ניתן לשחזר באמצעות $Error[0].

מאפייני האובייקט $Error

מאחר ש הכל ב־PowerShell הוא אובייקט, המשתנה $Error הוא אובייקט, ואובייקטים מכילים מאפיינים. על ידי שימוש בצינורות למשתנה $Error אל ה־cmdlet של Get-Member, אתה צריך לראות את רשימת המאפיינים הזמינים.

$Error | Get-Member
The $Error object properties

כדי לקבוע את סיבת השגיאה, ניתן להציג את תוכן המאפיין InvocationInfo באמצעות הפקודה למטה.

$Error[0].InvocationInfo
The InvocationInfo property

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

שגיאות סיום

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

כפי שתראה בתמונה למטה, כאשר הפקודה Get-Process notepad מתבצעת, הפקודה תקינה, ופרטי התהליך של ה- notepad מוצגים.

The notepad process details

אך, כאשר משתמשים בפרמטר שאינו קיים כמו Get-Process notepad -handle 251, הפקודה מציגה שגיאה שהפרמטר handle אינו תקין. לאחר מכן, הפקודה יוצאת מבלי להציג את פרטי התהליך של notepad.

Error is thrown because the parameter is invalid

שגיאות לא סופיות

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

$file_list =  Get-Content .\filelist.txt
foreach ($file in $file_list) {
    Write-Output "Reading file $file"
    Get-Content $file
}

תוכן הקובץ filelist.txt הם השמות של הקבצים המוצגים ברשימה למטה.

File_1.log
File_2.log
File_3.log
File_4.log
File_5.log
File_6.log
File_7.log
File_8.log
File_9.log
File_10.log

אך מה יקרה אם File_6.log לא קיים בפועל? כאשר אתה מפעיל את הקוד, תצפה בקריאת שגיאה כי התסריט לא יכול למצוא את ה- File_6.log. תראה פלט דומה שמוצג למטה.

Example of non-terminating error

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

המשתנה $ErrorActionPreference

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

ל-PowerShell יש מושג הנקרא משתני הפנייה. משתנים אלו משמשים לשינוי התנהגותו של PowerShell בדרכים רבות. אחד מהם נקרא $ErrorActionPreference.

המשתנה $ErrorActionPreference משמש לשינוי הדרך בה PowerShell מתייחסת לשגיאות שאינן מפסיקות. כברירת מחדל, ערך ה-$ErrorActionPreference מוגדר ל-Continue. שינוי ערך המשתנה $ErrorActionPreference ל-STOP מכריח את PowerShell להתייחס לכל השגיאות כשגיאות מפסיקות.

השתמש בקוד למטה כדי לשנות את ערך ה-$ErrorActionPreference.

$ErrorActionPreference = "STOP"

כדי ללמוד עוד על ערכי משתנה $ErrorActionPreference תקפים אחרים, בקר ב PowerShell ErrorActionPreference.

עכשיו, הפנה שוב לדוגמה המשמשת ב Non-Terminating Errors קטע במאמר זה. ניתן לשנות את הסקריפט כך שיכלול את השינוי ב $ErrorActionPreference כמו הקוד המופיע למטה:

# הגדרת ערך של $ErrorActionPreference לערך STOP
$ErrorActionPreference = "STOP"
$file_list =  Get-Content .\filelist.txt
foreach ($file in $file_list) {
    Write-Output "Reading file $file"
    Get-Content $file
}

הרצת הקוד ששונה למעלה תתנהג באופן שונה מקודם כאשר ערך ה $ErrorActionPreference מוגדר לערך ברירת המחדל של Continue.

Forcing a terminating error using the $ErrorActionPreference variable

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

ערך ה $ErrorActionPreference תקף רק בהפעלת PowerShell הנוכחית. הוא יאופס לערך ברירת המחדל בעת פתיחת הפעלת PowerShell החדשה.

הפרמטר המשותף של ErrorAction

אם ערך ה־$ErrorActionPreference מיושם במהלך הפעלת הפוורשל, הפרמטר ErrorAction יחול על כל cmdlet שתומך בפרמטרים רגילים. ערך הפרמטר ErrorAction מקבל את אותם ערכים של משתנה ה־$ErrorActionPreference.

ערך הפרמטר ErrorAction עולה על ערך המשתנה $ErrorActionPreference.

בואו נחזור ונשתמש באותו הקוד מהדוגמה הקודמת. אך, הפעם, נוסיף את פרמטר ה־ErrorAction לשורת ה־Get-Content.

# הגדר את ערך ה־$ErrorActionPreference לברירת מחדל (CONTINUE)
$ErrorActionPreference = "CONTINUE"
$file_list =  Get-Content .\filelist.txt
foreach ($file in $file_list) {
    Write-Output "Reading file $file"
		# השתמש בפרמטר המשותף -ErrorAction
		Get-Content $file -ErrorAction STOP
}

לאחר הרצת הקוד המודרף, תראה שאף על פי שערך ה־$ErrorActionPreference מוגדר ל־Continue, הסקריפט עדיין נפסק פעם אחת שנתקל בשגיאה. הסקריפט נפסק מאחר וערך הפרמטר ErrorAction של פוורשל בשורת ה־Get-Content מוגדר ל־STOP.

Forcing a terminating error using the PowerShell ErrorAction parameter

שימוש בבלוקים Try Catch של פוורשל

עד כה, למדת על שגיאות פוורשל ועל איך שעובדים משתנה ה־$ErrorActionPreference והפרמטרים של פוורשל ErrorAction. עכשיו, זמן ללמוד על הדברים הטובים – בלוקים של פוורשל Try Catch Finally.

גוש הכוח PowerShell בלוקי try catch (ובלוק finally אופציונלי) הם דרך להשים רשת סביב קטע קוד ולתפוס כל שגיאה שתחזור.

הקוד למטה מציג את התחביר של ההצהרה Try.

try {
    <statement list>
}
catch [[<error type>][',' <error type>]*]{
    <statement list>
}
finally {
    <statement list>
}

בלוק ה- Try מכיל את הקוד שברצונך שפו"ש ינסה לבצע ולצפות בו לשגיאות. אם הקוד בבלוק ה- Try נתקל בשגיאה, השגיאה מתווספת למשתנה $Error ואז מועברת לבלוק ה- Catch.

בלוק ה- Catch מכיל את הפעולות לביצוע כאשר הוא מקבל שגיאה מבלוק ה- Try. יכולים להיות מספר רב של בלוקי Catch בהצהרה של Try.

בלוק ה- Finally מכיל את הקוד שיתבצע בסופו של ההצהרה של Try. בלוק זה מופעל בלתי תלוי אם התרחשה שגיאה או לא.

תפיסת שגיאות לא ספציפיות (Catch-All) עם הפרמטר ErrorAction של PowerShell

A simple Try statement contains a Try and a Catch block. The Finally block is optional.

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

כפי שניתן לראות מהקוד למטה, הפעם, הפקודה foreach מוקפת בבלוק ה- Try. לאחר מכן, בלוק Catch מכיל את הקוד להצגת המחרוזת An Error Occurred אם התרחשה שגיאה. הקוד בבלוק Finally מאפס פשוט את המשתנה $Error.

$file_list = Get-Content .\filelist.txt
try {
    foreach ($file in $file_list) {
        Write-Output "Reading file $file"
        Get-Content $file -ErrorAction STOP
    }
}
catch {
    Write-Host "An Error Occured" -ForegroundColor RED
}
finally {
    $Error.Clear()
}

הקוד למעלה, לאחר הרצתו ב־PowerShell, יחזיר את הפלט הבא המוצג למטה.

Script terminated when an error occurred

הפלט למעלה מציג שהתסריט נתקל בשגיאה, הריץ את הקוד בתוך בלוק ה־Catch, ואז הסתיים.

השגיאה טופלה, שזהו המטרה של טיפול בשגיאות. אף על פי כן, השגיאה שהוצגה הייתה יותר מדי גנרית. כדי להציג שגיאה מתוארת יותר, ניתן לגשת למאפיין Exception של השגיאה שעברה מצד בלוק ה־Try.

הקוד למטה הוא מותאם, במיוחד הקוד בתוך בלוק ה־Catch, כדי להציג את הודעת השגיאה מהשגיאה הנוכחית שהועברה בצינור – $PSItem.Exception.Message

$file_list = Get-Content .\filelist.txt
try {
    foreach ($file in $file_list) {
        Write-Output "Reading file $file"
        Get-Content $file -ErrorAction STOP
    }
}
catch {
    Write-Host $PSItem.Exception.Message -ForegroundColor RED
}
finally {
    $Error.Clear()
}

הפעם, כאשר הקוד שונה שנמצא למעלה מורץ, הוד המוצג הוא הרבה יותר מתאר.

Script terminated with a descriptive error message

לתפיסת שגיאות ספציפיות

ישנם רקעים בהם טיפול בשגיאות כולל לא נכון. אולי תרצה שהתסריט יבצע פעולה התלויה בסוג השגיאה שנתקלת בה.

כיצד ניתן לקבוע את סוג השגיאה? על ידי בדיקת הערך TypeName של מאפיין Exception של השגיאה האחרונה. לדוגמה, כדי למצוא את סוג השגיאה מהדוגמה הקודמת, ניתן להשתמש בפקודה זו:

$Error[0].Exception | Get-Member

תוצאת הקוד למעלה תיראה כמו התמונה למטה. כפי שניתן לראות, הערך של TypeName מוצג – System.Management.Automation.ItemNotFoundException.

Getting the error TypeName value

כעת שאתה יודע את סוג השגיאה שאתה צריך לתפוס, שנה את הקוד כך שיתפס אותה באופן ספציפי. כפי שאתה רואה מהקוד ששונה למטה, יש כעת שני בלוקים Catch. הבלוק הראשון Catch מתפס סוג ספציפי של שגיאה (System.Management.Automation.ItemNotFoundException). להבנתך, הבלוק השני Catch מכיל את הודעת השגיאה הכללית והאולטימטיבית.

$file_list = Get-Content .\filelist.txt
try {
    foreach ($file in $file_list) {
        Write-Output "Reading file $file"
        Get-Content $file -ErrorAction STOP
    }
}
catch [System.Management.Automation.ItemNotFoundException]{
    Write-Host "The file $file is not found." -ForegroundColor RED
}
catch {
    Write-Host $PSItem.Exception.Message -ForegroundColor RED
}
finally {
    $Error.Clear()
}

התמונה למטה מראה את פלט הקוד ששונה למעלה.

Script terminated with a specific error message

מסקנה

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

למדת גם כיצד להשתמש בבלוקי Try Catch Finally של PowerShell לטיפול בשגיאות, בין אם לשגיאות ספציפיות או בצורה כללית.

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

קריאה נוספת

Source:
https://adamtheautomator.com/powershell-try-catch/