25/11/2019

מדריך ל Power Shell בעברית חלק 4 - לולאת foreach והפקודה foreach-object.




קורא יקר- לפני שאתה קורא את המאמר הזה חשוב לעבור על החלקים הראשונים של המדריך לצורך הבנה טובה יותר,

לכלל הפוסטים והמדריכים בנושא ה PowerShell ניתן למצוא כאן
לפורום בנושא באתר devhub.co.il כאן

באחת התגובות למאמר הקודם קיבלתי בקשה של קורא:


אז לבקשתך, מר "אנונימי" להלן מאמר המסביר על ההבדלים בין foreach-object לבין הללואה Foreach וכיצד לעובד איתן.

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


הלולאה\הצהרה (כל אחד קורא לזה בצורה אחרת) Foreach.


  • משהו שחשוב מאוד להבין לפני כן, "foreach" היא גם קיצור של הפקודה "foreach-object" אבל מדובר בשתי אובייקטים שונים, וכאשר משתמשים ב "foreach" שהיא הלולאה, אין אפשרות לרשום "foreach-object" אלה אך ורק "foreach" לעומת זאת כאשר משתמשים בפקודה "foreach-object" בתוך הפייפליין, ניתן לכתוב "foreach" במקום "foreach-object".


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

להבדיל מה foreach-object שעושה את אותו הדבר אבל היא חייבת להיות רק אחרי הפייפליין.

אתן שלושה דוגמאות ל foreach  ונלמד את מבנה הלולאה:



תחילה מבנה הלולאה:
foreach ($variable1 in $variable2) {

Do stuff with $variable1

}

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

החלק המבלבל בכל הסיפור הזה, זאת השורה הזאת (foreach (variable1 in variable2

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


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

$numbers = @(1, 2 , 3, 4)

עכשיו נשתמש בלולאה בשביל לעשות איזושהי פעולה על כל אחד מהאובייקטים האלה:

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

בדוגמא הזאת בחרתי להפעיל את המשתנה שניצל שמייצג כל מספר שהלולאה עוברת עליו כרגע, לכן הפלט יהיה:
 "זה מספר השניצלים שאני אוכל ביום:1"
"זה מספר השניצלים שאני אוכל ביום:2"
"זה מספר השניצלים שאני אוכל ביום:3"
"זה מספר השניצלים שאני אוכל ביום:4"

foreach ($shnitzel in $numbers) {


write-host "I eat this number of Shnitzels each day :" $shnitzel


}
פלט של הלולאה הראשונה:




דוגמא שניה:
בדוגמא זאת אני אפעיל את המשתנה numbers אשר מכיל בתוכו כרגע את המערך "1234" (אם נכתוב ב powershell את ה משתנה numbers$ נקבל את מה שהוא מכיל בתוכו) 


$numbers = @(1, 2 , 3, 4)

foreach ($shnitzels in $numbers) {

write-host "I eat $numbers of shnitzel each day"

}



במקרה של הדוגמא הנ"ל, הפלט יהיה:

 "אני אוכל 1234 שניצלים ביום"
 "אני אוכל 1234 שניצלים ביום"
 "אני אוכל 1234 שניצלים ביום"
 "אני אוכל 1234 שניצלים ביום"

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


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


$stuff = Get-Process

foreach ($thing in $stuff){

Write-Host "The name of the process is :" $thing.Name
Write-Host "`n"
Write-Host "The used cpu of the process is:" $thing.cpu
Write-Host "`n"

}

תשימו לב שבתוך מבנה הלולאה רשום thing.Name$ ואתם בטח שואלים את עצמכם מה זה?, אז אני שמח ששאלתם, התשובה מאוד פשוטה ודיי הגיונית, מאחר ואני רוצה לקבל את שם הפרוסס, אז אני אומר למערכת שתציג לי את המשתנה שכרגע נמצא בלולאה ואת העמודה name ואותו דבר גם  בשורה השניה thing.cpu$ וכך הלאה.. מאוד נוח נכון? והאמת שגם מאוד הגיוני כי הפרוש של הפקודה בעצם נראה ככה "process.property " (אני מקווה שאתם זוכרים ש property ב PowerShell הוא בעצם ה"עמודה", אם לא, אז הינה הזכרתי לכם :) ).

ועוד שאלה, מה זה" "Write-Host "`n " ??

אז אני שמח ששאלתם, המשמעות של הפקודה הזאת write-host היא להוציא פלט למסך שזה דיי הגיוני אם מתחשבים בתרגום הפקודה, אבל מה היא המשמעות של הגרש והאות n באנגלית?

אז ככה, המשמעות היא מאוד פשוטה, האות n היא קיצור של המילה "new" באנגלית והגרש "`" היא פרמטר "בריחה" (אני מת על תרגום ישיר מאנגלית לעברית :) ) יש המון כאלה ואנחנו נעבור עליהם באחד המדריכים בהמשך, כרגע המשמעות של הגרש בצירוף האות n באנלית היא פשוטה מאוד - שורה חדשה, ככה שכש write-host רואה את הצמד הזה, הוא יודע שהוא פשוט מייצר שורה חדשה בלי שום טקסט - ואת זה אנחנו נראה בדוגמא הזאת.

לא חייבים להשתמש בו אבל זה פשוט יותר נוח מבחינת קריאה.


הפלט של הלולאה:


תשימו לב שבין השורות יש רווח בלי טקסט - אז זה בעצם מה שעושה :"write-host "`n.



דוגמא רביעית:
אגב בעבודה עם קובץ csv, ברגע שמבצעים פקודה בסגנון import-csv ויש לכם עמודות, אז ניתן אחרי הנקודה לרשום את העמודה שאתם רוצים להציג והיא תופיע בלולאה עצמה, להלן דוגמא לסקריפט ליצירת משתמשים באקטיב דירקטורי שאני עובד איתו כל פעם שאני צריך לבנות אקטיב דירקטורי:

cls
#get the csv file
$filepath = import-csv "C:\scriptingstuff\User creation script\users.csv"

#set the variable for the uers
$newusers = $filepath

#start the loop 

foreach ($user in $newusers) {


#get user information
$firstname = $user.'First Name'.Trim()
$lastname = $user.Lastname.Trim()
$loginname= $user.SamAccountName
$securepassword = $user.Pass
$jobtitle = $user.'Job Title'
$Department= $user.Department
$Description = $user.Description
$OuPath= $user.Path
$LoginScript=$user.ScriptPath
$displayname= $user.DisplayName
$email = $user.Email

#creat the users in active directory

New-ADUser -Name "$firstname $lastname" -GivenName $firstname -Surname $lastname -UserPrincipalName $loginname -Path $OuPath -SamAccountName $loginname  -AccountPassword (ConvertTo-SecureString "AccountPassword" -AsPlainText -Force) -ChangePasswordAtLogon $false  -EmailAddress $email -DisplayName $displayname -Enabled $true 

Write-Host "`n"
Write-Host "The account for $firstname $lastname created in $OuPath successfully"

}

בחלק הראשון של הסקריפט, כפי שניתן לראות, אנחנו מייבאים את קובץ ה CSV בעזרת הפרודה import-csv, ולאחר מכן בתוך הסקריפט אנחנו רושמים על יד כל משתנה, איזו עמודה אנחנו רוצים לייצג בתוך הסקריפט, ככה שבעצם לדוגמא בשדה המייל בפרופיל של המשתמש אנחנו רוצים להוסיף את המייל, אז בפקודה להוספת המשתמש שהיא new-aduser נציג את הפרמטר EmailAddress ולידו נרשום את המשתנה שהגדרנו בו הפניה לעמודה המתאימה בקובץ ה CSV ובעצם בצורה קצרה זה יראה ככה new-aduser -EmailAddress  $email כי לפני כן הגדרנו את זה:
$email = $email.Email


הפקודה Foreach-object.

אז אחרי שעברנו על הלולאה foreach, הגיע הזמן שנעבור לחלק השני של המדריך הזה, הפקודה foreach-object, כעקרון הפקודה עובדת בצורה דומה מאוד ללולאה רק שכאן היא נמצאת אך ורק מאחורי הפייפליין, בדוגמאות הבאות אנחנו נראה איך זה נראה בפועל.

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

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

¿?(במידה ואתם לא מכירים את הסימן הזה "_$" או "psitem$" אני ממליץ לכם להפסיק לקרוא את המדריך ולעבור על החלק השלישי של המדריך כי באיזשהו שלב לא תבינו על מה אני מדבר במדריכים העתידיים וזה מאוד חיוני שתבינו את כל הדוגמא לצורך הבנה ולימוד פשוטים יותר- יש קישור בתחתית הפוסט וגם בתחילתו)¿?

דוגמא ראשונה (עם הסימון psitem$):
$numbers = @(1, 2 , 3, 4)

$numbers | foreach-object {write-host "I eat $numbers of $Psitem each day"}

פלט של הפקודה:





דוגמא שניה ( עם _$):

$numbers = @(1, 2 , 3, 4)

$numbers | foreach-object  {write-host "I eat $numbers of $_ each day"}

פלט של הפקודה:



דוגמא שלישית:


$stuff = Get-Process

$stuff |ForEach-Object {

Write-Host "the name of the procrss is: " $_.Name

}


פלט של הפקודה:



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

למה שלא תרשמו את כל המחשבים מראש ותריצו פקודה אחת שפשוט תעשה את זה עבורכם?

cls

$pcs = "www.google.co.il","www.ynet.co.il"

foreach ($pc in $pcs) {

ping $pc

}

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

הפוטנציאל הוא באמת אדיר והוא תלוי אך ורק בכם ובדמיון שלכם.







המייל שלי לכל שאלה :
levl@leidertech.co.il

אל תשכחו לתת לנו לייק בדף הפייסבוק - חפשו LeiderTech

לכלל הפוסטים והמדריכים בנושא ה PowerShell ניתן למצוא כאן
לפורום בנושא באתר devhub.co.il כאן

8 תגובות:

  1. כל הכבוד מדריך מפורט!
    כתיבה מוסברת תעשה עוד תודה.

    השבמחק
  2. היי, תודה רבה על התגובה,
    שמח שיכלתי לעזור.

    אני כל כמה זמן מעלה מדריכים, אבל לוקח זמן לכתוב אותם ולצלם אותם.

    השבמחק
  3. מדריך ברור ועדכני!
    עזר לי מאוד,
    תודה רבה:)

    השבמחק
  4. מדריך ממש מפורט מחכה לעוד !!

    השבמחק
    תשובות
    1. תודה רבה על הפידבק !
      לוקח זמן להוציא כל פעם מדריך כזה, לכן הם לא נכתבים כל כך מהר :)

      מחק

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

תודה :)