WMI/CIM מ-C# ומ-PowerShell — מדריך מעשי למידע חומרה, ניטור process ושאילתות remote

· עודכן בתאריך: · · Windows, C#, .NET, PowerShell, WMI, CIM, אפליקציות עסקיות, פיתוח Windows

היסטוריית עדכונים (גרסה ראשונה, פורסמה בתאריך 1 Aug 2026)
פרסום ראשון
לצטט את המאמר הזה(DOI: 10.5281/zenodo.22175752)

מאמר זה מאוחסן בארכיון Zenodo. להלן גם ה-DOI שתמיד מפנה לגרסה האחרונה וגם ה-DOI המקובע לגרסה שאתם קוראים.

Go Komura (2026). WMI/CIM מ-C# ומ-PowerShell — מדריך מעשי למידע חומרה, ניטור process ושאילתות remote. KomuraSoft LLC. https://doi.org/10.5281/zenodo.22175752 https://comcomponent.com/he/blog/wmi-cim-practical-guide/

DOI (הגרסה האחרונה)
10.5281/zenodo.22175752
DOI (הגרסה הזו)
10.5281/zenodo.22175753

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

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

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

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

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

1. קודם כל, המסקנות

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

ב-diagram, solid line מציינת relation שתמיד מתקיים ו-dashed line מציינת relation מותנה (התנאים מופיעים בהסבר של כל relation ב-detail page). הרשימה המלאה של ה-relations (סה”כ 26, כולל evidence ו-certainty) וההגדרות של ה-concepts המרכזיים נמצאות ב-detail page של ה-knowledge map (ביפנית). Data: JSON-LD / Turtle

2. מהו WMI/CIM — תקן מול מימוש, namespaces, classes ו-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 המסורתי, ורוב ה-providers החדשים נכתבים ב-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: היררכיה שאוספת classes. לשאילתה יום-יומית משתמשים כמעט תמיד ב-root/CIMV2, שהוא גם ברירת המחדל של CIM cmdlets.3 אחרים כוללים את root\default (Registry provider ועוד).
  • class: טיפוס שמייצג יעד ניהול, כמו Win32_ComputerSystem (המחשב עצמו), Win32_LogicalDisk (כונן לוגי) או Win32_Process (process). classes ייחודיות ל-Windows שיורשות מ-classes של תקן CIM (כמו CIM_LogicalDisk) נושאות את הקידומת Win32_.9
  • provider: הרכיב שמספק את התוכן הממשי של class. כששואלים אותו, ה-provider פונה ל-OS במקום ובונה את הערכים.
  • WQL: שפת שאילתה דמוית SQL. כמו ב-SELECT Name, State FROM Win32_Service WHERE StartMode = 'Auto', מתייחסים ל-class כאל טבלה ומסננים אותה. WQL היא גם שפת השאילתה שברירת המחדל של CIM cmdlets.3

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

מבנה שאילתת WMIשאילתת WQL מופנית ל-classes מסוג Win32_* ב-namespace root/CIMV2, ה-provider שמספק את תוכן ה-class פונה ל-OS במקום ובונה ערכים, והתוצאה חוזרתשאילתה ב-WQLnamespace root/CIMV2Win32_* classesproviderפנייה ל-OS במקוםהחזרת תוצאה

איור 3: השאילתה עוברת ב-namespace, ב-class וב-provider, והערכים נוצרים במקום.

3. שימוש מ-PowerShell —‏ CIM cmdlets הם הנוכחיים, WMI cmdlets הוסרו

3.1. הבסיס: Get-CimInstance

# לפי שם class (namespace ברירת מחדל 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.

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

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

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

3.2. טבלת מיגרציה מ-WMI cmdlets ישנים

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

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

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

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

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

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

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

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

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

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

# לשאילתות חוזרות משתמשים שוב ב-CIM session
$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

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

  • WinRM חייב להיות מוגדר ביעד. winrm quickconfig מגדיר את השירות להפעלה אוטומטית, יוצר HTTP listener (פורט ברירת מחדל 5985) ורושם חריג firewall, הכול בפעם אחת.10 אם רוצים להתחבר ב-HTTPS (פורט ברירת מחדל 5986), זה לבדו לא מספיק — צריך להכין certificate של שרת ולהגדיר בנפרד HTTPS listener, למשל ב-winrm quickconfig -transport:https.10
  • הפורטים הרלוונטיים חייבים להיות פתוחים ב-firewall בדרך. עבודת התכנון והרישום של inbound rules מכוסה במאמר “Windows Firewall ואפליקציות עסקיות”.
  • אימות. בסביבת domain, Kerberos מספק mutual authentication. ב-workgroup אין Kerberos, וייתכן שצריך לרשום את היעד ב-TrustedHosts של הלקוח. מצמצמים את הרשימה ככל האפשר.10
  • הרשאות. בתצורת ברירת המחדל, שאילתות ופעולות WMI remote נעשות בחשבון ששייך לקבוצת Administrators של היעד. כדי לפתוח זאת למשתמשים רגילים צריך להגדיר הרשאות גישה גם ב-WinRM וגם ב-namespace של WMI.10
  • שימו לב של-DCOM אין פורט האזנה קבוע (הוא משתמש בפורטים דינמיים של RPC), ולכן קשה יותר לתכנן אותו מעבר ל-firewall. בטוח להניח WSMan כברירת מחדל לכל דבר שבונים מעתה.
אישור התנאים המוקדמים לשאילתה remoteביעד winrm quickconfig מגדיר הפעלה אוטומטית של השירות, יוצר HTTP listener ורושם חריג firewall בפעם אחת, HTTPS listener מוגדר בנפרד אחרי הכנת certificate, ובסביבת workgroup לעיתים נדרש רישום ב-TrustedHostswinrm quickconfigהפעלה אוטומטית של השירותיצירת HTTP listener (5985)חריג firewallHTTPS listener (5986)מכינים certificate ומגדירים בנפרדסביבת workgroupרישום ב-TrustedHosts

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

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
class כניסה ManagementObjectSearcher (מעבירים WQL לשאילתה)5 CimSession (Create → QueryInstances / InvokeMethod / Subscribe)6
מערכת טיפוסים ManagementObject / ManagementEventWatcher11 CimInstance / CimSession — אותם טיפוסים כמו CIM cmdlets3
גישה remote מבוססת DCOM מבוססת WSMan (CIM session). גרסאות async (*Async) זמינות6
מתאים ל שליפת מידע מקומי. תחזוקת נכסי קוד קיימים בניית שאילתות remote וניטור. תכנונים שמשלבים 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, לכן צריך לבדוק בתיעוד ה-class את טיפוס 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 מטפל בגישה מקומית ו-remote באותה צורה. יש בו מנייה, שאילתה, קריאת מתודה, Subscribe לאירועים וגרסאות async במקום אחד.6

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

// CimSession.Create(null) למקומי, או שם מחשב ל-remote
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 cmdlets של PowerShell מחזירים, זרימת פיתוח של “מנסים ב-PowerShell ואז מעתיקים ל-C#” מתחברת באופן טבעי. אם מתכננים את שילוב C# ו-PowerShell עצמו, ראו גם “איך להריץ PowerShell מ-C# (CSharp) ולקבל את התוצאות כאובייקטים”.

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

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

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

6.1. טבלת עזר ל-classes נפוצות

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

6.2. הקלאסיקה של ניהול נכסים: serial number, שם דגם ודיסק פנוי

# מידע דגם ו-serial number (להצלבה מול ספר נכסי מחשבים)
$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 מייצג “דיסק מקומי”, ומחריג removable (2), כונני רשת (4) ו-CD (5).9 לניטור, די להריץ את הסקריפט הזה לכל שרת דרך CIM session כדי לקבל את הבסיס לניטור דיסק בלי agent.

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

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

6.3. זיהוי process שהתחיל — event subscription

במקום “לשלוף Win32_Process במחזור polling ולהשוות הפרשים”, משתמשים ב-event subscription. הדרך הפשוטה לתפוס process שהתחיל היא Subscribe ל-Win32_ProcessStartTrace (event class של kernel trace provider, עם מאפיינים כמו ProcessName / ProcessID / ParentProcessID8).

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

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

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

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

זרימת event subscription להפעלת processב-session PowerShell בהרשאות Administrator Register-CimIndicationEvent רושם subscription, בכל process שהתחיל מגיע event ו-Action רץ, ובסיום הניטור Unregister-Event מבטלWMIsession PowerShellWMIsession PowerShellהרצה בהרשאות Administratorרישום subscription ב-Register-CimIndicationEventevent מגיע בכל process שהתחילהרצת -Actionביטול ב-Unregister-Event (בסיום הניטור)

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

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

שני אופני subscription לזיהוי process שהתחילWin32_ProcessStartTrace הוא Subscribe ל-event class של kernel trace provider, ו-__InstanceCreationEvent הכללי הוא מנגנון שבו WMI עושה polling במרווח WITHIN והופך הפרש ל-event, לכן את הפשרה בין מרווח לעומס מחליטים בעצמכםזיהוי process שהתחילWin32_ProcessStartTrace__InstanceCreationEventSubscribe ל-kernel tracepolling במרווח WITHINפשרה בין מרווח לעומס

איור 12: Subscribe ל-event class ייעודית, או instance creation event כללי עם מרווח 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;

// מ-process שרץ כ-Administrator
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($"process התחיל: {name} (PID={pid})");
};
watcher.Start();
// בסיום הניטור לא שוכחים watcher.Stop() ו-Dispose

אם בונים זאת לרכיב ניטור קבוע, התכנון צריך לכלול גם רישום מחדש כשה-subscription נופל (ב-restart של service או בשגיאה). שיקולי התכנון של “בדיקה והצגה של מצב”, כולל ניטור התקנים, מכוסים ב”שיטות עבודה מומלצות לבדיקה ולהצגה של מצב התקן חיצוני”.

מחזור חיי ה-subscription בניטור קבועבניטור קבוע מצב ה-subscription עלול להיקטע ב-restart של service או בשגיאה, לכן כוללים בתכנון זיהוי של הניתוק, רישום מחדש וחזרה ל-subscriptionrestart של service או שגיאהב-subscriptionה-subscription נקטערישום מחדש

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

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

7.1. SELECT * וסערת polling

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

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

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

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

איור 14: סינון שורות, עמודות ו-keys והחלפה ב-event subscription מונעים כמחצית מבעיות הביצועים של WMI.

7.2. הרשאות ל-event subscription

כמפורט בסעיף 6.3, Subscribe למשפחת Win32_ProcessStartTrace מניח הרשאות Administrator.7 “עבד במכונת הפיתוח (הרצה כ-Administrator), אבל הניטור לא עובד בסביבת המשתמש הרגיל אצל הלקוח” הוא כשל קלאסי, לצד דיאלוג ההתראה של ה-firewall. אם בונים ניטור לאפליקציה עסקית שרצה כמשתמש רגיל, שוקלים להפריד את חלק הניטור ל-Windows service (שרץ כ-LocalSystem, למשל) ולחבר אותו לאפליקציה הראשית ב-IPC.

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

איור 15: subscription שדורש הרשאות Administrator מופרד לצד ה-service, וגוף האפליקציה מחובר ב-IPC.

7.3. 32bit/64bit ו-providers

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

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

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

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

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

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

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

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

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

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

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

תאריכי WMI מאוחסנים כמחרוזות בפורמט DMTF שמוגדר במפרט CIM: yyyymmddHHMMSS.mmmmmm±UUU (הסיומת היא offset מ-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
שליפת מידע חומרה ותצורת מערכת, שאילתות remote בלי agent WMI/CIM זה בדיוק מגרש הבית של WMI — אחיד יותר מלפנות ל-API ייעודי אחד-אחד
קריאה וכתיבה של הגדרות האפליקציה עצמה קריאה ישירה ל-Registry (Microsoft.Win32.Registry) או קובצי תצורה גישה ל-Registry דרך WMI היא דרך עקלקלה, והיא גם יורשת את בעיית הביטיות מסעיף 7.3
ניטור ביצועים רציף בתדירות גבוהה כמו שימוש ב-CPU performance counters (System.Diagnostics.PerformanceCounter וכדומה) ה-counters נועדו בדיוק לזה. polling של WMI במרווח קצר מפסיד גם בעומס וגם בדיוק
קריאה חד-פעמית לפונקציית מערכת, או עיבוד שצריך latency נמוכה Win32 API (P/Invoke) ל-WMI יש overhead של מעבר דרך COM/provider
מנייה ותפעול של processes מקומיים כשהרשאות ה-process עצמו מספיקות System.Diagnostics.Process נסגר בספרייה התקנית, עם פחות תלויות
תצורת יכולות ניהול Windows כמו firewall או רשת CIM cmdlets ייעודיים כמו Get-NetFirewallRule סט cmdlets שנבנה ומתוחזק למטרה מסוימת מדויק ובטוח יותר מחיפוש ב-classes גולמיות של WMI
זיהוי שינויים בקובץ או בתיקייה FileSystemWatcher לא מכניסים WMI לתחום שכבר יש לו API ייעודי

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

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

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

9. סיכום

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

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

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

KomuraSoft LLC מטפלת בבניית שליפת מידע חומרה, ניטור process ושאילתות מחשב remote עם WMI/CIM לתוך אפליקציות עסקיות, במיגרציית סקריפטים פנימיים מבוססי Get-WmiObject ל-CIM cmdlets, ובחקירת הבעיה מהסוג “עובד במכונת הפיתוח ונכשל בשגיאת הרשאות אצל הלקוח”. אפשר ללוות את כל הנתיב מניסוי ב-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 remote משתמשים ב-DCOM, עם WinRM מבוסס WS-Management כחלופה. ↩ ↩2 ↩3 ↩4 ↩5

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

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

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

  5. Microsoft Learn, ManagementObjectSearcher Class (System.Management). על כך שזו class הכניסה הנפוצה ביותר לשליפת מידע ניהול, ששולפת אוסף אובייקטי ניהול על בסיס שאילתת WQL שצוינה; על כך שהיא מקבלת ObjectQuery ו-ManagementScope (WMI namespace) ומחזירה 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; על יצירת session דרך Create(computerName); על הרצת שאילתה דרך QueryInstances(namespace, queryDialect, query); ועל כך שהוא מספק EnumerateInstances / GetInstance / InvokeMethod / Subscribe יחד עם גרסאות async (*Async) של כל אחת, תוך מימוש IDisposable. ↩ ↩2 ↩3 ↩4 ↩5

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

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

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

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

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

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

  13. Microsoft Learn, winmgmt. על כך ש-/verifyrepository של winmgmt.exe מבצע בדיקת עקביות של WMI repository; על כך ש-/salvagerepository מבצע בדיקת עקביות, ואם מתגלה חוסר עקביות בונה מחדש את ה-repository תוך מיזוג כל תוכן שהיה אפשר לקרוא; על כך ש-/resetrepository מחזיר את ה-repository למצבו בהתקנת מערכת ראשונית; על כך שה-repository מתפקד כמסד נתונים המורכב מהקבצים בתיקיית Repository; ועל כך ששגיאות שעולות דרך WMI לפעמים נובעות ממקום אחר במערכת, כך שיש להימנע ממחיקת ה-repository כתגובה ראשונה כי היא עלולה לגרום לנזק למערכת או לאפליקציות מותקנות. ↩ ↩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. בפיתוח יום-יומי מספיק להבין ששואלים classes של WMI (Win32_* וכדומה) דרך API ממשפחת CIM.
אפשר עדיין להשתמש ב-Get-WmiObject?
ב-Windows PowerShell 5.1 הוא עדיין רץ, אבל מ-PowerShell 6 ואילך (כולל PowerShell 7 הנוכחי) cmdlets של WMI v1 —‏ Get-WmiObject, Invoke-WmiMethod, Register-WmiEvent, Set-WmiInstance ו-Remove-WmiObject — הוסרו ואי אפשר להריץ אותם. אותה פונקציונליות מגיעה ממודול CimCmdlets (Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent וכדומה). בסקריפטים חדשים בטוח יותר לכתוב ב-CIM cmdlets גם אם הם ירוצו תחת 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 (MI API), לעומת זאת, חולק את אותה מערכת טיפוסים (CimSession / CimInstance) עם CIM cmdlets של PowerShell, ומטפל באופן עקבי בשאילתות remote דרך WSMan, בגרסאות async של מתודות וב-Subscribe לאירועים. אם בונים שאילתות וניטור של מחשבים remote למוצר של ממש, הבחירה ב-MI API היא ההחלטה הסבירה.
Get-CimInstance לא מתחבר למחשב remote. מה לבדוק?
קודם בודקים אם WinRM מוגדר במכונת היעד. פעולת CIM עם -ComputerName יוצרת session זמני בפרוטוקול WSMan (WinRM), ולכן מניחה ששירות WinRM ו-listener רצים ביעד. winrm quickconfig מבצע את תצורת ברירת המחדל (הפעלת השירות, יצירת listener וחריג firewall). פורטים ברירת המחדל הם 5985 ל-HTTP ו-5986 ל-HTTPS, לכן בודקים גם firewall בדרך. בסביבת workgroup אין mutual authentication ב-Kerberos, וייתכן שצריך לרשום את היעד ב-TrustedHosts של הלקוח. ליעד שאי אפשר בכלל להגדיר בו WinRM אפשר במקום זאת להתחבר ב-DCOM עם option שנוצרה ב-New-CimSessionOption -Protocol Dcom.
למה תאריך WMI חוזר בפורמט כמו 20260801100000.000000+540?
תאריכי WMI מאוחסנים במחרוזת שמוגדרת במפרט CIM של DMTF (yyyymmddHHMMSS.mmmmmm±UUU, והסיומת היא offset מ-UTC בדקות). אם קוראים את הערך הגולמי עם Get-WmiObject הישן או עם System.Management, מקבלים את המחרוזת כמו שהיא. ב-C# (System.Management) מספק ManagementDateTimeConverter מתודות המרה בין פורמט DMTF ל-DateTime / TimeSpan, לכן משתמשים בהן במקום לחתוך את המחרוזת ביד. כששולפים דרך API ממשפחת CIM כמו Get-CimInstance, מאפייני תאריך כבר חוזרים מומרים ל-DateTime, ולכן הבעיה הזאת כלל לא מתעוררת.

פרופיל הכותב

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

Go Komura

מנהל KomuraSoft LLC

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

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

חזרה לבלוג