גישה ליכולות ה Windows Power Shell מתוך אפליקציית .net
בעבר, הזכרתי כבר שניתן להשתמש ב cmdlets, functions ו providers של Windows Power Shell מכל אפליקציית .net שרוצים.
לצורך העניין, יצרתי פרוייקט Windows Application חדש ופשוט, ושמתי textbox אחד שבו תוכנת הפקודה ששמו cmdTextbox, כפתור שמבצע את הפעולה ו textbox שיציג את התוצאות בשם resultsTextbox.
תחילה, צריך להוסיף reference ל System.Management.Automation - בד"כ הSDK מתקין את הDLL לכאן: C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0 כדאי להוסיף using System.Management.Automation לראש הקוד, כמו גם ל System.Management.Automation.Runspaces. ול System.Collectiond.ObjectModel
תחילה, בואו נכיר כמה מחלקות:
System.Management.Automation.Runspace - מחלקה זאת, למעשה, מאפשרת לנו ליצור סביבת ריצה של Windows Power Shell מתוך האפליקציה הדוטץנטית שלנו, ולהשתמש בסביבה זאת להרצת פקודות וכו'.
System.Management.Automation.RunspaceFactory - מאפשר לנו ליצור את ה runspace ולהגדיר אותו בפועל, ואז להעביר אותו לשליטת אובייקט Runspace - מכיל מתודה סטאטית בשם CreateRunspace, שיוצרת בפועל את ה runspace.
RunspaceConfiguration - מכילה את ההגדרות של ה runspace, איזה pssnapins יופעלו בו וכו'.
עכשיו, לפני יצירת ה runspace שבו ירוצו הפקודות שלנו, אנחנו ניצור איזושהי קונפיגורציה כללית שניצור את ה runspace ישר איתה (ניתן גם לשנות לאחר מכן) - לצורך העניין, הסתכלו על הקוד הזה:
בקוד הזה, אנחנו יוצרים את RunspaceConfiguration ואת PSSnapnInException. מטרת הקוד ליצור סט הגדרות שמכיל כבר איזשהו Power Shell Snap In שקיים (במקרה הזה, אנחנו רק עושים Add, מתוך נקודת הנחה שהוא כבר רשום - עבר installutil) ובמידה ומתגלה שהוא לא קיים, אנחנו זורקים Exception. ה PSSnapInException שמועבר בתור out parameter יכיל את פרטי השגיאה.
עכשיו, כדאי שניצור את ה Runspace עצמו - ונעביר לו ב constructor את config, כלומר, שיפעיל את עצמו כבר עם סט ההגדרות שקבענו (ניתן גם לא להעביר כלום):

עם המתודה Open, אנחנו למעשה פותחים את ה stream של ה runspace.
השלב הבא, הוא ליצור את ה pipeline. ה pipeline הוא למעשה סט הפקודות שאנחנו מעבירים לביצוע ה powershell, מדובר בצינור שלק\ פקודות, שיכולות להיות משורשרות אחת לתוך השנייה, ולהשפיע אחת על השנייה. בדוגמא הזאת, אנחנו פשוט מעבירים את הפרמטר command שמקבלת המתודה שלנו שמכיל את הפקודות להריץ:

בשלב הזה, הפקודה כבר בשלה להרצה. אולם, אחד מהחוזקים של ה powershell הוא שהוא מעביר stream אל אובייקטים בין חלקיו השונים, בניגוד, למשל, ל shell-ים של מערכות אחרות שעובדות עם text streams. לכן, בגלל שמדובר ב stream של אובייקטים, אם נריץ למשל את הפקודה get-process, לא נקבל טקסט עם רשימת הפרוססים, אלא נקבל מערך שלא בוייקטים מסוג System.Diagnostics.Process - דבר שיכול מאד להעיל לנו בעת העבודה (אנחנו מקבלים הרבה מאד מידע, מקבלים אובייקט שלם שכשיר לעבודה ישירות בדוט.נט, בלי צורך להמיר את הטקסט לאובייקט).
אולם, במקרה הזה, אנחנו רוצים להוציא את מהידע בסוף לאיזשהו textbox, ולכן נוסיף ל pipeline שלנו את הפקודה out-text, שלמשל, דרך אגב, ב gui של ה powershell עצמו מתווספת אוטומטית לכל פקודה - כדי שיסגנן לנו את האובייקט שהוא מקבל לטקסט. פה אנחנו אומרים ל powershell שאנחנו לא מעוניינים ב stream של אובייקטים אלא ב stream של טקסט, ושידאג לספק את מבוקשינו.

עכשיו, הגיע הזמן להריץ את הפקודה ולעשות Invoke ל Pipeline. לשם כך, נשתמש בקוד הבא:
בהתחלה, אנחנו שמים ב try את הקריאה למתודת ה invoke עבור ה pipeline, שאת התוצאות שלו אנחנו מכניסים ל collection. אם הפקודה הזאת לא קיימת (לא נמצא cmdlet, function או provider בשם זה), ייזרק CommandNotFoundException. בכל אופן, בסוף התהליך, אנחנו סוגרים את ה runspace.
עכשיו, לנוחותכם, הנה כל קוד המתודה. בסוף, אנחנו עוברים על כל ה collection ומכניסים ל StringBuilder ובסוף מחזירים string.

באירוע הלחיצה על ה button אנחנו קוראים למתודה ומכניסים את הערך שלה לתוך ה textbox, כשבמידה והוא ריק, כותבים הודעה:

אם אנחנו רוצים, לשנות דברים הקשורים ל powershell, כמו להוסיף snapin תוך כדי ריצה לאחר שיצרנו את ה runspace עם ה configuration שלנו, או להוסיף משתנה, ניתן לעשות זאת כך:
בשורה הראשונה, הוספנו PSSnapin. בשורה השנייה הגדרנו משתנה כלשהו שיהיה זמין ובשלישית קיבלנו ערך של איזשהו משתנה. ניתן להגדיר כמשתנים גם הפניות לדברים שהם קחלק מהאפליקציה, נניח, לאיזשהו textbox, ושמתוך הפקודה יהיה ניתן לכתוב אליו.
היות שהוספנו את ה Snap In שכתבתי במהלך ה webcast, אתם יכולים לראות את זה שאני יכול בקלות להוסיף מהאפליקציה הזאת, באמצעות פקודה, website ל IIS:

תיבת הפלט ריקה, כי הפקודה לא מחזירה שום פלט, אולם, בIIS באמת התווסף הwebsite, ואתם יכולים לבדוק בעצמכם (אם יש לכם את ה snapin הזה מותקן).
הנה התוצאות עבור הפקודה get-service, שחוזרים כטקסט כי ציינו את זה והוספנו פקודה מתאימה ל pipeline, אחרת, היינו יכולים באפליקציה קצת יותר משמעותית, לקבל אותם כמערך ולעבוד עליהם מתוך האפליקציה, כשאנחנו יכולים לשלוט עליהם בקלות.
לנוחותכם, ניתן להוריד את הפרוייקט המלא מכאן.
בהצלחה.