הגדרות DNS מתקדמות במחשבי Client

המאמר הזה הוא חלק מסדרת המאמרים בנושא DNS – Domain Name system והוא ינסה להתמקד בהסברה של "פנייה מקוצרת למחשב" – דהיינו, פנייה באמצעות שם בלבד (netbios name), ולא ב FQDN. למשל :

\\host1

במקום ה FQDN

\\host1.mydomain.local

*חשוב מאד להבהיר בשלב הזה, שאני מדבר על "פניית netbios", אני מתכוון לפנייה לפי שם מחשב בלבד, באמצעות שרת ה DNS ולא לשימוש בפרוטוקול ה netbios. אלו שני דברים שונים!

אני אנסה לעשות את זה ע"י הסבר לגבי הגדרות CLIENT בכרטיס הרשת שיעזרו מאד לחדד את הנושא.  וכן, באמצעות הסברים בסיסיים על נושא ה zones וה namespaces ("מרחבי השמות") המנוהלים בשרת ה DNS.  כל הכתוב נוגע לתשתיות MS בלבד, אבל כמובן שאפשר ללמוד ממנו באופן כללי לגבי תשתיות אחרות.

קודם כל חזרה קצרה ובסיסית ביותר על נושא ה resolving במחשבים ברשת :

נניח שאני – Host1 רוצה להתחבר למחשב אחר ברשת. אני מחזיק בשם המחשב אליו אני רוצה להגיע – host2 , אבל כדי לתקשר אני צריך כמובן את ה IP (Layer3). ולכן, אבצע שאילתות או חיפושים כדי לדעת מה כתוב ה IP.

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

  • קובץ ה hosts. מין cache פנימי שקיים במחשבים. מדובר בקובץ טקסט פשוט שכל אחד יכול לערוך.
  • ה cache הפנימי בשירות הDNS Client

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

המקום השלישי הוא cache פנימי של ה netbios (פרוטוקול). אפשר לחפש מידע על ה cache בעזרת פקודת ה nbtstat. רלוונטי גם לסביבת Workgroup, לא רק לסביבת דומיין.

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

השיטה החמישית – שימוש ב multicast באמצעות פרוטוקול LLMNR שבדרך כלל נותן תשובה ב IPV6. אם רוצים לבטל את הפרוטוקול, הדרך הטובה ביותר לעשות את זה, היא לשים את הערך הבא ב Group Policy על enabled  :

Computer Configuration\Administrative Templates\Network\DNS Client\Turn off Multicast Name Resolution

האופציה השישית היא broadcast לכל המחשבים ברשת. מאד לא מומלץ להגיע לסיטואציה כזו, משום שזה מכביד מאד על הרשת. אז ב Workgroup עם חמישה מחשבים לא נרגיש כלום, אבל ברשת עם תחום שידור רחב יחסית, זה יהיה לא נעים.  אם רוצים לבטל את זה, אפשר לעשות את זה בהגדרות המתקדמות של כרטיס הרשת, תחת כרטיסיית ה Wins:

wins

המקום השביעי בו המחשב יחפש הוא קובץ ה lmhost , עוד cache פנימי שנמצא בתוך כ plain text.

אם כל הניסיונות האלו כשלו, אפשר לנסות לתקשר ישירות דרך IP. . .

עד פה סקירה קצרה על תהליך ה resolution . מי שרוצה להמשיך ללמוד מעט יותר לעומק, מוזמן לעשות את זה בסרטון המעולה הבא :

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

עכשיו, מכיוון שהפוסט עוסק בנושא resolving דרך שרת DNS בסביבות דומיין, לצורך ההדגמה אני מבטל את השימוש בפרוטוקול ה netbios ואת השימוש בפרוטוקל ה LLMNR (לגבי שניהם, הובהר לעיל איך מבטלים את השימוש בהם). כמו כן, לאורך כל ההדגמה לא יהיה שימוש בשום cache (dns client או אחד מקבצי ה hosts), כמובן שלא יהיה שום שימוש בשרת WINS.

הדומיין שעליו אדגים הכל נקראtest.local

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

netbios

כמו כן, בהגדרות ה DNS המתקדמות של כרטיס הרשת, אפשר לראות שמתאפשר ה append (הוספה) של שם הדומיין לשם מחשב אליו פונים :

dns suffix

ההגדרה המשלימה של ההגדרה הזו, היא ההגדרה : register this connection's addresses in dns –

register

פשוט אומר באופן פשוט, שה Client ירשום את הגררות כרטיס הרשת הרלוונטיות, בשרת ה DNS.

אם מסכמים באופן בסיסי את ההגדרות עד פה, אם למשל אתן פינג רק לשם מחשב, ואקבל את התשובה ב FQDN, זה בגלל שהשאילתא יצאה אחרי append (הוספה) של שם הדומיין לשם המחשב. הנה דוגמה כאשר אני נותן פינג ל netbios name של test1 :

ping2test1

התשובה ב FQDN מראה שהיה שימוש ב zone שהוא test.local שמוגדר בשרת ה DNS. אני כתבתי אמנם בפינג רק את ה netbios name (test1), אבל מאוחרי הקלעים היה append (הוספה) של test.local לשם הזה, כדי לחפש את ה zone הנכון באופן הכי מהיר בשרת ה DNS.

הנה מה שקורה כאשר עשיתי Pause לשרת ה DNS, ודווקא כן איפשרתי את ה LLMNR, זו לא תשובה DNS-ית

LLMNR reuest

והנה מה שקורה כאשר ביטלתי את ה LLMNR, ואיפשרתי שימוש בפרוטוקול netbios, גם זו לא תשובה DNS-ית

netbios protocolאבל זה היה רק לצורך ההדגמה. נבטל את הפרוטוקולים netbios ו LLMNR, ואחזיר לתפקוד את שרת ה DNS.

נסתכל על הגדרות נוספות בכרטיס הרשת :

sub

נניח שאנחנו במחשב sub-host שנמצא בסאב דומיין שנקרא sub.test.local. משתמש במחשב הזה רוצה להגיע באמצעות ה netbios name למחשב test1 שנמצא בדומיין test.local. עכשיו למשתמש הממוצע בסאב זה לא מובן שמדובר בשני דומיינים שונים. הוא חושב שמדובר אולי במחשב נוסף שנמצא "ברשת שלו". אז, ההגדרה הזו, של "append parent suffixes of the primary dns suffix", גורמת לכך, שאם המשתמש לא מצא ב zone שבדומיין שלו – sub.test.local את המחשב test1, אז הוא יבצע חיפוש ב zone של האב שהוא test.local, ושם כמובן הוא יקבל מענה ב FQDN של test1.test.local. אם ה checkbox הזה לא היה מסומן המחשב בסאב דומיין לא היה מצליח להגיע באמצעות שאילתת DNS למחשב test1, אלא באמצעות פרוטוקולים אחרים, או באמצעות IP.

הגדרה נוספת :

append

ההגדרה הזן דורסת כל הגדרה אחרת (כולל הגדרות שיגיעו אחריה), והיא אומרת כך : "בפניית netbios תבדוק ב suffix של הדומיינים הבאים (לפי הסדר) :"

זה גם יכול להיות שימושי בסיטואציה שבה נחבר את כרטיס הרשת לדומיין אחר לגמרי (שהוא לא (test.local, אליו לא משויכים, נניח microsoft.com. ב computer settings נמצא כרגיל את הדומיין test.local, אבל אם נרצה לקבל מענה לשאילתות netbios למחשבים שנמצאים בדומיין של microsoft.com או cola.coom או מה שלא הוגדר בכרטיס הרשת נשתמש במה שהוגדר ברשימה . . .

זאת אומרת, שאם אבצע פניית Netbios למחשב a, אז קודם כל יחפשו אותו בדומיין cola.com, ואם לא נמצא שם אז microsoft.com וכו'.

למה זה נצרך באופן יותר פרקטי?

נניח שאני משתמש במחשב שבדומיין test.local, ואני רוצה לבצע פניית netbios למחשב sub-host שנמצא בסאב דומיין sub.test.local. הדרך לעשות את זה, זה  אם נגדיר ברשימה של כרטיס הרשת במחשבי הדומיין test.local, את הדומיין sub.test.local.

*כמובן שיש גם אפשרות אחרת – להגדיר ידנית או DHCP במחשבי הדומיין test.local את ה DNS של הסאב דומיין, אבל אני לא יודע עד כמה זה נהוג.

ושתי הגדרות אחרונות (מודגשות בצהוב) :

dns connection

ההגדרה "dns suffix for this connection", נראת קצת מיותרת, היא בסך הכל נותנת את האפשרות להשתמש ב suffix מסוים כדי ליישם פנייה ב netbios name. למשל, אם אני בדומיין test.local, ואני רוצה להגיע לפי netbios name למחשב host3 שנמצא בדומיין sub.test.local. אם זה יוגדר שם.

 נשמע מוכר ? נכון! זה בדיוק מה שהיה בסעיף הקודם. אז מה הפונקציונאליות שמוסיפה ההגדרה הזו ? אז התשובה לדעתי היא זו :

ה checkbox האחרון – use this connection's dns suffix in dns registration –  מוסיף את היכולת הנוספות. הוא אומר בסך הכל שאם הוכנס שם דומיין אחר ב"dns suffix for this connection", אז גם שם – בדומיין הנוסף –  תבצע הרשמה של שם המחשב בשרת ה DNS.

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

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

נניח שבשרת ה DNS של הדומיין test.local פתחו לצרכי אדמיניסטרציה עוד Forward zone שנקרא computers.zzz. למי שלא בקיא, חשוב להדגיש שלא מדובר בדומיין כמובן, אלא רק ב zone שיוצר בעצם namespace ("מרחב שמות") חדש :

computers

אז בתוך CLIENT,  אם בהגדרת ה "dns suffix for this connection" מצורף ה computers.zzz, ואם בנוסף גם סימנו את ה checkbox של "use this connection's dns suffix in dns registration", אז אז, המחשב ירשום את עצמו בשרת ה DNS ב zone של computers.zzz.

שאלה קטנה שצריכה לעלות עכשיו היא, אם המחשב רשום בשני zones, כאשר מחשב אחר יפנה אליו ב netbios name, איזה FQDN הוא יקבל – האם זה שחלקו  ה test.local או את  ה computers.zzz ?

אם מחשב test1 רשום עכשיו גם ב zone של test.local וגם ב zone של computers.zzz, כנראה כאשר נפנה אליו בפניית netbios, התשובה תהיה לפי סדר ה zones בשרת, ה zone הדיפולטיבי הוא זה שמכיל את שם הדומיין, לכן ה FQDN שנקבל בתשובה הוא test1.test.local

PowerShell Tips Part 3

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

מטרת המאמר היא לא איך לקנפג שרת מדפסות, מי שרוצה ללמוד את הנושא, יכול לעשות את זה פה :
http://itfreetraining.com/70-642/printer-services/

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

כל תומך טכני בסביבת דומיין מכיר את השיחות (המאד מיותרות) ממשתמשים שמנסים להגדיר מדפסת רשת, ופשוט לא יודעים או לא מצליחים.
המשתמשים שקיבלו מחשב חדש או התקנה חדשה של מערכת ההפעלה יתקשרו למוקד בבקשה שיעזרו להם להתקין את מדפסת הרשת. המתוחכמים יותר ינסו להגדיר דרך ה GUI של "Add network printer". זה לא ילך, בגלל שהם כנראה לא ימצאו את הדרייבר הרלוונטי, ובסופו של דבר לא יוכלו להדפיס.
האמת היא שהתקנת מדפסת משרת היא אחד הדברים הכי פשוטים שיכול משתמש לבצע. בסך הכל מריצים את הפקודה הבאה (אפילו לא דרך ה CMD) :

servername\sharename\\

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

טוב חפרתי. ניגש לעניין. אפשר להפיץ לכל המשתמשים סקריפט שמתקין באופן אוטומטי את המדפסת.
המשתמש מצידו צריך לעשות שני דברים :
1. לפתוח את הקובץ PS שיכול להיות מוטמע לכל המשתמשים.
2. להקיש ב GUI את שם המדפסת.

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

הנה הסקריפט שנבנה ב PS, ואחרי כל שורה, קיים הסבר :

[void][system.reflection.assembly]::loadwithpartialname("Microsoft.Visualbasic")

בשורה הזו מעלים לקובץ ה PS את יכולות ה GUI של Visual Basic. לא צריכים להבין יותר מזה. מי שרוצה להעמיק מוזמן לחפש בגוגל .

$printer = [microsoft.visualbasic.interaction]::inputbox("Enter 4 digits", "digits", "Put value here")

אחרי שהטענו את יכולות ה Visual Basic, נוכל להשתמש באחד מהם. נקרא למתודה inputbox שתיתן פרומפט שמבקש מהמשתמש קלט. זה צריך להראות כך :

powershell

שלושת הפרמטרים ששמנו במתודה inputbox, הם בסך הכל : 1. בקשה מהמשתמש להכניס ספרות. 2. כותרת לפרופמט. 3. ערך ברירת מחדל. הערך שהמשתמש יזין יושם בתוך משתנה – printer.

$printersAtTheServer = net view \\servername

יצרנו משתנה והשמנו בתוכו את כל הערך שבשורש השרת (בעזרת הפקודה net view). נוצר לנו מערך שמכיל את כל השמות של המדפסות שנמצאות על השרת.

$printerWasfound = 0;

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

for($i = 0; $i -lt $printersAtTheServer.length; $i++)
{
if ($printersAtTheServer[$i].indexof($printer) -ne -1 ){
rundll32 printui.dll,PrintUIEntry /in /n\\printerAtTheServer\$printer
$printerWasfound = 1
break; }
}

זה הקטע "המפחיד". רצים בלופ על כל המדפסות שבמערך. אם נמצא שם המדפסת (יש התאמה בין הערך שהמשתמש הזין לבין מה שקיים על השרת) – תתקין את המדפסת (rundll32 printui.dll,PrintUIEntry /in /n\\printerAtTheServer\$printer). תעדכן את הדגל ($printerWasfound = 1). תעוף מהלולאה, כי המשימה הושלמה (break).

if($printerWasfound -eq 1) {
write-host "configuring the printer, please wait"
}
else
{
write-host "Cannot find. please call the Help Desk team"
}

ולסיום, הודעה למשתמש בתוך קובץ ה PS שרץ. אם נמצא המדפסת (ערך הדגל הוא 1) אז תעדכן שמתבצעת התקנה של המדפסת/הדרייבר.
אם לא – תתקשר לתמיכה.

אשמח לשמוע הערות והארות מהקוראים באתר
חוץ מזה, לפעמים יכול להיות ששם המדפסת שהמשתמש רואה, קצת שונה מהשם שנמצא בשרת (יש איזה prefix או משהו)
במקרה הזה אפשר לבצע עוד כמה שינויים בקוד כדי להתאים אותו

אשמח לשמוע הערות והארות מהקוראים באתר

Share folders at domain environment

כאשר מתנסים בעבודה עם Windows בסביבות דומיין, מבינים את ההבדל בין עבודה ברשת Workgroup לעבודה בדומיין. ברשת Workgroup, כאשר משתמש שאינו בעל הרשאות Admin רוצה לשתף תיקייה, אין שום בעיה מיוחדת והשיתוף יתבצע באופן הכי פשוט דרך ה GUI (כמובן, לא לשכוח הרשאות NTFS).

בדומיין מדובר בסיפור קצת שונה. משתמש דומיין שאינו אדמין לוקאלי (קבוצת Administrators) על אותו מחשב, לא יוכל לבצע שיתוף, כאשר ינסה לשתף הוא יראה את ההודעה הבאה  :

cannot share

UAC דלוק היה פותר את הבעיה בדומיין, בגלל שהוא היה מבקש הרשאות מנהל כאשר הייתי מבקש לשתף, ואז המנהל יכול להשתמש ב Credentials שלו עבור המשתמש המבקש לשתף. הבעיה בדומיין בו אני תומך הוא שה UAC כבוי כברירת מחדל, ולכן, לפחות דרך ה GUI של ה share, לא יכולתי לעזור למשתמש לשתף בעזרת ה Credentials שלי.

הפתרון היא דווקא די פשוט, ואולי לא הכרתם אותו. כידוע, ה UAC לא משפיע לחלוטין על היכולת שלי כמנהל להריץ קבצים כמנהל, ולכן אפשר להריץ את קונסולת הניהול של המחשב (compmgmt.msc) עם הרשאות מנהל (Run as different user), ובעמודה הימנית של המסך שנפתח מגיעים ל share, בוחרים ב New Share ומשם יפתח ממשק פשוט (שונה מה GUI  הדיפולטיבי של ה share) המאפשר ליצור   Share :

new share

*תודה לאביתר – ראש הצוות התותח בעולם!!!

PowerShell Tips Part 2

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

נניח שאני רוצה לראות את כל ה Process-ים שבכל המחשבים שלי בדומיין. במחשב שבו יש הרשאות ל AD, וה Module של AD הורד אליו, בתור התחלה, אפשר להריץ את הפקודה הבאה :

$Names = Get-ADComputer -filter * | select  name

תיאור קצר : הפקודה בסך הכל משימה (assign-השמה) את השמות של כל המחשבים בדומיין בתוך משתנה ה Names. בגלל שפקודת ה Get-ADcomputer מחזירה אובייקט על שלל המאפיינים של המחשבים, נשתמש בפקודת ה Select כ "בורר" שמה שיושם במשתנה זה רק שמות המחשבים (name), ולא מאפיינים אחרים של אובייקט המחשב.

עכשיו נשתמש בפקודה הבודקת את כל ה Processes :

Get-Process * -ComputerName $names | select machinename,name | group machinename

הפקודה קוראת לכל ה Process של כל המחשבים שנמצאים במשתנה ה names$, מבקשת להציג אך ורק את שם המכונה  (machinename)  ושם ה process (שמיוצג ע"י name), בעזרת פקודת ה Select התחומה בין ה Pipeline הראשון והשני. ובסופו של דבר, לשם נוחות הקריאה, עשינו איחוד/קיבוץ של המידע בעזרת פקודת ה Group, לפי שם המחשב.

לכאורה אמור לעבוד יופי, אבל זה מה שיקרה, כאשר נריץ את הפקודה :

PS C:\Users\ehud> Get-Process * -ComputerName $names | select machinename,name | group machinename

Get-Process : Couldn't connect to remote machine.
At line:1 char:12
+ Get-Process <<<< * -ComputerName $names | select machinename,name | group machinename
+ CategoryInfo : NotSpecified: (:) [Get-Process], InvalidOperationException
+ FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.PowerShell.Commands.GetProcessCommand

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

$Names = Get-ADComputer -filter * | select name

לכאורה הכל נראה בשורה הזאת תקין, אבל הבעיה היא כזו: למרות שבחרנו שמשתנה הnames$ יכול רק name (שם המכונה), גם שם המכונה עצמו (name) הועבר למשתנה ה names$ בתור אובייקט מסוג psCustomObject.

 עכשיו, כדאי לעשות קצת סדר למי שלא בקיא כ"כ בנושאי ה NET.

כל טיפוסי הנתונים ב PS מסתמכים על הגדרות שנקבעות ה .net framework. באופן כללי מאד אפשר לומר שכל טיפוסי הנתונים בעולם ה .NET הם אובייקטים, אבל (וזה אבל חשוב מאד), יש טיפוסי נתונים שהם אובייקטים ספציפיים יותר. String (בעברית "מחרוזת") הוא אחד כזה – הוא פשוט אובייקט מסוג "מחרוזת". אם למשל אני שם בתוך משתנה מסוים קטע טקסט, זה מחרוזת. הנה דוגמה :

PS C:\Users\ehud> $str="ehud"
PS C:\Users\ehud> $str.gettype()

IsPublic      IsSerial    Name        BaseType
——–       ——–   —-        ——–
True            True      String     System.Object

יצרנו משתנה, השמנו בתוכו מחרוזת, ואז קראנו למתודה (פונקציה) שבודקת את הטייפ של האובייקט. תחת טור ה name, אפשר לראות שמדובר ב String. תחת ה BaseType(צד ימין) אפשר לראות שהמחלקה יורשת (זה מושג שלא צריך להכיר) ממחלקת ה Object, ומכן שגם ה String הוא אובייקט, אבל ממחלקה ספציפית יותר.

עכשיו  נחזור לתרגיל הראשוני, ולפני זה נבהיר נקודה חשובה. אם נריץ את ה help עבור פקודת ה Get-Process, נראה שה flag/switch – computername, יכול לקבל רק משתנה מטייפ String :

PARAMETERS
-ComputerName <string[]>
Gets the processes running on the specified computers. The default is the local computer.

עכשיו נבדוק איזה טייפ נמצא בתוך המשתנה names שהעברנו ל ComputerName נבקש את הטייפ של האובייקט הראשון במערך (השם הראשון של המחשב שהפקודה הכניסה במערך) :

PS C:\Windows\system32> $names[0].gettype()

IsPublic    IsSerial    Name   BaseType
——– ——– —- ——–
True      False    PSCustomObject     System.Object

זאת אומרת, לא מדובר במחרוזת, אלא אובייקט גנרי של PS שהוא – PSCUstomObject.

 נריץ שוב את הפקודה שקוראת ל Process, אבל נעשה את זה עם כלי דיבאגינג חזק ביותר שקיים ב PowerShell. למי שלא מכיר את הפקודה הבאה, היכונו להצדיע :

PS C:\Windows\system32> Trace-Command -PSHost -Name parameterbinding -Expression {Get-Process * -ComputerName $names|select machinenam,name|group machinename}

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

DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Get-Process]
DEBUG: ParameterBinding Information: 0 : BIND arg [System.Object[]] to parameter [ComputerName]
DEBUG: ParameterBinding Information: 0 : COERCE arg to [System.String[]]
DEBUG: ParameterBinding Information: 0 : Trying to convert argument value from System.Object[] to
System.String[]

ניתן לראות את עבודת ה Shell מאחורי הקלעים. מזהה את CMDLET – Get-Process, בשורה השנייה, הוא מנסה לבצע השמה של ערך (arg) ל Switch ComputerName, בשורות שמתחת רואים שהוא מנסה לבצע המרה מ Object ל String.

השורות הבאות יראו שהוא כן מצליח לבצע איזו שהיא המרה :

LanguagePrimitives.ConvertTo
DEBUG: ParameterBinding Information: 0 : CONVERT SUCCESSFUL using LanguagePrimitives.ConvertTo:
[@{name=COMPUTER1}]

בתמונה שלעיל רואים שהוא מצליח לבצע המרה לטייפ של סטרינג. הוא ממיר את הטייפ מסוג PsCustomObject לבוג של Srtine. שימו לב למילה Successful.

אחרי שהוא המיר את כל שמות המחשבים ל String, הוא ממשיך להריץ את שאר הפקודות שנמצאות

בפקודה. בסופו של דבר הוא מנסה להתחבר בפועל למחשבים שנמצאים במחרוזות שהוא השים מקודם ב Switch ComputerName. אך שימו לב מה קורה שהוא מנסה להתחבר למחשבים (Remote machines) :

DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : System.InvalidOperationException: Couldn't connect to remote machine
at System.Diagnostics.NtProcessManager.GetProcessInfos(String machineName, Boolean isRemoteMachine)

הסיבה היא כזו – ההמרה לסטרינג אמנם הצליחה. אבל הערך בסטרינג (כמו שניתן לראות שתי תמונות מלמעלה) הוא כזה :

@{name=COMPUTER1}

ה Shell לא מצליח להתמודד עם הערך הזה, ולהתחבר באמצעותו למחשב  אחר. ההמרה הייתה חסרת משמעות בסופו של דבר, כי הוא לא מבין מה המשמרות של הסטרינג name=computer1.

שימוש ב Switch קטן מאד בפקודה הראשונה יכול לפתור את כל הבעיה. ה Switch הזה ידאג שמה שיושם במשתנה ה names יהיה String, ולא האובייקט הגנרי של PS. תיקון הפקודה יראה כך:

$Names = Get-ADComputer -filter * | select -ExpandProperty  name

אם נבדוק עכשיו מה בדיוק מושם בתוך המשתנה names, נוכל נראה את התוצאה הבאה (האובייקט הראשון בתוך המערך) :

PS C:\Windows\system32> $names[0].gettype()

IsPublic   IsSerial    Name    BaseType
——–   ——–   —-     ——–
True      True    String    System.Object

יש לנו סטרינג בתוך המערך!

הסיבה היא שימוש ב Switch בעל השם Expandproperty, שלוקח את תכונה name, ודואג שיושם במשתנה names הערך האימית של התכונה (מחרוזת), ולא האובייקט הגנרי, כמו שהיה מקודם.

עדיין, כאשר נריץ את פקודת ה Get-Process מה שיועבר ל Switch של ה ComputerName יהיה מערך, אבל הפעם, במקום שבכל אובייקט במערך יהיה איזה psCustomObject, הפעם יהיה שם String

ולכן גם התוצאה תוצג כמו שצריך :

PS C:\Windows\system32> Get-Process * -ComputerName $Names | select machinename,name | Group machinename

Count    Name                           Group
—–       —-                         —–
27        COMPUTER2                    {@{MachineName=COMPUTER2; Name=conhost}, @{MachineName=COMPUTER2; Name=conhost}, @{M…
35        COMPUTER1                    {@{MachineName=COMPUTER1; Name=conhost}, @{MachineName=COMPUTER1; Name=conhost}, @{M…
42        SERVER2008-MAIN        {@{MachineName=SERVER2008-MAIN; Name=conhost}, @{MachineName=SERVER2008-MAIN; Name=c…

PowerShell Tips Part 1

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

אפשור של remote-session מתאפשר ב PowerShell באמצעות פקודת ה  Enable-psssesion במחשב אליו רוצים להתחבר (Listener), פקודה המאפשרת את הרצת הסרביס WinRM, ופתיחת הפורטים המתאימים בחומת האש. מכאן ואילך הדרך להתחבר ל Listener היא פשוט ע"י הרצת הפקודה הבאה:

pssession with credentials

*המשתמש cred בסך הכל מכיל את Credentials שיאפשרו להיכנס למחשב אחר במקרה וה Credentials של המשתמש במחשב המשתלט אינם מספיקים. הזנתי במשתנה cred את השורה הבאה get-credentials, קיבלתי Prompt לשם משתמש וסיסמה, שמתי שם משתמש וסיסמה מתאימים למחשב המרוחק. ואז פשוט אפשר להעביר את המשתנה עם ה Credentials ל Session.

 – – – – – – – – – – – – – – – – – – – – – – – – – – –

כאשר רוצים להוציא מידע מסוים ממחשב אחר אפשר לעשות זאת גם מבלי להתחבר אליו באמצעות  Session ייעודי. אם למשל נריץ את הפקודה שמנסה להוציא מידע על ה BIOS של המחשב השני ברשת :

winbios

בלי קשר לזה שאפשרנו או לא אפשרנו חיבור מרחוק נקבל את השגיאה הבאה :

winbios err

ב Event Viewer זה יראה כך :

event

הסיבה היא ש Rule נוסף בחומת האש אינו מאפשר את העברת המידע שקשור ל WMI. אפשר לקנפג  את ה Rule הזה דרך ה GUI של ה FW:

fw wmi

או דרך ה NETSH :

netsh advfirewall firewall set rule group="windows management instrumentation (wmi)" new enable=yes

– – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – –

עוד בעיית הוצאת מידע ממחשב מרוחק – כאשר רוצים להוציא Process (למשל) ממחשב אחר, לעתים נקבל את השגיאה הבאה :

process error

הפתרון הוא פשוט לאפשר את ה Service הנוכחי (אצלי הוא לא היה מאופשר כברירת מחדל) :

service stoped

UAC : Admin Approval Mode

במחשב שלי, ובמכונות הוירטואליות שרצות עליו, יש משתמש מנהל הנושא את שמי, Ehud, משתמש שיצרתי בהתקנות מערכת ההפעלה. המשתמש הוא משתמש מנהל לכל דבר, הוא משויך לקבוצת Administrator, אך שמתי לב לתופעה די מרגיזה. כאשר אני פותח את ה CMD באופן רגיל עם משתמש זה (בלי Run as administrator), ה CMD נפתח כ CMD של משתמש רגיל, ז"א, בלי יכולות מנהל. אם למשל אנסה להריץ פקודה NETSH שמצריכה הרשאות מנהל, אקבל הודעה : "the requested operation requires elevation ". רק כאשר פתחתי את ה CMD כ Run as administrator, אכן ה CMD נפתח כבעל הרשאות מנהל.

cmd

הנקודה היא כמובן לא ה CMD עצמו, אלא שימוש בכל אובייקט במערכת ההפעלה שמצריך רמה מסוימת של הרשאה, נותן פרומפט לבקשת אישור או בקשת שם משתמש וסיסמא בהתאם להגדרות ה UAC. למשל, אם רמת ה UAC שלי גורמת לפרומפט על כל כניסה למאפייני כרטיס הרשת (אפילו בלי שינוי שלהם), אז גם פה המשתמש המנהל Ehud יצטרך לאשר את הפעולה, למרות שהוא בעצמו מנהל . . .

שני דברים הוסיפו על המוזרות של הנושא הזה :

1. חשבון המנהל הדיפולטיבי – Administrator – אינו נדרש לפעולות האישור האלו כאשר משתמשים בו. למשל, ה CMD נפתח אוטומטית עם הרשאות מנהל.

2. ישנם מחשבים אחרים בהם גם משתמש מנהל שאינו ה Administrator הדיפולטיבי, יכולים להתנהל כמו משתמש מנהל, בלי כל מיני פרומפטים.

כמובן שעולה מיד המסקנה שיש אפשרות לדאוג שם משתמש Ehud במחשב שלי יוכל להתנהל כמשתמש Administrator. המחשבים שבהם כן כל מיני משתמשי מנהל שאינם משתמשים דיפולטיביים פשוט עלו מ Image שבה הוגדר שהם יכולים להתנהל כמו משתמש Administrator הדיפולטיבי.

בדיקה ב Group Policy  במיקום הבא :

computer configuration\windows settings\security settings\local policies\security options

מביאה אותנו לפוליסי הבא :

User Account Control: Turn on Admin Approval Mode – run all administrators in admin approval mode

כברירת מחדל הפוליסי הזו מאופשרת (מצב enable). מה שהיא אומרת, זה שכל משתמש מנהל במחשב (כולל המשתמש הדיפולטיבי Administrator) רצים במצב של "Admin Approval Mode", שזה אומר שגם המנהלים עצמם כפופים לרמת האבטחה ב UAC, ולכן ה CMD עצמו (למשל) לא נפתח כברירת מחדל עם הרשאות מנהל.

השאלה שצריכה להישאל מיד היא : "למה ה Administrator הדיפולטיבי לא רץ ב Admin Approval Mode? למה הוא לא סבל מה UAC ?

התשובה נמצאת בפוליסי אחר שדורס את הפוליסי הנ"ל, פוליסי שגורם שהפוליסי הנ"ל לא יכול על משתמש ה Administrator – משתמש מנהל שבא כברירת מחדל :

User Account Control: Use Admin Approval Mode for the built-in Administrator account

הפוליסי הזו נמצאת באותו מיקום כמו הקודמת, היא אומרת שמשתמש ה Administrator הדיפולטיבי כן ירוץ עם Admin Approval Mode, אבל הפוליסי הזו הייתה על Disable, וזו הסיבה שהמשתמש Administrator כן הצליח להיכנס מיידית לכל אובייקט ללא בקשת אישורים מה UAC.

DNS Caching חלק ב' – Server Caching

חלק א' של סדרת מאמרי ה cache של ה DNS עסק ב client caching שמיושם בזעות dns client service  שרץ בכל תחנה (כולל בשרתים). חלק ב', הנוכחי, יעסוק ב server caching. הנושא של server caching הוא חשוב מאד, משום שאפשר להשתמש בשרת DNS שיאגור כל הזמן בקשות של משתמשים בדומיין לגבי אתרים ספציפיים ברשת האינטרנט, ואז במקום להוציא שוב את המשתמשים לשאילתות DNS מפרכות ברשת האינטרנט, ה server  שאחראי על ה caching כבר יחזיק בתשובות.

לפני שניגע בנקודת מפתח, למי שלא מכיר, נציין איפה בדיוק ניתן לראות את רשומות ה cache שנשמרות בתוך השרת. כברירת מחדל, ה role של ה DNS לא של מציג את רשומות ה cache. על מנת להציג אותן, לוחצים על כפתור ה view מסמנים ב V את ה Advanced. ואז ניתן לראות בתפריט ה role שנוספה תיקיית cached lookups. התיקייה הזו מכילה את רשומות שה DNS עשה עליהם resolving למשתמשים בשרותו.

התיקייה הזו מכילה תיקיית משנה ".root" שמייצגת את השרת עצמו, ובתוכה יש תיקיות משנה. הנה דוגמה :

cachedns

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

ב. תיקיית local – שאילתות לגבי רשומות שנמצאות בדומיין שלנו (הסיומת של הדומיין הספציפי היא local, באותה מידה היא הייתה יכולה להיות POP, אם כך למשל ה סיומת הדומיין שלי). בתוך תיקייה זו יהיה את ההתחלה של הדומיין שלי, במקרה הזה (לא מוצג בתמונה) – MCITP.

כמובן שיכולות להיות גם תיקיות בעלות סיומת com, ru וכו'.  וכן יכולה להיווצר גם תיקיות משנה, אם למשל פניתי לאתר co.il. בתוך תיקיית ה il שתיווצר, תהיה גם תיקיית co, ובתוכה הרשומות עצמן.

את הרשומות ניתן למחוק, בהקשה על ה action שבתפריט, ואז clear server cache. במצב הזה, מוחקים את כל ה cache שבשרת. אם רוצים למחוק רק  cache ספציפי, את תיקיית ה local, נלחץ בתוך תפריט ה action על כפתור ה delete. את תיקיית ה net אי אפשר למחוק, כנראה בשל הפוטנציאל שלה להכיל את ה root hints/servers.

כמובן שישנה אפשרות למחוק את ה server cache בעזרת שימוש בכלי שורת הפקודה של שרת ה DNS והוא dnscmd. הפקודה היא :

dnscmd /clearcache

החיסרון בשימוש בפקודה, זה שאני לא מצאתי אפשרות להגביל את המחיקה לפי תיקייה ספציפית, בניגוד ל GUI שם הדבר אפשרי.

דגש חשוב לגבי שרת DNS: רשומות שהוא פתר עשה resolving לעצמו, בין אם בדומיין ובין אם באינטרנט, הוא ישמור גם ב server cache, אך גם ב client cache הפרטי שלו. אך רשומות שהוא לא עשה resolving לעצמו, אלא למחשב אחר בתחנה, אינן נשמרות ב client dns cache בשרת .

איך בודקים תקינות של שרת DNS

בקטע הקרוב אני רוצה להראות על הטעיה בבדיקת תקינות תקשורת ה DNS שעלולה להיגרם בגלל ה server cache, ובכך להראות עד כמה כדאי לתת את תשומת הלב לנושא הזה.

נניח שיש לנו Forest שה Root Domain שלו הוא  MCITP.LOCAL. על ה DC של ה Root Domain ממוקם שירות DNS, ה FQDN שלו הוא DNSSRV.MCITP.LOCAL. ה IP שלו הוא 192.168.1.1. נניח שלדומיין הזה מצורף מחשב רגיל, ה FQDN שלו הוא STATION1.MCITP.LOCAL, והוא מקבל, כמובן, את שירות ה DNS מה DNSSRV –  בכרטיס הרשת שלו מוגדרת הכתובת של שרת ה DNS. הכתובת של המחשב היא 192.168.1.40.

נניח שיש לנו ב Forest גם סאב דומיין : EAST.MCITP.LOCAL. ממקום עליו שרת DNS עם zone משלו. ה FQDN שלו הוא : SUB2.EAST.MCITP.LOCAL. ה IP שלו הוא 192.168.1.2 לסאב דומיין הזה מצורפת תחנה שה FQDN שלה הוא : SUBSTATION.EAST.MCITP.LOCAL. ה IP שלה הוא 192.168.1.50. בכרטיס הרשת של התחנה שרת ה DNS  המועדף הוא השרת של הדומיין אליה היא משויכת – הסאב דומיין – 192.168.1.2. ה DNS המשני בכרטיס הרשת הוא 192.168.1.1 – שרת ה DNS של הדומיין.

הנה תמונה שתמחיש את מבנה ה Forest :

dns

אז קודם כל חשוב להבין למה בתחנה של הסאב דומיין יש בכתובת ה DNS המשני את ה DNS  של הדומיין. ה DNS של הסאב דומיין הוא Delegetion, הוא מנהל את ה ZONE – EAST.MCITP.LOCAL. התקשורת בין שני שרתי ה DNS הוא כדלקמן : ה DNS בדומיין הראשי מכיל reference לשם ול IP של הסאב דומיין. ה DNS של הדומיין כמובן לא מכיל את הרשומות של הסאב דומיין, אלא רק IP של DNSSRV.EAST.MCITP.LOCAL. כאשר תחנות בדומיין רוצות לקבל resolving לתחנות בסאב דומיין, ה DNS של הדומיין מפנה אותם ל DNS של הסאב דומיין באמצעות הרשומה הזו. הנה תמונה שתמחיש את ההפניה :

DELEGATION

 לעומתו, הסאב דומיין יודע לתקשר עם הדומיין באמצעות השמת הכתובת שלו (של הדומיין) ב forwarders או ב conditional forwarding של הסאב דומיין. כאשר תחנות בסאב דומיין רוצות לקבל resolving לתחנות דומיין, השאילתא תקבל מענה באמצעות שרת דומיין האב שמוגדר ב conditional forwarding או ב forwarders שבתוך הסאב דומיין. הנה תמונה שתמחיש את ה forwarder:

forwarder

עכשיו נראה איפה יכול לצוץ בלבול בזיהוי בעיית DNS כאשר. אם קרס ה SERVICE ה  DNS SERVER בסאב דומיין (EAST.MCITP.LOCAL). נניח שהתחנה בסאב דומיין SUBSTATION לא מצליחה לתקשר עם באופן DNS עם מחשבים בסאב דומיין. כזכור, בתחנה של הסאב דומיין, שרת ה DNS הראשי הוא הסאב דומיין, ושרת ה DNS המשני הוא השרת של הדומיין.

למשתמש בתחנת הסאב דומיין, הדבר הראשון שיעלה בראש, ובצדק, שיש בעיה DNS-ית. נניח שהמשתמש בתחנה בסאב דומיין SUBSTATION.EAST.MCITP.LOCAL, ימחק את ה cache הפנימי שלו (IPCONFIG/FLUSHDNS), וינסה לעשות פינג לשרת ה DNS בדומיין שלו – DNSSRV.EAST.MCITP.LOCAL, סביר להניח שהוא יקבל תגובה שלילית. אך, גם אם הוא מחק את ה cache הפנימי שלו, ולמרות ששרת ה DNS בסאב דומיין נפל, הוא עדיין עשוי לקבל תגובה חיובית כאשר הוא עושה פינג ל DNS שלו.

למה? בגלל ה server cache בדומיין הראשי.

כזכור, למשתמש בתחנה בסאב דומיין מוגדר גם ה DNS של ה Root Domain שהוא DNSSRV.MCITP.LOCAL – כאופציה של ה  DNS המשני בכרטיס רשת. כאשר הוא יראה ששרת ה DNS בדומיין שלו (הסאב דומיין) קרס, הוא יפנה לקבל resolving ל DNS של ה ROOT, אם ב cache server DNS של ה ROOT שמורה רשומה של הסאב דומיין DNSSRV.EAST.MCITP.LOCAL, הפינג שמבצע המשתמש לשרת ה DNS שלו יהיה מוצלח, וזה יכול להיות ככה למשך דקות ארוכות, בגלל שהרשומה שמורה ב CACHE SERVER של ה ROOT באותן הדקות. המשתמש עשוי לחשוב שהתקשורת עם שרת ה DNS עצמו תקינה. ולא כך היא.

איך אפשר להגיע למסקנה בכל זאת שיש בעיה עם שרת ה DNS בסאב דומיין ?

אפשר לנסות לעשות פינג לסאב דומיין עצמו, ולא ל FQDN של השרת.

זאת אומרת רשומת DNS-SRV.CHILD.PARENT.LOCAL אינה שוות ערך לרשומת DNS-SRV.CHILD.PARENT.LOCAL.

למרות זאת, יש לזכור שבכל זאת, ייתכן שגם רשומת הסאב דומיין עצמו  CHILD.PARENT.LOCAL , נמצאת בתוך ה CACHE SERVER של ה ROOT DOMAIN, ולכן גם זה לא פיתרון מושלם.

האופציה העדיפה היא למחוק את ה SERVER CACHE שנמצא בתוך ה ROOT.