Usar WMI/CIM desde C# y PowerShell ── Guía práctica de obtención de información de hardware, monitorización de procesos y consultas remotas
· Actualizado el: · Go Komura · Windows, C#, .NET, PowerShell, WMI, CIM, Aplicaciones empresariales, Desarrollo en Windows
«Quiero mostrar el número de serie y el modelo del PC en la pantalla de la aplicación empresarial», «quiero monitorizar el espacio libre en disco del servidor y avisar cuando escasee», «quiero detectar que se ha iniciado un proceso concreto», «quiero consultar de forma centralizada el estado de PC ubicados en otro lugar» ── en el desarrollo de aplicaciones empresariales y herramientas de administración para Windows, este tipo de solicitudes son habituales. Y la respuesta habitual a ellas es WMI (Windows Management Instrumentation), o, dicho con su nombre estándar, CIM (Common Information Model).
flowchart TB
accTitle: Solicitudes habituales y WMI/CIM
accDescr: La respuesta habitual a las solicitudes típicas de las aplicaciones empresariales, mostrar el número de serie y el modelo, monitorizar el espacio libre en disco, detectar el inicio de procesos y consultar PC remotos, es WMI, cuyo nombre estándar es CIM
r1["Número de serie y modelo"] --> ans["WMI(cuyo nombre estándar es CIM)"]
r2["Monitorizar el espacio libre en disco"] --> ans
r3["Detectar el inicio de procesos"] --> ans
r4["Consultar PC remotos"] --> ans
Figura 1: WMI/CIM es la respuesta habitual a las cuatro solicitudes típicas de las aplicaciones empresariales.
Lo complicado es que la información sobre WMI mezcla lo antiguo y lo nuevo. Al buscar, conviven artículos de hace diez años que usan Get-WmiObject con artículos que usan Get-CimInstance, y en el lado de C# también hay dos líneas: System.Management y Microsoft.Management.Infrastructure. Es difícil distinguir cuál es la forma actual de escribirlo y cuál es «todavía funciona, pero no se elige para código nuevo». De hecho, Get-WmiObject no existe en PowerShell 7, y el problema suele aflorar de repente al migrar scripts internos escritos para 5.1.
Este artículo está dirigido a desarrolladores de C#/PowerShell que implementan la obtención de información de hardware, la monitorización de procesos y la consulta de PC remotos en aplicaciones empresariales. Organiza, con base en fuentes primarias vigentes en agosto de 2026, desde la comprensión mínima de la estructura de WMI/CIM hasta los cmdlets CIM de PowerShell, las dos API de C#, recetas prácticas de uso habitual, las trampas de rendimiento, permisos y 64 bits, y el criterio para decidir «cuándo no conviene usar WMI».
1. Conclusión principal
- CIM es el estándar de la industria para la información de administración definido por el DMTF, y WMI es su implementación de Microsoft. Las API de la familia «CIM» de PowerShell y C# son las API de la generación actual que siguen ese estándar, y se conectan a la misma infraestructura de WMI. 1
- En PowerShell, lo actual son los cmdlets CIM (Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent). Los antiguos cmdlets WMI (los cinco, entre ellos Get-WmiObject) se eliminaron a partir de PowerShell 6 y no funcionan en PowerShell 7. 2
- El espacio de nombres predeterminado es root/CIMV2, y la forma básica de las consultas diarias es filtrar con WQL las clases Win32_* que hay ahí. 3
- WSMan (WinRM) es el predeterminado para las consultas remotas. Al indicar
-ComputerNamese crea una sesión temporal WSMan. Si se va a consultar varias veces al mismo destino, lo habitual por rendimiento es reutilizar una sesión CIM (New-CimSession), y para destinos antiguos donde no se puede configurar WinRM existe la opción del protocolo DCOM. 34 - En C# hay dos líneas: System.Management (ManagementObjectSearcher) y Microsoft.Management.Infrastructure (CimSession). Ambas son exclusivas de Windows y, en el .NET actual, se instalan desde NuGet. Si se va a hacer en serio la parte remota o de monitorización, la API MI, que comparte el sistema de tipos con los cmdlets CIM, es la más adecuada. 56
- Detecte el inicio de procesos mediante suscripción a eventos, no con sondeo (polling). La suscripción a
Win32_ProcessStartTracedebe ejecutarse con privilegios de administrador. 78 - No use
SELECT *por comodidad. Filtrar los datos a transferir con-Filter/-Property/-KeyOnlypreviene la mitad de los problemas de rendimiento de WMI. 3 - WMI no es una solución universal. Para la monitorización de rendimiento de alta frecuencia, la lectura y escritura de la configuración de la propia aplicación o las llamadas puntuales a funciones del sistema operativo, son más adecuados los contadores de rendimiento, el registro, la API de Win32 o los cmdlets dedicados (tabla de decisión del capítulo 8).
2. Qué es WMI/CIM ── Estándar e implementación, espacios de nombres, clases y WQL
Primero, aclaremos de una vez la relación entre los términos.
| Término | Qué es |
|---|---|
| CIM (Common Information Model) | Modelo estándar de la industria para representar objetos administrados, como sistemas, aplicaciones, redes y dispositivos. Definido y mantenido por el DMTF (Distributed Management Task Force)1 |
| WBEM (Web-Based Enterprise Management) | Iniciativa de la industria que crea la tecnología estándar para acceder a la información de administración en entornos empresariales1 |
| WMI | Implementación de Microsoft de WBEM. Representa los objetos administrados usando el estándar CIM y viene integrado en Windows1 |
| MI (Windows Management Infrastructure) | Versión de próxima generación de WMI. Totalmente compatible con el WMI tradicional; la mayoría de los proveedores nuevos están escritos en MI1 |
flowchart TB
accTitle: Relación entre el estándar CIM y la implementación WMI
accDescr: El estándar CIM, definido y mantenido por el DMTF, se usa dentro del marco de la iniciativa WBEM, su implementación de Microsoft es WMI, la versión de próxima generación MI es totalmente compatible con el WMI tradicional, y las API de la familia CIM se conectan a la misma infraestructura de 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(próxima generación, totalmente compatible)"]
api["API de la familia CIM(PowerShell / C#)"] --> wmi
Figura 2: CIM es la especificación, WMI es su implementación en Windows. Las API de la familia CIM se conectan a la misma infraestructura de WMI.
Como desarrollador, hay cuatro elementos de la estructura que conviene tener claros.
- Espacio de nombres (namespace): es la jerarquía que agrupa las clases. En las consultas diarias se usa casi siempre root/CIMV2, que también es el predeterminado de los cmdlets CIM. 3 También existen otros, como
root\default(por ejemplo, el proveedor del registro). - Clase: es el tipo del objeto administrado, como
Win32_ComputerSystem(el equipo en sí),Win32_LogicalDisk(una unidad lógica) oWin32_Process(un proceso). Las clases específicas de Windows que heredan de una clase del estándar CIM (comoCIM_LogicalDisk) llevan el prefijoWin32_. 9 - Proveedor: es el componente que aporta la entidad real de la clase. Al consultar, el proveedor pregunta al sistema operativo en el momento y genera los valores.
- WQL: es un lenguaje de consulta similar a SQL. Trata la clase como si fuera una tabla y filtra, por ejemplo, con
SELECT Name, State FROM Win32_Service WHERE StartMode = 'Auto'. El lenguaje de consulta predeterminado de los cmdlets CIM también es WQL. 3
flowchart TB
accTitle: Estructura de una consulta WMI
accDescr: La consulta WQL se dirige a las clases Win32_* dentro del espacio de nombres root/CIMV2, el proveedor que ofrece la entidad de la clase consulta al sistema operativo en el momento para generar los valores, y se devuelve el resultado
wql["Consulta con WQL"] --> ns["Espacio de nombres root/CIMV2"]
ns --> cls["Clase Win32_*"]
cls --> prov["Proveedor"]
prov --> osq["Consulta al SO en el momento"]
osq --> res["Devuelve el resultado"]
Figura 3: La consulta recorre el espacio de nombres, la clase y el proveedor en ese orden, y los valores se generan en el momento.
«Poder leer la información del sistema operativo y del hardware con un conjunto unificado de clases y un lenguaje de consulta» ── ese es el valor de WMI. Dicho de otro modo, la escritura o la manipulación se limita a las clases que tienen métodos invocables con Invoke-CimMethod; no es un mecanismo capaz de hacerlo todo.
3. Uso desde PowerShell ── Los cmdlets CIM son los actuales; los cmdlets WMI ya se eliminaron
3.1. Lo básico: Get-CimInstance
# Especificar la clase (espacio de nombres predeterminado root/CIMV2)
Get-CimInstance -ClassName Win32_OperatingSystem
# Escribir solo la cláusula WHERE en -Filter (sin la palabra clave WHERE)
Get-CimInstance -ClassName Win32_Service -Filter "StartMode = 'Auto' AND State <> 'Running'"
# Obtener solo las propiedades necesarias para reducir el volumen transferido
Get-CimInstance -ClassName Win32_Process -Property Name, ProcessId, CreationDate
# Si se quiere escribir WQL directamente, usar -Query
Get-CimInstance -Query "SELECT * FROM Win32_Process WHERE Name LIKE 'p%'"
-Filter es directamente la cláusula WHERE de WQL, y -Property limita las columnas obtenidas. 3 El valor devuelto es un objeto CimInstance, y las propiedades de fecha (como CreationDate o LastBootUpTime) se devuelven ya convertidas a DateTime. A diferencia del antiguo Get-WmiObject, el objeto obtenido no tiene métodos propios, así que la llamada a un método se hace pasándolo a Invoke-CimMethod.
flowchart TB
accTitle: Llamada a métodos de CimInstance
accDescr: El CimInstance que devuelve Get-CimInstance trae las propiedades de fecha ya convertidas a DateTime pero no tiene métodos propios, por lo que la llamada a un método se hace pasando la instancia a Invoke-CimMethod
gci["Get-CimInstance"] --> inst["Objeto CimInstance"]
inst -.-> dt["Las fechas ya están convertidas a DateTime"]
inst -.-> nom["No tiene métodos propios"]
inst --> icm["Se pasa a Invoke-CimMethod"]
icm --> call["Llamada al método"]
Figura 4: Como CimInstance no tiene métodos, la llamada a un método se hace pasándolo a Invoke-CimMethod.
# Llamar a un método de 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' }
# Consultar la definición de la clase (lista de propiedades y métodos)
Get-CimClass -ClassName Win32_Process
3.2. Tabla de migración desde los antiguos cmdlets WMI
A partir de PowerShell 6 (la versión actual, PowerShell 7), los siguientes cmdlets WMI v1 han sido eliminados. La misma funcionalidad la ofrece el módulo CimCmdlets (WMI v2). 2
| Antiguo (hasta Windows PowerShell 5.1) | Actual (cmdlets CIM) | Nota |
|---|---|---|
Get-WmiObject |
Get-CimInstance |
El concepto de -Filter / -Query es el mismo |
Get-WmiObject -List |
Get-CimClass |
Exploración de clases y comprobación de su definición |
Invoke-WmiMethod |
Invoke-CimMethod |
Los argumentos se pasan como tabla hash en -Arguments @{ } |
Register-WmiEvent |
Register-CimIndicationEvent |
Suscripción a eventos (apartado 6.3) |
Set-WmiInstance |
Set-CimInstance |
Cambio de propiedades editables |
Remove-WmiObject |
Remove-CimInstance |
Eliminación de instancias |
Como los cmdlets CIM también funcionan en Windows PowerShell 5.1, lo que se escriba de nuevo conviene escribirlo con CIM aunque vaya a ejecutarse en 5.1; así no queda coste de migración pendiente. El panorama general de la convivencia y la migración entre 5.1 y 7 está recogido en «Diferencias entre Windows PowerShell 5.1 y PowerShell 7».
flowchart TB
accTitle: Por qué escribir los scripts nuevos con CIM
accDescr: Un script escrito con cmdlets WMI funciona en 5.1 pero como fueron eliminados a partir de PowerShell 6 hay que reescribirlo al migrar, en cambio los cmdlets CIM también funcionan en 5.1 así que si lo nuevo se escribe con CIM no queda coste de migración pendiente
new["Script nuevo"] --> q1{"¿Con cuál escribirlo?"}
q1 -->|Cmdlets WMI| old["Funciona en 5.1"]
q1 -->|Cmdlets CIM| cur["También funciona en 5.1"]
old --> del["Eliminados en PowerShell 7"]
del --> rew["Reescritura al migrar"]
cur --> norew["Sin coste de migración pendiente"]
Figura 5: Escribiendo lo nuevo con cmdlets CIM, no hace falta reescribirlo al migrar a PowerShell 7.
4. Consultas remotas ── Sesiones CIM (WSMan por defecto) y la opción DCOM
Los cmdlets CIM, si no se indica nada, se conectan por COM al WMI local; si se indica -ComputerName, se conectan creando una sesión temporal con el protocolo WSMan (WinRM). Cuando se van a realizar varias operaciones sobre el mismo equipo, es más ventajoso por rendimiento crear una sesión CIM y reutilizarla. 3
flowchart TB
accTitle: Elección del método de conexión CIM
accDescr: Sin especificar nada se conecta por COM al WMI local, al indicar ComputerName se crea una sesión temporal WSMan en cada consulta, para varias operaciones contra el mismo destino reutilizar una sesión con New-CimSession es más eficiente, y para destinos sin WinRM configurado existe la opción del protocolo DCOM
exec["Ejecución del cmdlet CIM"] --> q1{"¿Se indica ComputerName?"}
q1 -->|No| local["Conexión COM al WMI local"]
q1 -->|Sí| q2{"¿Varias operaciones contra el mismo destino?"}
q2 -->|Una sola vez| temp["Sesión temporal WSMan"]
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 6: WSMan es el predeterminado para las consultas remotas; para varias operaciones contra el mismo destino, lo habitual es reutilizar la sesión CIM.
# Para un uso puntual, -ComputerName (se crea una sesión temporal en cada llamada)
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
Para destinos con los que no se puede conectar por WSMan, como máquinas antiguas 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
Los requisitos previos para las consultas remotas son los siguientes.
- Que WinRM esté configurado en el destino.
winrm quickconfigrealiza de una vez el arranque automático del servicio, la creación del agente de escucha HTTP (puerto predeterminado 5985) y el registro de la excepción del firewall. 10 Si se quiere conectar por HTTPS (puerto predeterminado 5986), esto no basta: hay que preparar un certificado de servidor y configurar aparte el agente de escucha HTTPS, por ejemplo conwinrm quickconfig -transport:https. 10 - Que el puerto correspondiente esté abierto en el firewall del trayecto. El diseño y el registro práctico de las reglas de entrada se tratan en el artículo «El firewall de Windows y las aplicaciones empresariales».
- Autenticación. En un entorno de dominio, la autenticación mutua se realiza con Kerberos. En un grupo de trabajo no se puede usar Kerberos, por lo que puede ser necesario registrar el destino en
TrustedHostsdel lado cliente. Limite ese registro al mínimo imprescindible. 10 - Permisos. Con la configuración predeterminada, la consulta u operación remota de WMI se realiza básicamente con una cuenta que pertenece al grupo de administradores del destino. Si se quiere abrir a usuarios estándar, hay que configurar los permisos de acceso tanto en WinRM como en el espacio de nombres de WMI. 10
- Cabe señalar que DCOM no tiene un puerto de escucha fijo (usa puertos dinámicos de RPC), lo que dificulta el diseño cuando hay que atravesar un firewall. Para los mecanismos que se construyan de aquí en adelante, lo prudente es considerar WSMan como opción predeterminada.
flowchart TB
accTitle: Comprobación de los requisitos de las consultas remotas
accDescr: En el destino winrm quickconfig realiza de una vez el arranque automático del servicio, la creación del agente de escucha HTTP y el registro de la excepción del firewall, el agente de escucha HTTPS se configura aparte con un certificado, y en un entorno de grupo de trabajo puede ser necesario registrar el destino en TrustedHosts
qc["winrm quickconfig"] --> svc["Arranque automático del servicio"]
qc --> lis["Creación del agente de escucha HTTP(5985)"]
qc --> fw["Excepción del firewall"]
lis ~~~ https["Agente de escucha HTTPS(5986)"]
https -.-> cert["Se prepara el certificado y se configura aparte"]
fw ~~~ wg["Entorno de grupo de trabajo"]
wg -.-> th["Registro en TrustedHosts"]
Figura 7: winrm quickconfig realiza de una vez la configuración predeterminada; el agente de escucha HTTPS y la autenticación en grupo de trabajo se atienden aparte.
5. Uso desde C# ── System.Management y Microsoft.Management.Infrastructure
Hay dos líneas de API para usar WMI desde C#. Ambas son exclusivas de Windows.
| System.Management | Microsoft.Management.Infrastructure (API MI) | |
|---|---|---|
| Instalación | Estándar en .NET Framework. En el .NET actual, paquete NuGet System.Management5 | Paquete NuGet Microsoft.Management.Infrastructure6 |
| Clase de entrada | ManagementObjectSearcher (se consulta pasando WQL)5 |
CimSession (Create → QueryInstances / InvokeMethod / Subscribe)6 |
| Sistema de tipos | ManagementObject / ManagementEventWatcher11 |
CimInstance / CimSession ── el mismo tipo que los cmdlets CIM3 |
| Remoto | Basado en DCOM | Basado en WSMan (sesión CIM). Hay versión asíncrona (*Async)6 |
| Casos adecuados | Obtención de información local. Mantenimiento de código existente | Incorporar consultas remotas y monitorización. Diseño combinado con PowerShell |
5.1. System.Management: lo básico de ManagementObjectSearcher
Se pasa WQL como cadena y se recibe la colección de resultados con Get(). 5
// NuGet: System.Management (exclusivo de 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"]} libre {freeGb:F1} GB / total {sizeGb:F1} GB");
}
Como las propiedades se devuelven como object a través del indexador, hay que consultar el tipo CIM en la documentación de la clase (en este ejemplo, FreeSpace y Size son uint649) y convertirlas en consecuencia. El primer tropiezo habitual es asumir que es int y convertir así, lo que produce InvalidCastException.
flowchart TB
accTitle: La trampa de obtener propiedades y convertirlas de tipo
accDescr: En System.Management las propiedades se devuelven como object a través del indexador por lo que hay que comprobar el tipo CIM en la documentación de la clase antes de convertirlas, si se asume erróneamente que es int la conversión produce InvalidCastException
idx["Obtención con el indexador"] --> obj["Se devuelve como object"]
obj --> chk["Comprobar el tipo CIM en la documentación"]
chk --> cast["Conversión al tipo correcto"]
obj -.-> wrong["Se asume int y se convierte"]
wrong -.-> ex["InvalidCastException"]
Figura 8: Como las propiedades se devuelven como object, hay que comprobar el tipo CIM antes de convertirlas.
5.2. API MI: lo básico de CimSession
CimSession permite manejar lo local y lo remoto de la misma forma. Dispone de enumeración, consulta, llamada a métodos, suscripción a eventos y sus versiones asíncronas, todo en un mismo paquete. 6
// NuGet: Microsoft.Management.Infrastructure (exclusivo de Windows)
using Microsoft.Management.Infrastructure;
// Para local, CimSession.Create(null); para remoto, se pasa el nombre del equipo
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} libre {free / 1024.0 / 1024 / 1024:F1} GB");
}
Como se maneja el mismo CimInstance que devuelven los cmdlets CIM de PowerShell, el flujo de desarrollo de «probar primero en PowerShell y luego trasladarlo a C#» encaja de forma natural. Si se va a diseñar la propia integración entre C# y PowerShell, consulte también «Cómo ejecutar PowerShell desde C# y recibir los resultados como objetos».
flowchart TB
accTitle: El flujo de probar en PowerShell y trasladarlo a C#
accDescr: Como los cmdlets CIM de PowerShell y la API MI de C# manejan el mismo tipo CimInstance, el flujo de desarrollo de prototipar en PowerShell y luego trasladarlo a C# encaja de forma natural
trial["Prototipo en PowerShell"] --> gci["Cmdlets CIM"]
impl["Implementación final en C#"] --> mi["API MI"]
gci --> ci["Mismo tipo CimInstance"]
mi --> ci
ci -.-> flow["El traslado encaja de forma natural"]
Figura 9: Como los cmdlets CIM y la API MI manejan el mismo tipo CimInstance, el prototipo enlaza directamente con la implementación final.
6. Recetas prácticas de uso habitual
6.1. Tabla de referencia rápida de clases habituales
| Información deseada | Clase | Propiedades principales |
|---|---|---|
| Fabricante y modelo | Win32_ComputerSystem |
Manufacturer, Model |
| Número de serie del equipo | Win32_BIOS |
SerialNumber |
| Versión del SO 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 |
6.2. Lo habitual en gestión de activos: número de serie, modelo y espacio en disco
# Información del modelo y número de serie (para cotejar con el inventario de equipos)
$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 los 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 representa «disco local», y excluye las unidades extraíbles (2), las unidades de red (4) y las de CD (5). 9 Para la monitorización, basta con ejecutar este script en cada servidor a través de una sesión CIM para tener la base de una monitorización de disco sin agente.
flowchart TB
accTitle: La base de la monitorización de disco sin agente
accDescr: Al filtrar por DriveType 3 se excluyen las unidades extraíbles de red y de CD dejando solo los discos locales, al ejecutar el mismo script en cada servidor a través de una sesión CIM se obtiene la base de una monitorización de disco sin agente
scr["Script de obtención de espacio libre"] --> flt["Filtrar por DriveType = 3"]
flt -.-> exc["Excluye unidades extraíbles, etc."]
scr --> ses["A través de una sesión CIM"]
ses --> srvs["Se ejecuta en cada servidor"]
srvs --> mon["Monitorización sin agente"]
Figura 10: La base de la monitorización consiste en ejecutar, mediante una sesión CIM, un script centrado en discos locales en cada servidor.
6.3. Detección del inicio de procesos ── Suscripción a eventos
En lugar de «obtener periódicamente Win32_Process mediante sondeo y comparar las diferencias», use la suscripción a eventos. Lo más sencillo es suscribirse a Win32_ProcessStartTrace (una clase de evento del proveedor de rastreo del núcleo que tiene propiedades como ProcessName, ProcessID y ParentProcessID8) para detectar el inicio de un proceso.
# Ejecutar en una sesión de PowerShell con privilegios de administrador
$action = {
$name = $Event.SourceEventArgs.NewEvent.ProcessName
$id = $Event.SourceEventArgs.NewEvent.ProcessID
Write-Host "Proceso iniciado: $name (PID=$id)"
}
Register-CimIndicationEvent -ClassName Win32_ProcessStartTrace `
-SourceIdentifier ProcessStarted -Action $action
La suscripción permanece activa mientras viva la sesión de PowerShell donde se hizo el registro, y -Action se ejecuta cada vez que se inicia un proceso. Tenga cuidado de no ejecutar de corrido el comando de cancelación justo después: la suscripción desaparecería antes de que empiece la monitorización. La cancelación se ejecuta cuando se termina la monitorización.
# Al terminar la monitorización: cancelar la suscripción
Unregister-Event -SourceIdentifier ProcessStarted
Register-CimIndicationEvent registra la suscripción con el nombre de la clase o con una consulta de evento WQL, y el bloque de script de -Action se ejecuta cada vez que llega un evento. 7 La suscripción a esta clase requiere privilegios de administrador. 7 Quién puede recibir el evento está controlado por el descriptor de seguridad de la clase de evento, y con un usuario estándar se obtiene un acceso denegado. 8
sequenceDiagram
accTitle: Flujo de la suscripción al evento de inicio de proceso
accDescr: En una sesión de PowerShell con privilegios de administrador Register-CimIndicationEvent registra la suscripción, cada vez que se inicia un proceso llega el evento y se ejecuta Action, y al terminar la monitorización se cancela con Unregister-Event
participant ps as Sesión de PowerShell
participant wmi as WMI
ps->>wmi: Registra la suscripción con Register-CimIndicationEvent
Note over ps: Se ejecuta con privilegios de administrador
wmi-->>ps: Llega un evento cada vez que se inicia un proceso
ps->>ps: Ejecuta -Action
ps->>wmi: Cancela con Unregister-Event (al finalizar la monitorización)
Figura 11: La suscripción permanece activa mientras viva la sesión que la registró, y la cancelación se hace al terminar la monitorización.
Otro método es el evento genérico de creación de instancia (__InstanceCreationEvent), utilizable con cualquier clase. En este caso, WMI sondea con el intervalo indicado en WITHIN y convierte las diferencias en eventos, así que hay que decidir uno mismo el equilibrio entre el intervalo de detección y la carga.
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 la clase de evento del proveedor de rastreo del núcleo, el genérico __InstanceCreationEvent hace que WMI sondee con el intervalo indicado en WITHIN y convierta las diferencias en eventos por lo que hay que decidir uno mismo el equilibrio entre el intervalo de detección y la carga
goal["Detección del inicio de procesos"] --> t1["Win32_ProcessStartTrace"]
goal --> t2["__InstanceCreationEvent"]
t1 -.-> k1["Suscripción al rastreo del núcleo"]
t2 -.-> w1["Sondeo con intervalo WITHIN"]
w1 -.-> tr["Equilibrio entre intervalo y carga"]
Figura 12: Suscribirse a la clase de evento dedicada o usar el evento genérico de creación de instancia con un intervalo de sondeo.
# Monitorizar nuevas instancias de Win32_Process con un sondeo de 5 segundos
$query = "SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process'"
Register-CimIndicationEvent -Query $query -SourceIdentifier ProcPoll -Action {
Write-Host "Iniciado: $($Event.SourceEventArgs.NewEvent.TargetInstance.Name)"
}
En C# (System.Management), ManagementEventWatcher cumple el mismo papel. 11
using System.Management;
// En un proceso que se ejecute 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($"Proceso iniciado: {name} (PID={pid})");
};
watcher.Start();
// Al terminar la monitorización, no olvide watcher.Stop() y Dispose
Si se incorpora a una monitorización permanente, incluya en el diseño el reingreso de la suscripción cuando esta se interrumpa (al reiniciar el servicio o ante un error). La teoría de diseño de «comprobación y presentación del estado», que incluye la monitorización de dispositivos, se trata en «Buenas prácticas para comprobar y mostrar el estado de dispositivos externos».
stateDiagram-v2
accTitle: Ciclo de vida de la suscripción en una monitorización permanente
accDescr: En una monitorización permanente el estado de suscripción activa puede interrumpirse por un reinicio del servicio o un error, así que el diseño debe incluir la detección de esa interrupción y el reingreso a la suscripción activa
s1: Suscripción activa
s2: Suscripción interrumpida
s3: Reingreso
[*] --> s1
s1 --> s2: Reinicio del servicio / error
s2 --> s3
s3 --> s1
Figura 13: En la monitorización permanente, el diseño debe contemplar el reingreso a la suscripción activa cuando esta se interrumpe.
7. Trampas habituales ── Rendimiento, permisos, 64 bits, repositorio y fechas
7.1. El abuso de SELECT * y del sondeo (polling)
Una consulta WMI es un proceso en el que «el proveedor genera los valores en el momento», y eso tiene un coste. Hay dos antipatrones habituales.
- El uso perezoso de
SELECT *. Obtener todos los registros deWin32_Processcon todas sus propiedades aumenta tanto el trabajo del proveedor como la transferencia por red (en el caso remoto). Filtre las filas con-Filtery las columnas con-Property, y si solo necesita las claves para una operación posterior, use-KeyOnly. Todas son herramientas oficiales pensadas «para reducir el tamaño de los objetos y el tráfico de red». 3 - El sondeo de ciclo corto. Un diseño como «
Get-CimInstance Win32_Processcada segundo» debe sustituirse por la suscripción a eventos del apartado 6.3. Si de todos modos se usa el tipo de sondeo (WITHIN), amplíe el intervalo hasta el mínimo suficiente para el requisito.
Además, repetir -ComputerName equipo por equipo contra destinos remotos también es una forma muy ineficiente: se crea una sesión temporal en cada consulta. Cambie las operaciones múltiples a reutilizar una sesión CIM. 3
flowchart TB
accTitle: Antipatrones de rendimiento y sus sustitutos
accDescr: El uso perezoso de SELECT asterisco se sustituye filtrando filas y columnas con Filter y Property y usando KeyOnly si solo se necesitan las claves, el sondeo de ciclo corto se sustituye por la suscripción a eventos, y la repetición de ComputerName equipo por equipo se sustituye por la reutilización de una sesión CIM
a1["Uso perezoso de SELECT *"] --> f1["Filtrar con Filter y Property"]
f1 -.-> f2["Solo claves: usar KeyOnly"]
a2["Sondeo de ciclo corto"] --> f3["Sustituir por suscripción a eventos"]
a3["ComputerName equipo por equipo"] --> f4["Reutilizar una sesión CIM"]
Figura 14: Filtrar filas, columnas y claves, y sustituir el sondeo por la suscripción a eventos, previene la mitad de los problemas de rendimiento de WMI.
7.2. Permisos para la suscripción a eventos
Como se explicó en el apartado 6.3, la suscripción a la familia Win32_ProcessStartTrace requiere privilegios de administrador. 7 El incidente de «funcionaba en la máquina de desarrollo (ejecutada como administrador), pero la monitorización no funciona en el entorno de usuario estándar del cliente» es tan habitual como el del cuadro de diálogo de notificación del firewall. Si se va a incorporar monitorización a una aplicación empresarial que se ejecuta como usuario estándar, considere separar la parte de monitorización en un servicio de Windows (por ejemplo, con LocalSystem) y conectarla con la aplicación principal mediante comunicación entre procesos.
flowchart TB
accTitle: Configuración de la monitorización en un entorno de usuario estándar
accDescr: La suscripción que requiere privilegios de administrador se separa de la aplicación principal que se ejecuta como usuario estándar, aislando la parte de monitorización en un servicio de Windows que se ejecuta como LocalSystem por ejemplo, y conectándola con la aplicación principal mediante comunicación entre procesos
svcm["Servicio de Windows de monitorización"] --> subm["Se suscribe al rastreo de inicio"]
svcm -.-> lsm["Se ejecuta como LocalSystem, etc."]
appm["Aplicación principal(usuario estándar)"] ---|Comunicación entre procesos| svcm
Figura 15: La suscripción que requiere privilegios de administrador se aísla en el servicio y se conecta con la aplicación principal mediante comunicación entre procesos.
7.3. Proveedores de 32 bits y 64 bits
En Windows de 64 bits, algunos proveedores tienen versiones de 32 y 64 bits que coexisten, y por defecto responde el lado que coincide con los bits de la aplicación que llama. 12 Un caso típico es el proveedor del registro de root\default (StdRegProv): al leerlo desde una aplicación de 32 bits, se devuelve el valor del lado Wow6432Node (la vista de 32 bits). 12 Cuando «el valor del registro leído por WMI es distinto del que se ve en regedit», sospeche de esto en primer lugar. Si se necesita la vista contraria, se puede solicitar explícitamente indicando __ProviderArchitecture (y, si se quiere hacer obligatorio, __RequiredArchitecture) en el contexto de la conexión. 12 El panorama general del problema de los bits también se trata en «Llamar de forma segura a la 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: Por defecto responde el proveedor cuyo número de bits coincide con el de la aplicación que llama, una consulta de registro desde una aplicación de 32 bits recibe el valor del lado Wow6432Node, pero indicando __ProviderArchitecture se puede solicitar explícitamente la vista contraria
q1{"¿Cuántos bits tiene el llamador?"} -->|32 bits| p32["Responde el proveedor de 32 bits"]
q1 -->|64 bits| p64["Responde el proveedor de 64 bits"]
p32 -.-> wow["El registro es el valor del lado Wow6432Node"]
ctx["Indicar __ProviderArchitecture"] -.-> ov["Solicita explícitamente la vista contraria"]
Figura 16: Por defecto responde el lado que coincide con los bits del llamador, así que una aplicación de 32 bits lee el lado Wow6432Node.
7.4. Síntomas y solución cuando el repositorio de WMI se corrompe
Las definiciones de las clases de WMI se guardan en un repositorio (no es un único archivo: el conjunto de archivos de la carpeta Repository funciona como base de datos13). Cuando este repositorio 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 no se haya cambiado nada en la aplicación. Para diagnosticar y reparar se usa winmgmt.exe. 13
rem Comprobación de coherencia (si el resultado es inconsistent, hay incoherencia)
winmgmt /verifyrepository
rem Comprobación de coherencia + reconstrucción si hay incoherencia (lo que se puede leer se fusiona)
winmgmt /salvagerepository
Lo importante es no recurrir a eliminar o reinicializar el repositorio como primer paso. Los errores que aparecen a través de WMI a veces tienen su origen en otra parte del sistema operativo, y Microsoft advierte explícitamente que eliminar el repositorio como primer tratamiento «puede provocar daños al sistema o a las aplicaciones instaladas». 13 Respete el orden: comprobar con /verifyrepository → reparar con /salvagerepository.
flowchart TB
accTitle: Procedimiento de diagnóstico ante una incoherencia del repositorio de WMI
accDescr: Si aparecen errores como que no se encuentra una clase se comprueba la coherencia con winmgmt verifyrepository, si hay incoherencia se reconstruye con salvagerepository, y no se recurre a eliminar o reinicializar el repositorio como primer paso
sym["Error como «clase no encontrada»"] --> verify["winmgmt /verifyrepository"]
verify --> q1{"¿El resultado es inconsistent?"}
q1 -->|Sí| salvage["winmgmt /salvagerepository"]
q1 -->|No| other["Sospechar de otra parte del SO"]
salvage -.-> merge["Lo que se puede leer se fusiona"]
del["Eliminar o reinicializar el repositorio"] -.-> ng["No como primer paso"]
Figura 17: Respete el orden de comprobar con verify y reparar con salvage, y no elimine el repositorio como primer paso.
7.5. Conversión del formato de fecha DMTF
Las fechas de WMI se almacenan como una cadena en el formato DMTF de la especificación CIM, yyyymmddHHMMSS.mmmmmm±UUU (el sufijo es el desfase en minutos respecto a UTC; por ejemplo, 20260801100000.000000+540). No manipule el valor en bruto con procesamiento de cadenas: use la API de conversión.
- C# (System.Management):
ManagementDateTimeConverterofrece la conversión mutua entre el formato DMTF yDateTime/TimeSpan. 11 - API de la familia CIM (Get-CimInstance / API MI): la propiedad de fecha se devuelve ya convertida a
DateTime, así que este problema ni siquiera se presenta.(Get-CimInstance Win32_OperatingSystem).LastBootUpTimese puede usar directamente comoDateTimeen los cálculos.
flowchart TB
accTitle: Tratamiento del formato de fecha DMTF
accDescr: Las fechas de WMI se almacenan como una cadena en formato DMTF, si se lee el valor en bruto con System.Management se convierte con ManagementDateTimeConverter, si es una API de la familia CIM se devuelve ya convertida a DateTime, por lo que no se manipula la cadena a mano
dmtf["Cadena en formato DMTF"] --> q1{"¿Con qué API se obtiene?"}
q1 -->|System.Management| conv["ManagementDateTimeConverter"]
q1 -->|API de la familia CIM| done["Se devuelve ya convertida a DateTime"]
conv --> dtv["Conversión a DateTime / TimeSpan"]
cut["Manipular la cadena a mano"] -.-> ng["No se usa"]
Figura 18: Deje la conversión de la cadena DMTF a la API de conversión; con una API de la familia CIM, use directamente el DateTime ya convertido.
8. Casos en los que no conviene usar WMI ── Tabla de decisión de medios
WMI es excelente como «punto de lectura unificado», pero no siempre es la solución óptima. A continuación, una guía práctica para elegir entre las distintas opciones.
| Qué se quiere hacer | Medio adecuado | Por qué no elegir WMI |
|---|---|---|
| Obtener información de hardware y configuración del SO, consultas remotas sin agente | WMI/CIM | Aquí es donde WMI brilla de verdad. Más unificado que llamar a API específicas por separado |
| Lectura y escritura de la configuración de la propia aplicación | Lectura directa del registro (Microsoft.Win32.Registry), archivos de configuración |
Manipular el registro a través de WMI es un rodeo y arrastra también el problema de bits del apartado 7.3 |
| Monitorización de rendimiento de alta frecuencia y continua, como el uso de CPU | Contadores de rendimiento (System.Diagnostics.PerformanceCounter, etc.) |
Los contadores existen precisamente para eso. El sondeo de ciclo corto de WMI es peor en carga y precisión |
| Llamadas puntuales a funciones del SO, procesos que necesitan baja latencia | API de Win32 (P/Invoke) | WMI tiene la sobrecarga de pasar por COM/el proveedor |
| Enumeración y manejo local de procesos que basta hacer con los permisos del propio proceso | System.Diagnostics.Process |
Se resuelve con la biblioteca estándar y reduce dependencias |
| Configuración de funciones de administración de Windows como el firewall o la red | Cmdlets dedicados basados en CIM, como Get-NetFirewallRule |
Un conjunto de cmdlets preparado por finalidad es más preciso y seguro que buscar la clase de WMI en bruto |
| Detección de cambios en archivos y carpetas | FileSystemWatcher |
No lleve WMI a un terreno que ya tiene una API dedicada |
El eje de decisión es simple: «usar el mecanismo dedicado donde exista uno, y usar WMI/CIM para las consultas transversales y remotas». Los cmdlets de la última fila, como Get-NetFirewallRule, están internamente construidos sobre CIM, así que se puede decir que son una forma de «aprovechar las ventajas de WMI/CIM sin tocarlo directamente».
flowchart TB
accTitle: El eje de decisión sobre los medios
accDescr: El eje de decisión es usar el mecanismo dedicado en las áreas donde existe uno, y usar WMI y CIM para las consultas transversales o remotas en las áreas donde no lo hay, los cmdlets dedicados basados en CIM son una forma de aprovechar sus ventajas sin tocar WMI y CIM directamente
q1{"¿Existe un mecanismo dedicado?"} -->|Sí| ded["Usar el mecanismo dedicado"]
q1 -->|No| wmi["Usar WMI / CIM"]
wmi -.-> use["Consultas transversales y remotas"]
cmd["Cmdlets dedicados basados en CIM"] -.-> ben["Aprovechar solo las ventajas"]
Figura 19: En las áreas con un mecanismo dedicado, úselo; para las consultas transversales y remotas, use WMI/CIM.
9. Resumen
- CIM es el estándar de la industria del DMTF, y WMI es su implementación de Microsoft. Tanto los cmdlets CIM de PowerShell como la API MI de C# son puntos de entrada de la generación actual que siguen ese estándar.
- En PowerShell, lo actual son Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent. Como los cmdlets WMI, como Get-WmiObject, no existen en PowerShell 7, los scripts nuevos se escriben con CIM aunque estén orientados a 5.1.
- WSMan (WinRM) es el predeterminado para las consultas remotas, y las operaciones múltiples reutilizan una sesión CIM. Para los destinos sin WinRM configurado existe la salida de la opción DCOM.
- En C# se elige entre dos líneas: System.Management (sencilla, orientada a lo local) y Microsoft.Management.Infrastructure (orientada a lo remoto y a la monitorización, con el mismo sistema de tipos que los cmdlets CIM). Ambas son paquetes NuGet exclusivos de Windows.
- Monitorice los procesos con suscripción a eventos, no con sondeo. La suscripción a Win32_ProcessStartTrace requiere privilegios de administrador.
- Evite SELECT * y el sondeo de ciclo corto; filtre con -Filter / -Property / -KeyOnly. Recuerde que una consulta desde un proceso de 32 bits se dirige al proveedor de 32 bits, que las fechas DMTF deben tratarse con la API de conversión, y que una incoherencia del repositorio se trata con el orden verify → salvage, no con la eliminación.
- No lleve WMI a las áreas que ya tienen un mecanismo dedicado (configuración, contadores de rendimiento, llamadas puntuales a API); use WMI/CIM para las consultas transversales y remotas ── esa es, en una frase, la clave de cuándo usarlo.
Artículos relacionados
- Cómo ejecutar PowerShell desde C# (CSharp) y recibir los resultados como objetos
- Colección práctica de comandos de PowerShell ── Amplíe las pequeñas funciones que se usan a diario
- 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 dispositivos externos - Un diseño que no se limita a decir «conectado»
- Llamar de forma segura a la API de Win32 desde C# ── Guía práctica de P/Invoke (DllImport / LibraryImport / CsWin32)
- Qué es el TPM de Windows ── Entendido con diagramas: la «caja fuerte que no deja salir la clave» y el arranque medido
Áreas de consultoría relacionadas
KomuraSoft LLC se ocupa de incorporar a aplicaciones empresariales la obtención de información de hardware, la monitorización de procesos y la consulta de PC remotos mediante WMI/CIM, de migrar scripts internos basados en Get-WmiObject a los cmdlets CIM, y de investigar el tipo de causa detrás de «funciona en la máquina de desarrollo, pero da un error de permisos en el cliente». Puede consultarnos de forma continua, desde el prototipo en PowerShell hasta la implementación final en C#.
- Desarrollo de aplicaciones Windows
- Investigación de fallos y análisis de causas
- 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 la tecnología estándar para el acceso a la información de administración en entornos empresariales); que usa el estándar de la industria CIM (Common Information Model) para representar los objetos administrados, y que el CIM lo desarrolla y mantiene el DMTF (Distributed Management Task Force); que la versión de próxima generación MI (Windows Management Infrastructure) es totalmente compatible con el WMI tradicional; y que la conexión remota a WMI se realiza por DCOM, existiendo como alternativa WinRM basado en WS-Management. ↩ ↩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 eliminaron de PowerShell, y que los cmdlets del módulo CimCmdlets (WMI v2) ofrecen la misma funcionalidad con nuevas características y una sintaxis rediseñada. ↩ ↩2
-
Microsoft Learn, Get-CimInstance (CimCmdlets). Sobre que, si no se indica ni ComputerName ni CimSession, se conecta al WMI local con una sesión COM, y que al indicar -ComputerName se crea una sesión temporal con el protocolo WsMan; que para varias operaciones sobre el mismo equipo se recomienda por rendimiento conectar con una sesión CIM; que -Filter es la cláusula where de WQL/CQL sin la palabra clave WHERE; que -Property y -KeyOnly permiten reducir el tamaño del objeto y el tráfico de red; que el espacio de nombres predeterminado es root/CIMV2 y el lenguaje de consulta predeterminado (-QueryDialect) es WQL; que la salida es Microsoft.Management.Infrastructure.CimInstance; un ejemplo de llamada a GetOwner combinado con Invoke-CimMethod; y que es un cmdlet 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; que -Protocol admite Dcom / Default / Wsman; un ejemplo de creación de una sesión CIM por DCOM pasando a -SessionOption de New-CimSession la opción creada con New-CimSessionOption -Protocol Dcom; y que el nivel de suplantación predeterminado de una sesión DCOM es Impersonate. ↩ ↩2
-
Microsoft Learn, ManagementObjectSearcher Class (System.Management). Sobre que es la clase de entrada más habitual para obtener información de administración, ya que recupera una colección de objetos administrados según la consulta WQL indicada; que recibe un ObjectQuery y un ManagementScope (el espacio de nombres de WMI) y devuelve un ManagementObjectCollection con Get(); y que System.Management.dll se distribuye como el paquete NuGet System.Management. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, CimSession Class (Microsoft.Management.Infrastructure). Sobre que Microsoft.Management.Infrastructure.dll se distribuye como el paquete NuGet Microsoft.Management.Infrastructure; la creación de sesiones con Create(computerName); la ejecución de consultas con QueryInstances(namespace, queryDialect, query); y que dispone de EnumerateInstances / GetInstance / InvokeMethod / Subscribe junto con sus versiones asíncronas respectivas (*Async), e implementa IDisposable. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Register-CimIndicationEvent (CimCmdlets). Sobre que se suscribe a una indicación (evento) mediante el nombre de la clase o una expresión de consulta, asignando el nombre de la suscripción con -SourceIdentifier; un ejemplo de suscripción a Win32_ProcessStartTrace y la nota de que su ejecución requiere ejecutar PowerShell como administrador; un ejemplo de referencia a ProcessName / ProcessId desde $Event.SourceEventArgs.NewEvent dentro del bloque de script de -Action; que al indicar -ComputerName se conecta con una sesión temporal WsMan, y sin indicarlo se conecta localmente por COM; y que se usa Unregister-Event para cancelar la suscripción. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Win32_ProcessStartTrace class. Sobre que es una clase de evento que indica el inicio de un proceso nuevo y tiene propiedades como ProcessName, ProcessID, ParentProcessID, SessionID y Sid; que la propiedad SECURITY_DESCRIPTOR es el descriptor que usa el proveedor del evento para decidir qué usuario puede recibirlo; y que el espacio de nombres es Root\CIMV2 y lo aporta el proveedor de rastreo del núcleo (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; los valores de DriveType (2 = extraíble, 3 = disco local, 4 = unidad de red, 5 = CD, etc.); que FreeSpace y Size son valores en bytes de tipo uint64; que DeviceID es la clave; y ejemplos de consulta en VBScript / C# que filtran por DriveType = 3. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Installation and configuration for Windows Remote Management. Sobre que, por defecto, el agente de escucha de WinRM no está configurado y no se pueden enviar ni recibir mensajes WS-Management; que winrm quickconfig realiza el arranque automático del servicio, la configuración del agente de escucha HTTP/HTTPS y el registro de la excepción del firewall; que los puertos predeterminados de WinRM 2.0 son HTTP 5985 y HTTPS 5986; que, cuando no se puede establecer la autenticación mutua (Kerberos), como en un grupo de trabajo, hay que configurar TrustedHosts limitándolo en la medida de lo posible; y sobre el descriptor de seguridad predeterminado (RootSDDL) que controla el acceso remoto al agente de escucha, así como la configuración adicional necesaria para permitir el uso del complemento de WMI a usuarios que no sean administradores. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, System.Management Namespace. Sobre que es el espacio de nombres que realiza las consultas a la infraestructura de WMI mediante las clases de la familia ManagementObjectSearcher y la suscripción a eventos mediante ManagementEventWatcher; que WqlEventQuery representa una consulta de evento en formato WQL; y que ManagementDateTimeConverter ofrece métodos de conversión mutua entre las fechas e intervalos DMTF y los DateTime / TimeSpan del CLR. ↩ ↩2 ↩3
-
Microsoft Learn, Requesting WMI Data on a 64-bit Platform. Sobre que, cuando coexisten una versión de 32 bits y otra de 64 bits de un proveedor, por defecto responde el proveedor de 32 bits a las aplicaciones de 32 bits (incluidos los scripts) y el de 64 bits a las de 64 bits; que con __ProviderArchitecture (32 o 64) y __RequiredArchitecture en el contexto se puede solicitar o exigir el proveedor del lado no predeterminado (si se exige y no existe esa versión, se produce WBEM_E_PROVIDER_LOAD_FAILURE); y, como ejemplo con el proveedor del registro, que un cliente de 32 bits recibe los datos del lado HKLM\SOFTWARE\Wow6432Node. ↩ ↩2 ↩3
-
Microsoft Learn, winmgmt. Sobre que /verifyrepository de winmgmt.exe comprueba la coherencia del repositorio de WMI; que /salvagerepository, además de comprobar la coherencia, reconstruye el repositorio si detecta una incoherencia y fusiona el contenido que se pudo leer; que /resetrepository devuelve el repositorio al estado de la instalación inicial del sistema operativo; que el repositorio funciona como base de datos mediante el conjunto de archivos de la carpeta Repository; y que, como los errores producidos a través de WMI a veces se originan en otra parte del sistema operativo, no se debe eliminar el repositorio como primer tratamiento, ya que puede provocar 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.
Buenas prácticas de multithreading en la práctica — Edición .NET: qué decidir antes de aumentar los hilos
Reglas de diseño en .NET/C# para evitar fallos y bloqueos intermitentes con hilos: usar Task en lugar de hilos propios, reducir el estado...
Prevención de la ejecución múltiple en aplicaciones de Windows — Mutex con nombre y activación en el segundo inicio
Analizamos cómo implementar la prevención de la ejecución múltiple en apps Windows mediante un Mutex con nombre. Cubrimos Global\ y Local...
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,...
Guía práctica del almacén de certificados de Windows — ¿en el de usuario o en el de equipo?
¿En qué almacén debe colocarse un certificado de cliente, en el de usuario o en el del equipo? Esta guía repasa certmgr.msc y certlm.msc,...
El firewall de Windows y las aplicaciones empresariales — Registre las reglas de entrada con el instalador
El firewall de Windows es la causa típica de que "funcione en el equipo de desarrollo pero no se comunique en el cliente". Explicamos el ...
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 objetos administrados, como sistemas y dispositivos», definido y mantenido por el DMTF (Distributed Management Task Force). WMI es la implementación de Microsoft de esa norma dentro de la iniciativa WBEM, y viene integrado en Windows. Es decir, CIM es la especificación y WMI es su implementación en Windows. El motivo de que Get-CimInstance en PowerShell o Microsoft.Management.Infrastructure en C# se llamen «CIM» es que son API que siguen ese estándar, pero el destino de la conexión sigue siendo la misma infraestructura de WMI. Para el trabajo diario basta con entender que «se consultan las clases de WMI (como Win32_*) mediante las API de la familia CIM».
- ¿Ya no se puede usar Get-WmiObject?
- En Windows PowerShell 5.1 todavía funciona, pero desde PowerShell 6 en adelante (la versión actual, PowerShell 7) los cmdlets WMI v1 —Get-WmiObject, Invoke-WmiMethod, Register-WmiEvent, Set-WmiInstance y Remove-WmiObject— han sido eliminados y no se pueden ejecutar. La misma funcionalidad la ofrece el módulo CimCmdlets (Get-CimInstance, Invoke-CimMethod, Register-CimIndicationEvent, etc.). Para los scripts nuevos, lo más seguro es escribirlos con los cmdlets CIM aunque vayan a ejecutarse en 5.1. De ese modo, no habrá que reescribir la parte de WMI cuando se migre a PowerShell 7.
- Para usar WMI desde C#, ¿debo usar System.Management o Microsoft.Management.Infrastructure?
- Ambas son exclusivas de Windows y, desde el .NET actual, se usan como paquetes NuGet. System.Management es la API clásica: basta con pasar WQL a ManagementObjectSearcher, y es suficiente si el objetivo principal es obtener información local. También incluye ManagementDateTimeConverter, que convierte las fechas DMTF. Por otro lado, Microsoft.Management.Infrastructure (la API MI) comparte el mismo sistema de tipos que los cmdlets CIM de PowerShell (CimSession / CimInstance) y permite manejar de forma coherente las consultas remotas por WSMan, las versiones asíncronas de los métodos e incluso la suscripción a eventos (Subscribe). Si se va a incorporar de forma seria la consulta o la monitorización de PC remotos, lo razonable es elegir la API MI.
- Get-CimInstance no se conecta a un PC remoto. ¿Qué debo comprobar?
- Primero compruebe si WinRM está configurado en el equipo de destino. Las operaciones CIM con -ComputerName crean una sesión temporal mediante el protocolo WSMan (WinRM), por lo que se da por hecho que el servicio WinRM y su agente de escucha están activos en el destino. Con winrm quickconfig se puede realizar la configuración predeterminada (inicio del servicio, creación del agente de escucha y registro de la excepción en el firewall). Los puertos predeterminados son 5985 para HTTP y 5986 para HTTPS, así que compruebe también el firewall del trayecto. En un entorno de grupo de trabajo no se puede usar la autenticación mutua Kerberos, por lo que puede ser necesario registrar el destino en TrustedHosts del lado cliente. Si de ningún modo se puede configurar WinRM en el destino, otra opción es conectar por DCOM usando las opciones creadas con New-CimSessionOption -Protocol Dcom.
- ¿Por qué las fechas de WMI se devuelven en un formato como «20260801100000.000000+540»?
- Porque las fechas de WMI se almacenan en el formato de cadena definido por la especificación CIM del DMTF (yyyymmddHHMMSS.mmmmmm±UUU, donde el sufijo es el desfase en minutos respecto a UTC). Si se lee el valor en bruto con el antiguo Get-WmiObject o con System.Management, se obtiene esta cadena tal cual. En C# (System.Management), ManagementDateTimeConverter ofrece métodos para convertir entre el formato DMTF y DateTime / TimeSpan, así que utilícelos en lugar de manipular la cadena a mano. Además, si se obtiene el dato con una API de la familia CIM, como Get-CimInstance, la propiedad de fecha ya se devuelve convertida a DateTime, por lo que este problema ni siquiera se presenta.
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.