Usar WMI/CIM desde C# y PowerShell — guía práctica de inventario de hardware, supervisión de procesos y consultas remotas
· Actualizado el: · Go Komura · Windows, C#, .NET, PowerShell, WMI, CIM, Aplicaciones de negocio, Desarrollo para Windows
Historial de revisiones (primera versión, publicada el 1 Aug 2026)
- Primera publicación
Citar este artículo(DOI (archivo registrado): 10.5281/zenodo.22175746)
Los DOI siguientes remiten a versiones ya archivadas y pueden diferir del texto actual. Para citar el texto actual, utilice la URL de esta página.
Go Komura (2026). Usar WMI/CIM desde C# y PowerShell — guía práctica de inventario de hardware, supervisión de procesos y consultas remotas. KomuraSoft LLC. https://comcomponent.com/es/blog/wmi-cim-practical-guide/
- DOI (archivo registrado)
- 10.5281/zenodo.22175746
- DOI (última versión registrada)
- 10.5281/zenodo.22175747
«Quiero mostrar el número de serie y el modelo del PC». «Quiero comprobar el espacio libre en disco de un servidor». «Quiero detectar cuándo se inicia un proceso». En las aplicaciones de negocio y las herramientas de administración de Windows, WMI/CIM es lo que permite tratar este tipo de información con un único mecanismo común.
CIM es el modelo estándar para representar información de administración, y WMI es la infraestructura de administración de Windows que usa ese estándar. Los cmdlets CIM de PowerShell y las API de C# son las puertas de entrada a esa infraestructura.1
flowchart TB
accTitle: Requisitos habituales y WMI/CIM
accDescr: Mostrar el número de serie y el modelo, vigilar el espacio libre en disco, detectar el inicio de procesos y consultar PC remotos son requisitos habituales de las aplicaciones de negocio cuya respuesta estándar es WMI, que usa el estándar CIM para representar la información de administración
r1["Número de serie y modelo"] --> ans["WMI (infraestructura que usa el estándar CIM)"]
r2["Vigilancia del espacio libre en disco"] --> ans
r3["Detección del inicio de procesos"] --> ans
r4["Consulta de PC remotos"] --> ans
Figura 1: WMI/CIM es la respuesta estándar a cuatro requisitos que aparecen una y otra vez en las aplicaciones de negocio.
Lo que confunde es que hay más de una puerta de entrada. Los resultados de búsqueda mezclan el antiguo Get-WmiObject con Get-CimInstance, y en C# están tanto System.Management como Microsoft.Management.Infrastructure. Los antiguos cmdlets WMI siguen funcionando en Windows PowerShell 5.1, pero no existen en PowerShell 7.2
Este artículo está dirigido a desarrolladores de C#/PowerShell que implementan obtención de información de hardware, supervisión de procesos y consultas a PC remotos. El orden es: decidir si WMI es la herramienta adecuada, probarlo en PowerShell, comprobar los requisitos de conexión, incorporarlo a C# y, por último, redondearlo con supervisión y resolución de incidencias. Los ejemplos y las precauciones se organizan a partir de fuentes primarias vigentes a agosto de 2026.
1. Primero la conclusión: elija la puerta de entrada según el uso y el destino
Escriba el PowerShell nuevo con los cmdlets CIM y elija la API de C# según el uso. Dicho esto, no hace falta empujar hacia WMI el trabajo que ya cubre un mecanismo específico.
| Decisión o tarea | Enfoque básico | Capítulo que lo trata |
|---|---|---|
| Decidir si usar WMI | Úselo para obtención transversal de información y consultas remotas; elija un mecanismo específico para la configuración y la supervisión de rendimiento de alta frecuencia | Capítulo 2 |
| Decidir qué consultar | Elija el espacio de nombres, la clase y las propiedades, y acote el destino con WQL. El valor predeterminado del día a día es root/CIMV23 |
Capítulos 3 y 4 |
| Probarlo en PowerShell | Lea con Get-CimInstance y actúe con Invoke-CimMethod. Escriba el código nuevo del lado CIM aunque el destino sea 5.12 |
Capítulo 4 |
| Ampliarlo a equipos remotos | Tome WSMan/WinRM como base y reutilice una sesión CIM para varias operaciones contra el mismo destino. Elija DCOM cuando no quede más remedio34 | Capítulo 5 |
| Incorporarlo a C# | Use System.Management para consultas locales rápidas, y considere la API MI cuando incorpore consultas remotas o supervisión56 |
Capítulo 6 |
| Supervisar el inicio de procesos | Use una suscripción a eventos, y diseñe también los privilegios, la baja de la suscripción y el nuevo registro tras una desconexión78 | Capítulo 7 |
| Averiguar por qué va lento, devuelve un valor incorrecto o no encuentra una clase | Aísle el volumen y la frecuencia de las consultas, los bits del proveedor y la coherencia del repositorio | Capítulo 8 |
En particular, poder enumerar algo y poder suscribirse a sus eventos son dos cosas distintas. El ejemplo de suscripción a Win32_ProcessStartTrace se ejecuta con privilegios de administrador.7 Y no recurra por inercia a SELECT * ni al sondeo a intervalos cortos: acote el resultado a la información que necesita con -Filter, -Property y -KeyOnly.3
En el diagrama, una línea continua marca una relación que siempre se cumple y una línea discontinua una relación condicional (las condiciones están en la explicación de cada relación en la página de detalle). La lista completa de relaciones (26 en total, con evidencia y grado de certeza) y las definiciones de los conceptos principales están reunidas en la página de detalle del mapa de conocimiento (en japonés). Datos: JSON-LD / Turtle
2. Cuándo usar WMI/CIM y cuándo elegir un mecanismo específico
WMI es excelente como interfaz unificada de lectura, pero no siempre es la mejor respuesta. Estas son las pautas prácticas para distinguir los dos casos.
| Lo que quiere hacer | Mecanismo adecuado | Por qué no WMI |
|---|---|---|
| Obtener información de hardware y de configuración del sistema operativo, y consultas remotas sin agente | WMI/CIM | Aquí WMI está en su terreno. Es más uniforme que llamar a API específicas de una en una |
| Leer y escribir la configuración de su propia aplicación | Leer el Registro directamente (Microsoft.Win32.Registry) o un archivo de configuración |
Tocar el Registro a través de WMI es un rodeo, y arrastra el problema de bits del apartado 8.2 |
| Supervisión de rendimiento continua y de alta frecuencia, como el uso de CPU | Contadores de rendimiento (System.Diagnostics.PerformanceCounter y similares) |
Los contadores existen precisamente para esto. El sondeo WMI a intervalos cortos pierde tanto en carga como en precisión |
| Llamadas puntuales a funciones del sistema operativo, y procesamiento que necesita baja latencia | La API de Win32 (P/Invoke) | WMI lleva el coste de pasar por COM y un proveedor |
| Enumeración y control de procesos locales que ya cubren los privilegios del propio proceso | System.Diagnostics.Process |
Está autocontenido en la biblioteca estándar, así que se arrastran menos dependencias |
| Configurar funciones de administración de Windows como el firewall y la red | Cmdlets específicos basados en CIM como Get-NetFirewallRule |
Los conjuntos de cmdlets curados por tarea son más precisos y más seguros que buscar clases WMI en bruto |
| Detectar cambios en archivos y carpetas | FileSystemWatcher |
No lleve WMI a un área que ya tiene una API específica |
El principio de decisión es simple: use el mecanismo específico en las áreas que lo tienen, y use WMI/CIM para consultas transversales y remotas. La familia Get-NetFirewallRule de la tabla es, ella misma, un conjunto de cmdlets construido sobre CIM: se puede describir como obtener el beneficio de WMI/CIM sin tocarlo directamente.
flowchart TB
accTitle: El principio de decisión
accDescr: El principio de decisión es usar el mecanismo específico en las áreas que lo tienen y usar WMI y CIM para consultas transversales y remotas en las que no, mientras que los cmdlets específicos basados en CIM son una forma de obtener el beneficio sin tocar WMI y CIM directamente
q1{"¿Hay un mecanismo específico?"} -->|Sí| ded["Use el mecanismo específico"]
q1 -->|No| wmi["Use WMI / CIM"]
wmi -.-> use["Consultas transversales y remotas"]
cmd["Cmdlets específicos basados en CIM"] -.-> ben["Obtener solo el beneficio"]
Figura 2: Use el mecanismo específico donde exista, y use WMI/CIM para consultas transversales y remotas.
3. Dejar claro el mecanismo: el estándar, los espacios de nombres, las clases y WQL
3.1. CIM es el estándar, WMI es la implementación en Windows
Primero, ordene de una vez cómo se relacionan los términos.
| Término | Qué es en realidad |
|---|---|
| CIM (Common Information Model) | El modelo estándar de la industria para representar destinos de administración como sistemas, aplicaciones, redes y dispositivos. Lo define y mantiene el DMTF (Distributed Management Task Force)1 |
| WBEM (Web-Based Enterprise Management) | Una iniciativa de la industria que crea tecnologías estándar para acceder a la información de administración en entornos empresariales1 |
| WMI | La implementación de Microsoft de WBEM. Usa el estándar CIM para representar destinos de administración y está integrada en Windows1 |
| MI (Windows Management Infrastructure) | La versión de siguiente generación de WMI. Totalmente compatible con el WMI clásico, y la mayoría de los proveedores nuevos se escriben para MI1 |
flowchart TB
accTitle: Cómo se relaciona el estándar CIM con la implementación WMI
accDescr: El estándar CIM definido y mantenido por el DMTF se usa en el marco de la iniciativa WBEM, WMI es la implementación de Microsoft, la siguiente generación MI es totalmente compatible con el WMI clásico, y las API de la familia CIM se conectan todas a la misma infraestructura WMI
dmtf["Definido y mantenido por el DMTF"] --> cim["CIM (modelo estándar de la industria)"]
wbem["WBEM (iniciativa de la industria)"] --> wmi["WMI (implementación de Microsoft)"]
cim --> wmi
wmi -.-> mi["MI (siguiente generación, totalmente compatible)"]
api["API de la familia CIM (PowerShell / C#)"] --> wmi
Figura 3: CIM es la especificación y WMI es la implementación en Windows. Las API de la familia CIM se conectan todas a la misma infraestructura WMI.
3.2. Leer espacios de nombres, clases, proveedores y WQL como una sola cadena
Como desarrollador, hay cuatro piezas de estructura que hay que tener claras.
- Espacio de nombres: una jerarquía que agrupa clases. Las consultas del día a día usan casi siempre root/CIMV2, que también es el valor predeterminado de los cmdlets CIM.3 Otros incluyen
root\default(el proveedor del Registro, entre otros). - Clase: un tipo de destino de administración, como
Win32_ComputerSystem(el propio equipo),Win32_LogicalDisk(una unidad lógica) oWin32_Process(un proceso). Las clases específicas de Windows que derivan de clases estándar CIM (CIM_LogicalDisky similares) llevan el prefijoWin32_.9 - Proveedor: el componente que suministra las instancias reales de una clase. Al emitir una consulta, el proveedor pregunta al sistema operativo en el momento y produce los valores.
- WQL: un lenguaje de consulta similar a SQL. Se trata una clase como una tabla y se acota, como en
SELECT Name, State FROM Win32_Service WHERE StartMode = 'Auto'. WQL es también el lenguaje de consulta predeterminado de los cmdlets CIM.3
Poder leer información del sistema operativo y del hardware a través de un conjunto unificado de clases y un solo lenguaje de consulta: ese es el valor de WMI. No todas las clases admiten escritura u operaciones, no obstante. Las clases que tienen métodos se accionan con Invoke-CimMethod, y los cambios de propiedades escribibles se hacen con Set-CimInstance. Como muestra la tabla de correspondencia del apartado 4.1, se elige la puerta de entrada según lo que ofrezca la clase.
flowchart TB
accTitle: La estructura de una consulta WMI
accDescr: Una consulta WQL se dirige a una clase Win32 dentro del espacio de nombres root/CIMV2, el proveedor que suministra las instancias reales de la clase pregunta al sistema operativo en el momento y produce los valores, y se devuelve el resultado
wql["Consultar con WQL"] --> ns["Espacio de nombres root/CIMV2"]
ns --> cls["Clase Win32_*"]
cls --> prov["Proveedor"]
prov --> osq["Pregunta al sistema operativo en el momento"]
osq --> res["Devuelve el resultado"]
Figura 4: Una consulta sigue espacio de nombres, luego clase, luego proveedor, y los valores se producen en el momento.
4. Probarlo en PowerShell: leer, llamar a métodos e información de activos
A partir de aquí, pruébelo en PowerShell sobre Windows. Incluso al portar código antiguo, empiece por confirmar cómo se corresponden los cmdlets entre sí y cómo difieren los valores de retorno.
4.1. Escriba el código nuevo con los cmdlets CIM
En PowerShell 6 y posteriores (el PowerShell 7 actual), los siguientes cmdlets WMI v1 se han eliminado. La misma funcionalidad la ofrece el módulo CimCmdlets (WMI v2).2
| Antiguo (hasta Windows PowerShell 5.1) | Actual (cmdlets CIM) | Notas |
|---|---|---|
Get-WmiObject |
Get-CimInstance |
La idea de -Filter / -Query es la misma |
Get-WmiObject -List |
Get-CimClass |
Descubrir clases y comprobar sus definiciones |
Invoke-WmiMethod |
Invoke-CimMethod |
Los argumentos se pasan como tabla hash con -Arguments @{ } |
Register-WmiEvent |
Register-CimIndicationEvent |
Suscripción a eventos (capítulo 7) |
Set-WmiInstance |
Set-CimInstance |
Cambiar propiedades escribibles |
Remove-WmiObject |
Remove-CimInstance |
Eliminar una instancia |
Los cmdlets CIM también funcionan en Windows PowerShell 5.1, así que escribir cualquier cosa nueva del lado CIM, aunque se vaya a ejecutar en 5.1, es la forma de no dejar coste de migración. El panorama completo de ejecutar 5.1 y 7 en paralelo y migrar entre ellos se trata en «Diferencias entre Windows PowerShell 5.1 y PowerShell 7».
flowchart TB
accTitle: Por qué los scripts nuevos deben escribirse con CIM
accDescr: Un script escrito con los cmdlets WMI se ejecuta en 5.1 pero se ha eliminado en PowerShell 6 y posteriores, de modo que hay que reescribirlo al migrar, mientras que los cmdlets CIM también funcionan en 5.1, así que escribir cualquier cosa nueva del lado CIM no deja coste de migración
new["Un script nuevo"] --> q1{"¿Con cuál lo escribe?"}
q1 -->|Cmdlets WMI| old["Se ejecuta en 5.1"]
q1 -->|Cmdlets CIM| cur["También funciona en 5.1"]
old --> del["Eliminado en PowerShell 7"]
del --> rew["Reescribir al migrar"]
cur --> norew["No queda coste de migración"]
Figura 5: Escriba el código nuevo con los cmdlets CIM y no tendrá que reescribirlo al pasar a PowerShell 7.
4.2. Acote filas y columnas con Get-CimInstance
# Especificar la clase (espacio de nombres predeterminado root/CIMV2)
Get-CimInstance -ClassName Win32_OperatingSystem
# Poner solo la cláusula WHERE en -Filter (no escribir la palabra clave WHERE)
Get-CimInstance -ClassName Win32_Service -Filter "StartMode = 'Auto' AND State <> 'Running'"
# Recuperar solo las propiedades necesarias para reducir el volumen transferido
Get-CimInstance -ClassName Win32_Process -Property Name, ProcessId, CreationDate
# Usar -Query si se quiere escribir el WQL uno mismo
Get-CimInstance -Query "SELECT * FROM Win32_Process WHERE Name LIKE 'p%'"
-Filter es la propia cláusula WHERE de WQL, y -Property limita qué columnas se recuperan.3 El valor de retorno es un objeto CimInstance, y las propiedades de fecha (CreationDate, LastBootUpTime, etc.) vuelven ya convertidas a DateTime.
4.3. Llame a los métodos con Invoke-CimMethod
A diferencia del antiguo Get-WmiObject, no se llaman los métodos WMI directamente sobre el objeto recuperado, así que las llamadas a métodos pasan por Invoke-CimMethod.
flowchart TB
accTitle: Llamar a un método de un CimInstance
accDescr: El CimInstance que devuelve Get-CimInstance vuelve con las propiedades de fecha ya convertidas a DateTime, pero no es una forma sobre la que se llamen los métodos WMI directamente, así que una llamada a método se hace pasando la instancia a Invoke-CimMethod
gci["Get-CimInstance"] --> inst["Objeto CimInstance"]
inst -.-> dt["Fechas ya convertidas a DateTime"]
inst -.-> nom["Los métodos WMI van por otra puerta"]
inst --> icm["Pasarlo a Invoke-CimMethod"]
icm --> call["Llamada a método"]
Figura 6: No llame a los métodos WMI de un CimInstance directamente; haga las llamadas a método pasando la instancia a Invoke-CimMethod.
# Llamar a un método de una instancia: obtener el propietario de cada proceso
Get-CimInstance -ClassName Win32_Process -Filter "Name = 'notepad.exe'" |
Invoke-CimMethod -MethodName GetOwner
# Llamar a un método estático de la clase: iniciar un proceso
Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{ CommandLine = 'notepad.exe' }
# Inspeccionar la definición de la clase (la lista de propiedades y métodos)
Get-CimClass -ClassName Win32_Process
4.4. Elija la clase a partir de la información que quiere
| Información que quiere | Clase | Propiedades principales |
|---|---|---|
| Fabricante y modelo | Win32_ComputerSystem |
Manufacturer, Model |
| Número de serie del chasis | Win32_BIOS |
SerialNumber |
| Edición del sistema operativo y hora de arranque | Win32_OperatingSystem |
Caption, Version, LastBootUpTime |
| Espacio libre en disco | Win32_LogicalDisk |
DeviceID, FreeSpace, Size, DriveType9 |
| Estado del servicio | Win32_Service |
Name, State, StartMode |
| Lista de procesos | Win32_Process |
Name, ProcessId, CommandLine |
4.5. Un ejemplo de gestión de activos: modelo, número de serie y espacio libre en disco
# Información de modelo y número de serie (para conciliar un registro de activos de PC)
$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
}
# Espacio libre en discos locales (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 es el valor que significa «disco local», y excluye unidades extraíbles (2), unidades de red (4) y CD (5).9 Una vez cumplidos los requisitos de conexión del capítulo 5, ejecutar este script contra cada servidor a través de una sesión CIM da la base de una supervisión de disco sin agente.
flowchart TB
accTitle: La base de la supervisión de disco sin agente
accDescr: Filtrar por DriveType 3 excluye unidades extraíbles, unidades de red y CD de modo que solo quedan los discos locales, y ejecutar el mismo script contra cada servidor a través de una sesión CIM da la base de una supervisión de disco sin agente
scr["Script de obtención de espacio libre"] --> flt["Filtrar por DriveType = 3"]
flt -.-> exc["Excluye unidades extraíbles y similares"]
scr --> ses["A través de una sesión CIM"]
ses --> srvs["Ejecutarlo contra cada servidor"]
srvs --> mon["Supervisión sin agente"]
Figura 7: Ejecutar un script acotado a discos locales contra cada servidor por una sesión CIM es la base de la supervisión.
5. Ampliarlo a equipos remotos: métodos de conexión y requisitos previos
5.1. El método de conexión cambia entre local y remoto
Un cmdlet CIM al que no se le pasa -CimSession se conecta a WMI local por COM si tampoco se especifica -ComputerName, y crea una sesión temporal por el protocolo WSMan (WinRM) cuando se especifica -ComputerName. Si va a realizar varias operaciones contra el mismo equipo, crear una sesión CIM y reutilizarla rinde más.3
flowchart TB
accTitle: Elegir un método de conexión CIM
accDescr: Sin CimSession, omitir ComputerName conecta a WMI local por COM mientras que especificar ComputerName crea una sesión WSMan temporal en cada consulta, reutilizar New-CimSession rinde más para varias operaciones contra el mismo destino, y hay una opción de protocolo DCOM para destinos donde WinRM no está configurado
exec["Ejecutar sin pasar CimSession"] --> q1{"¿Está especificado ComputerName?"}
q1 -->|No| local["Conexión COM a WMI local"]
q1 -->|Sí| q2{"¿Varias operaciones en el mismo destino?"}
q2 -->|Puntual| temp["Sesión WSMan temporal"]
q2 -->|Varias| sess["Reutilizar New-CimSession"]
temp -.-> cost["Se crea en cada consulta"]
nowinrm["Destino sin WinRM configurado"] -.-> dcom["Opción de protocolo DCOM"]
Figura 8: Las consultas remotas usan WSMan de forma predeterminada, y reutilizar una sesión CIM es la práctica establecida para varias operaciones contra el mismo destino.
5.2. Prepare WinRM, el firewall, la autenticación y los privilegios
Los requisitos previos para consultar por WSMan/WinRM son los siguientes. Antes de escribir código de conexión, compruebe por separado el servicio, la ruta de red, la autenticación y los privilegios.
- WinRM debe estar configurado en el destino.
winrm quickconfiglo hace todo de una vez: poner el servicio en inicio automático, crear un agente de escucha HTTP (puerto predeterminado 5985) y registrar una excepción de firewall.10 Si quiere conectar por HTTPS (puerto predeterminado 5986), eso solo no basta: hay que preparar un certificado de servidor y configurar aparte un agente de escucha HTTPS, por ejemplo conwinrm quickconfig -transport:https.10 - Los puertos correspondientes deben estar abiertos en los firewalls del trayecto. Diseñar y registrar reglas de entrada en la práctica funciona exactamente como se trata en el artículo sobre Windows Firewall y las aplicaciones de negocio.
- Autenticación. En un entorno de dominio, Kerberos proporciona autenticación mutua. Kerberos no está disponible en un grupo de trabajo, de modo que puede hacer falta registrar el destino en la lista
TrustedHostsdel cliente. Mantenga esa lista en el mínimo imprescindible.10 - Privilegios. Con la configuración predeterminada, las consultas y operaciones WMI remotas se realizan normalmente con una cuenta que pertenece al grupo de administradores del destino. Si quiere abrirlo a usuarios estándar, hay que configurar permisos de acceso tanto en WinRM como en el espacio de nombres WMI.10
flowchart TB
accTitle: Comprobar los requisitos previos de las consultas remotas
accDescr: En el destino, winrm quickconfig pone el servicio en inicio automático, crea un agente de escucha HTTP y registra una excepción de firewall de una vez, un agente de escucha HTTPS se configura aparte tras preparar un certificado, y en un grupo de trabajo puede hacer falta el registro en TrustedHosts
qc["winrm quickconfig"] --> svc["Servicio en inicio automático"]
qc --> lis["Agente de escucha HTTP creado (5985)"]
qc --> fw["Excepción de firewall"]
lis ~~~ https["Agente de escucha HTTPS (5986)"]
https -.-> cert["Preparar un certificado y configurar aparte"]
fw ~~~ wg["Entorno de grupo de trabajo"]
wg -.-> th["Registrar solo donde haga falta"]
Figura 9: winrm quickconfig aplica la configuración predeterminada de un paso; el agente de escucha HTTPS y la autenticación de grupo de trabajo se tratan aparte.
5.3. Reutilice una sesión CIM para varias operaciones contra el mismo destino
# Para una consulta puntual, usar -ComputerName (se crea una sesión temporal cada vez)
Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName Server01, Server02
# Para consultas repetidas, reutilizar una sesión 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
5.4. Considere DCOM en destinos donde no se puede configurar WinRM
Para destinos a los que no se llega por WSMan, como equipos antiguos donde no se puede configurar WinRM, se puede elegir el protocolo DCOM.4
$dcom = New-CimSessionOption -Protocol Dcom
$session = New-CimSession -ComputerName OldServer -SessionOption $dcom
DCOM también usa puertos RPC dinámicos, lo que complica diseñar cualquier cosa que cruce un firewall. Para lo que se construya ahora, tratar WSMan como valor predeterminado es la hipótesis más segura.
Los ejemplos de sesión muestran cómo conectar. Al incorporarlo, garantice la limpieza con try / finally o similar para que se llegue a Remove-CimSession aunque una consulta falle a medias. La sesión creada en el ejemplo DCOM se libera del mismo modo.
6. Incorporarlo a C#: dos API y cómo tratan los tipos y las fechas
6.1. Elija entre las dos API según el uso
Hay dos linajes de API para usar WMI desde C#. Ambas son exclusivas de Windows.
| System.Management | Microsoft.Management.Infrastructure (API MI) | |
|---|---|---|
| Cómo se obtiene | Integrada en .NET Framework. En el .NET actual, el paquete NuGet System.Management5 | El paquete NuGet Microsoft.Management.Infrastructure6 |
| Clase de entrada | ManagementObjectSearcher (se le pasa WQL para consultar)5 |
CimSession (Create, luego QueryInstances / InvokeMethod / Subscribe)6 |
| Sistema de tipos | ManagementObject / ManagementEventWatcher11 |
CimInstance / CimSession — los mismos tipos que los cmdlets CIM3 |
| Remoto | Basado en DCOM | Basado en WSMan (sesiones CIM). Variantes asíncronas (*Async) disponibles6 |
| Dónde encaja | Obtención de información local. Mantener una base de código existente | Incorporar consultas remotas y supervisión. Diseños que también usan PowerShell |
6.2. System.Management: páselo WQL y lea según los tipos CIM
Pase el WQL como cadena y reciba la colección de resultados de Get().5
// NuGet: System.Management (solo 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"]} free {freeGb:F1} GB / total {sizeGb:F1} GB");
}
Las propiedades vuelven por el indizador como object, así que compruebe el tipo CIM en la documentación de la clase (aquí FreeSpace y Size son uint649) y haga la conversión en consecuencia. Convertir a int porque se asumió que ese era el tipo, sin comprobar, da un InvalidCastException: ese es el primer tropiezo clásico.
flowchart TB
accTitle: Recuperar propiedades y la trampa de la conversión
accDescr: Las propiedades de System.Management vuelven por el indizador como object, así que hay que comprobar el tipo CIM en la documentación de la clase antes de convertir, y convertir asumiendo que es un int da un InvalidCastException
idx["Recuperado por el indizador"] --> obj["Vuelve como object"]
obj --> chk["Comprobar el tipo CIM en la documentación"]
chk --> cast["Convertir al tipo correcto"]
obj -.-> wrong["Convertir asumiendo que es un int"]
wrong -.-> ex["InvalidCastException"]
Figura 10: Las propiedades vuelven como object, así que compruebe el tipo CIM antes de convertir.
6.3. La API MI: consultar con los mismos tipos que PowerShell
CimSession trata lo local y lo remoto del mismo modo. Enumeración, consultas, llamadas a métodos, suscripción a eventos y variantes asíncronas están todas ahí.6
// NuGet: Microsoft.Management.Infrastructure (solo Windows)
using Microsoft.Management.Infrastructure;
// CimSession.Create(null) en local; pasar un nombre de equipo para remoto
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 {free / 1024.0 / 1024 / 1024:F1} GB");
}
Como se trata el mismo CimInstance que devuelven los cmdlets CIM de PowerShell, el flujo de desarrollo «probarlo en PowerShell y luego transcribirlo a C#» encaja de forma directa. Si está diseñando la propia integración de C# con PowerShell, vea también «Ejecutar PowerShell desde C# y recibir los resultados como objetos».
flowchart TB
accTitle: Prototipar en PowerShell y transcribir a C#
accDescr: Como los cmdlets CIM de PowerShell y la API MI de C# tratan el mismo tipo CimInstance, el flujo de desarrollo de prototipar en PowerShell y luego transcribir a C# encaja de forma directa
trial["Prototipar en PowerShell"] --> gci["Cmdlets CIM"]
impl["Implementación real en C#"] --> mi["API MI"]
gci --> ci["El mismo tipo CimInstance"]
mi --> ci
ci -.-> flow["La transcripción encaja de forma directa"]
Figura 11: Los cmdlets CIM y la API MI tratan el mismo tipo CimInstance, de modo que un prototipo pasa a la implementación real.
6.4. No recorte las fechas DMTF a mano; páselas a la API de conversión
Las fechas de WMI se almacenan como cadenas en el formato DMTF de la especificación CIM, yyyymmddHHMMSS.mmmmmm±UUU (el valor final es el desplazamiento respecto a UTC en minutos; por ejemplo 20260801100000.000000+540). Deje de recortar el valor en bruto con operaciones de cadena y use una API de conversión.
- C# (System.Management):
ManagementDateTimeConverterofrece conversión en ambos sentidos entre el formato DMTF yDateTime/TimeSpan.11 - API de la familia CIM (Get-CimInstance / la API MI): las propiedades de fecha vuelven ya convertidas a
DateTime, de modo que el problema no aparece.(Get-CimInstance Win32_OperatingSystem).LastBootUpTimese puede usar en cálculos comoDateTimedirectamente.
flowchart TB
accTitle: Tratar el formato de fecha DMTF
accDescr: Las fechas de WMI se almacenan como cadenas en el formato DMTF, de modo que un valor en bruto leído por System.Management se convierte con ManagementDateTimeConverter mientras que una API de la familia CIM lo devuelve ya convertido a DateTime, y no se recorta la cadena uno mismo
dmtf["Cadena en formato DMTF"] --> q1{"¿Qué API lo recuperó?"}
q1 -->|System.Management| conv["ManagementDateTimeConverter"]
q1 -->|API de la familia CIM| done["Devuelto ya convertido a DateTime"]
conv --> dtv["Convertir a DateTime / TimeSpan"]
cut["Recortar la cadena uno mismo"] -.-> ng["No hacer esto"]
Figura 12: Deje la conversión de cadenas DMTF a la API de conversión, y con una API de la familia CIM use el DateTime que le dan.
El código de aquí muestra la forma básica de cada API. En una aplicación real también hay que tratar los fallos de recuperación y los valores no establecidos, y disponer de las colecciones de resultados, los objetos recuperados y las sesiones del modo que exija la API que use.
7. Supervisar el inicio de procesos: privilegios, suscribirse, darse de baja y volver a registrar
En lugar de «sondear Win32_Process a intervalos y comparar las diferencias», use una suscripción a eventos. Para el inicio de procesos, el enfoque más simple es suscribirse a Win32_ProcessStartTrace (una clase de evento del proveedor de seguimiento del kernel, con propiedades como ProcessName, ProcessID y ParentProcessID8).
7.1. Decida primero los privilegios de ejecución y dónde vive la supervisión
Register-CimIndicationEvent registra una suscripción por nombre de clase o consulta de eventos WQL, y el bloque de script de -Action se ejecuta cada vez que llega una indicación.7 Suscribirse a esta clase exige privilegios de administrador.7 Quién puede recibir un evento lo controla el descriptor de seguridad de la clase de evento, y un usuario estándar recibe acceso denegado.8
Las suscripciones a la familia Win32_ProcessStartTrace presuponen privilegios de administrador.7 «En el equipo de desarrollo, donde se ejecutaba como administrador, funcionaba, pero en el entorno de usuario estándar del cliente la supervisión no funciona» es un fallo tan clásico como el diálogo de notificación del firewall. Si va a incorporar supervisión a una aplicación de negocio que se ejecuta como usuario estándar, considere separar la parte de supervisión en un servicio de Windows (que se ejecute como LocalSystem o similar) y conectarla a la propia aplicación mediante comunicación entre procesos.
flowchart TB
accTitle: Un diseño de supervisión para entornos de usuario estándar
accDescr: Una suscripción que exige privilegios de administrador se extrae de la propia aplicación que se ejecuta como usuario estándar, la parte de supervisión se separa en un servicio de Windows que se ejecuta como LocalSystem o similar, y ambos se conectan mediante comunicación entre procesos
svcm["Servicio de Windows de supervisión"] --> subm["Se suscribe al seguimiento de inicio"]
svcm -.-> lsm["Se ejecuta como LocalSystem o similar"]
appm["La propia aplicación (usuario estándar)"] ---|Comunicación entre procesos| svcm
Figura 13: Separe una suscripción que necesita privilegios de administrador hacia el lado del servicio y conéctela a la aplicación mediante comunicación entre procesos.
7.2. Suscríbase en PowerShell y dése de baja cuando termine la supervisión
# Ejecutar en una sesión de PowerShell elevada
$action = {
$name = $Event.SourceEventArgs.NewEvent.ProcessName
$id = $Event.SourceEventArgs.NewEvent.ProcessID
Write-Host "Process started: $name (PID=$id)"
}
Register-CimIndicationEvent -ClassName Win32_ProcessStartTrace `
-SourceIdentifier ProcessStarted -Action $action
La suscripción está ligada a la sesión de PowerShell que la registró y, mientras siga ejecutándose con normalidad, -Action se ejecuta cada vez que se inicia un proceso. Tenga cuidado de no ejecutar el comando de baja justo a continuación de un tirón: eso solo elimina la suscripción antes de que la supervisión llegue a empezar.
Dése de baja cuando haya terminado de supervisar.
# Al terminar la supervisión: eliminar la suscripción
Unregister-Event -SourceIdentifier ProcessStarted
sequenceDiagram
accTitle: El flujo de una suscripción al evento de inicio de proceso
accDescr: Una sesión de PowerShell elevada registra una suscripción con Register-CimIndicationEvent, llega un evento cada vez que se inicia un proceso y se ejecuta Action, y la suscripción se elimina con Unregister-Event al terminar la supervisión
participant ps as sesión de PowerShell
participant wmi as WMI
ps->>wmi: Registrar la suscripción con Register-CimIndicationEvent
Note over ps: Ejecutar con privilegios de administrador
wmi-->>ps: Llega un evento cada vez que se inicia un proceso
ps->>ps: Ejecutar -Action
ps->>wmi: Eliminarla con Unregister-Event (al terminar la supervisión)
Figura 14: Una suscripción está ligada a la sesión que la registró, y se da de baja al terminar la supervisión.
7.3. El evento genérico que usa WITHIN es un sondeo
El otro enfoque es el evento genérico de creación de instancia (__InstanceCreationEvent), que vigila la creación de instancias de una clase. Aquí WMI sondea al intervalo que se da con WITHIN y convierte las diferencias en eventos, de modo que el equilibrio entre latencia de detección y carga lo fija usted.
flowchart TB
accTitle: Dos métodos de suscripción para detectar el inicio de procesos
accDescr: Win32_ProcessStartTrace es un método que se suscribe a una clase de evento del proveedor de seguimiento del kernel, mientras que el __InstanceCreationEvent genérico hace que WMI sondee al intervalo dado con WITHIN y convierta las diferencias en eventos, de modo que el equilibrio entre latencia de detección y carga lo fija usted
goal["Detectar el inicio de procesos"] --> t1["Win32_ProcessStartTrace"]
goal --> t2["__InstanceCreationEvent"]
t1 -.-> k1["Suscribirse a un seguimiento del kernel"]
t2 -.-> w1["Sondea al intervalo WITHIN"]
w1 -.-> tr["Equilibrio entre intervalo y carga"]
Figura 15: O se suscribe a una clase de evento dedicada, o usa el evento genérico de creación de instancia con un intervalo de sondeo.
# Vigilar nuevas instancias de Win32_Process sondeando a intervalos de 5 segundos
$query = "SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process'"
Register-CimIndicationEvent -Query $query -SourceIdentifier ProcPoll -Action {
Write-Host "Started: $($Event.SourceEventArgs.NewEvent.TargetInstance.Name)"
}
7.4. En C#, reciba los eventos con ManagementEventWatcher
En C# (System.Management), ManagementEventWatcher desempeña el mismo papel.11
using System.Management;
// En un proceso que se ejecuta como administrador
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 started: {name} (PID={pid})");
};
watcher.Start();
// Al terminar la supervisión, no olvide watcher.Stop() y Dispose
7.5. En una supervisión permanente, diseñe el nuevo registro tras una caída de la suscripción
Cuando lo incorpore a una supervisión permanente, incluya en el diseño el nuevo registro tras una caída de la suscripción (al reiniciar el servicio, o tras un error). El pensamiento de diseño detrás de «comprobar y mostrar el estado», incluida la supervisión de dispositivos, se trata en «Buenas prácticas para comprobar y mostrar el estado de un dispositivo externo».
stateDiagram-v2
accTitle: El ciclo de vida de la suscripción en una supervisión permanente
accDescr: En una supervisión permanente el estado suscrito puede caer al reiniciar el servicio o ante un error, de modo que el diseño tiene que incluir detectar que cayó, volver a registrar y regresar al estado suscrito
s1: Suscrito
s2: Suscripción caída
s3: Volver a registrar
[*] --> s1
s1 --> s2: Reinicio del servicio o error
s2 --> s3
s3 --> s1
Figura 16: Una supervisión permanente tiene que incluir el diseño para volver a registrar y regresar al estado suscrito cuando cae una suscripción.
8. Aislar fallos: rendimiento, bits y repositorio
Si no puede conectar, vuelva al apartado 5.2; si solo se deniega la suscripción, al 7.1; para la conversión y el tratamiento de fechas, a los apartados 6.2 y 6.4. Este capítulo separa las otras cosas con las que se tropieza a menudo: «lento», «valor incorrecto» y «clase no encontrada».
8.1. Lento: revise cuánto recupera, con qué frecuencia y las sesiones
Una consulta WMI es un trabajo en el que «el proveedor produce los valores en el momento», y no es gratis. Hay dos antipatrones clásicos.
- Recurrir a
SELECT *por inercia. Recuperar todas las instancias deWin32_Processcon todas las propiedades infla tanto el trabajo del proveedor como, en consultas remotas, la transferencia de red. Acote filas con-Filtery columnas con-Property, y use-KeyOnlysi solo quiere las claves para una operación posterior. Todos son medios oficiales de «reducir el tamaño de los objetos y el tráfico de red».3 - Sondeo a intervalos cortos. Un diseño como «
Get-CimInstance Win32_Processuna vez por segundo» debería sustituirse por la suscripción a eventos del capítulo 7. Incluso cuando de verdad hay que usar la forma de sondeo (WITHIN), ensanche el intervalo hasta el más pequeño que siga cubriendo el requisito.
Repetir -ComputerName un equipo cada vez contra destinos remotos también es bastante desperdicio. Se crea una sesión temporal en cada consulta, así que pase las operaciones múltiples a reutilizar una sesión CIM.3
flowchart TB
accTitle: Antipatrones de rendimiento y por qué sustituirlos
accDescr: Recurrir a SELECT asterisco por inercia se sustituye por acotar filas y columnas con Filter y Property y usar KeyOnly cuando solo se necesitan las claves, el sondeo a intervalos cortos se sustituye por una suscripción a eventos, y repetir ComputerName un equipo cada vez se sustituye por reutilizar una sesión CIM
a1["Recurrir a SELECT * por inercia"] --> f1["Acotar con Filter y Property"]
f1 -.-> f2["KeyOnly si solo quiere las claves"]
a2["Sondeo a intervalos cortos"] --> f3["Sustituir por una suscripción a eventos"]
a3["ComputerName un equipo cada vez"] --> f4["Reutilizar una sesión CIM"]
Figura 17: Acotar filas, columnas y claves, el método de supervisión adecuado y la reutilización de sesiones mantienen baja la carga innecesaria.
8.2. Valor incorrecto: compruebe los proveedores de 32 y 64 bits
En Windows de 64 bits, algunos proveedores existen en versión de 32 y de 64 bits, y de forma predeterminada responde el que coincide con los bits de la aplicación que llama.12 El caso clásico es el proveedor del Registro (StdRegProv) en root\default: léalo desde una aplicación de 32 bits y obtiene los valores del lado Wow6432Node (la vista de 32 bits).12 Cuando «el valor del Registro que leí por WMI es distinto de lo que muestra regedit», sospeche esto primero.
Si necesita la otra vista, puede pedirla de forma explícita especificando __ProviderArchitecture en el contexto al conectar (más __RequiredArchitecture si quiere hacerlo obligatorio).12 El panorama completo del problema de bits se trata también en «Llamar con seguridad a las API de Win32 desde C# — guía práctica de P/Invoke».
flowchart TB
accTitle: Selección de proveedor en un entorno de 64 bits
accDescr: De forma predeterminada responde el proveedor que coincide con los bits de la aplicación que llama, de modo que una consulta al Registro desde una aplicación de 32 bits recibe los valores del lado Wow6432Node, pero especificar __ProviderArchitecture permite pedir de forma explícita la otra vista
q1{"¿Cuáles son los bits de quien llama?"} -->|32 bits| p32["Responde el proveedor de 32 bits"]
q1 -->|64 bits| p64["Responde el proveedor de 64 bits"]
p32 -.-> wow["Los valores del Registro vienen de Wow6432Node"]
ctx["Especificar __ProviderArchitecture"] -.-> ov["Pedir de forma explícita la otra vista"]
Figura 18: De forma predeterminada responde el lado que coincide con los bits de quien llama, de modo que una aplicación de 32 bits lee el lado Wow6432Node.
8.3. Clase no encontrada: verifique el repositorio antes de repararlo
Las definiciones de clase de WMI se almacenan en el repositorio (no es un solo archivo: el conjunto de archivos dentro de la carpeta Repository funciona como base de datos13). Cuando se vuelve incoherente, empiezan a aparecer errores como «no se encuentra una clase que debería existir» o «espacio de nombres no válido» aunque del lado de la aplicación no haya cambiado nada.
Use winmgmt.exe para aislarlo y repararlo.13
rem Consistency check (a result of inconsistent means there is an inconsistency)
winmgmt /verifyrepository
rem Consistency check plus a rebuild if there is an inconsistency (readable content is merged)
winmgmt /salvagerepository
De lo que hay que cuidarse es de no hacer de la eliminación o la reinicialización del repositorio el primer movimiento. Los errores que afloran a través de WMI pueden originarse en otra parte del sistema operativo, y Microsoft afirma de forma explícita que hacer de la eliminación del repositorio el primer remedio «puede causar daños al sistema o a las aplicaciones instaladas».13 Conserve el orden: verificar con /verifyrepository y luego reparar con /salvagerepository.
flowchart TB
accTitle: Aislar una incoherencia del repositorio WMI
accDescr: Cuando aparecen errores como que no se encuentra una clase, compruebe la coherencia con winmgmt verifyrepository, reconstruya con salvagerepository si es incoherente, y no haga nunca de la eliminación o la reinicialización del repositorio el primer movimiento
sym["Errores como clase no encontrada"] --> verify["winmgmt /verifyrepository"]
verify --> q1{"¿El resultado es inconsistent?"}
q1 -->|Sí| salvage["winmgmt /salvagerepository"]
q1 -->|No| other["Sospechar una causa en otra parte del sistema operativo"]
salvage -.-> merge["Se combina el contenido legible"]
del["Eliminar o reinicializar el repositorio"] -.-> ng["No es el primer movimiento"]
Figura 19: Conserve el orden de verificar primero y luego recuperar, y no haga de la eliminación el primer movimiento.
9. Resumen: unir las consultas con la supervisión y la operación
WMI/CIM es una puerta de entrada común para consultar de forma transversal la información de administración de Windows. No es una herramienta para embudar en WMI también el trabajo que ya cubre una API específica.
| Etapa de la incorporación | Qué comprobar |
|---|---|
| Elegir la herramienta | Prefiera un mecanismo específico para la configuración, la supervisión de rendimiento de alta frecuencia y las operaciones puntuales del sistema operativo, y use WMI/CIM para la obtención de información y las consultas remotas |
| Probarlo en PowerShell | Escriba con los cmdlets CIM incluso para 5.1. Elija una clase en root/CIMV2 y acote filas, columnas y claves |
| Ampliarlo a equipos remotos | Deje listos los requisitos de conexión WSMan/WinRM y reutilice una sesión para varias operaciones. Considere la opción DCOM en los destinos que la necesiten |
| Pasarlo a C# | Elija entre System.Management, que encaja en las consultas locales, y la API MI, que encaja en las consultas remotas y la supervisión. Compruebe cómo se tratan los tipos y las fechas |
| Convertirlo en supervisión permanente | Compruebe los privilegios que exige Win32_ProcessStartTrace, y diseñe suscribirse, darse de baja y volver a registrar tras una desconexión como un solo flujo continuo |
| Investigar un fallo | Aísle el sondeo a intervalos cortos, los bits del proveedor y la coherencia del repositorio. No haga de la eliminación el primer remedio |
Cuando se piensa el estándar CIM y la implementación WMI, las consultas y las suscripciones a eventos, y las conexiones y los permisos de acceso como cosas distintas, queda claro qué herramienta elegir y qué comprobar. Empiece por recuperar en PowerShell la información que necesita, y lleve ese resultado hasta la implementación en C# y el diseño de operación.
Artículos relacionados
- Cómo ejecutar PowerShell desde C# (CSharp) y recibir los resultados como objetos
- Recetas prácticas de comandos de PowerShell — hacer crecer las pequeñas herramientas que se usan cada día
- Las diferencias entre Windows PowerShell 5.1 y PowerShell 7 — guía práctica para migrar scripts internos
- Buenas prácticas para comprobar y mostrar el estado de un dispositivo externo - diseñar más allá de un solo «conectado»
- Llamar con seguridad a las API de Win32 desde C# — guía práctica de P/Invoke (DllImport / LibraryImport / CsWin32)
- Qué es el TPM en Windows — guía ilustrada de la «caja fuerte que nunca deja salir las claves» y el arranque medido
Ámbitos de consulta relacionados
En KomuraSoft LLC nos ocupamos de incorporar a aplicaciones de negocio la obtención de información de hardware, la supervisión de procesos y las consultas a PC remotos basadas en WMI/CIM, de migrar a los cmdlets CIM scripts internos construidos sobre Get-WmiObject, y de investigar la clase de problema en la que «en el equipo de desarrollo funciona pero en el cliente da un error de permisos». Puede encargarnos desde el prototipo en PowerShell hasta la implementación real en C#, como un único encargo continuo.
- Desarrollo de aplicaciones para Windows
- Investigación de errores y análisis de causa raíz
- Consultoría técnica y revisión de diseño
- Contacto
Referencias
-
Microsoft Learn, About WMI. Sobre que WMI es la implementación de Microsoft de WBEM (una iniciativa de la industria que desarrolla tecnologías estándar para acceder a la información de administración en entornos empresariales), sobre que usa el estándar de la industria CIM (Common Information Model) para representar destinos de administración y sobre que CIM lo desarrolla y mantiene el DMTF (Distributed Management Task Force), sobre que la siguiente generación MI (Windows Management Infrastructure) es totalmente compatible con el WMI clásico, y sobre que las conexiones WMI remotas se hacen por DCOM, con WinRM basado en WS-Management como alternativa. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Differences between Windows PowerShell 5.1 and PowerShell 7.x. Sobre que los cmdlets WMI v1 (Register-WmiEvent / Set-WmiInstance / Invoke-WmiMethod / Get-WmiObject / Remove-WmiObject) se han eliminado de PowerShell, y sobre que los cmdlets del módulo CimCmdlets (WMI v2) ofrecen la misma funcionalidad con características nuevas y una sintaxis rediseñada. ↩ ↩2 ↩3
-
Microsoft Learn, Get-CimInstance (CimCmdlets). Sobre que, si no se especifica ComputerName ni CimSession, se conecta a WMI local con una sesión COM y, si se especifica -ComputerName, se crea una sesión temporal por el protocolo WsMan; sobre que se recomienda una conexión de sesión CIM por rendimiento al realizar varias operaciones contra el mismo equipo; sobre que -Filter es una cláusula where de WQL/CQL que no incluye la palabra clave WHERE; sobre que -Property y -KeyOnly reducen el tamaño de los objetos y el tráfico de red; sobre que el espacio de nombres predeterminado es root/CIMV2 y el dialecto de consulta predeterminado (-QueryDialect) es WQL; sobre que la salida es Microsoft.Management.Infrastructure.CimInstance; sobre el ejemplo de llamada a GetOwner combinado con Invoke-CimMethod; y sobre que el cmdlet es exclusivo de Windows. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10
-
Microsoft Learn, New-CimSessionOption (CimCmdlets). Sobre que las opciones de sesión CIM tienen dos conjuntos de parámetros, uno para WsMan y otro para DCOM; sobre que -Protocol acepta Dcom / Default / Wsman; sobre el ejemplo que pasa una opción creada con New-CimSessionOption -Protocol Dcom al parámetro -SessionOption de New-CimSession para crear una sesión CIM DCOM; y sobre que el nivel de suplantación predeterminado de una sesión DCOM es Impersonate. ↩ ↩2
-
Microsoft Learn, ManagementObjectSearcher Class (System.Management). Sobre que esta es la clase de entrada más habitual para recuperar información de administración, que recupera una colección de objetos de administración a partir de una consulta WQL especificada; sobre que toma un ObjectQuery y un ManagementScope (un espacio de nombres WMI) y devuelve un ManagementObjectCollection desde Get(); y sobre que System.Management.dll se ofrece como el paquete NuGet System.Management. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, CimSession Class (Microsoft.Management.Infrastructure). Sobre que Microsoft.Management.Infrastructure.dll se ofrece como el paquete NuGet Microsoft.Management.Infrastructure; sobre crear una sesión con Create(computerName); sobre ejecutar una consulta con QueryInstances(namespace, queryDialect, query); y sobre que la clase ofrece EnumerateInstances / GetInstance / InvokeMethod / Subscribe junto con la variante asíncrona de cada uno (*Async) e implementa IDisposable. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Register-CimIndicationEvent (CimCmdlets). Sobre suscribirse a indicaciones (eventos) por nombre de clase o expresión de consulta y nombrar la suscripción con -SourceIdentifier; sobre el ejemplo de suscripción a Win32_ProcessStartTrace y la nota de que ejecutarlo exige ejecutar PowerShell como administrador; sobre el ejemplo que referencia ProcessName / ProcessId desde $Event.SourceEventArgs.NewEvent dentro del bloque de script -Action; sobre crear una sesión WsMan temporal cuando se especifica -ComputerName y conectar en local por COM cuando no; y sobre usar Unregister-Event para eliminar una suscripción. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Win32_ProcessStartTrace class. Sobre que esta es una clase de evento que indica el inicio de un proceso nuevo y tiene propiedades como ProcessName / ProcessID / ParentProcessID / SessionID / Sid; sobre que la propiedad SECURITY_DESCRIPTOR es el descriptor con el que el proveedor de eventos determina qué usuarios pueden recibir el evento; y sobre que la clase vive en el espacio de nombres Root\CIMV2 y la suministra el proveedor de seguimiento del kernel (Krnlprov.dll). ↩ ↩2 ↩3
-
Microsoft Learn, Win32_LogicalDisk class. Sobre que Win32_LogicalDisk es una clase derivada de CIM_LogicalDisk que representa un dispositivo de almacenamiento local; sobre los valores de DriveType (2 = extraíble, 3 = disco local, 4 = unidad de red, 5 = CD, etc.); sobre que FreeSpace / Size son valores uint64 en bytes; sobre que DeviceID es la clave; y sobre los ejemplos de consulta en VBScript y C# que filtran con DriveType = 3. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Installation and configuration for Windows Remote Management. Sobre que de forma predeterminada no hay configurado ningún agente de escucha de WinRM, de modo que no se pueden enviar ni recibir mensajes WS-Management; sobre que winrm quickconfig pone el servicio en inicio automático, configura agentes de escucha HTTP/HTTPS y registra una excepción de firewall; sobre que los puertos predeterminados de WinRM 2.0 son HTTP 5985 / HTTPS 5986; sobre configurar TrustedHosts lo más estrecho posible cuando no se puede establecer autenticación mutua (Kerberos), como en un grupo de trabajo; y sobre el descriptor de seguridad predeterminado (RootSDDL) que controla el acceso remoto al agente de escucha y la configuración adicional necesaria para que usuarios que no son administradores usen el complemento WMI. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, System.Management Namespace. Sobre que este es el espacio de nombres que consulta la infraestructura WMI a través de la familia de clases ManagementObjectSearcher y se suscribe a eventos con ManagementEventWatcher; sobre que WqlEventQuery representa una consulta de eventos en forma WQL; y sobre que ManagementDateTimeConverter ofrece métodos para convertir entre fechas e intervalos DMTF y DateTime / TimeSpan del CLR. ↩ ↩2 ↩3
-
Microsoft Learn, Requesting WMI Data on a 64-bit Platform. Sobre que, donde existen versiones de 32 y de 64 bits de un proveedor, de forma predeterminada el proveedor de 32 bits responde a las aplicaciones de 32 bits (incluidos los scripts) y el de 64 bits a las de 64 bits; sobre que los valores de contexto __ProviderArchitecture (32 o 64) y __RequiredArchitecture permiten pedir y forzar el proveedor no predeterminado (con WBEM_E_PROVIDER_LOAD_FAILURE si la versión pedida no existe cuando se fuerza); y sobre el ejemplo del proveedor del Registro en el que un cliente de 32 bits recibe datos del lado HKLM\SOFTWARE\Wow6432Node. ↩ ↩2 ↩3
-
Microsoft Learn, winmgmt. Sobre que /verifyrepository de winmgmt.exe realiza una comprobación de coherencia del repositorio WMI; sobre que /salvagerepository realiza una comprobación de coherencia y reconstruye el repositorio cuando se detecta una incoherencia, combinando el contenido que pudo leer; sobre que /resetrepository lo devuelve al estado de la instalación inicial del sistema operativo; sobre que el repositorio es un conjunto de archivos dentro de la carpeta Repository que funciona como base de datos; y sobre que los errores que afloran a través de WMI a veces se originan en otra parte del sistema operativo, de modo que no hay que eliminar el repositorio como primer remedio porque puede causar daños al sistema o a las aplicaciones instaladas. ↩ ↩2 ↩3
Artículos relacionados
Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.
Cómo ejecutar PowerShell desde C# (CSharp) y recibir los resultados como objetos
Explica, con enfoque práctico, cómo iniciar PowerShell desde C# y recibir los resultados como PSObject en vez de cadenas: PowerShell SDK,...
Time Travel Debugging — Grabar y rebobinar los errores que no se reproducen en aplicaciones de larga duración
Un error que aparece una vez al mes deja en el volcado de memoria solo el resultado. Grabe y rebobine la ejecución con Time Travel Debugg...
Por qué se rompen los argumentos — Las reglas de los argumentos de línea de comandos de Windows
Windows pasa a CreateProcess una sola cadena que el receptor divide. Cubre las reglas de CommandLineToArgvW, el CRT y .NET, ArgumentList ...
Fin del mantenimiento de los controladores de impresora de Windows — Cómo deben preparar las aplicaciones empresariales la impresión de informes y etiquetas
Microsoft retira de forma gradual los controladores de impresora v3/v4. Qué elimina Windows protected print mode y cómo inventariar y pre...
Buenas prácticas de multithreading en la práctica: edición .NET — qué decidir antes de aumentar los hilos
Evitar que los hilos de .NET/C# se caigan o se cuelguen: apoyarse en Task, reducir el estado mutable compartido, disciplina de bloqueos, ...
Temas relacionados
Estas páginas sitúan el tema en un contexto más amplio de servicios y decisiones.
Temas técnicos de Windows
Portal sobre desarrollo de Windows, investigación de fallos y aprovechamiento de activos existentes.
Servicios relacionados con este tema
El artículo está directamente relacionado con los siguientes servicios.
Desarrollo de aplicaciones para Windows
Aplicaciones empresariales, integración de dispositivos y herramientas de comunicación, de los requisitos al desarrollo.
Preguntas frecuentes
Preguntas habituales en las consultas sobre el tema del artículo.
- ¿Cuál es la diferencia entre WMI y CIM?
- CIM es el modelo estándar de la industria para representar destinos de administración como sistemas y dispositivos, definido y mantenido por el DMTF (Distributed Management Task Force). WMI es la implementación de Microsoft de WBEM, una iniciativa que usa ese estándar, y está integrada en Windows. Es decir, CIM es la especificación y WMI es la implementación en Windows. Get-CimInstance de PowerShell y Microsoft.Management.Infrastructure de C# se llaman CIM porque son API que siguen ese estándar, pero se conectan a la misma infraestructura de WMI. En el desarrollo diario basta con entenderlo como consultar clases de WMI (Win32_* y similares) a través de las API de la familia CIM.
- ¿Ya no se puede usar Get-WmiObject?
- Sigue funcionando en Windows PowerShell 5.1, pero a partir de PowerShell 6 (el PowerShell 7 actual) se han eliminado los cmdlets WMI v1 Get-WmiObject, Invoke-WmiMethod, Register-WmiEvent, Set-WmiInstance y Remove-WmiObject, y no se pueden ejecutar. La misma funcionalidad la ofrece el módulo CimCmdlets (Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent, entre otros). Al escribir scripts nuevos, lo más seguro es escribirlos con los cmdlets CIM aunque vayan a ejecutarse en 5.1. Así no hay que reescribir la parte de WMI al pasar a PowerShell 7.
- Para usar WMI desde C#, ¿hay que elegir System.Management o Microsoft.Management.Infrastructure?
- Ambas son exclusivas de Windows y, desde el .NET actual, se incorporan como paquetes NuGet. System.Management es la API clásica, usable con solo pasar WQL a un ManagementObjectSearcher, y basta si lo principal es obtener información local. También incluye ManagementDateTimeConverter, que convierte fechas DMTF. Microsoft.Management.Infrastructure (la API MI), en cambio, comparte el mismo sistema de tipos (CimSession / CimInstance) que los cmdlets CIM de PowerShell, y trata de forma coherente las consultas remotas por WSMan, las variantes asíncronas de los métodos y la suscripción a eventos (Subscribe). Si va a incorporar de verdad consultas y supervisión de PC remotos, elegir la API MI es lo razonable.
- Get-CimInstance no se conecta a un PC remoto. ¿Qué hay que comprobar?
- Primero compruebe si WinRM está configurado en el equipo de destino. Una operación CIM que especifica -ComputerName crea una sesión temporal por el protocolo WSMan (WinRM), así que presupone que el servicio WinRM y un agente de escucha están en marcha en el destino. winrm quickconfig aplica la configuración predeterminada: iniciar el servicio, crear un agente de escucha y añadir una excepción de firewall. Los puertos predeterminados son 5985 para HTTP y 5986 para HTTPS, así que compruebe también los firewalls del trayecto. En un grupo de trabajo no hay autenticación mutua por Kerberos, de modo que puede hacer falta registrar el destino en TrustedHosts del cliente. Si de ningún modo se puede configurar WinRM en el destino, se puede conectar por DCOM con una opción creada con New-CimSessionOption -Protocol Dcom.
- ¿Por qué una fecha de WMI vuelve en un formato como 20260801100000.000000+540?
- Las fechas de WMI se almacenan en el formato de cadena definido por la especificación CIM del DMTF (yyyymmddHHMMSS.mmmmmm±UUU, donde el valor final es el desplazamiento respecto a UTC en minutos). Si lee el valor en bruto con el antiguo Get-WmiObject o con System.Management, obtiene esa cadena tal cual. En C# (System.Management), ManagementDateTimeConverter ofrece métodos para convertir entre el formato DMTF y DateTime / TimeSpan, así que úselos en lugar de recortar la cadena a mano. Tenga en cuenta que, al recuperar datos con una API de la familia CIM como Get-CimInstance, las propiedades de fecha ya vuelven convertidas a DateTime, de modo que este problema no aparece.
Perfil del autor
Página de presentación del autor del artículo.
Go Komura
Representante de KomuraSoft LLC
Especializado en desarrollo de software para Windows, consultoría técnica e investigación de fallos, sobre todo en proyectos con sistemas existentes y errores difíciles de reproducir.