שימוש ב-WMI/CIM מ-C# ומ-PowerShell — מדריך מעשי לשליפת מידע חומרה, ניטור תהליכים ושאילתות מרוחקות

· · Windows, C#, .NET, PowerShell, WMI, CIM, יישומים עסקיים, פיתוח Windows

«רוצים להציג את המספר הסידורי ואת שם הדגם של המחשב במסך של יישום עסקי.» «רוצים לנטר שטח דיסק פנוי בשרת ולהרים אזהרה.» «רוצים לזהות שתהליך מסוים הופעל.» «רוצים לשלוף במרוכז את מצב המחשבים במקום מרוחק.» — דרישות מהסוג הזה עולות שוב ושוב בפיתוח יישומים עסקיים וכלי ניהול ל-Windows. והתשובה הסטנדרטית להן היא WMI ‏(Windows Management Instrumentation), או, בשם התקן, CIM ‏(Common Information Model).

דרישות קלאסיות ו-WMI/CIMהתשובה הקלאסית לדרישות הקלאסיות של יישום עסקי — הצגת מספר סידורי ושם דגם, ניטור שטח דיסק פנוי, זיהוי הפעלת תהליך ושאילתת מחשב מרוחק — היא WMI, ובשם הסטנדרטי CIMמספר סידורי ושם דגםWMI (השם הסטנדרטי: CIM)ניטור שטח דיסק פנויזיהוי הפעלת תהליךשאילתת מחשב מרוחק

איור 1: התשובה הקלאסית לארבע הדרישות הקלאסיות של יישום עסקי היא WMI/CIM.

מה שמסבך הוא שמידע על WMI מערבב ישן וחדש. חיפוש מעלה זה לצד זה מאמרים בני עשר שנים שמשתמשים ב-Get-WmiObject ומאמרים שמשתמשים ב-Get-CimInstance, ובצד C# יש שתי שושלות נפרדות: System.Management ו-Microsoft.Management.Infrastructure. קשה לדעת מהי הכתיבה הנוכחית ומה «עדיין רץ אבל לא בוחרים לקוד חדש». בפועל Get-WmiObject כלל לא קיים ב-PowerShell 7, והעובדה הזאת צצה בבת אחת כשמגרים סקריפט פנימי שנכתב ל-5.1.

המאמר הזה מיועד למפתחי C#/PowerShell שמיישמים ביישום עסקי שליפת מידע חומרה, ניטור תהליכים ושאילתות מחשב מרוחק. הוא מסדר, מעוגן במקורות ראשוניים נכון לאוגוסט 2026, את ההבנה המינימלית של מבנה WMI/CIM, את פקודות CIM של PowerShell, את שני ממשקי ה-API ב-C#, מתכונים נפוצים בפועל, מלכודות של ביצועים, הרשאות ו-64bit, ולבסוף איך לשפוט «מתי לא להשתמש ב-WMI».

1. השורה התחתונה קודם

  • CIM הוא מודל התקן התעשייתי למידע ניהול שהוגדר ב-DMTF, ו-WMI הוא המימוש של Microsoft. ממשקי API ממשפחת «CIM» ב-PowerShell וב-C# הם דור נוכחי שעוקב אחרי התקן, והם מתחברים לאותה תשתית WMI.1
  • ב-PowerShell הדור הנוכחי הוא פקודות CIM ‏(Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent). פקודות WMI הישנות (Get-WmiObject ועוד ארבע) הוסרו מ-PowerShell 6 ואילך ואינן רצות ב-PowerShell 7.2
  • מרחב השמות שברירת המחדל הוא root/CIMV2, ושאילתה יום-יומית היא בעיקרה צמצום מחלקות Win32_* שם ב-WQL.3
  • שאילתה מרוחקת ברירת המחדל שלה WSMan ‏(WinRM). ציון -ComputerName יוצר סשן WSMan זמני. אם שואלים את אותו יעד שוב ושוב, שימוש חוזר בסשן CIM ‏(New-CimSession) הוא הנוהג המבוסס לביצועים, וליעד ישן שאי אפשר להגדיר בו WinRM יש אפשרות פרוטוקול DCOM.34
  • ב-C# יש שתי שושלות: System.Management ‏(ManagementObjectSearcher) ו-Microsoft.Management.Infrastructure ‏(CimSession). שתיהן ייעודיות ל-Windows, וב-.NET הנוכחי מביאים אותן מ-NuGet. אם בונים שאילתות מרוחקות או ניטור למוצר של ממש, API של MI — שחולק את מערכת הטיפוסים עם פקודות CIM — מתאים יותר.56
  • זיהוי הפעלת תהליך נעשה במנוי לאירוע, לא ב-polling. מנוי ל-Win32_ProcessStartTrace חייב לרוץ בהרשאות מנהל.78
  • לא משתמשים ב-SELECT * מתוך הרגל. צמצום מה שמועבר עם -Filter / -Property / -KeyOnly מונע בערך מחצית מבעיות הביצועים של WMI.3
  • WMI אינו פתרון אוניברסלי. לניטור ביצועים בתדירות גבוהה, לקריאה וכתיבה של הגדרות האפליקציה עצמה, או לקריאה חד-פעמית לפונקציית מערכת, מונים, הרישום, Win32 API או פקודות ייעודיות מתאימים יותר (ראו טבלת ההחלטה בפרק 8).

2. מהו WMI/CIM — תקן מול מימוש, מרחבי שמות, מחלקות ו-WQL

קודם מסדרים אחת ולתמיד את יחסי המונחים.

מונח מה זה
CIM ‏(Common Information Model) מודל התקן התעשייתי לייצוג יעדי ניהול כמו מערכות, יישומים, רשתות והתקנים. מוגדר ומתוחזק על ידי DMTF ‏(Distributed Management Task Force)1
WBEM ‏(Web-Based Enterprise Management) יוזמה תעשייתית ליצירת טכנולוגיות תקן לגישה למידע ניהול בסביבה ארגונית1
WMI המימוש של Microsoft ל-WBEM. מייצג יעדי ניהול לפי תקן CIM ומובנה ב-Windows1
MI ‏(Windows Management Infrastructure) הדור הבא של WMI. תואם לחלוטין ל-WMI המסורתי, ורוב הספקים החדשים נכתבים ב-MI1
הקשר בין תקן CIM למימוש WMIתקן CIM ש-DMTF מגדיר ומתוחזק משמש במסגרת יוזמת WBEM, המימוש של Microsoft הוא WMI, MI מהדור הבא תואם לחלוטין ל-WMI המסורתי, וממשקי API ממשפחת CIM מתחברים לאותה תשתית WMIDMTF מגדיר ומתוחזקCIM (מודל תקן תעשייתי)WBEM (יוזמה תעשייתית)WMI (מימוש Microsoft)MI (דור הבא, תאימות מלאה)API ממשפחת CIM (PowerShell / C#)

איור 2: CIM הוא המפרט, WMI הוא המימוש ב-Windows. ממשקי API ממשפחת CIM מתחברים לאותה תשתית WMI.

יש ארבעה חלקי מבנה שכדאי למפתח להבין.

  • מרחב שמות (namespace): היררכיה שאוספת מחלקות. לשאילתה יום-יומית משתמשים כמעט תמיד ב-root/CIMV2, שהוא גם ברירת המחדל של פקודות CIM.3 אחרים כוללים את root\default (ספק הרישום ועוד).
  • מחלקה: טיפוס שמייצג יעד ניהול, כמו Win32_ComputerSystem (המחשב עצמו), Win32_LogicalDisk (כונן לוגי) או Win32_Process (תהליך). מחלקות ייחודיות ל-Windows שיורשות ממחלקות תקן CIM (כמו CIM_LogicalDisk) נושאות את הקידומת Win32_.9
  • ספק (provider): הרכיב שמספק את התוכן הממשי של מחלקה. כששואלים אותו, הספק פונה למערכת ההפעלה במקום ובונה את הערכים.
  • WQL: שפת שאילתה דמוית SQL. כמו ב-SELECT Name, State FROM Win32_Service WHERE StartMode = 'Auto', מתייחסים למחלקה כאל טבלה ומצמצמים אותה. WQL היא גם שפת השאילתה שברירת המחדל של פקודות CIM.3

«לקרוא מידע על מערכת ההפעלה ועל החומרה דרך מחלקות ושפת שאילתה אחידות» — זה הערך ש-WMI נותן. ולהפך, כתיבה ופעולות מוגבלות למחלקות שיש להן מתודות שאפשר לקרוא ב-Invoke-CimMethod; זה לא מנגנון שיכול הכול.

מבנה שאילתת WMIשאילתת WQL מופנית למחלקות Win32_* במרחב השמות root/CIMV2, הספק שמספק את תוכן המחלקה פונה למערכת ההפעלה במקום ובונה ערכים, והתוצאה חוזרתשאילתה ב-WQLמרחב שמות root/CIMV2מחלקות Win32_*ספקפנייה למערכת במקוםהחזרת תוצאה

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

3. שימוש מ-PowerShell — פקודות CIM הן הנוכחיות, פקודות WMI הוסרו

3.1. הבסיס: Get-CimInstance

# לפי שם מחלקה (מרחב שמות ברירת מחדל root/CIMV2)
Get-CimInstance -ClassName Win32_OperatingSystem

# כותבים ב-Filter רק את תוכן פסוקית WHERE (בלי מילת המפתח WHERE עצמה)
Get-CimInstance -ClassName Win32_Service -Filter "StartMode = 'Auto' AND State <> 'Running'"

# שולפים רק את המאפיינים הנחוצים כדי לצמצם את נפח ההעברה
Get-CimInstance -ClassName Win32_Process -Property Name, ProcessId, CreationDate

# כדי לכתוב WQL גולמי משתמשים ב-Query
Get-CimInstance -Query "SELECT * FROM Win32_Process WHERE Name LIKE 'p%'"

-Filter הוא בדיוק פסוקית WHERE של WQL, ו--Property מגביל אילו עמודות נשלפות.3 ערך ההחזרה הוא אובייקט CimInstance, ומאפייני תאריך (כמו CreationDate או LastBootUpTime) חוזרים כבר מומרים ל-DateTime. בניגוד ל-Get-WmiObject הישן, האובייקט שנשלף אינו נושא מתודות ישירות, ולכן קריאות למתודה נעשות בהעברה ל-Invoke-CimMethod.

קריאת מתודה על CimInstanceCimInstance ש-Get-CimInstance מחזיר מגיע עם מאפייני תאריך שכבר הומרו ל-DateTime, אבל בלי מתודות ישירות, לכן קריאת מתודה נעשית בהעברת המופע ל-Invoke-CimMethodGet-CimInstanceאובייקט CimInstanceתאריכים כבר DateTimeאין מתודות ישירותמעבירים ל-Invoke-CimMethodקריאת מתודה

איור 4: ל-CimInstance אין מתודות, לכן קריאת מתודה נעשית בהעברה ל-Invoke-CimMethod.

# קריאת מתודה על מופע: בעלים של כל תהליך
Get-CimInstance -ClassName Win32_Process -Filter "Name = 'notepad.exe'" |
    Invoke-CimMethod -MethodName GetOwner

# קריאת מתודה סטטית של המחלקה: הפעלת תהליך
Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{ CommandLine = 'notepad.exe' }

# בדיקת הגדרת המחלקה (מאפיינים ומתודות)
Get-CimClass -ClassName Win32_Process

3.2. טבלת מיגרציה מפקודות WMI הישנות

מ-PowerShell 6 ואילך (כולל PowerShell 7 הנוכחי) פקודות WMI v1 הבאות הוסרו. אותה פונקציונליות מסופקת במודול CimCmdlets ‏(WMI v2).2

ישן (עד Windows PowerShell 5.1) נוכחי (פקודות CIM) הערות
Get-WmiObject Get-CimInstance עקרון -Filter / -Query זהה
Get-WmiObject -List Get-CimClass גילוי ובדיקת הגדרות מחלקה
Invoke-WmiMethod Invoke-CimMethod ארגומנטים מועברים כטבלת גיבוב ב--Arguments @{ }
Register-WmiEvent Register-CimIndicationEvent מנוי לאירוע (סעיף 6.3)
Set-WmiInstance Set-CimInstance שינוי מאפיינים הניתנים לכתיבה
Remove-WmiObject Remove-CimInstance מחיקת מופע

פקודות CIM רצות גם תחת Windows PowerShell 5.1, לכן כל מה שכותבים מעתה נכתב בצד CIM גם אם ירוץ תחת 5.1 — כך לא נשארת עלות מיגרציה. לתמונה המלאה של דו-קיום ומיגרציה בין 5.1 ל-7 ראו «ההבדלים בין Windows PowerShell 5.1 ל-PowerShell 7».

למה לכתוב סקריפט חדש ב-CIMסקריפט שנכתב בפקודות WMI רץ ב-5.1 אבל הוסר מ-PowerShell 6 ואילך ולכן דורש שכתוב במיגרציה, ופקודות CIM זמינות גם ב-5.1 ולכן כתיבה חדשה בצד CIM לא משאירה עלות מיגרציהפקודות WMIפקודות CIMסקריפט שנכתב עכשיובאיזה מהם כותבים?רץ ב-5.1זמין גם ב-5.1הוסר ב-PowerShell 7שכתוב במיגרציהאין עלות מיגרציה

איור 5: כתיבה חדשה בפקודות CIM חוסכת שכתוב כשמגרים ל-PowerShell 7.

4. שאילתות מרוחקות — סשן CIM ‏(WSMan כברירת מחדל) ואפשרות DCOM

אם לא מציינים יעד, פקודות CIM מתחברות ל-WMI המקומי ב-COM; אם מציינים -ComputerName, הן יוצרות סשן זמני בפרוטוקול WSMan ‏(WinRM) כדי להתחבר. כשמבצעים כמה פעולות מול אותו מחשב, יצירת סשן CIM ושימוש חוזר בו עדיפה לביצועים.3

בחירת אופן החיבור של CIMבלי ציון מתחברים ב-COM ל-WMI המקומי, עם ComputerName נוצר סשן WSMan זמני בכל שאילתה, כמה פעולות לאותו יעד מרוויחות משימוש חוזר ב-New-CimSession, וליעד בלי WinRM יש אפשרות פרוטוקול DCOMאיןכןחד-פעמיכמההרצת פקודת CIMצוין ComputerName?חיבור COM ל-WMI מקומיכמה פעולות לאותו יעד?סשן WSMan זמנישימוש חוזר ב-New-CimSessionנוצר בכל שאילתהיעד בלי WinRMאפשרות פרוטוקול DCOM

איור 6: שאילתה מרוחקת ברירת המחדל שלה WSMan, ולכמה פעולות מול אותו יעד שימוש חוזר בסשן CIM הוא הנוהג.

# לשאילתה חד-פעמית משתמשים ב-ComputerName (סשן זמני נוצר בכל פעם)
Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName Server01, Server02

# לשאילתות חוזרות משתמשים שוב בסשן CIM
$session = New-CimSession -ComputerName Server01
Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $session
Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType = 3" -CimSession $session
Remove-CimSession $session

ליעדים שאי אפשר להגיע אליהם ב-WSMan — מכונות ישנות שאי אפשר להגדיר בהן WinRM, למשל — אפשר לבחור במקום זאת בפרוטוקול DCOM.4

$dcom = New-CimSessionOption -Protocol Dcom
$session = New-CimSession -ComputerName OldServer -SessionOption $dcom

התנאים המוקדמים לשאילתה מרוחקת הם אלה.

  • WinRM חייב להיות מוגדר ביעד. winrm quickconfig מגדיר את השירות להפעלה אוטומטית, יוצר מאזין HTTP (יציאת ברירת מחדל 5985) ורושם חריג חומת אש, הכול בפעם אחת.10 אם רוצים להתחבר ב-HTTPS (יציאת ברירת מחדל 5986), זה לבדו לא מספיק — צריך להכין אישור שרת ולהגדיר בנפרד מאזין HTTPS, למשל ב-winrm quickconfig -transport:https.10
  • היציאות הרלוונטיות חייבות להיות פתוחות בחומות האש בדרך. עבודת התכנון והרישום של כללי כניסה מכוסה במאמר «Windows Firewall ויישומים עסקיים».
  • אימות. בסביבת דומיין Kerberos מספק אימות הדדי. בקבוצת עבודה אין Kerberos, וייתכן שצריך לרשום את היעד ב-TrustedHosts של הלקוח. מצמצמים את הרשימה ככל האפשר.10
  • הרשאות. בתצורת ברירת המחדל, שאילתות ופעולות WMI מרוחקות נעשות בחשבון ששייך לקבוצת המנהלים של היעד. כדי לפתוח זאת למשתמשים רגילים צריך להגדיר הרשאות גישה גם ב-WinRM וגם במרחב השמות של WMI.10
  • שימו לב ש-DCOM אין לו יציאת האזנה קבועה (הוא משתמש ביציאות RPC דינמיות), ולכן קשה יותר לתכנן אותו מעבר לחומת אש. בטוח להניח WSMan כברירת מחדל לכל דבר שבונים מעתה.
אישור התנאים המוקדמים לשאילתה מרוחקתביעד winrm quickconfig מגדיר הפעלה אוטומטית של השירות, יוצר מאזין HTTP ורושם חריג חומת אש בפעם אחת, מאזין HTTPS מוגדר בנפרד אחרי הכנת אישור, ובסביבת קבוצת עבודה לעיתים נדרש רישום ב-TrustedHostswinrm quickconfigהפעלה אוטומטית של השירותיצירת מאזין HTTP (5985)חריג חומת אשמאזין HTTPS (5986)מכינים אישור ומגדירים בנפרדסביבת קבוצת עבודהרישום ב-TrustedHosts

איור 7: winrm quickconfig מבצע את תצורת ברירת המחדל בפעם אחת; מאזין HTTPS ואימות בקבוצת עבודה דורשים טיפול נפרד.

5. שימוש מ-C# — System.Management מול Microsoft.Management.Infrastructure

יש שתי שושלות API לשימוש ב-WMI מ-C#. שתיהן ייעודיות ל-Windows.

  System.Management Microsoft.Management.Infrastructure ‏(MI API)
הבאה כלול כברירת מחדל ב-.NET Framework. ב-.NET הנוכחי חבילת NuGet System.Management5 חבילת NuGet Microsoft.Management.Infrastructure6
מחלקת כניסה ManagementObjectSearcher (מעבירים WQL לשאילתה)5 CimSession (Create → QueryInstances / InvokeMethod / Subscribe)6
מערכת טיפוסים ManagementObject / ManagementEventWatcher11 CimInstance / CimSessionאותם טיפוסים כמו פקודות CIM3
גישה מרוחקת מבוססת DCOM מבוססת WSMan (סשן CIM). גרסאות אסינכרוניות (*Async) זמינות6
מתאים ל שליפת מידע מקומי. תחזוקת נכסי קוד קיימים בניית שאילתות מרוחקות וניטור. תכנונים שמשלבים PowerShell

5.1. System.Management: היסודות של ManagementObjectSearcher

מעבירים WQL כמחרוזת ומקבלים אוסף תוצאות דרך Get().5

// NuGet: System.Management (Windows בלבד)
using System.Management;

using var searcher = new ManagementObjectSearcher(
    @"root\cimv2",
    "SELECT DeviceID, FreeSpace, Size FROM Win32_LogicalDisk WHERE DriveType = 3");

foreach (ManagementObject disk in searcher.Get())
{
    var freeGb = (ulong)disk["FreeSpace"] / 1024.0 / 1024.0 / 1024.0;
    var sizeGb = (ulong)disk["Size"] / 1024.0 / 1024.0 / 1024.0;
    Console.WriteLine($"{disk["DeviceID"]} פנוי {freeGb:F1} GB / סך הכל {sizeGb:F1} GB");
}

מאפיינים חוזרים כ-object דרך indexer, לכן צריך לבדוק בתיעוד המחלקה את טיפוס CIM (בדוגמה הזאת FreeSpace / Size הם uint649) ולהמיר בהתאם. להניח שזה int ולהמיר על בסיס ההנחה, עד שמקבלים InvalidCastException, היא המעידה הקלאסית הראשונה כאן.

מלכודת שליפת מאפיין והמרהמאפיינים ב-System.Management חוזרים כ-object דרך indexer, לכן צריך לאשר את טיפוס CIM בתיעוד ולהמיר, והמרה מתוך הנחה שזה int גורמת ל-InvalidCastExceptionשליפה ב-indexerחוזר כ-objectאישור טיפוס CIM בתיעודהמרה לטיפוס הנכוןהמרה מתוך הנחה שזה intInvalidCastException

איור 8: מאפיינים חוזרים כ-object, לכן מאשרים את טיפוס CIM לפני המרה.

5.2. MI API: היסודות של CimSession

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

// NuGet: Microsoft.Management.Infrastructure (Windows בלבד)
using Microsoft.Management.Infrastructure;

// CimSession.Create(null) למקומי, או שם מחשב למרוחק
using CimSession session = CimSession.Create(null);

IEnumerable<CimInstance> disks = session.QueryInstances(
    @"root\cimv2", "WQL",
    "SELECT DeviceID, FreeSpace, Size FROM Win32_LogicalDisk WHERE DriveType = 3");

foreach (CimInstance disk in disks)
{
    var deviceId = (string)disk.CimInstanceProperties["DeviceID"].Value;
    var free = (ulong)disk.CimInstanceProperties["FreeSpace"].Value;
    Console.WriteLine($"{deviceId} פנוי {free / 1024.0 / 1024 / 1024:F1} GB");
}

מפני שהוא עובד עם אותו CimInstance שפקודות CIM של PowerShell מחזירות, זרימת פיתוח של «מנסים ב-PowerShell ואז מעתיקים ל-C#» מתחברת באופן טבעי. אם מתכננים את שילוב C# ו-PowerShell עצמו, ראו גם «איך להריץ PowerShell מ-C# (CSharp) ולקבל את התוצאות כאובייקטים».

ניסוי ב-PowerShell והעתקה ל-C#פקודות CIM של PowerShell ו-API של MI ב-C# מטפלים באותו טיפוס CimInstance, לכן זרימת פיתוח שמנסה ב-PowerShell ואז מעתיקה ל-C# מתחברת באופן טבעיניסוי ב-PowerShellפקודות CIMמימוש מלא ב-C#MI APIאותו טיפוס CimInstanceההעתקה מתחברת באופן טבעי

איור 9: פקודות CIM ו-API של MI מטפלים באותו CimInstance, לכן ניסוי מוביל למימוש מלא.

6. מתכונים נפוצים בפועל

6.1. טבלת עזר למחלקות נפוצות

מידע רצוי מחלקה מאפיינים עיקריים
יצרן / שם דגם Win32_ComputerSystem Manufacturer, Model
מספר סידורי של השלדה Win32_BIOS SerialNumber
גרסת מערכת / זמן אתחול Win32_OperatingSystem Caption, Version, LastBootUpTime
שטח דיסק פנוי Win32_LogicalDisk DeviceID, FreeSpace, Size, DriveType9
מצב שירות Win32_Service Name, State, StartMode
רשימת תהליכים Win32_Process Name, ProcessId, CommandLine

6.2. הקלאסיקה של ניהול נכסים: מספר סידורי, שם דגם ושטח דיסק פנוי

# מידע דגם ומספר סידורי (להצלבה מול ספר נכסי מחשבים)
$cs   = Get-CimInstance -ClassName Win32_ComputerSystem -Property Manufacturer, Model
$bios = Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber
[pscustomobject]@{
    Manufacturer = $cs.Manufacturer
    Model        = $cs.Model
    Serial       = $bios.SerialNumber
}

# שטח פנוי בדיסקים מקומיים (DriveType = 3)
Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType = 3" |
    Select-Object DeviceID,
        @{ Name = 'FreeGB'; Expression = { [math]::Round($_.FreeSpace / 1GB, 1) } },
        @{ Name = 'SizeGB'; Expression = { [math]::Round($_.Size / 1GB, 1) } }

DriveType = 3 מייצג «דיסק מקומי», ומחריג נתיק (2), כונני רשת (4) ו-CD ‏(5).9 לניטור, די להריץ את הסקריפט הזה לכל שרת דרך סשן CIM כדי לקבל את הבסיס לניטור דיסק בלי סוכן.

הבסיס לניטור דיסק בלי סוכןצמצום DriveType 3 מחריג נתיקים, כונני רשת ו-CD ומשאיר רק דיסקים מקומיים, ואותו סקריפט מועבר לכל שרת דרך סשן CIM וכך נוצר בסיס לניטור דיסק בלי סוכןסקריפט שליפת שטח פנוימצמצמים ב-DriveType = 3מחריגים נתיקים וכדומהדרך סשן CIMמעבירים לכל שרתניטור בלי סוכן

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

6.3. זיהוי הפעלת תהליך — מנוי לאירוע

במקום «לשלוף Win32_Process במחזור polling ולהשוות הפרשים», משתמשים במנוי לאירוע. הדרך הפשוטה לתפוס הפעלת תהליך היא מנוי ל-Win32_ProcessStartTrace (מחלקת אירוע של ספק מעקב הליבה, עם מאפיינים כמו ProcessName / ProcessID / ParentProcessID8).

# להריץ מסשן PowerShell מוגבה (מנהל)
$action = {
    $name = $Event.SourceEventArgs.NewEvent.ProcessName
    $id   = $Event.SourceEventArgs.NewEvent.ProcessID
    Write-Host "תהליך הופעל: $name (PID=$id)"
}
Register-CimIndicationEvent -ClassName Win32_ProcessStartTrace `
    -SourceIdentifier ProcessStarted -Action $action

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

# כשמסיימים את הניטור: מסירים את המנוי
Unregister-Event -SourceIdentifier ProcessStarted

Register-CimIndicationEvent רושם מנוי לפי שם מחלקה או לפי שאילתת אירוע WQL, ובלוק הסקריפט של -Action רץ בכל הגעה של אירוע.7 מנוי למחלקה הזאת דורש הרשאות מנהל.7 מי יכול לקבל את האירוע נשלט במתאר האבטחה של מחלקת האירוע, ומשתמש רגיל בלי הרשאות מוגבהות יידחה.8

זרימת מנוי לאירוע הפעלת תהליךבסשן PowerShell בהרשאות מנהל Register-CimIndicationEvent רושם מנוי, בכל הפעלת תהליך מגיע אירוע ו-Action רץ, ובסיום הניטור Unregister-Event מבטלWMIסשן PowerShellWMIסשן PowerShellהרצה בהרשאות מנהלרישום מנוי ב-Register-CimIndicationEventאירוע מגיע בכל הפעלת תהליךהרצת -Actionביטול ב-Unregister-Event (בסיום הניטור)

איור 11: המנוי תקף כל עוד הסשן שרשם אותו חי, והביטול נעשה כשמסיימים את הניטור.

דרך נוספת היא אירוע יצירת מופע הכללי (__InstanceCreationEvent), שניתן לשימוש עם כל מחלקה. כאן WMI עושה polling במרווח שמציינים ב-WITHIN והופך את ההפרש לאירוע, לכן את הפשרה בין מרווח הזיהוי לעומס מחליטים בעצמכם.

שני אופני מנוי לזיהוי הפעלת תהליךWin32_ProcessStartTrace הוא מנוי למחלקת אירוע של ספק מעקב הליבה, ו-__InstanceCreationEvent הכללי הוא מנגנון שבו WMI עושה polling במרווח WITHIN והופך הפרש לאירוע, לכן את הפשרה בין מרווח לעומס מחליטים בעצמכםזיהוי הפעלת תהליךWin32_ProcessStartTrace__InstanceCreationEventמנוי למעקב ליבהpolling במרווח WITHINפשרה בין מרווח לעומס

איור 12: מנוי למחלקת אירוע ייעודית, או אירוע יצירת מופע כללי עם מרווח polling.

# ניטור מופעי Win32_Process חדשים ב-polling כל 5 שניות
$query = "SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process'"
Register-CimIndicationEvent -Query $query -SourceIdentifier ProcPoll -Action {
    Write-Host "הופעל: $($Event.SourceEventArgs.NewEvent.TargetInstance.Name)"
}

ב-C# ‏(System.Management) ManagementEventWatcher ממלא את אותו תפקיד.11

using System.Management;

// מתהליך שרץ כמנהל
var watcher = new ManagementEventWatcher(
    new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"));
watcher.EventArrived += (_, e) =>
{
    var name = (string)e.NewEvent["ProcessName"];
    var pid  = (uint)e.NewEvent["ProcessID"];
    Console.WriteLine($"תהליך הופעל: {name} (PID={pid})");
};
watcher.Start();
// בסיום הניטור לא שוכחים watcher.Stop() ו-Dispose

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

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

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

7. מלכודות — ביצועים, הרשאות, 64bit, המאגר ותאריכים

7.1. SELECT * וסערת polling

שאילתת WMI היא «ספק שבונה את הערכים במקום» — היא לא בחינם. יש שני דפוסי-נגד קלאסיים.

  • שימוש ב-SELECT * מתוך הרגל. שליפת כל מאפיין של כל שורה ב-Win32_Process מנפחת בהתאם את עבודת הספק ואת ההעברה ברשת (כשמרוחק). מצמצמים שורות ב--Filter, עמודות ב--Property, ומשתמשים ב--KeyOnly אם כל מה שצריך הוא מפתחות לפעולה המשך. כולם אמצעים רשמיים שנועדו «להקטין את גודל האובייקטים ואת תעבורת הרשת».3
  • polling במרווח קצר. תכנון כמו «Get-CimInstance Win32_Process כל שנייה» מחליפים במנוי לאירוע מסעיף 6.3. גם אם חייבים סגנון polling ‏(WITHIN), מרחיבים את המרווח למה שבאמת מספיק לדרישה.

גם חזרה על -ComputerName יעד-יעד מול מכונות מרוחקות בזבזנית, כי סשן זמני נוצר בכל שאילתה — עוברים לשימוש חוזר בסשן CIM לכמה פעולות.3

דפוסי-נגד של ביצועים ולאן מחליפים אותםשימוש מתוך הרגל ב-SELECT כוכבית מצמצמים ב-Filter ו-Property וב-KeyOnly אם צריך רק מפתחות, polling במרווח קצר מחליפים במנוי לאירוע, וחזרה על ComputerName מכונה-מכונה מחליפים בשימוש חוזר בסשן CIMשימוש מתוך הרגל ב-SELECT *מצמצמים ב-Filter ו-Propertyרק מפתחות: KeyOnlypolling במרווח קצרמחליפים במנוי לאירועComputerName מכונה-מכונהשימוש חוזר בסשן CIM

איור 14: צמצום שורות, עמודות ומפתחות והחלפה במנוי לאירוע מונעים כמחצית מבעיות הביצועים של WMI.

7.2. הרשאות למנוי לאירועים

כמפורט בסעיף 6.3, מנוי למשפחת Win32_ProcessStartTrace מניח הרשאות מנהל.7 «עבד במכונת הפיתוח (הרצה כמנהל), אבל הניטור לא עובד בסביבת המשתמש הרגיל אצל הלקוח» הוא כשל קלאסי, לצד דיאלוג ההתראה של חומת האש. אם בונים ניטור ליישום עסקי שרץ כמשתמש רגיל, שוקלים להפריד את חלק הניטור לשירות Windows (שרץ כ-LocalSystem, למשל) ולחבר אותו לאפליקציה הראשית בתקשורת בין-תהליכים.

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

איור 15: מנוי שדורש הרשאות מנהל מופרד לצד השירות, וגוף האפליקציה מחובר בתקשורת בין-תהליכים.

7.3. 32bit/64bit וספקים

ב-Windows ‏64bit חלק מהספקים קיימים גם בגרסת 32bit וגם בגרסת 64bit, וכברירת מחדל הגרסה שתואמת לביטיות של הקורא עונה.12 הדוגמה הקלאסית היא ספק הרישום (StdRegProv) תחת root\default: קריאה מיישום 32bit מחזירה ערכים מצד Wow6432Node (תצוגת 32bit).12 אם «ערך הרישום שנקרא דרך WMI לא תואם למה ש-regedit מראה», זה הדבר הראשון לחשוד בו. אם צריך את התצוגה השנייה, אפשר לבקש אותה במפורש בהגדרת __ProviderArchitecture (ואם רוצים לכפות, __RequiredArchitecture) בהקשר החיבור.12 התמונה הכללית של בעיות ביטיות מכוסה גם ב«קריאה בטוחה ל-Win32 API מ-C# — מדריך מעשי ל-P/Invoke».

בחירת ספק בסביבת 64bitכברירת מחדל עונה הספק שתואם לביטיות של היישום הקורא, שאילתת רישום מיישום 32bit מקבלת ערכים מצד Wow6432Node, אבל ציון __ProviderArchitecture מבקש במפורש את התצוגה השנייה32bit64bitמה ביטיות הקורא?ספק 32bit עונהספק 64bit עונההרישום הוא ערך מצד Wow6432Nodeציון __ProviderArchitectureבקשה מפורשת לתצוגה השנייה

איור 16: כברירת מחדל עונה הצד שתואם לביטיות הקורא, ולכן יישום 32bit קורא את צד Wow6432Node.

7.4. תסמינים וטיפול כשמאגר WMI פגום

הגדרות המחלקה של WMI מאוחסנות במאגר (לא קובץ יחיד — הקבצים בתיקיית Repository יחד מתפקדים כמסד נתונים13). כשהוא הופך ללא-עקבי, מתחילות להופיע שגיאות כמו «מחלקה שאמורה להתקיים לא נמצאת» או «מרחב השמות אינו תקף», אף שמצד האפליקציה לא השתנה דבר. משתמשים ב-winmgmt.exe לאבחון ולתיקון.13

rem בדיקת עקביות (תוצאה inconsistent פירושה שיש בעיה)
winmgmt /verifyrepository

rem בדיקת עקביות, ובנייה מחדש אם יש בעיה (תוכן קריא ממוזג)
winmgmt /salvagerepository

החשוב הוא לא להפוך מחיקה או איפוס של המאגר למהלך הראשון. שגיאות שעולות דרך WMI יכולות לנבוע ממקום אחר במערכת, ו-Microsoft עצמה אומרת במפורש שמחיקת המאגר כתגובה ראשונה «עלולה לגרום לנזק למערכת או ליישומים מותקנים».13 שומרים על הסדר: בדיקה ב-/verifyrepository, ואז תיקון ב-/salvagerepository.

הליך הבירור לחוסר עקביות במאגר WMIכשעולה שגיאה כמו מחלקה שלא נמצאת מאשרים עקביות ב-verifyrepository של winmgmt, אם אין עקביות בונים מחדש ב-salvagerepository, ולא הופכים מחיקה או איפוס של המאגר למהלך הראשוןכןלאשגיאה כמו מחלקה שלא נמצאתwinmgmt /verifyrepositoryהתוצאה inconsistent?winmgmt /salvagerepositoryחשודים בגורם אחר במערכתתוכן קריא ממוזגמחיקה או איפוס של המאגרלא המהלך הראשון

איור 17: שומרים על הסדר verify ואז salvage, ולא הופכים מחיקה למהלך הראשון.

7.5. המרת פורמט תאריך DMTF

תאריכי WMI מאוחסנים כמחרוזות בפורמט DMTF שמוגדר במפרט CIM: yyyymmddHHMMSS.mmmmmm±UUU (הסיומת היא היסט מ-UTC בדקות — למשל 20260801100000.000000+540). לא חותכים ומרכיבים את הערך הגולמי בעיבוד מחרוזות; משתמשים ב-API ההמרה.

  • C# ‏(System.Management): ManagementDateTimeConverter מספק המרה בין פורמט DMTF ל-DateTime / TimeSpan.11
  • ממשקי API ממשפחת CIM ‏(Get-CimInstance / MI API): מאפייני תאריך חוזרים כבר מומרים ל-DateTime, ולכן הבעיה הזאת כלל לא מתעוררת. אפשר להשתמש ב-(Get-CimInstance Win32_OperatingSystem).LastBootUpTime ישירות כ-DateTime בחישובים.
טיפול בפורמט תאריך DMTFתאריכי WMI מאוחסנים כמחרוזת בפורמט DMTF, אם קוראים ערך גולמי ב-System.Management ממירים ב-ManagementDateTimeConverter, וב-API ממשפחת CIM חוזר DateTime שכבר הומר, לכן לא חותכים ומדביקים מחרוזות בידSystem.ManagementAPI ממשפחת CIMמחרוזת בפורמט DMTFבאיזה API נשלף?ManagementDateTimeConverterחוזר כבר כ-DateTimeהמרה ל-DateTime / TimeSpanחיתוך והדבקה בידלא משתמשים

איור 18: המרת מחרוזת DMTF מושארת ל-API ההמרה, וב-API ממשפחת CIM משתמשים ב-DateTime שכבר הומר.

8. מתי לא להשתמש ב-WMI — טבלת החלטה

WMI מצוין כ«ממשק קריאה אחיד», אבל הוא לא תמיד הבחירה המיטבית. כלל אצבע מעשי לבחירה בין כלים.

מה רוצים לעשות הכלי המתאים למה לא WMI
שליפת מידע חומרה ותצורת מערכת, שאילתות מרוחקות בלי סוכן WMI/CIM זה בדיוק מגרש הבית של WMI — אחיד יותר מלפנות ל-API ייעודי אחד-אחד
קריאה וכתיבה של הגדרות האפליקציה עצמה קריאה ישירה לרישום (Microsoft.Win32.Registry) או קובצי תצורה גישה לרישום דרך WMI היא דרך עקלקלה, והיא גם יורשת את בעיית הביטיות מסעיף 7.3
ניטור ביצועים רציף בתדירות גבוהה כמו שימוש במעבד מוני ביצועים (System.Diagnostics.PerformanceCounter וכדומה) המונים נועדו בדיוק לזה. polling של WMI במרווח קצר מפסיד גם בעומס וגם בדיוק
קריאה חד-פעמית לפונקציית מערכת, או עיבוד שצריך השהיה נמוכה Win32 API ‏(P/Invoke) ל-WMI יש תקורה של מעבר דרך COM/ספק
מנייה ותפעול של תהליכים מקומיים כשהרשאות התהליך עצמו מספיקות System.Diagnostics.Process נסגר בספרייה התקנית, עם פחות תלויות
תצורת יכולות ניהול Windows כמו חומת אש או רשת פקודות CIM ייעודיות כמו Get-NetFirewallRule סט פקודות שנבנה ומתוחזק למטרה מסוימת מדויק ובטוח יותר מחיפוש במחלקות WMI גולמיות
זיהוי שינויים בקובץ או בתיקייה FileSystemWatcher לא מכניסים WMI לתחום שכבר יש לו API ייעודי

כלל האצבע פשוט: משתמשים במנגנון הייעודי במקום שיש אחד, ושומרים את WMI/CIM לשאילתות רוחביות ולשאילתות מרוחקות. הדוגמה Get-NetFirewallRule בשורה האחרונה היא, פנימית, סט פקודות שנבנה מעל CIM — מקרה של «לקבל את התועלת של WMI/CIM בלי לגעת בו ישירות».

ציר ההחלטה בין האמצעיםבמקום שיש מנגנון ייעודי משתמשים במנגנון הייעודי, ובמקום שאין — בשאילתה רוחבית או מרוחקת — משתמשים ב-WMI וב-CIM, ופקודות CIM ייעודיות הן צורה שמקבלת את התועלת בלי לגעת ב-WMI וב-CIM ישירותישאיןיש מנגנון ייעודי?משתמשים במנגנון הייעודימשתמשים ב-WMI / CIMשאילתה רוחבית או מרוחקתפקודות CIM ייעודיותצורה שמקבלת רק את התועלת

איור 19: במקום שיש מנגנון ייעודי משתמשים בייעודי, ולשאילתה רוחבית ומרוחקת משתמשים ב-WMI/CIM.

9. סיכום

  • CIM הוא תקן התעשייה של DMTF, ו-WMI הוא המימוש של Microsoft. גם פקודות CIM של PowerShell וגם API של MI ב-C# הם נקודות כניסה מדור נוכחי שעוקבות אחרי התקן.
  • ב-PowerShell, Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent הם הנוכחיים. Get-WmiObject ופקודות WMI האחרות אינן קיימות ב-PowerShell 7, לכן סקריפטים חדשים נכתבים בצד CIM גם אם היעד הוא 5.1.
  • שאילתה מרוחקת ברירת המחדל שלה WSMan ‏(WinRM), ולכמה פעולות משתמשים שוב בסשן CIM. ליעד שבו WinRM אינו מוגדר, DCOM הוא נתיב מילוט זמין.
  • ב-C# בוחרים בין System.Management (נוח, מוכוון מקומי) ל-Microsoft.Management.Infrastructure (מוכוון מרוחק וניטור, עם מערכת הטיפוסים של פקודות CIM). שתיהן חבילות NuGet ייעודיות ל-Windows.
  • מנטרים תהליכים במנוי לאירוע, לא ב-polling. מנוי ל-Win32_ProcessStartTrace דורש הרשאות מנהל.
  • נמנעים מ-SELECT * ומ-polling במרווח קצר — מצמצמים ב--Filter / -Property / -KeyOnly. זוכרים ששאילתה מתהליך 32bit נענית על ידי ספק 32bit, שתאריכי DMTF צריכים את API ההמרה, ושמאגר פגום מטופל בסדר verify → salvage, לא במחיקה.
  • לא מכניסים WMI לתחום שכבר יש לו מנגנון ייעודי (הגדרות, מוני ביצועים, קריאות API חד-פעמיות) — שומרים את WMI/CIM לשאילתות רוחביות ולשאילתות מרוחקות. המשפט הזה מסכם את מקומו.

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

תחומי ייעוץ קשורים

KomuraSoft LLC מטפלת בבניית שליפת מידע חומרה, ניטור תהליכים ושאילתות מחשב מרוחק עם WMI/CIM לתוך יישומים עסקיים, במיגרציית סקריפטים פנימיים מבוססי Get-WmiObject לפקודות CIM, ובחקירת הבעיה מהסוג «עובד במכונת הפיתוח ונכשל בשגיאת הרשאות אצל הלקוח». אפשר ללוות את כל הנתיב מניסוי ב-PowerShell עד מימוש מלא ב-C#.

מקורות

  1. Microsoft Learn, About WMI. על כך ש-WMI הוא המימוש של Microsoft ל-WBEM (יוזמה תעשייתית לפיתוח טכנולוגיות תקן לגישה למידע ניהול בסביבה ארגונית), שמייצג יעדי ניהול באמצעות תקן התעשייה CIM ‏(Common Information Model) שפותח ומתוחזק על ידי DMTF ‏(Distributed Management Task Force); על כך ש-MI ‏(Windows Management Infrastructure) מהדור הבא תואם לחלוטין ל-WMI המסורתי; ועל כך שחיבורי WMI מרוחקים משתמשים ב-DCOM, עם WinRM מבוסס WS-Management כחלופה.  2 3 4 5

  2. Microsoft Learn, Differences between Windows PowerShell 5.1 and PowerShell 7.x. על כך שפקודות WMI v1 ‏(Register-WmiEvent / Set-WmiInstance / Invoke-WmiMethod / Get-WmiObject / Remove-WmiObject) הוסרו מ-PowerShell, ועל כך שפקודות מודול CimCmdlets ‏(WMI v2) מספקות אותה פונקציונליות עם תכונות חדשות ותחביר שעוצב מחדש.  2

  3. Microsoft Learn, Get-CimInstance (CimCmdlets). על כך שכשלא מציינים ComputerName ולא CimSession מתחברים ל-WMI המקומי בסשן COM, ושציון -ComputerName יוצר סשן זמני בפרוטוקול WsMan; על כך שחיבור דרך סשן CIM מומלץ לביצועים כשמבצעים כמה פעולות מול אותו מחשב; על כך ש--Filter הוא פסוקית where של WQL/CQL בלי מילת המפתח WHERE; על כך ש--Property ו--KeyOnly מקטינים גודל אובייקט ותעבורת רשת; על כך שמרחב השמות שברירת המחדל הוא root/CIMV2 ושפת השאילתה שברירת המחדל ‏(-QueryDialect) היא WQL; על כך שהפלט הוא Microsoft.Management.Infrastructure.CimInstance; על דוגמה לקריאת GetOwner בשילוב Invoke-CimMethod; ועל כך שהפקודה ייעודית ל-Windows.  2 3 4 5 6 7 8 9 10

  4. Microsoft Learn, New-CimSessionOption (CimCmdlets). על כך שלאפשרויות סשן CIM יש שתי קבוצות פרמטרים, ל-WsMan ול-DCOM; על כך ש--Protocol מקבל Dcom / Default / Wsman; על דוגמה להעברת אפשרות שנוצרה ב-New-CimSessionOption -Protocol Dcom אל -SessionOption של New-CimSession כדי ליצור סשן CIM ב-DCOM; ועל כך שרמת ההתחזות שברירת המחדל לסשן DCOM היא Impersonate.  2

  5. Microsoft Learn, ManagementObjectSearcher Class (System.Management). על כך שזו מחלקת הכניסה הנפוצה ביותר לשליפת מידע ניהול, ששולפת אוסף אובייקטי ניהול על בסיס שאילתת WQL שצוינה; על כך שהיא מקבלת ObjectQuery ו-ManagementScope (מרחב שמות WMI) ומחזירה ManagementObjectCollection דרך Get(); ועל כך ש-System.Management.dll מסופק כחבילת NuGet System.Management.  2 3 4

  6. Microsoft Learn, CimSession Class (Microsoft.Management.Infrastructure). על כך ש-Microsoft.Management.Infrastructure.dll מסופק כחבילת NuGet Microsoft.Management.Infrastructure; על יצירת סשן דרך Create(computerName); על הרצת שאילתה דרך QueryInstances(namespace, queryDialect, query); ועל כך שהוא מספק EnumerateInstances / GetInstance / InvokeMethod / Subscribe יחד עם גרסאות אסינכרוניות (*Async) של כל אחת, תוך מימוש IDisposable.  2 3 4 5

  7. Microsoft Learn, Register-CimIndicationEvent (CimCmdlets). על מנוי לאינדיקציה (אירוע) לפי שם מחלקה או ביטוי שאילתה ומתן שם למנוי ב--SourceIdentifier; על דוגמת מנוי ל-Win32_ProcessStartTrace, עם הערה שנדרשת הרצת PowerShell כמנהל; על דוגמה להפניה ל-ProcessName / ProcessId מתוך $Event.SourceEventArgs.NewEvent בבלוק הסקריפט של -Action; על חיבור בסשן WsMan זמני כשמציינים -ComputerName, ומקומית ב-COM כשלא; ועל שימוש ב-Unregister-Event להסרת מנוי.  2 3 4

  8. Microsoft Learn, Win32_ProcessStartTrace class. על כך שזו מחלקת אירוע שמציינת התחלת תהליך חדש, עם מאפיינים כולל ProcessName / ProcessID / ParentProcessID / SessionID / Sid; על כך שמאפיין SECURITY_DESCRIPTOR הוא המתאר שספק האירוע משתמש בו כדי לקבוע אילו משתמשים יכולים לקבל את האירוע; ועל כך שמרחב השמות הוא Root\CIMV2, ומסופק על ידי ספק מעקב הליבה (Krnlprov.dll).  2 3

  9. Microsoft Learn, Win32_LogicalDisk class. על כך ש-Win32_LogicalDisk היא מחלקה הנגזרת מ-CIM_LogicalDisk שמייצגת התקן אחסון מקומי; על ערכי DriveType (2 = נתיק, 3 = דיסק מקומי, 4 = כונן רשת, 5 = CD, וכן הלאה); על כך ש-FreeSpace / Size הם ערכי בתים מסוג uint64; על כך ש-DeviceID הוא המפתח; ועל דוגמאות שאילתת VBScript / C# שמסננות ב-DriveType = 3.  2 3 4

  10. Microsoft Learn, Installation and configuration for Windows Remote Management. על כך שמאזין WinRM אינו מוגדר כברירת מחדל, כלומר אי אפשר לשלוח או לקבל הודעות WS-Management; על כך ש-winrm quickconfig מגדיר את השירות להפעלה אוטומטית, מגדיר מאזין HTTP/HTTPS ורושם חריג חומת אש; על כך שיציאות ברירת המחדל של WinRM 2.0 הן HTTP 5985 / HTTPS 5986; על הגדרת TrustedHosts בצמצום מרבי כשאי אפשר לכונן אימות הדדי (Kerberos), למשל בקבוצת עבודה; ועל מתאר האבטחה שברירת המחדל (RootSDDL) ששולט בגישה מרוחקת למאזין, ועוד התצורה הנוספת שנדרשת כדי לאפשר למשתמשים שאינם מנהלים להשתמש בתוספי WMI.  2 3 4

  11. Microsoft Learn, System.Management Namespace. על כך שזה מרחב השמות ששואל את תשתית WMI דרך משפחת המחלקות ManagementObjectSearcher, ומטפל במנוי לאירועים דרך ManagementEventWatcher; על כך ש-WqlEventQuery מייצג שאילתת אירוע בצורת WQL; ועל כך ש-ManagementDateTimeConverter מספק מתודות המרה בין ייצוגי תאריך/שעה ומרווח זמן של DMTF ל-DateTime / TimeSpan של CLR.  2 3

  12. Microsoft Learn, Requesting WMI Data on a 64-bit Platform. על כך שכשספק קיים בגרסת 32bit ובגרסת 64bit, כברירת מחדל ספק 32bit עונה ליישומי 32bit (כולל סקריפטים) וספק 64bit עונה ליישומי 64bit; על היכולת לבקש או לכפות את גרסת הספק שאינה ברירת המחדל דרך __ProviderArchitecture (32 או 64) ו-__RequiredArchitecture בהקשר (עם WBEM_E_PROVIDER_LOAD_FAILURE אם כופים לגרסה שאינה קיימת); ועל דוגמת ספק הרישום שבה לקוח 32bit מקבל נתונים מצד HKLM\SOFTWARE\Wow6432Node.  2 3

  13. Microsoft Learn, winmgmt. על כך ש-/verifyrepository של winmgmt.exe מבצע בדיקת עקביות של מאגר WMI; על כך ש-/salvagerepository מבצע בדיקת עקביות, ואם מתגלה חוסר עקביות בונה מחדש את המאגר תוך מיזוג כל תוכן שהיה אפשר לקרוא; על כך ש-/resetrepository מחזיר את המאגר למצבו בהתקנת מערכת ראשונית; על כך שהמאגר מתפקד כמסד נתונים המורכב מהקבצים בתיקיית Repository; ועל כך ששגיאות שעולות דרך WMI לפעמים נובעות ממקום אחר במערכת, כך שיש להימנע ממחיקת המאגר כתגובה ראשונה כי היא עלולה לגרום לנזק למערכת או ליישומים מותקנים.  2 3

מאמרים עדכניים עם אותן תגיות, להעמקה בנושאים קרובים.

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

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

שאלות נפוצות

שאלות נפוצות בפניות בנושא המאמר.

מה ההבדל בין WMI ל-CIM?
CIM הוא מודל התקן התעשייתי לייצוג יעדי ניהול כמו מערכות והתקנים, שמוגדר ומתוחזק על ידי DMTF (Distributed Management Task Force). WMI הוא המימוש של Microsoft ל-WBEM, יוזמה שמשתמשת בתקן הזה, והוא מובנה ב-Windows. כלומר CIM הוא המפרט ו-WMI הוא המימוש ב-Windows. Get-CimInstance ב-PowerShell ו-Microsoft.Management.Infrastructure ב-C# נקראים CIM כי הם ממשקי API שעוקבים אחרי התקן, אבל הם מתחברים לאותה תשתית WMI. בפיתוח יום-יומי מספיק להבין ששואלים מחלקות WMI (Win32_* וכדומה) דרך ממשקי API ממשפחת CIM.
אפשר עדיין להשתמש ב-Get-WmiObject?
ב-Windows PowerShell 5.1 הוא עדיין רץ, אבל מ-PowerShell 6 ואילך (כולל PowerShell 7 הנוכחי) פקודות WMI v1 — Get-WmiObject, Invoke-WmiMethod, Register-WmiEvent, Set-WmiInstance ו-Remove-WmiObject — הוסרו ואי אפשר להריץ אותן. אותה פונקציונליות מסופקת במודול CimCmdlets (Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent וכדומה). בסקריפטים חדשים בטוח יותר לכתוב בפקודות CIM גם אם הם ירוצו תחת 5.1. כך אין צורך לשכתב את חלק ה-WMI כשמגרים אחר כך ל-PowerShell 7.
כדי לגשת ל-WMI מ-C#, להשתמש ב-System.Management או ב-Microsoft.Management.Infrastructure?
שניהם ייעודיים ל-Windows, ומה-.NET הנוכחי מביאים אותם כחבילות NuGet. System.Management הוא ה-API הקלאסי: מספיק להעביר WQL ל-ManagementObjectSearcher, והוא מספיק לבדו אם עיקר העבודה היא שליפת מידע מקומי. גם ManagementDateTimeConverter להמרת תאריכי DMTF נמצא שם. Microsoft.Management.Infrastructure (API של MI), לעומת זאת, חולק את אותה מערכת טיפוסים (CimSession / CimInstance) עם פקודות CIM של PowerShell, ומטפל באופן עקבי בשאילתות מרוחקות דרך WSMan, בגרסאות אסינכרוניות של מתודות ובמנוי לאירועים (Subscribe). אם בונים שאילתות וניטור של מחשבים מרוחקים למוצר של ממש, הבחירה ב-API של MI היא ההחלטה הסבירה.
Get-CimInstance לא מתחבר למחשב מרוחק. מה לבדוק?
קודם בודקים אם WinRM מוגדר במכונת היעד. פעולת CIM עם -ComputerName יוצרת סשן זמני בפרוטוקול WSMan (WinRM), ולכן מניחה ששירות WinRM ומאזין רצים ביעד. winrm quickconfig מבצע את תצורת ברירת המחדל (הפעלת השירות, יצירת מאזין וחריג חומת אש). יציאות ברירת המחדל הן 5985 ל-HTTP ו-5986 ל-HTTPS, לכן בודקים גם חומות אש בדרך. בסביבת קבוצת עבודה אין אימות הדדי ב-Kerberos, וייתכן שצריך לרשום את היעד ב-TrustedHosts של הלקוח. ליעד שאי אפשר בכלל להגדיר בו WinRM אפשר במקום זאת להתחבר ב-DCOM עם אפשרות שנוצרה ב-New-CimSessionOption -Protocol Dcom.
למה תאריך WMI חוזר בפורמט כמו 20260801100000.000000+540?
תאריכי WMI מאוחסנים במחרוזת שמוגדרת במפרט CIM של DMTF (yyyymmddHHMMSS.mmmmmm±UUU, והסיומת היא היסט מ-UTC בדקות). אם קוראים את הערך הגולמי עם Get-WmiObject הישן או עם System.Management, מקבלים את המחרוזת כמו שהיא. ב-C# (System.Management) מספק ManagementDateTimeConverter מתודות המרה בין פורמט DMTF ל-DateTime / TimeSpan, לכן משתמשים בהן במקום לחתוך את המחרוזת ביד. כששולפים דרך API ממשפחת CIM כמו Get-CimInstance, מאפייני תאריך כבר חוזרים מומרים ל-DateTime, ולכן הבעיה הזאת כלל לא מתעוררת.

פרופיל הכותב

עמוד היכרות עם כותב המאמר.

Go Komura

מנהל KomuraSoft LLC

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

קישורים ציבוריים

חזרה לבלוג