Home Scripting PowerShell Scripting for Beginners – מדריך מקיף למתחילים לאנשי סיסטם

PowerShell Scripting for Beginners – מדריך מקיף למתחילים לאנשי סיסטם

by Tal Ben Shushan 11/09/2021 0 comment
PowerShell Scripting for Beginners – מדריך מקיף למתחילים לאנשי סיסטם
נהנתם מהמאמר ? שתפו אותו!

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 למשל להוציא רישיונות

פקודה זו מהאתר של מיקרוסופט בקישור

https://docs.microsoft.com/en-us/microsoft-365/enterprise/view-licensed-and-unlicensed-users-with-microsoft-365-powershell?view=o365-worldwide

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} }

 

 

 

 

מאמרים קשורים

Leave a Comment