PowerShell Scripting for Beginners – מדריך מקיף למתחילים
במאמר זה נלמד PowerShell Scripting מהבסיס עד לרמה שבה תבינו כיצד עובד Powershell, נכתוב תוכניות שיעזרו לנו הניהול הארגון
נתחיל מעורך ה Powershell, נשתמש בעורך המקורי של ווינדוס ובשביל התרגול נצטרך Windows Domain Controller שמותקן על DC1
תוכלו להיעזר במדריכים הבאים:
הגדרת Domain Controller ב Windows Server 2019/2016
את כל המעבדות שלנו נבצע בתוך ה DC שבמכונה הוירטואלית
עורכי PowerShell
נפתח את ההתחל ונכתוב Powershell, בשביל העורך של Powershell שאיתו נכתוב נלחץ קליק ימני על Windows Powershell ISE ונבחר ב Run as administrator
כעת נלחץ על File ואז שמור בשם, נשמור את הסקריפט בשולחן העבודה
תנו שם לסקריפט בשם script.ps1
אני אשתמש ב PowerShell ISE במהלך המדריך אבל ההמלצה היא להשתמש בעורך איכותי כמו Visual Studio Code
אכנסו לקישור הבא
https://code.visualstudio.com/download
כעת לאחר שהתקנתם אותו והוא עלה, לחצו על הריבוע בצד שמאל
כעת רשמו Powershell בחיפוש בשביל להתקין את Powershell בתוך העורך
כעת בסיום, ניצור סקריפט חדש ולכן לחצו על File – New File
תנו שם Script ואז בחרו Powershell בחלון הבחירה
בסיום תוכלו לכתוב קוד ב PS, בדיוק כמו בPS ISE גם כאן ניתן להריץ חלק מהקוד שבחרתם או את הקוד כולו, אם זה עדיין לא מובן בהמשך אסביר על הכפתור Run ו Run On Selection
Cmdlets
אפשר להשוות אותם לCommands CMD שאתם כבר מכירים ממערכת ההפעלה של ווינדוס, Cmdlets הם למעשה פקודות .net והם עוברים תהליך דרך Pipline | שנלמד בהמשך.
ניתן להעביר cmdlets אחד בכל פעם ל Pipeline ואת זה נלמד בהמשך
Cmdlets משתמש בשני מושגים -Verbs וNouns שעליהם נעבור בהמשך, אבל בעקרון זה אומר שהשפה בנויה בשפה אנושים Get יביא לכם מידע Set יחיל את המשתנה או המידע שאתם רוצים להחיל על האובייקט
הVerb הוא למשל ה Get ואז נשים מקו ואז את ה Nouns , ככה
Get-Proccess
או הפקודה הבאה שמציגה לנו את כל התיקיות והקבצים במיקום בו אנו נמצאים והוא תיקיית הבית
Get-ChildItem
Run vs Run Only Selected
נוכל להריץ את הקוד כולו או חלק שבחרנו מתוכו
הכפתור הירוק או הקיצור F5 יריצו את הקוד כולו
הכפתור לידו Run Selection יריץ רק את הקוד שבחרנו כדוגמא את Get-Service ולא את הקוד כולו
ישנו גם את ה cmdlets New שהוא יוצר אובייקטים כמו קבוצה חדשה
או למשל להתחיל תהליך כמו צייר
Objects
אובייקטים מכילים מידע ויכילו אפשרויות ושיטות Methods
Classes
הם טמפלטים שמהם נוצרים האובייקטים
Paramaters
פרמטרים בדומה לשפות אחרות Arguments או אופציות נניח רוצים לסגור תהליך מסוים אז לאחר הcmdlets נגדיר את הפרמטר למשל , שם התהליך
Stop-Proccess -Name mspaint
ה-Name הוא הפרמטר
ה – mspaint הוא הערך Value
הפרמטרים מחולקים לכמה נושאים:
Name Positional
Mandatory and Optional – פרמטרים שהם חובה וכאלו שלא
בפקודה הבאה ה -Name הוא חובה בשביל ל"הביא" נתונים של שירות הDNS ואילו RequiredServices לא חובה
Get-Service -Name DNS -RequiredServices
Swtich – ברגע שהגדרנו את ה Cmdlets ואז את הפרמטר אנחנו נגדיר את שם התהליך, נניח כמו בתמונה את השירות DNS אם לא נוסיף את הסוויצ' הפקודה תהיה
Get-Service -Name DNS
והמידע שיתקבל הוא שם השירות ואם הוא רץ
אם נוסיף את ה סוויצ' נקבל מידע רחב יותר , נניח איזה שירותים הוא דורש בשביל לעבוד
Get-Help
פקודה חשובה שמציגה לכם את האפשרויות של כל פקודה, נניח ונרצה לדעת מה הוא פרמטר חובה ואילו פרמטרים יש נוכל לבדוק ע"י הפקודה Get Help ולאחריה הCmdlets שאתם רוצים
ואם תוסיפו את הערך Full
Get-Help Get-Service -Full
תקבלו את כל ההסבר המלא על הcmdlets
Set-location vs cd
כאשר רצינו ב CMD לזוז ממקום למקום היינו משתמשים ב cd, זאת אומרת בשביל להגיע לתיקייה X שנמצאת בתוך התיקייה בה אתם נמצאים הייתם מקישים
cd tal
ואילו רציתם לחזור אחורה הייתם משתמשים ב
cd ..
הנקודה הראשונה היא המיקום בו אתם נמצאים , שתי נקודות זה המיקום בו אתם נמצאים ואחורה
לעומת זאת עדיף בPS להשתמש ב Set-Location בשביל להגיע ממקום למקום וזאת כי ל Set-Location יש אופציות מתוחכמות יותר
למשל לעבור לשולחן העבודה נקיש את ה Absolute Path
intger and string
" " אם אנחנו כותבים טקסט נניח נתיב ויש בו רווח, נגדיר את הטקסט בתוך "" וזאת כדי שPS לא יחשוב שאחרי הרווח זה פרמטר
למשל
New-Location " C:\Users\Tal User"
אם לא היה את ה "" הPS היה חושב שUser הוא פרמטר
String – הוא ערך טקסטואלי זאת אומרת שכל טקסט נכניס ל "" ואילו ערך מספרי נגדיר ללא "" מסביבו
Intger – הוא ערך מספרי שלא מוסיפים מסביבו ""
Path – Relative and Absolute
relative Path – הוא הנתיב הרלטיבי זאת אומרת הנתיב בו אתם נמצאים כעת, זאת אומרת אם אני אצור תיקייה ע"י ה Cmdlets הבא
New-Item -Name "New Folder" -ItemType File
אז התיקייה New Folder תיווצר בתיקייה בה אני נמצא שזה תיקיית ה Administrator או כל יוזר שאתם מחוברים אליו
לעומת זאת
Absolute Path הוא הנתיב המלא, בדוגמה הבאה אני מציין את כל הנתיב בשביל להגיד לו בדיוק איפה ליצור את התיקייה ולכן אצטרך את כל הנתיב
Net-Item vs mkdir
כמו מקודם mkdir קיים בCMD או לינוקס אך אנחנו נרצה להשתמש ב New-Item כיוון שאנחנו רוצים להשתמש ביכולות של PS ולכן אכתוב את ה cmdlets שהוא New-item ואז את הOptions או הפרמטר והוא -Path
לאחר מכן אגדיר את הנתיב המלא או נוכחי ואז את שם התיקייה עם הפרמטר -name ולבסוף אוסיף פרמטר שאינו חובה אך אציין שהקובץ הוא File לעומת Directory
$home
ישנם משתנים קבועים בPS כמו $home שהוא תמיד תיקיית הבית של המשתמש המריץ את הסקריפט, לכן אם ארצה ליצור קובץ בתיקייה הבית של המשתמש כול להשתמש בו
Test-path
תוכלו לבדוק אם תיקייה או קובץ קיימים, בהמשך בתנאים נבין למה זה חשוב ונקבל כתשובה אם קיים True ואם לא אז Flase
Invoke-item
נוכל להשתמש ב Invoke-item בשביל להריץ קובץ עם התוכנה שפותחת אותו כברירת מחדל, למשל txt יפתח עם notepad.exe
ואם יש לכם mp3 שבברירת מחדל שלו נפתח עם Winmap אז הוא יפתח עם Winmap
Copy-Item
אם תרצו להעתיק קובץ ממקום למקום נשתמש ב copyitem
Copy-Item -Recurse
נניח והתיקייה שאתם רוצים להעתיק יש בתוכה קבצים אז נשתמש בפרמטר Recurse שאומר רקורסיבי וכך כל הקבצים בפנים יעותקו גם
Rename-Item
שינוי שם לקובץ או תיקייה
Remove-Item
הסרה של קובץ או תיקייה
אם תרצו להסיר בכוח השתמש בפרמטר -force ואם את הקבצים שבתקיה אז בפרמטר -recurse
Wildcards Remove-Item
נניח ואתם רוצים להסיר קבצים שנמצאים בתוך כל תיקייה של משתמש במערכת ההפעלה, נוכל להשתמש ב* בדיוק בשם של המשתמש , הכוכבית תחליף כל טקסט שקיים, זאת אומרת כל שם משתמש ואז תמחק את הקובץ של המשתמש משם
יכולתי באותה המידה להזין רק כוכבית בשם של הקובץ נניח
*tal.txt
ואז להשתמש בפקודה
Remove-Item C:\*\*\*.log
וכל קובץ שנמצא בתוך כל המשתמשים ונגמר ב.log ימחק
Variables – משתנים
משתנה הוא תא שמאחסנים בו מידע לזמן הריצה של הסקריפט זאת אומרת שאוכל לקבוע משתנה בשם Name שיכיל את השם Tal
כך שכל פעם שאריץ Name השם טל יופיע אבל ברגע שחלון הPS יסגר אז המשתנה יעלם או שאחרי שהכרזתי על משתנה Name בשם אחר אז השם האחר יופיע
בדוגמה הבאה כתבתי את המשתנה, את המשתנה כותבים עם $ בהתחלה, החלטתי ששמו הוא name לאחר מכן כתבתי את השם טל בתוך ""
ואז כתבתי רק $name בשביל שPS ידפיס את התוכן של המשתנה
אבל מיד לאחר מכן שיניתי את אותו המשתנה לנוי , ואז ניתן לראות שהמשתנה נשאר noy גם בפעם השניה שכתבתי שכן כעת בזיכרון כתוב שמשתנה הוא noy
בפקודה get-variable בדקתי מה המשתנה כעת של name וכפי שאתם יכולים להבחין הוא noy
סוגי מידע Data Types
בPS כמו בכל שפת סקריפטים יש סוגי מידע, סוגי המידע מאפשרים להזין מידע לתוך משתנה או בפקודות
בשביל ההבנה נעבור על סוגי המידע, מתחיל מ String vs Intger
String – הוא טקסט, לרוב נכניס אותו למשתנה
Intger – הוא ערך מסוג מספר, נניח בחישובים
בדוגמה הבאה הכנסתי למשתנה a את המספר 1 בלי "" וגם לb וכאשר בצעתי a+b קיבלתי 2 שכן 1+1 שווה ל2
אבל מה קרה בפעם השניה שעשיתי את זה? מה שקרה הוא שהכנסתי אותם ל"" וכעת הם טקסט ולכן 1+1 הוא 11 שכן אני מוסיף את ה1 לידו
Arithmetics
גם ב PS יש קדימות לחישובים מתמטיים נניח החישוב הבא
3+6/3*4
אם נכניס את אותו החישוב למחשבון נקבל את התוצאה
11
אבל במתמטיקה יש קדימות לפעולת הכפל ולכן נכניס אותו לסוגריים
3+6/(3*4)
התוצאה תיהיה שונה לגמרי
3.5
ומה יקרה אם נרצה שהפלוס יהיה קודם בחישוב, אז נכניס אותו ל ()
(3+6)/3*4
והתוצאה
12
Boolean
בוליאן מציג True או Flase נניח ואני רוצה לבדוק אם תיקייה קיימת, אז התשובה שתתקבל היא בוליאנית
Comparison Operators אופרטורים השוואתיים
אם נרצה לבדוק אם מספר שווה למספר או ערך שהגיע ממשתנה שווה לערך מסוים אז נשתמש בהשוואה , בשפות אחרות משתמשים ב == בשביל לבדוק אם שווה ואם רוצים לבדוק לא שווה אז != וכו' אבל ב PS משתמשים באופרטורים קצת שונים
-eq -ne -gt -ge -lt -le -like -notlike -match -notmatch -replace -contains -notcontains -in -notin -is -isnot
לדוגמה אשתמש ב -eq שאומר שווה או -ne שאומר not equel לא שווה
Assignment Operators
באופרטורים מסוג שיוך נוכל להוסיף בקיצור מספר למשתנה בצורה קלה
למשל להשתמש ב += שאומר תוסיף למשתנה את המספר הבא, כמו בתמונה
או אוכל להוסיף ++ שאומר להוסיף מספר אחד כלפי מעלה או — כלפי מטה
Split
פיצול כשמו כן, מפצל את התוצאה, אם התוצאה של משתנה זה טקסט אחד אחרי השני ואני רוצה להציג כל טקסט בנפרד, אשתמש בSplit
Join
אם טקסט יופיע מפוצל אחד אחרי השני אוכל להשתמש ב Join בשביל לחבר אותו, ההבדל בינו לבין Split הוא שצריך להגדיר אותו בהתחלה
OR \ NOT \ AND
כמו בכל שפת סקריפטים אפשר להגדיר בדיקה מסוימת כמו מספר ששווה למספר ורק אם המספר השני שווה לו אז התוצאה תיהיה True
OR- התוצאה הזו או הזו נכונה ולכן התוצאה תיהיה True
AND – שתי התוצאות צריכות להיות שוות מספיק שאחת לא והתוצאה תיהיה False
NOT – לרוב נשתמש בו בתנאי IF ונבדוק אופרטור זה בהמשך
Redirect Operators
באופרטורים מסוג כיוון נוכל לכתוב לתוך טקסט בעזרת echo ואז הטקסט שאנו רוצים
יצרתי קובץ בשולחן העבודה בשם tal.txt ואליו אוסיף את שמי אשתמש באופרטור < שאומר את ההדפסה של השם – תכניס לקובץ הבא
אם ארצה לכתוב את שמי עם "אנטר" בין כל שם אזין ללא ""
Append
אם ארצה להוסיף טקסט לטקסט הקיים אשתמש ב << פעמיים בצורה הזו
Output \ Warning \ Error
נניח ואתם רוצים להדפיס את השגיאות אל קובץ מסוים שנקרא לו error.log ואזהרות שנקבל מהPS אל קובץ בשם warning.log ולבסוף את מה שתקין אל output.log
בשביל להדפיס שגיאות , אזהרות וoutput תקין של הסקריפט נשתמש ב
Write-output Write-Error Write-Warning
כך שנוכל להבין את > בהקשר של שגיאות אזהרות וoutput רגיל
output אומר שכל טקסט שהוא לא שגיאה או אזהרה יכתב לקובץ ואתם יודעים שבכל סקריפט יש שגיאות גם אם הוא תקין , שכן בצעתם בדיקה נניח אם שירות עובד, אם הוא לא עובד הפקודה שבה השתמשנו תציג שגיאה וזה יכול להיות בסדר שכן בדקנו אם השירות עובד או לא
בתמונה ניתן לראות שהטקסט hello נכתב לכל קובץ שהגדרנו אבל בשביל להגדיר שהוא יכתב לשם השתמשתי במספור של <
הכוונה היא שהוספתי מספר ליד ה<
1 – אם אין שגיאה או אזהרה והפלט של הפקודה תקין נניח הפקודה
dir
הפקודה תצא תקינה ותציג את כל הקבצים שיש בתיקייה בה אני נמצא ולכן היא תגיע output ותגיע ל1
2 – שגיאות, אם אקיש dir עם שגיאה אקבל שגיאה ולכן רק שגיאות יופנו לקובץ זה
3 – אזהרות , אם יש אזהרות בזמן ריצה הקובץ לוג יקבל רק את אזהרות לשם
דוגמה היא שפה הגדרתי 2> שרק שגיאות יגיעו לקובץ, בגלל שאין שגיאה בפקודה dir הקובץ ריק וdir מוצג לי
כעת אצור שגיאה בכוונה, אנסה להציג ע"י dir מיקום שאינו קיים
תוכלו להבחין שPS לא נותן לנו שגיאה שכן הוא "העביר" אותה אל הקובץ במקום
כעת אוכל להשתמש ב
Write-output Write-Error Write-Warning
שהסברתי קודם עליהם הכוונה הייתה שהם מציגים את הטקסט כשגיאה וגם PS מתייחס לטקסט שכתבתם בפנים ככזו אז <2 יובל את write-error אל הקובץ אבל אם נשנה ל>1 הקובץ יהיה ריק כיוון ש write-error הוא שגיאה
מערך
נוכל לכתוב מערך כמו בכל שפת סקריפטים, המערך למשל יכלול שמות ואותם נוכל להציג במשתנה שלנו
למשל המשתנה name והשמות tal noy
כעת נוכל להפעיל method שיטה על המשתנה בעזרת הוספת . הנקודה תתן לי אפשרויות על המשתנה ובכך להציג נתונים שקיימים בתוך המשתנה למשל, ספור את כמות "השמות" בתא או תספור לי או length
ולבסוף לבדוק מה מכיל המערך שבו משתמש עוד מעט
אופרטור נוסף למשל הוא add אך ברגע שננסה להשתמש בו נקבל שגיאה, הסיבה היא שהוא Tuple זאת אומרת שהוא Immutable ולא יכול להשתנות, אז נוכל להשתמש ב [System.Collections.ArrayList] , זאת אומרת לשנות את סוג המשתנה
נבצע זאת כך
ואם נרצה להסיר?
נוכל להסיר גם בדרך הזו של -ne
Indexs in Arrys
אינדקסים הם המיקום של הטקסטים בתוך המערך, נניח ונרצה להציג רק את Tal או רק את Yarden
אז נשתמש באינדקס
למשל ארצה להציג את Yarden בלבד, האינדקס של ירדן הוא 3 , מדוע לא 4? כיוון שאנחנו סופרים מ 0 ולכן טל הוא במיקום 0 ונוי במיקום 1 וככה הלאה
נוכל גם להחליף במיקום מסוים שם אחר תחילה נציין את המיקום ואז נגדיר את השם במקומו
כך למשל החלפנו את השם amit ב aviv
Objects
האובייקטים הם "הנושאים" המוצגים לנו בכל פקודה נניח בפקודה Get-Aduser נקבל כותרות מתחת לשמות המשתמשים ב AD וכותרות אלו הם האובייקטים
בדוגמה הבאה כל כותרת כמו DistinguishedName או Name הם אובייקטים
Pipeline |
פייפליין הוא הסימן הבא | והוא שילוב של המקשים Shift + | לרוב המקש יהיה ליד הEnter במקלדת
אפשר להשתמש בPipeline יותר מפעם אחת בפקודה אחת בתוך או מחוץ למשתנה
הPipeline מעביר את הOutput של פקודה מסוימת לפקודה הבאה שאתם רוצים, דמיינו זאת כך, המידע עובד בצינור שהוא ה Pipeline ואז מבוצע על המידע שהתקבל אחרי עוד פעולה
בשביל להבין זאת טוב יותר אציג דוגמה קטנה
מקודם השתמשנו ב Get-aduser בשביל להציג נתונים על המשתמש Administrator כעת נניח ואני רוצה להציג רק את השם ואת כל השאר שלא יציג, אשתמש בPipeline בשביל להעביר את המידע לפקודה הבאה וכעת אבחר ב Select-Object בשביל להציג רק את השם בצורה הזו
או כמו הפקודה Get-Service שמציגה את כל השירותים במחשב , אם הם רצים או לא, שם השירות ואז את השם המלא של השירות
כעת אחרי Get-Service אגדיר | ואז גם פה אבחר רק את שם השירות
בהמשך נבצע סקריפטים בהם השימוש בPipline שבהם תוכלו לקבל הבנה רחבה יותר עליהם
Method Objects- שיטות
Methods ניתן להגדיר עם . אחרי המשתנה בשביל להציג אובייקטים מסוימים שאנחנו רוצים מתוך מה שמשתנה מציג למשל בדוגמה הבאה
ארצה להציג רק את השם בלי כותרת של Administrator מתוך Get-Aduser
תוכלו להבחין בתמונה שהוא הציג רק את Administrator
לאחר מכן בפקודה Get-Service אחרי שהוספתי נקודה קיבלתי אפשרויות להציג מתוך המשתנה שהוא Get-Service
ע"י Method ניתן גם לבצע פקודה על התוצאה, נניח ונרצה לעצור שירות מסוים, נוכל על ידי Method לעצור את השירות מתוך מה שנבחר במשתנה, תחילה נגדיר למשתנה מה השירות הספציפי
כיוון שאנחנו רוצים שירות מסוים מתוך הרשימה ולא אובייקט שלם (האובייקט השלם יציג לי את כל השירותים באותה הקטגוריה) אשתמש ב Where-Object איפה שאובייקט עצמו נמצא והוא השירות המסוים הזה
אשתמש ב.name בשביל לבחור בשם והשירות לדוגמה שאחפש הוא Telephone
כעת אוסיף נקודה למשתנה ואוכל להבחין שיש אייקון של ריבועים ואייקון סגול
הריבועים הם מידע, נניח StartType שאומר האם השירות במצב Automatic או Manual או Disabled
הסגול אומר פעולה שאפשר לבצע על השירות נניח Start ואבצע אותו כעת
בהתחלה רציתי להציג את הסטטוס שלו כעת, שהוא Stopped ואז בשביל לבצע עליו פעולה כמו הפעלה השתמשתי ב Start ובשביל זה צריך להוסיף () בסוף כמו בתמונה
לאחר מכן הקשתי שוב את המשתנה עם ה Get-Service, מדוע? כיוון שהסטטוס של השירות השתנה , המשתנה צריך להתעדכן, אם לא הייתי עושה זאת הייתי מקבל עדיין Stopped שכן בהתחלה השירות היה Stopped ואז קיבלתי Start Pending
אם נניח הייתי רוצה לחכות 10 שניות בשביל שהשירות יעלה כמו שצריך אוסיף Start-Sleep שאומר לסקריפט לחכות 10 שניות ואז להריץ את ההמשך ושם אבקש שוב את השירות עם המשתנה ואז אבדוק שוב ע"י Status
בהתחלה רשמתי שניתן להשתמש בPipline כמה פעמים שרוצים, תלוי בפקודה , אז הוספתי Pipline בשביל לעצור את השירות, יכלתי לעצור אותו ע"י . אחרי המשתנה ואז Stop אבל אוכל גם בצורה הבאה
Foreach
foreach היא לולאה שבה נוכל להשתמש בשביל להחיל פעולה מסוימת על פקודה
נניח אני רוצה להציג כל תוצאה ב Get-ChildItem בנפרד ושיוצג לי רק שמות התיקיות, אבצע את זה עם Foreach
בהמשך כמובן נבצע סקריפט יותר "מסובך" עם Foreach שבו תוכלו להבין איפה הוא בא לידי שימוש
כעת אוכל לקצר את ה foreach על ידי %
_$ $PSitem
$PSITEM הוא משתנה קבוע בPS והוא משמש בתור האובייקטים שמועברים מcmdlet שהקשתם
נניח ב get-childitem האובייקטים הם התיקיות והקבצים שהוא מציג ולכן כאשר בפקודה הבאה השתמשתי ב% אז הגדרתי foreach ואז הגדרתי $psitem נקודה name שה Name הוא האובייקט שמות של הקבצים בלבד
נוכל לקצר זאת ע"י _$
_$ With Where-Object
נניח ואני רוצה מתוך Get-Service להשיג שם של שירות מסוים, אוכל להשתמש ב | אחרי Get-service ואז להשתמש ב Where-Object
ניתן לקצר את Where-Object ע"י ? הסימן שאלה מחליף בדיוק את המיקום בו תכתבו אותו כמובן בלי רווח
לאחר מכן אגדיר שעבור המידע שהתקבל ועבור כל אובייקט בתוכו הוא יבדוק את ה Disply Name ולכן אשתמש ב _$
לאחר מכן אני מחפש את שירות ה Firewall ולכן אגדיר -like ולא -eq, הסיבה היא שהDispaly Name ב Windows 7 ו Windows 10 של FW הוא לא אותו דבר, לכן אני רוצה שזה יהיה "דומה – Like" ואז אכניס את המילה Firewall עם כוכביות בצדדים שאיזה שירות שמכיל את המילה Firewall הוא יציג , גם אם יש שירות נוסף שמכיל את השם
Condition – תנאים
תנאים קיימים בכל שפות התיכנות ומציגות את היכולת של הסקריפט לבצע פעולה מסוימת רק אם פעולה אחרת התרחשה
ניקח למשל סקריפט שנרצה להריץ רק אם התנאי התקיים נניח:
השירות Firewall Service שבמחשב יופעל אם הוא במצב Stop ואם הוא במצב Running אז נקבל את ההודעה "השירות כבר רץ, אין צורך להריצו"
תחילה נצטרך להשיג את המצב בו ה Service של ה Firewall ואם הוא ב Running או Stop ולכן אכתוב את הסקריפט
Get-Service | Where-Object {$_.DisplayName -like "*Firewall*"} | Select -ExpandProperty Status
ע"י הפקודה הזו תחילה אני מבצע Get-Service
לאחר מכן בוחר איפה שהאובייקט ומכניס את $_ בשביל שיציג לי רק את השם Firewall ולכן משתמש ב -like ומוסיף את הכוכביות בשביל כל שירות שהשם שלו מכיל Firewall
לאחר מכן אני משתמש ב
Select -ExpandProperty Status
בשביל שיציג לי בלי שם האובייקט את המצב של השירות, אם אשתמש בהגדרה שבצענו קודם והיא Select-Object אני אקבל גם את השם בצורה הזו
אני מעוניין לקבל רק את התוצאה Running או Stopped ולכן אשתמש כעת ב Select -ExpandProperty Status והתוצאה
כעת אחרי שהשגתי האם השירות רץ או לא אכניס אותו למשתנה $fwservice
$fwservice = Get-Service | Where-Object {$_.DisplayName -like "*Firewall*"} | Select -ExpandProperty Status
וכעת אתחיל לכתוב את התנאי של if
תנאי if יתחיל עם המילה if ואז התנאי בתוך () , ככה
if (התנאי)
{
הקוד שלכם
}
ה{} הם הקוד שיורץ במידה והתנאי מתקיים, רק אם הוא מתקיים לכן כעת אכניס את המשתנה שהתוצאה שלו היא Running
ואם המשתנה שווה ל "Running" אז תריץ את הקוד הבא
הקוד שאני רוצה הוא להדפיס את המשפט Service Is Running
if ($fwservice -eq "Running") { Write-Host "Service Is Running" }
אוכל שוב לבדוק אם ה Get עובד כמו שצריך בכך שאבחר רק אותו (אסמן אותו עם העכבר מבלי לסמן את כל הקוד) ואז Run Selection או בקיצור F8
והתוצאה היא Running כל שהכל תקין
כעת אפעיל את הסקריפט כולו
התוצאה מעולה התנאי עבד וכעת כתוב את הטקסט שאני רוצה
אז מה קורה כאשר התנאי לא מתרחש?
מחקו את הקוד שכתבתם והכניסו את הקוד הבא
$remotereg = Get-Service | Where-Object {$_.DisplayName -like "*Remote Registry*"} | Select -ExpandProperty Status if ($remotereg -eq "Running") { Write-Host "Service Is Running" }
הקוד הבא בודק האם השירות Remote Registry רץ או לא בדיוק כמו ה FW, אצלי במחשב הוא כרגע ב Stopped
אבחר רק את Get-Service | Where-Object {$_.DisplayName -like "*Remote Registry*"} | Select -ExpandProperty Status
ואריץ רק אותו לבדוק שהוא באמת ב Stopped (אם הוא רץ אצלכם כנסו ל Services וכבו אותו בשביל התרגיל)
ניתן להבחין שהוא ב Stopped
אז מה יקרה לif שלנו? בגלל שהתנאי לא מתקיים ברגע שנריץ את הקוד כולו לא נקבל שום תגובה
לכן נשתמש בתנאי Else שאומר אם התנאי לא התרחש, else ירוץ
Else
else אומר שאם התנאי if לא התרחש אז הוא יבצע את else זאת אומרת שאם השירות לא ב Running אז הוא יציג Service is Stopped
Elseif
elseif כמו בשפות סקריפטים אחרות מוצג לפעמים כ elif הוא למעשה תנאי נוסף שאם התנאי הראשון לא התרחש אז תבדוק עוד תנאי במקומו
נניח ונכניס שם של שירות שלא קיים, אולי הוא לא קיים במערכת ההפעלה כי אנחנו משתמשים ב Windows 10 במקום Windows Server ובו מותקן Active Directory
אז נשנה את השורה הבאה ונוסיף 1 בסוף , רק בשביל שהסקריפט לא ימצא שום שירות כזה
{$_.DisplayName -like "*Remote Registry1*"}
התוצאה
אז מה יקרה אם אין שירות כזה? במצב של else ו if כמו שעשינו קודם לכן, נקבל את התשובה הבאה:
התשובה היא שהשירות במצב Stopped, אבל זה לא נכון, שכן אין בכלל שירות כזה
אז נכניס elseif שאומר שאם המשתנה ריק אז הוא ידפיס " אין שירות בשם זה"
נשתמש ב$null שהוא משתנה מערכת שאומר "ריק" אין מידע במשתנה והמשתנה ריק
אז נשווה את המשתנה $remotereg ל$null שאומר שאם הוא ריק אז תכתוב את התשובה הבאה
ואז כאשר נריץ את הסקריפט נקבל את התשובה השירות לא נמצא
בניית תוכנית קטנה
בוא נבנה תוכנית קטנה, כאשר הסקריפט ירוץ המשתמש יזין שם של שירות, אם השירות קיים התוכנית תבדוק אם השירות Running או Stopped אם הוא Stopped אז התוכנית תפעיל את השירות ואם הוא ב Running נקבל את התשובה שהשירות כבר רץ
נוסיף כמובן טקסט בהתאמה למשתמש שיקבל Output על מה מבצע הסקריפט, נתחיל
תחילה ניצור משתנה חדש בשם $servicename שבו המשתמש יזין את שם השירות שהוא רוצה
$ServiceName = Read-Host "Enter The Service Name"
Read-Host הוא הcmdlet שמגדיר את הטקסט שיזין המשתמש, לאחר מכן בתוך "" נרשום למשתמש מה להזין
אחרי זה נשאיר את הקוד שלנו אותו הדבר חוץ מכך שאם השירות במצב Stopped אז הוא יריץ אותו ע"י הפקודה
הבחינו שהכנסתי את המשתנה $ServiceName אחרי ה -like שכן אני רוצה שהנתון שיהיה שם יהיה שם השירות שהמשתמש יכניס
Get-Service | Where-Object {$_.DisplayName -like "*$ServiceName*"} | Start-Service
שיניתי גם את הif הראשון לשווה ל Stopped
$ServiceName = Read-Host "Enter The Service Name" $remotereg = Get-Service | Where-Object {$_.DisplayName -like "*$ServiceName*"} | Select -ExpandProperty Status if ($remotereg -eq "Stopped") { Get-Service | Where-Object {$_.DisplayName -like "*$ServiceName*"} | Start-Service } elseif ($remotereg -eq $null) { Write-Host "No Service Found" } else { Write-Host "Service Is Alerady Running" }
כעת הסקריפט יעבוד אבל נרצה להציג למשתמש "מידע" מה עושה הסקריפט
אז הוספתי Write-Host שיציג עוד מידע למשתמש
$ServiceName = Read-Host "Enter The Service Name" $remotereg = Get-Service | Where-Object {$_.DisplayName -like "*$ServiceName*"} | Select -ExpandProperty Status if ($remotereg -eq "Stopped") { Write-Host "----------------------------------------" Write-Host "Service Is Stopped Starting The Serivce" Get-Service | Where-Object {$_.DisplayName -like "*$ServiceName*"} | Start-Service } elseif ($remotereg -eq $null) { Write-Host "No Service Found" } else { Write-Host "Service Is Alerady Running" }
מצויין, ואם השירות כבר רץ? הריצו את הסקריפט שוב ותקבלו הודעה שהוא כבר רץ
Break
תארו לכם מצב בו אתם רוצים לעצור את הסקריפט כולו בנקודה אחת, איפה שיהיה רשום break הסקריפט כולו יעצר ללא קשר אם יש בהמשך תנאים או פקודות תקינות אחרות
אפשר למשל לבנות את השאלה הידוע "האם אתה בטוח להמשיך" רשום y או n
בואו נבצע את זה על הסקריפט שלנו
נוסיף את השורות קוד הבאות אחרי ה $servicename, בהמשך אדביק את כל הקוד
יצרתי משתנה בשם $confirm ואז שאלתי את המשתמש אם y או n
לאחר מכן באותה הצורה כמו מקודם בדקתי בתנאי אם הטקסט שהזין המשתמש שווה ל y אם כן המשתמש יקבל את הטקסט The Script Will Proceed
אם לא, שזה הelse אז הגדרתי את הפעולה Break
ע"י כך הסקריפט כולו יעצר ולא ימשיך
$confirm = Read-Host "Are you Sure $ServiceName Is The Service You Want? Write y or n" if ($confirm -eq 'y') { Write-Host "The Script Will Proceed" } else { break }
ככה זה נראה
ואם נכניס n או כל טקסט אחר הסקריפט פשוט יעצר, נסו את זה
זה הקוד כולו
$ServiceName = Read-Host "Enter The Service Name" $confirm = Read-Host "Are you Sure $ServiceName Is The Service You Want? Write y or n" if ($confirm -eq 'y') { Write-Host "The Script Will Proceed" } else { break } $remotereg = Get-Service | Where-Object {$_.DisplayName -like "*$ServiceName*"} | Select -ExpandProperty Status if ($remotereg -eq "Stopped") { Write-Host "----------------------------------------" Write-Host "Service Is Stopped Starting The Serivce" Get-Service | Where-Object {$_.DisplayName -like "*$ServiceName*"} | Start-Service } elseif ($remotereg -eq $null) { Write-Host "No Service Found" } else { Write-Host "Service Is Alerady Running" }
Loops לולאות For \ While \ Foreach
נתחיל מ foreach כיוון שלולאה זו תתן לכם הבנה קלה יותר של "מדוע להשתמש בלולאות"
לולאות הם האופציה להריץ סקריפט על כמה אובייקטים , נניח ויש לכם רשימה של מחשבים, על כל מחשב בנפרד אתם רוצים לקבל מידע
אז נכניס את רשימת המחשבים לרשימה Arrys ואז נגדיר לסקריפט שירוץ על כל מחשב בנפרד
או בדוגמה הבאה, נכתוב מערך עם שמות המשתמשים שיצרתי בAD בצורה בתוך ה OU הבא
כעת נכתוב את המערך בסקריפט עם משתנה בשם $users
$users = ("Amity", "avivn", "ord")
כעת בשביל for נכניס את הפקודה foreach ובתוך ה foreach בסוגריים עגולים נכניס את הפקודה
$user in $users
Users זה המשתנה שמכיל את הרשימה של המשתמשים
user זה משתנה חדש, שכן לתוך המשתנה הזה כל משתמש ברשימה יכנס וכך בקוד עצמו כאשר נבצע get-aduser לאחר מכן נגדיר את המשתנה user
ברגע שתריצו את הפקודה, הPS "ילך" לכל שם ויביא את הנתונים של המשתמש מתוך הפקודה Get-Aduser
כמו בתמונה
אתם בטח רשומים אוקיי מזה עוזר לי? אז להביא פרטים יכול לעזור, אבל נניח ואתם רוצים לבצע פעולה על המשתמשים , נניח להוסיף לכל משתמש בDescription את הנתון Jerusalem Office
נבצע זאת כך:
נניח ואתם רוצים לשדרג את הקוד, נניח ואתם לא רוצים בכל פעם לכתוב כל משתמש ומשתמש כי המשתמשים מתעדכנים ונוצרים חדשים בכל יום.
נוכל להביא את הרשימה מתוך הAD בפקודה הבאה
$users = Get-ADUser -Filter * -SearchBase "OU=Finance,OU=UserAccounts,DC=FABRIKAM,DC=COM"
בשביל למצוא את הDistinguishedName שהוא הOU=Finance,OU=UserAccounts,DC=FABRIKAM,DC=COM שלנו בAD, נכנס לActive Direcotry Users And Computers ואז נלחץ על View, לאחר מכן על Advanced Features
לאחר מכן קליק ימני על OU שאתם רוצים, ואז Attribute Editor והעתיקו את ה DistinguishedName
נעתיק אותו לתוך הפקודה
$users = Get-ADUser -Filter * -SearchBase "OU=Jerusalem,DC=tal,DC=local"
וכעת הסקריפט שלנו יראה כך
$users = Get-ADUser -Filter * -SearchBase "OU=Jerusalem,DC=tal,DC=local" foreach ($user in $users) { Set-ADUser -Identity $user -Description "Jerusalem Office" }
כעת השמות יגיעו ישירות מAD
Error Handling
try and catch
בתוך try נוכל להכניס פקודה למשל להביא משתמש, אך אם השם משתמש שהזנו לא נכון, נקבל שגיאה
בשביל שנוכל להציג למשתמש שגיאה מותאמת אישית נוכל לבצע זאת על ידי try and catch
בתוך try נזין את הפקודה שהיא get-aduser לאחר מכן את המשתנה user שכן המשתמש יזין את שם המשתמש
$user = Read-Host "Enter Username" try{ Get-ADUser $user }
את הקוד עד כה אתם מכירים, כעת כל עוד הקוד תקין try יריץ את הסקריפט והתוצאה תתקבל, כמובן שבמקרה הזה חייבים את catch
שכן אם יש שגיאה הסקריפט יעבור ל catch זה אומרת שאם יש Exception אז הוא יעבור ל catch
$user = Read-Host "Enter Username" try{ Get-ADUser $user } catch{ Write-Host "User Not Exists" } Write-Host "Done"
כעת תוכלו להבחין שרשמתי בתוך catch שהמשתמש לא קיים, כך שבמקום השגיאה הרגילה שנקבל (הטקסט עם הצבע האדום בתמונה למעלה) נקבל שגיאה משתמש לא קיים
נסו את הסקריפט ובדקו
נוכל להוסיף לקוד Finally בצורה הזו
Finally למעשה מציג את ההודעה גם אם שגיאה התרחשה או שלא התרחשה ולכן טוב כאשר סוגרים חיבור למסד נתונים מסירים קבצים שקיימים או לא וכך התוצאה תשאר נקייה למשתמש
$user = Read-Host "Enter Username" try{ Get-ADUser $user } catch{ Write-Host "User Not Exists" } finally { write-host "Script Was Done" }
FOR
לולאת for מגדירה שפעולה תרוץ שוב ושוב על אובייקט שקבענו, בדוגמה הבאה נוכל להגדיר את המשתנה i שהוא 1 ואז אם המשתנה i שהוא 1 פחות מ120 נוסיף למשתנה i =+ שזה אומר הוספה של המספר 1
כעת שנריץ את הלולאה נקבל מהמספר 1 עד 120
While
פונקציית While מגדירה לולאה אינסופית, הלולאה תמשיך בלי הפסקה, דוגמה ללולאה פשוטה שלא עוצרת היא הדוגמה הזו
כל עוד while נכון, רשום Hello, בשביל שהמחשב שלכם לא ידפיס במהירות Hello הכנסתי Start-sleep 1 כך שכל שניה הוא ימתין ואז יבצע את הקוד שוב מההתחלה
זאת אומרת שהקוד שלכם ירוץ שוב ושוב בתוך לולאת While
דוגמה לסקריפט אחר, נניח ואנחנו רוצים שהמשתמש ינחש סיסמא שהוא יקיש והתוכנית לא תצא עד שהוא ינחש אותה או יצא בעצמו
נוכל לכתוב את הסקריפט הבא
Do While Loop
Do הוא למעשה תנאי, הוא לולאת While אבל הוא יתרחש פעם אחת עד אשר תנאי מסוים יתרחש
זאת אומרת אם המשתמש ינחש את הסיסמא בתוכנית שנכתוב אז התוכנית תפסיק ואם לא היא תמשיך
Do { $pass = Read-Host "Enter Password To Stop" } while ($pass -ne "123")
Do Until
במצב זה הלולאה תעצר כל עוד לא התרחש התנאי , נניח והגדרנו שהסיסמא היא 123 והגדרנו בתוך until שהסיסמא לא שווה ל123 אז כל עוד נקיש את הסיסמא 123 הקוד ימשיך, כל מספר אחר הקוד יעצור
כמו בדוגמה הבאה
Functions
פונקציות מכילות סקריפט \ קוד שאתם כותבים, המטרה של פונקציה היא Stay DRY מהביטוי באנגלית השאר יבש, אך כאן הכוונה של Dry – Don't repeat yourself המטרה היא שכאשר אתם כותבים קוד, אל תחזרו על אותו הקוד שוב ושוב, למשל הקוד הבא שמציג את השירות Remote Registry
נפתח את הקוד עם function ולאחריו השם של הפונקציה שאתם רוצים נניח ShowServices לאחר מכן הקוד
בסיום בשביל להריץ את הפונקציה נרשום את ShowServices בלבד
הריצו את הקוד ובדקו מה אתם מקבלים
ככה למעשה בכל מקום בסקריפט בו תרצו להריץ את הקוד כולו שוב , פשוט כתבו את השם של הפונקציה וכך תחסכו לכתוב את הקוד שוב פעם.
function ShowServices { Write-Host "Services WIll Be Dispaly" Get-Service | where-Object {$_.DisplayName -like "*Remote Registry*"} } ShowServices
External Modules
נניח ויש לכם בארגון Office 365 ואתם רוצים לייבא את כל המשתמשים שאין להם רישיון, בשביל זה תצטרכו מודל חיצוני, תחילה לייבא אותו ל PS ואז להשתמש ב cmdlets שלו, דוגמה אחת הוא ה ExchangeOnline
Import-Module ExchangeOnlineManagement
באותו הרגע PS יתקין את המודל של Office 365 ואז תאלצו להתחבר ל Office 365 שלכם בשביל שPS יוכל משם לקחת את המידע הרצוי
Connect-ExchangeOnline -UserPrincipalName navin@contoso.com
מאותו הרגע תוכלו להשתמש ב cmdlets של Exchange Online למשל להוציא רישיונות
פקודה זו מהאתר של מיקרוסופט בקישור
Get-AzureAdUser | ForEach{ $licensed=$False ; For ($i=0; $i -le ($_.AssignedLicenses | Measure).Count ; $i++) { If( [string]::IsNullOrEmpty( $_.AssignedLicenses[$i].SkuId ) -ne $True) { $licensed=$true } } ; If( $licensed -eq $false) { Write-Host $_.UserPrincipalName} }