שימוש ב-WMI/CIM מ-C# ומ-PowerShell — מדריך מעשי לשליפת מידע חומרה, ניטור תהליכים ושאילתות מרוחקות
· Go Komura · Windows, C#, .NET, PowerShell, WMI, CIM, יישומים עסקיים, פיתוח Windows
«רוצים להציג את המספר הסידורי ואת שם הדגם של המחשב במסך של יישום עסקי.» «רוצים לנטר שטח דיסק פנוי בשרת ולהרים אזהרה.» «רוצים לזהות שתהליך מסוים הופעל.» «רוצים לשלוף במרוכז את מצב המחשבים במקום מרוחק.» — דרישות מהסוג הזה עולות שוב ושוב בפיתוח יישומים עסקיים וכלי ניהול ל-Windows. והתשובה הסטנדרטית להן היא WMI (Windows Management Instrumentation), או, בשם התקן, CIM (Common Information Model).
flowchart TB
accTitle: דרישות קלאסיות ו-WMI/CIM
accDescr: התשובה הקלאסית לדרישות הקלאסיות של יישום עסקי — הצגת מספר סידורי ושם דגם, ניטור שטח דיסק פנוי, זיהוי הפעלת תהליך ושאילתת מחשב מרוחק — היא WMI, ובשם הסטנדרטי CIM
r1["מספר סידורי ושם דגם"] --> ans["WMI (השם הסטנדרטי: CIM)"]
r2["ניטור שטח דיסק פנוי"] --> ans
r3["זיהוי הפעלת תהליך"] --> ans
r4["שאילתת מחשב מרוחק"] --> ans
איור 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 |
flowchart TB
accTitle: הקשר בין תקן CIM למימוש WMI
accDescr: תקן CIM ש-DMTF מגדיר ומתוחזק משמש במסגרת יוזמת WBEM, המימוש של Microsoft הוא WMI, MI מהדור הבא תואם לחלוטין ל-WMI המסורתי, וממשקי API ממשפחת CIM מתחברים לאותה תשתית WMI
dmtf["DMTF מגדיר ומתוחזק"] --> cim["CIM (מודל תקן תעשייתי)"]
wbem["WBEM (יוזמה תעשייתית)"] --> wmi["WMI (מימוש Microsoft)"]
cim --> wmi
wmi -.-> mi["MI (דור הבא, תאימות מלאה)"]
api["API ממשפחת CIM (PowerShell / C#)"] --> wmi
איור 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; זה לא מנגנון שיכול הכול.
flowchart TB
accTitle: מבנה שאילתת WMI
accDescr: שאילתת WQL מופנית למחלקות Win32_* במרחב השמות root/CIMV2, הספק שמספק את תוכן המחלקה פונה למערכת ההפעלה במקום ובונה ערכים, והתוצאה חוזרת
wql["שאילתה ב-WQL"] --> ns["מרחב שמות root/CIMV2"]
ns --> cls["מחלקות Win32_*"]
cls --> prov["ספק"]
prov --> osq["פנייה למערכת במקום"]
osq --> res["החזרת תוצאה"]
איור 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.
flowchart TB
accTitle: קריאת מתודה על CimInstance
accDescr: CimInstance ש-Get-CimInstance מחזיר מגיע עם מאפייני תאריך שכבר הומרו ל-DateTime, אבל בלי מתודות ישירות, לכן קריאת מתודה נעשית בהעברת המופע ל-Invoke-CimMethod
gci["Get-CimInstance"] --> inst["אובייקט CimInstance"]
inst -.-> dt["תאריכים כבר DateTime"]
inst -.-> nom["אין מתודות ישירות"]
inst --> icm["מעבירים ל-Invoke-CimMethod"]
icm --> call["קריאת מתודה"]
איור 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».
flowchart TB
accTitle: למה לכתוב סקריפט חדש ב-CIM
accDescr: סקריפט שנכתב בפקודות WMI רץ ב-5.1 אבל הוסר מ-PowerShell 6 ואילך ולכן דורש שכתוב במיגרציה, ופקודות CIM זמינות גם ב-5.1 ולכן כתיבה חדשה בצד CIM לא משאירה עלות מיגרציה
new["סקריפט שנכתב עכשיו"] --> q1{"באיזה מהם כותבים?"}
q1 -->|פקודות WMI| old["רץ ב-5.1"]
q1 -->|פקודות CIM| cur["זמין גם ב-5.1"]
old --> del["הוסר ב-PowerShell 7"]
del --> rew["שכתוב במיגרציה"]
cur --> norew["אין עלות מיגרציה"]
איור 5: כתיבה חדשה בפקודות CIM חוסכת שכתוב כשמגרים ל-PowerShell 7.
4. שאילתות מרוחקות — סשן CIM (WSMan כברירת מחדל) ואפשרות DCOM
אם לא מציינים יעד, פקודות CIM מתחברות ל-WMI המקומי ב-COM; אם מציינים -ComputerName, הן יוצרות סשן זמני בפרוטוקול WSMan (WinRM) כדי להתחבר. כשמבצעים כמה פעולות מול אותו מחשב, יצירת סשן CIM ושימוש חוזר בו עדיפה לביצועים.3
flowchart TB
accTitle: בחירת אופן החיבור של CIM
accDescr: בלי ציון מתחברים ב-COM ל-WMI המקומי, עם ComputerName נוצר סשן WSMan זמני בכל שאילתה, כמה פעולות לאותו יעד מרוויחות משימוש חוזר ב-New-CimSession, וליעד בלי WinRM יש אפשרות פרוטוקול DCOM
exec["הרצת פקודת CIM"] --> q1{"צוין ComputerName?"}
q1 -->|אין| local["חיבור COM ל-WMI מקומי"]
q1 -->|כן| q2{"כמה פעולות לאותו יעד?"}
q2 -->|חד-פעמי| temp["סשן WSMan זמני"]
q2 -->|כמה| sess["שימוש חוזר ב-New-CimSession"]
temp -.-> cost["נוצר בכל שאילתה"]
nowinrm["יעד בלי WinRM"] -.-> dcom["אפשרות פרוטוקול 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 כברירת מחדל לכל דבר שבונים מעתה.
flowchart TB
accTitle: אישור התנאים המוקדמים לשאילתה מרוחקת
accDescr: ביעד winrm quickconfig מגדיר הפעלה אוטומטית של השירות, יוצר מאזין HTTP ורושם חריג חומת אש בפעם אחת, מאזין HTTPS מוגדר בנפרד אחרי הכנת אישור, ובסביבת קבוצת עבודה לעיתים נדרש רישום ב-TrustedHosts
qc["winrm quickconfig"] --> svc["הפעלה אוטומטית של השירות"]
qc --> lis["יצירת מאזין HTTP (5985)"]
qc --> fw["חריג חומת אש"]
lis ~~~ https["מאזין HTTPS (5986)"]
https -.-> cert["מכינים אישור ומגדירים בנפרד"]
fw ~~~ wg["סביבת קבוצת עבודה"]
wg -.-> th["רישום ב-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, היא המעידה הקלאסית הראשונה כאן.
flowchart TB
accTitle: מלכודת שליפת מאפיין והמרה
accDescr: מאפיינים ב-System.Management חוזרים כ-object דרך indexer, לכן צריך לאשר את טיפוס CIM בתיעוד ולהמיר, והמרה מתוך הנחה שזה int גורמת ל-InvalidCastException
idx["שליפה ב-indexer"] --> obj["חוזר כ-object"]
obj --> chk["אישור טיפוס CIM בתיעוד"]
chk --> cast["המרה לטיפוס הנכון"]
obj -.-> wrong["המרה מתוך הנחה שזה int"]
wrong -.-> ex["InvalidCastException"]
איור 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) ולקבל את התוצאות כאובייקטים».
flowchart TB
accTitle: ניסוי ב-PowerShell והעתקה ל-C#
accDescr: פקודות CIM של PowerShell ו-API של MI ב-C# מטפלים באותו טיפוס CimInstance, לכן זרימת פיתוח שמנסה ב-PowerShell ואז מעתיקה ל-C# מתחברת באופן טבעי
trial["ניסוי ב-PowerShell"] --> gci["פקודות CIM"]
impl["מימוש מלא ב-C#"] --> mi["MI API"]
gci --> ci["אותו טיפוס CimInstance"]
mi --> ci
ci -.-> flow["ההעתקה מתחברת באופן טבעי"]
איור 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 כדי לקבל את הבסיס לניטור דיסק בלי סוכן.
flowchart TB
accTitle: הבסיס לניטור דיסק בלי סוכן
accDescr: צמצום DriveType 3 מחריג נתיקים, כונני רשת ו-CD ומשאיר רק דיסקים מקומיים, ואותו סקריפט מועבר לכל שרת דרך סשן CIM וכך נוצר בסיס לניטור דיסק בלי סוכן
scr["סקריפט שליפת שטח פנוי"] --> flt["מצמצמים ב-DriveType = 3"]
flt -.-> exc["מחריגים נתיקים וכדומה"]
scr --> ses["דרך סשן CIM"]
ses --> srvs["מעבירים לכל שרת"]
srvs --> mon["ניטור בלי סוכן"]
איור 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
sequenceDiagram
accTitle: זרימת מנוי לאירוע הפעלת תהליך
accDescr: בסשן PowerShell בהרשאות מנהל Register-CimIndicationEvent רושם מנוי, בכל הפעלת תהליך מגיע אירוע ו-Action רץ, ובסיום הניטור Unregister-Event מבטל
participant ps as סשן PowerShell
participant wmi as WMI
ps->>wmi: רישום מנוי ב-Register-CimIndicationEvent
Note over ps: הרצה בהרשאות מנהל
wmi-->>ps: אירוע מגיע בכל הפעלת תהליך
ps->>ps: הרצת -Action
ps->>wmi: ביטול ב-Unregister-Event (בסיום הניטור)
איור 11: המנוי תקף כל עוד הסשן שרשם אותו חי, והביטול נעשה כשמסיימים את הניטור.
דרך נוספת היא אירוע יצירת מופע הכללי (__InstanceCreationEvent), שניתן לשימוש עם כל מחלקה. כאן WMI עושה polling במרווח שמציינים ב-WITHIN והופך את ההפרש לאירוע, לכן את הפשרה בין מרווח הזיהוי לעומס מחליטים בעצמכם.
flowchart TB
accTitle: שני אופני מנוי לזיהוי הפעלת תהליך
accDescr: Win32_ProcessStartTrace הוא מנוי למחלקת אירוע של ספק מעקב הליבה, ו-__InstanceCreationEvent הכללי הוא מנגנון שבו WMI עושה polling במרווח WITHIN והופך הפרש לאירוע, לכן את הפשרה בין מרווח לעומס מחליטים בעצמכם
goal["זיהוי הפעלת תהליך"] --> t1["Win32_ProcessStartTrace"]
goal --> t2["__InstanceCreationEvent"]
t1 -.-> k1["מנוי למעקב ליבה"]
t2 -.-> w1["polling במרווח WITHIN"]
w1 -.-> tr["פשרה בין מרווח לעומס"]
איור 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
אם בונים זאת לרכיב ניטור קבוע, התכנון צריך לכלול גם רישום מחדש כשהמנוי נופל (בהפעלה מחדש של שירות או בשגיאה). שיקולי התכנון של «בדיקה והצגה של מצב», כולל ניטור התקנים, מכוסים ב«שיטות עבודה מומלצות לבדיקה ולהצגה של מצב התקן חיצוני».
stateDiagram-v2
accTitle: מחזור חיי המנוי בניטור קבוע
accDescr: בניטור קבוע מצב המנוי עלול להיקטע בהפעלה מחדש של שירות או בשגיאה, לכן כוללים בתכנון זיהוי של הניתוק, רישום מחדש וחזרה למנוי
s1: במנוי
s2: המנוי נקטע
s3: רישום מחדש
[*] --> s1
s1 --> s2: הפעלה מחדש של שירות או שגיאה
s2 --> s3
s3 --> s1
איור 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
flowchart TB
accTitle: דפוסי-נגד של ביצועים ולאן מחליפים אותם
accDescr: שימוש מתוך הרגל ב-SELECT כוכבית מצמצמים ב-Filter ו-Property וב-KeyOnly אם צריך רק מפתחות, polling במרווח קצר מחליפים במנוי לאירוע, וחזרה על ComputerName מכונה-מכונה מחליפים בשימוש חוזר בסשן CIM
a1["שימוש מתוך הרגל ב-SELECT *"] --> f1["מצמצמים ב-Filter ו-Property"]
f1 -.-> f2["רק מפתחות: KeyOnly"]
a2["polling במרווח קצר"] --> f3["מחליפים במנוי לאירוע"]
a3["ComputerName מכונה-מכונה"] --> f4["שימוש חוזר בסשן CIM"]
איור 14: צמצום שורות, עמודות ומפתחות והחלפה במנוי לאירוע מונעים כמחצית מבעיות הביצועים של WMI.
7.2. הרשאות למנוי לאירועים
כמפורט בסעיף 6.3, מנוי למשפחת Win32_ProcessStartTrace מניח הרשאות מנהל.7 «עבד במכונת הפיתוח (הרצה כמנהל), אבל הניטור לא עובד בסביבת המשתמש הרגיל אצל הלקוח» הוא כשל קלאסי, לצד דיאלוג ההתראה של חומת האש. אם בונים ניטור ליישום עסקי שרץ כמשתמש רגיל, שוקלים להפריד את חלק הניטור לשירות Windows (שרץ כ-LocalSystem, למשל) ולחבר אותו לאפליקציה הראשית בתקשורת בין-תהליכים.
flowchart TB
accTitle: תצורת ניטור בסביבת משתמש רגיל
accDescr: מנוי שמניח הרשאות מנהל מוצא מגוף האפליקציה שרצה כמשתמש רגיל, חלק הניטור מופרד לשירות Windows שרץ כ-LocalSystem וכדומה, והגוף מחובר אליו בתקשורת בין-תהליכים
svcm["שירות Windows לניטור"] --> subm["מנוי למעקב הפעלה"]
svcm -.-> lsm["רץ כ-LocalSystem וכדומה"]
appm["גוף האפליקציה (משתמש רגיל)"] ---|תקשורת בין-תהליכים| svcm
איור 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».
flowchart TB
accTitle: בחירת ספק בסביבת 64bit
accDescr: כברירת מחדל עונה הספק שתואם לביטיות של היישום הקורא, שאילתת רישום מיישום 32bit מקבלת ערכים מצד Wow6432Node, אבל ציון __ProviderArchitecture מבקש במפורש את התצוגה השנייה
q1{"מה ביטיות הקורא?"} -->|32bit| p32["ספק 32bit עונה"]
q1 -->|64bit| p64["ספק 64bit עונה"]
p32 -.-> wow["הרישום הוא ערך מצד Wow6432Node"]
ctx["ציון __ProviderArchitecture"] -.-> ov["בקשה מפורשת לתצוגה השנייה"]
איור 16: כברירת מחדל עונה הצד שתואם לביטיות הקורא, ולכן יישום 32bit קורא את צד Wow6432Node.
7.4. תסמינים וטיפול כשמאגר WMI פגום
הגדרות המחלקה של WMI מאוחסנות במאגר (לא קובץ יחיד — הקבצים בתיקיית Repository יחד מתפקדים כמסד נתונים13). כשהוא הופך ללא-עקבי, מתחילות להופיע שגיאות כמו «מחלקה שאמורה להתקיים לא נמצאת» או «מרחב השמות אינו תקף», אף שמצד האפליקציה לא השתנה דבר. משתמשים ב-winmgmt.exe לאבחון ולתיקון.13
rem בדיקת עקביות (תוצאה inconsistent פירושה שיש בעיה)
winmgmt /verifyrepository
rem בדיקת עקביות, ובנייה מחדש אם יש בעיה (תוכן קריא ממוזג)
winmgmt /salvagerepository
החשוב הוא לא להפוך מחיקה או איפוס של המאגר למהלך הראשון. שגיאות שעולות דרך WMI יכולות לנבוע ממקום אחר במערכת, ו-Microsoft עצמה אומרת במפורש שמחיקת המאגר כתגובה ראשונה «עלולה לגרום לנזק למערכת או ליישומים מותקנים».13 שומרים על הסדר: בדיקה ב-/verifyrepository, ואז תיקון ב-/salvagerepository.
flowchart TB
accTitle: הליך הבירור לחוסר עקביות במאגר WMI
accDescr: כשעולה שגיאה כמו מחלקה שלא נמצאת מאשרים עקביות ב-verifyrepository של winmgmt, אם אין עקביות בונים מחדש ב-salvagerepository, ולא הופכים מחיקה או איפוס של המאגר למהלך הראשון
sym["שגיאה כמו מחלקה שלא נמצאת"] --> verify["winmgmt /verifyrepository"]
verify --> q1{"התוצאה inconsistent?"}
q1 -->|כן| salvage["winmgmt /salvagerepository"]
q1 -->|לא| other["חשודים בגורם אחר במערכת"]
salvage -.-> merge["תוכן קריא ממוזג"]
del["מחיקה או איפוס של המאגר"] -.-> ng["לא המהלך הראשון"]
איור 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בחישובים.
flowchart TB
accTitle: טיפול בפורמט תאריך DMTF
accDescr: תאריכי WMI מאוחסנים כמחרוזת בפורמט DMTF, אם קוראים ערך גולמי ב-System.Management ממירים ב-ManagementDateTimeConverter, וב-API ממשפחת CIM חוזר DateTime שכבר הומר, לכן לא חותכים ומדביקים מחרוזות ביד
dmtf["מחרוזת בפורמט DMTF"] --> q1{"באיזה API נשלף?"}
q1 -->|System.Management| conv["ManagementDateTimeConverter"]
q1 -->|API ממשפחת CIM| done["חוזר כבר כ-DateTime"]
conv --> dtv["המרה ל-DateTime / TimeSpan"]
cut["חיתוך והדבקה ביד"] -.-> ng["לא משתמשים"]
איור 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 בלי לגעת בו ישירות».
flowchart TB
accTitle: ציר ההחלטה בין האמצעים
accDescr: במקום שיש מנגנון ייעודי משתמשים במנגנון הייעודי, ובמקום שאין — בשאילתה רוחבית או מרוחקת — משתמשים ב-WMI וב-CIM, ופקודות CIM ייעודיות הן צורה שמקבלת את התועלת בלי לגעת ב-WMI וב-CIM ישירות
q1{"יש מנגנון ייעודי?"} -->|יש| ded["משתמשים במנגנון הייעודי"]
q1 -->|אין| wmi["משתמשים ב-WMI / CIM"]
wmi -.-> use["שאילתה רוחבית או מרוחקת"]
cmd["פקודות CIM ייעודיות"] -.-> ben["צורה שמקבלת רק את התועלת"]
איור 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 לשאילתות רוחביות ולשאילתות מרוחקות. המשפט הזה מסכם את מקומו.
מאמרים קשורים
- איך להריץ PowerShell מ-C# (CSharp) ולקבל את התוצאות כאובייקטים
- מתכוני פקודות PowerShell מעשיים — להרחיב את הכלים הקטנים שבשימוש יום-יומי
- ההבדלים בין Windows PowerShell 5.1 ל-PowerShell 7 — מדריך מעשי למיגרציית סקריפטים פנימיים
- שיטות עבודה מומלצות לבדיקה ולהצגה של מצב התקן חיצוני - תכנון שלא מסתפק ב«מחובר»
- קריאה בטוחה ל-Win32 API מ-C# — מדריך מעשי ל-P/Invoke (DllImport / LibraryImport / CsWin32)
- מהו TPM ב-Windows? — מדריך מאויר ל«כספת שלא מוציאה מפתחות» ול-Measured Boot
תחומי ייעוץ קשורים
KomuraSoft LLC מטפלת בבניית שליפת מידע חומרה, ניטור תהליכים ושאילתות מחשב מרוחק עם WMI/CIM לתוך יישומים עסקיים, במיגרציית סקריפטים פנימיים מבוססי Get-WmiObject לפקודות CIM, ובחקירת הבעיה מהסוג «עובד במכונת הפיתוח ונכשל בשגיאת הרשאות אצל הלקוח». אפשר ללוות את כל הנתיב מניסוי ב-PowerShell עד מימוש מלא ב-C#.
מקורות
-
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
-
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
-
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 -
Microsoft Learn, New-CimSessionOption (CimCmdlets). על כך שלאפשרויות סשן CIM יש שתי קבוצות פרמטרים, ל-WsMan ול-DCOM; על כך ש-
-Protocolמקבל Dcom / Default / Wsman; על דוגמה להעברת אפשרות שנוצרה ב-New-CimSessionOption -Protocol Dcom אל -SessionOption של New-CimSession כדי ליצור סשן CIM ב-DCOM; ועל כך שרמת ההתחזות שברירת המחדל לסשן DCOM היא Impersonate. ↩ ↩2 -
Microsoft Learn, ManagementObjectSearcher Class (System.Management). על כך שזו מחלקת הכניסה הנפוצה ביותר לשליפת מידע ניהול, ששולפת אוסף אובייקטי ניהול על בסיס שאילתת WQL שצוינה; על כך שהיא מקבלת ObjectQuery ו-ManagementScope (מרחב שמות WMI) ומחזירה ManagementObjectCollection דרך Get(); ועל כך ש-System.Management.dll מסופק כחבילת NuGet System.Management. ↩ ↩2 ↩3 ↩4
-
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
-
Microsoft Learn, Register-CimIndicationEvent (CimCmdlets). על מנוי לאינדיקציה (אירוע) לפי שם מחלקה או ביטוי שאילתה ומתן שם למנוי ב-
-SourceIdentifier; על דוגמת מנוי ל-Win32_ProcessStartTrace, עם הערה שנדרשת הרצת PowerShell כמנהל; על דוגמה להפניה ל-ProcessName / ProcessId מתוך $Event.SourceEventArgs.NewEvent בבלוק הסקריפט של -Action; על חיבור בסשן WsMan זמני כשמציינים -ComputerName, ומקומית ב-COM כשלא; ועל שימוש ב-Unregister-Event להסרת מנוי. ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, Win32_ProcessStartTrace class. על כך שזו מחלקת אירוע שמציינת התחלת תהליך חדש, עם מאפיינים כולל ProcessName / ProcessID / ParentProcessID / SessionID / Sid; על כך שמאפיין SECURITY_DESCRIPTOR הוא המתאר שספק האירוע משתמש בו כדי לקבוע אילו משתמשים יכולים לקבל את האירוע; ועל כך שמרחב השמות הוא Root\CIMV2, ומסופק על ידי ספק מעקב הליבה (Krnlprov.dll). ↩ ↩2 ↩3
-
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
-
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
-
Microsoft Learn, System.Management Namespace. על כך שזה מרחב השמות ששואל את תשתית WMI דרך משפחת המחלקות ManagementObjectSearcher, ומטפל במנוי לאירועים דרך ManagementEventWatcher; על כך ש-WqlEventQuery מייצג שאילתת אירוע בצורת WQL; ועל כך ש-ManagementDateTimeConverter מספק מתודות המרה בין ייצוגי תאריך/שעה ומרווח זמן של DMTF ל-DateTime / TimeSpan של CLR. ↩ ↩2 ↩3
-
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
-
Microsoft Learn, winmgmt. על כך ש-/verifyrepository של winmgmt.exe מבצע בדיקת עקביות של מאגר WMI; על כך ש-/salvagerepository מבצע בדיקת עקביות, ואם מתגלה חוסר עקביות בונה מחדש את המאגר תוך מיזוג כל תוכן שהיה אפשר לקרוא; על כך ש-/resetrepository מחזיר את המאגר למצבו בהתקנת מערכת ראשונית; על כך שהמאגר מתפקד כמסד נתונים המורכב מהקבצים בתיקיית Repository; ועל כך ששגיאות שעולות דרך WMI לפעמים נובעות ממקום אחר במערכת, כך שיש להימנע ממחיקת המאגר כתגובה ראשונה כי היא עלולה לגרום לנזק למערכת או ליישומים מותקנים. ↩ ↩2 ↩3
מאמרים קשורים
מאמרים עדכניים עם אותן תגיות, להעמקה בנושאים קרובים.
שיטות עבודה מומלצות לרב־תהליכוניות בפועל: מהדורת .NET — מה להחליט לפני שמוסיפים תהליכונים
סיכום מעשי של כללי התכנון שמונעים מקוד רב־תהליכוני ב-.NET/C# לקרוס או להיתקע מדי פעם: לעלות על Task במקום ליצור תהליכונים בעצמכם, לצמצם מ...
Named Pipes בפועל — ה-IPC הסטנדרטי של Windows, מתכנון ועד אבטחה
מדריך מעשי ל-Named Pipes, התקשורת הסטנדרטית בין תהליכים ב-Windows. המאמר מסדר ממקורות ראשוניים את הבחירה בין מצב בתים למצב הודעות, תכנון ...
יישומים שנשברים בחזרה משינה — איך אירועי צריכת החשמל של Windows עובדים ואיך לבנות יישומים עסקיים ששורדים אותם
פתחתם את המחשב הנייד והחיבורים של היישום העסקי היו מתים — הסיבה היא תכנון שלא חשב על שינה. המאמר מכסה את זרימת ההודעות WM_POWERBROADCAST,...
רשימת בדיקה לטיפול בטוח בתהליכי ילד ביישום Windows
כדי לטפל בבטחה בתהליכי ילד ביישום Windows, תכנון הבעלות על עץ התהליכים ונוהל הסיום חשוב יותר מבחירת ה-API להפעלה. המאמר מסדר את Job Objec...
רשימת בדיקה לפני מעבר מ-.NET Framework ל-.NET
רשימת בדיקה מעשית לפני מעבר מ-.NET Framework ל-.NET, שבודקת סוג פרויקט, טכנולוגיות לא נתמכות, תלויות NuGet, סגנון SDK, WPF/WinForms, ...
נושאים קשורים
העמודים האלה ממקמים את הנושא בהקשר רחב יותר של שירותים והחלטות.
נושאים טכניים ב-Windows
שער לנושאי פיתוח Windows, חקירת תקלות וניצול נכסים קיימים.
שירותים הקשורים לנושא הזה
המאמר קשור ישירות לשירותים הבאים.
פיתוח יישומי Windows
יישומים עסקיים, חיבור התקנים וכלי תקשורת, מהגדרת הדרישות ועד הפיתוח.
שאלות נפוצות
שאלות נפוצות בפניות בנושא המאמר.
- מה ההבדל בין 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, ולכן הבעיה הזאת כלל לא מתעוררת.