כאשר אתה כותב סקריפט ב-PowerShell בלי פונקציות וללא תלות חיצונית בסקריפטים אחרים, המושג של סקופים ב-PowerShell אינו של דאגה רבה. המושג של משתנים גלובליים ב-PowerShell אינו במקום המרכזי. אך כשאתה מתחיל לבנות פונקציות, מודולים וללמוד לקרוא סקריפטים מסקריפטים אחרים, הנושא הזה הופך יותר חשוב.
במאמר זה, אתה הולך לקבל שיעור עמוק על מהם הסקופים ב-PowerShell, איך הם פועלים, וכיצד ניתן לכתוב קוד עם סקופים בדעת. עד שתסיים, תבין את משתני הגלובליים של PowerShell ועוד הרבה!
סקופים: כמו דליים
האם כתבת סקריפט שבו אתה מגדיר משתנה וכשאתה בודק את ערך המשתנה, זה משהו אחר? יתכן שתחשוב כיצד המשתנה השתנה כאשר הגדרת אותו באופן ברור. סיבה אחת יתכן שהערך של המשתנה נכתב מחדש בסקופ אחר.
אולי תשאל איך משתנים מסויימים ב-PowerShell יש להם ערכים כאשר אתה מתייחס אליהם בקונסולה שלך אך הם אינם קיימים בסקריפטים שלך. יש סיכוי שהמשתנים הם ב"דלי" אחר שאינו זמין באותו הזמן.
סקופים הם כמו דליים. סקופים משפיעים על הדרך שבה PowerShell מבדילה בין משתנים, קישוריות, פונקציות ו-PSDrives בין אזורים שונים. סקופ הוא כמו דלי. זה מקום לאסוף את כל הפריטים הללו יחד.
כאשר PowerShell מתחיל, הוא יוצר אוטומטית את ה"דליים" הללו עבורך. בנקודה זו, אתה כבר משתמש בסקופים מבלי להבין את זה. כל הסקופים מוגדרים על ידי PowerShell ונוצרים בלעדייך.
סוגי ההיקף
כאשר PowerShell מתחיל, הוא יוצר אוטומטית ארבע "דליים" או היקפים לפריטים שונים להיות מונחים בהם. אין באפשרותך ליצור היקפים באופן עצמאי. אתה יכול רק להוסיף ולהסיר פריטים מההיקפים המוגדרים למטה.
היקף גלובלי
פריטים שמוגדרים כאשר PowerShell נפתחים מוגדרים בהיקף הגלובלי. פריטים אלו כוללים אובייקטים שנוצרו על ידי המערכת כמו דיסקים של PowerShell וגם כל דבר שהגדרת ב פרופיל PowerShell שלך מאז הפרופיל שלך רץ בהפעלה.
פריטים בהיקף הגלובלי זמינים בכל מקום. תוכל להתייחס לפריטים בהיקף הגלובלי באופן אינטראקטיבי בקונסול, בכל סקריפט שאתה מפעיל, ובכל פונקציה. המשתנים הגלובליים של PowerShell נמצאים בכל מקום. לכן, השימוש הנפוץ במשתנים גלובליים של PowerShell הוא להשתמש ביניהם בין סקריפטים.
יש רק היקף גלובלי אחד ששולט בכלל.
היקף סקריפט
A script scope is automatically created every time a PowerShell script runs. You can have many different script scope instances. Script scopes are created when you execute a PS1 script or a module, for example.
רק פריטים שנוצרו במופע ההיקף של סקריפט מסוים יכולים להתייחס אחד לשני.
היקף פרטי
לרוב, ניתן לגשת לפריט שהוגדר ממקום אחר – אך זה אינו תקף עבור פריטים בהיקף פרטי. פריטים בהיקף פרטי מכילים אובייקטים שמוסתרים מההיקפים האחרים. היקף פרטי משמש ליצירת פריטים באותו שם כמו פריטים בהיקפים אחרים כדי למנוע חפיפה.
היקף מקומי
לעומת הקטעים האחרים, הקטע המקומי שונה קצת. הקטע המקומי הוא מצביע לטווח הגלובלי, התסריט או הפרטי. הטווח המקומי יחסי להקשר שבו הקוד רץ בזמן.
אם תיצור משתנה, שם נפש, פונקציה או PSDrive מבלי להקצות בבירור לו טווח (שנדון בהמשך) זה ייכנס לטווח המקומי.
עיון בטווחים
עכשיו שיש לך רעיון על ארבעת סוגי הטווחים שקיימים, כדאי לך גם לדעת שישנם שני אופנים לעיון בטווחים אלו.
בפוורשל, ישנם שני אופנים לעיון בטווחים – לפי שמות או לפי מספרים. שני השיטות מתייחסות לאותם טווחים, אך פשוט בדרך שונה. אלו שני דרכים שונות לשימוש בטווחים.
טווחים בשמות
למעלה בחלק הסוגי טווח, למדת על טווחים שמתייחסים לפי שמות. התייחסות לטווח לפי שם נקראת, באופן ברור, טווח בשם. המטרה העיקרית של התייחסות לטווח לפי שם היא להקצות פריט לטווח. תלמד איך לעשות זאת למטה.
טווחים לפי מספרים
בנוסף לשם, כל טווח מקבל מספר המתחיל באפס שתמיד יהיה הטווח המקומי. הטווחים מקבלים מספרים באופן דינמי יחסית לטווח המקומי הנוכחי.
לדוגמה, מייד לאחר פתיחת ישיבת פוורשל אתה פועל בטווח הגלובלי. בנקודה זו, הטווח הגלובלי הוא הטווח המקומי (זכור שהטווח המקומי הוא פשוט מצביע).
מאחר והטווח המקומי הוא תמיד טווח אפס, בנקודה זו, גם הטווח הגלובלי הוא כרגע גם טווח אפס. אך, כאשר אתה מפעיל סקריפט מהסשן הזה, טווח סקריפט נוצר. במהלך הרצת הסקריפט, האינדיקטור של הטווח המקומי שונה לטווח הסקריפט. כעת טווח הסקריפט הוא טווח אפס והטווח הגלובלי הוא טווח אחד.
הטווחים מסודרים לפי מספרים. התהליך חוזר על עצמו עבור כל הטווחים שבהם הטווח המקומי הוא 0. הטווחים מסופרים באופן דינמי לפי היררכיה של הטווחים.
יררכיה וירושה של הטווחים
כפי שאומר למעלה, כאשר אתה משיק סשן PowerShell, PowerShell יוצרת פריטים מסוימים עבורך בטווח הגלובלי. אלו יכולים להיות פונקציות, משתנים, כינויים או PSDrives. כל דבר שאתה מגדיר בסשן PowerShell שלך יוגדר גם בטווח הגלובלי.
מאחר ואתה כרגע נמצא בטווח הגלובלי כברירת מחדל, אם אתה עושה משהו שיוצר טווח נוסף כמו להפעיל סקריפט או להריץ פונקציה, יוצר טווח ילד עם ההורה הוא הטווח הגלובלי. טווחים דומים לתהליכים עם הורים וילדים.
כל דבר שמוגדר בטווח ההורה, הטווח הגלובלי במקרה זה, יהיה נגיש בטווח הילד. אך רק בטווח שבו הוא הוגדר.
נניח שיש לך סקריפט בשם Test.ps1. בתוך סקריפט זה יש שורה אחת כפי שמוצג למטה.
כאשר אתה מריץ את סקריפט זה, $a
מקבל ערך בתחום המקומי (הסקריפט בזמן ריצת הסקריפט). כאשר נרצה להריץ Test.ps1, ניתן לראות שלא ניתן להפנות אליו לאחר ביצוע הסקריפט. מאחר ש- $a
ניתן עוד בתחום הסקריפט, התחום הגלובלי (בקונסול האינטראקטיבי) לא יכול לראות אותו.

בוא נקדם את הדוגמה הזו צעד נוסף ונשנה את הסקריפט Test.ps1 כך. הסקריפט מנסה כעת להדפיס את ערך ה- $a
לפני שמגדירים אותו באותו התחום.
כדי להדגיש, הקצה ערך ל- $a
בקונסול האינטראקטיבי. זה מקצה את הערך בתחום הגלובלי. כעת, כאשר הסקריפט מרוץ, הוא יירש את התחום האב (גלובלי) ואמור לראות את הערך.
ניתן לראות למטה כאשר Test.ps1 מוריץ (יצירת תחום ילד של התחום הגלובלי), הוא יכול לראות את ערך ה- $a
. ניתן גם לראות כי ערך המשתנה זמין בתחום הגלובלי גם מאחר שזהו התחום שבו הוא נקבע. זה אומר ש- $a
זמין גם בתחום הסקריפט (ילד) וההורה (גלובלי).

זכור את התנהגות זו של התחום המורשה. בעזרת כך תוכל לעזור בזמן פתרון בעיות כאשר יתרחשו סכסוכי משתנים כמו משתנים בתחומים שונים עם אותו השם.
הגדרת וגישה לפריטים בתחומים
עכשיו שאתה יודע מהו תחום וכיצד הם פועלים, איך אפשר לגשת אליהם? בוא נראה איך להשתמש בפוורשל כדי להגדיר את תחום המשתנים (ולגשת אליהם).
קבל/קבע-משתנה
בפוורשל, ישנם שני קומנדלטים שמאפשרים לך להגדיר משתנים הנקראים Get-Variable
ו־Set-Variable
. קומנדלטים אלו מאפשרים לך לאחזר את ערך המשתנה או להגדיר ערך.
שני הקומנדלטים דומים עם פרמטרי Name
ו־Scope
. באמצעות פרמטרים אלו, פוורשל מאפשר לך להגדיר ולאחזר ערכי משתנים בכל התחומים.
תחומים מקומיים
כדי להגדיר משתנה בתחום מקומי, השתמש ב־Set-Variable
וספק לו שם משתנה מקומי וערך כמצויין למטה.
תחום המקומי הוא תמיד הברירת מחדל, לכן אי שימוש בפרמטר ה־Scope
יגדיר תמיד את המשתנה בתחום המקומי.
כדי לאחזר את ערך המשתנה בתחום מקומי, השתמש ב־Get-Variable
וספק את השם.
תחומים פרטי/תסריט/גלובליים
תשתמש באותם פרמטרים (Name
ו־Value
) כאשר אתה עובד עם משתנים פרטיים, תסריטיים וגלובליים כמו כן. ההבדל היחידי הוא שהפעם תשתמש בפרמטר Scope להגדיר באופן פעיל את התחום.
השיטות להגדרת משתנה בתחום פרטי, תסריט או גלובלי זהות. פשוט החלף את הערך שמועבר לפרמטר ה־Scope
כ־פרטי
, תסריט
גלובלי
.
שים לב: כדי לשלוף את ערך התסריט או משתנה שנמצא בתחום הגלובלי, השתמש ב- Get-Variable
וספק לו את השם והתחום.
הערה: תוכל גם להפנות לתחומים באמצעות מספרי תחומים במקום בשמות, בעזרת הפקודות
Get
/Set-Variable
.
הוספת תחום לפני
תוכל גם לשלוף ולהגדיר משתנים בתחומים באמצעות קיצור דרך. במקום להשתמש בפקודות PowerShell, תוסיף את התחום לפני המשתנה בהתייחסות אליו.
תחומים מקומיים
מאחר והתחום המקומי הוא תמיד הברירת מחדל, הגדרת משתנה והתייחסות אליו יגדירו וישליפו משתנה בתחום מקומי
תחומים פרטיים/תסריט/גלובליים
אם תרצה להגדיר ולהפנות לתחומי תסריט או גלובליים, תוכל להוסיף את התחום לפני המשתנים עם שם התחום ונקודה פסיק.
לדוגמה, כדי להגדיר את המשתנה $a
בתחום הגלובלי, תוסיף את $global:
לפני a.
אותו הדבר אפשר לעשות גם עבור משתנה בתחום התסריט.
פעם שהמשתנים מוגדרים בתחום המועדף, יש להם תפקיד ייחודי וניתן להם להתייחס אליהם באותו הדרך. גם שים לב שאפשר להתעלם מהתחום המוסמך אם התחום שהוגדר הוא התחום המקומי.
תחומים בבלוקי תסריט
ב-PowerShell יש בנייה מועילה בשם "בלוקי תסריט". בלוקי תסריט מאפשרים לך להעביר קטעי קוד סיפורט סביב ולהפעיל אותם בכמעט כל מקום.
כמו קובץ סקריפט PS1, בלוקי תסריט רצים בתחום התסריט שלהם. כאשר אתה מפעיל בלוק תסריט, אתה בעצם מפעיל סקריפט PS1.
שים לב בדוגמה למטה לאיפה שמשתנה מוגדר בטווח הגלובלי ואז מנסה להתאים מחדש בטווח הסקריפט. כפי שלמדת למעלה, זה לא יעבוד מכיוון שטווח ילד לא יכול להתייחס לטווח ההורה.

דוגמה זו מראה שכאשר $a
משתנה בבלוק הסקריפט, ההגדרה הגלובלית למשתנה $a
אינה משתנה מכיוון שהבלוק הסקריפט הוא טווח ילד של הסקריפט.
שלטון סקריפטים דרך נקודה (החלפת טווחים מקומיים)
יש ל-PowerShell מושג הנקרא dot-sourcing. זהו שיטה המאפשרת לך להריץ סקריפט PS1 ולהביא הכל שהיה מוגדר בטווח הסקריפט לטווח המקומי במקום.
על ידי שנתון נקודה (.) לפני הפנייה לסקריפט PS1 והרצתו, זה "dot sources" את תוכן הסקריפט ומביא את הכל לטווח המקומי.
לדוגמא, יש לי סקריפט Test.ps1 שוב המגדיר משתנה כפי שמוצג למטה.
במקונסול PowerShell, הגדר ערך למשתנה $a
ואז dot source את הסקריפט הזה כמוצג למטה. שים לב שהמשתנה המקורי הופקע. PowerShell "משלב" את שני טווחי המקומיים יחד.

שימוש במאפיין AllScope (אפשרות)
ראית כיצד להתמודד עם פריטים בטווחים ספציפיים, אך עד כה כל פריט עדיין מוגדר בטווח יחיד. אך מה קורה אם אינך יודע באיזה טווח המשתנה מוגדר?
כאשר אתה מגדיר משתנה עם הפקודה Set-Variable
, תוכל לשים את המשתנה בכל ההקשרים בו זמנית. כדי לעשות זאת, השתמש בערך AllScope
עבור הפרמטר Option
.
כדי להדגים, נערכה שינויים בקובץ התסריט Test.ps1 כך שהוא יגדיר משתנה בכל ההקשרים. הערך של המשתנה הזה יוצא כפי שמוצג למטה.
בתמונה למטה תראה שערך מוגדר עבור $a
בהקשר הגלובלי והתסריט Test.ps1 מתבצע. אך במקום שלא יהיה לו השפעה, ערך $a
כתובתו. לא רק שהוא מוגדר בהקשר התסריט (Write-Output $a
) אלא שהוא כתובת את ההקשר הגלובלי.

האפשרות AllScope
היא שימושית, אך יש להיות זהירים. אפשרות זו בעצם מתעלמת מהמושג של קשרים וממזגת הכל יחד.
קשרי פונקציה
כאשר אתה מפעיל פונקציה, כל הקוד בתוך הפונקציה נמצא בהקשר ילד של עצמו. קשרי הפונקציה עוקבים אחרי אותה התנהגות של קשרי ילד/הורה כמו קשרים אחרים.
החשיבה בקשר לקשר נפרד לכל פונקציה היא רעיון טוב. זה מאפשר שליטה טובה יותר על פריטים בלתי נדרשים לדאוג על קונפליקטים, וגם נותן את היתרון הנוסף של ניקיון אוטומטי של משתנים בפונקציה. מהרגע שהפונקציה מסתיימת, כל הפריטים שהוגדרו בפונקציה יימחקו.
להדגים, העתק/הדבק את הפונקציה לקונסול PowerShell ישירות.
ברגע שתדביק, בצע את הפונקציה. שים לב שאין באפשרותך לגשת למשתנה $var
מחוץ לפונקציה.
שמירת פריטים כפרטיים (ניטרול ירושה)
בדרך כלל, אם משתנה מוגדר בקטע אב, המשתנה יהיה מוגדר גם בקטע הילד. אך אולי תרצה להשתמש בשם משתנה אך שם זה כבר הוגדר באחד מהקטעים להרצה באותה ישיבה. במקרה כזה, תוכל לבחור בשם משתנה שונה או להגדיר את המשתנה בקטע פרטי, כך שיהפוך למשתנה פרטי.
A way to use scopes to reduce conflicts is to use the private scope. Using the private scope disables inheritance on that specific variable. When multiple child scopes are created, those child scopes will not see any variables defined in a private scope.
A Test.ps1 script outputs the value of $a as shown below.
תראה מטה שאני מגדיר משתנה בקטע המוגדר פרטית בתחום הגלובלי ואז מבצע את סקריפט Test.ps1. בדרך כלל, כאשר אתה מגדיר משתנה בקטע אב, המשתנה יהיה זמין בקטע הילד – לא כך עם משתנה בקטע המוגדר פרטית.
בדוגמה למטה, תראה שהקטע הילד של הסקריפט שנוצר על ידי הפעלת הסקריפט Test.ps1 לא יכול לראות את המשתנה $a
המוגדר בקטע האב.

בניגוד לקטעי גלובל או לאפשרות AllScope
בפקודת Set-Variable
, משתנים המוגדרים כפרטיים הם אופציה מצוינת לארגן פריטים.
תרגום שקופים מומלץ
חשיבה כי הגדרת משתנים בקשר הגלובלי או שימוש באפשרות AllScope
היא הדרך ללכת היא נפוצה. בסופו של דבר, כל המשתנים זמינים בכל מקום. אין צורך לדאוג לקושיי הנוגעים לטווחים. בעוד שזה מספק חופש נוסף לגבי גישה למה שהוגדר, זה יכול להפוך במהירות ללא ניהולי ולהקשות על הבעיות.
במקום לנסות למנוע שימוש בטווחים עקוב אחר הטיפים האלה:
- במקום לציין טווחים בפונקציות, השתמשו בפרמטרים כדי להעביר את המידע הדרוש לפונקציה.
- נשארו בטווח המקומי כמה שניתן.
- במקום להגדיר משתנים גלובליים מתוך סקריפט, השתמשו בפקודת
Write-Output
כדי להוציא הכל ולשמור את זה במשתנה כאשר נדרש מהקונסולה.
הנקודה העיקרית כאן היא לקבל טווחים וללמוד להשתמש בהם לטובתך במקום לנסות להימנע מהם.