Capítulo 7: Trabajo con WMI
WMI y CIM
Windows PowerShell se incluye de forma predeterminada con cmdlets para trabajar con otras tecnologías, como Instrumental de administración de Windows (WMI). Los cmdlets de WMI están en desuso y no están disponibles en PowerShell 6 y versiones posteriores, pero se tratan aquí, ya que pueden encontrarse en scripts anteriores que se ejecutan en Windows PowerShell. Para el nuevo desarrollo, use los cmdlets CIM en su lugar.
Hay varios cmdlets nativos de WMI que existen en PowerShell sin necesidad de instalar ningún software ni módulo adicional. Get-Command
se puede usar para determinar qué cmdlets WMI existen en Windows PowerShell. Los siguientes resultados corresponden a mi equipo del entorno de laboratorio de Windows 10 con la versión 5.1 de PowerShell. Sus resultados pueden diferir en función de la versión de PowerShell que esté ejecutando.
Get-Command -Noun WMI*
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Get-WmiObject 3.1.0.0 Microsof...
Cmdlet Invoke-WmiMethod 3.1.0.0 Microsof...
Cmdlet Register-WmiEvent 3.1.0.0 Microsof...
Cmdlet Remove-WmiObject 3.1.0.0 Microsof...
Cmdlet Set-WmiInstance 3.1.0.0 Microsof...
Los cmdlets de Modelo de información común (CIM) se incorporaron en la versión 3.0 de PowerShell. Los cmdlets de CIM están diseñados para usarse en equipos Windows y no Windows.
Todos los cmdlets de CIM están incluidos en un módulo. Para obtener una lista de los cmdlets de CIM, use Get-Command
con el parámetro Module, como se muestra en el ejemplo siguiente.
Get-Command -Module CimCmdlets
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Export-BinaryMiLog 1.0.0.0 CimCmdlets
Cmdlet Get-CimAssociatedInstance 1.0.0.0 CimCmdlets
Cmdlet Get-CimClass 1.0.0.0 CimCmdlets
Cmdlet Get-CimInstance 1.0.0.0 CimCmdlets
Cmdlet Get-CimSession 1.0.0.0 CimCmdlets
Cmdlet Import-BinaryMiLog 1.0.0.0 CimCmdlets
Cmdlet Invoke-CimMethod 1.0.0.0 CimCmdlets
Cmdlet New-CimInstance 1.0.0.0 CimCmdlets
Cmdlet New-CimSession 1.0.0.0 CimCmdlets
Cmdlet New-CimSessionOption 1.0.0.0 CimCmdlets
Cmdlet Register-CimIndicationEvent 1.0.0.0 CimCmdlets
Cmdlet Remove-CimInstance 1.0.0.0 CimCmdlets
Cmdlet Remove-CimSession 1.0.0.0 CimCmdlets
Cmdlet Set-CimInstance 1.0.0.0 CimCmdlets
Los cmdlets de CIM siguen permitiendo trabajar con WMI, así que no se desconcierte si alguien afirma "Cuando consulto WMI con los cmdlets de CIM de PowerShell..."
Como he mencionado anteriormente, WMI es una tecnología independiente de PowerShell y simplemente se están usando los cmdlets de CIM para acceder a WMI. Puede encontrar un VBScript antiguo que usa lenguaje de consulta de WMI (WQL) para consultar WMI como en el ejemplo siguiente.
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colBIOS = objWMIService.ExecQuery _
("Select * from Win32_BIOS")
For each objBIOS in colBIOS
Wscript.Echo "Manufacturer: " & objBIOS.Manufacturer
Wscript.Echo "Name: " & objBIOS.Name
Wscript.Echo "Serial Number: " & objBIOS.SerialNumber
Wscript.Echo "SMBIOS Version: " & objBIOS.SMBIOSBIOSVersion
Wscript.Echo "Version: " & objBIOS.Version
Next
Puede tomar la consulta de WQL de ese VBScript y usarla con el cmdlet Get-CimInstance
sin ninguna modificación.
Get-CimInstance -Query 'Select * from Win32_BIOS'
SMBIOSBIOSVersion : 090006
Manufacturer : American Megatrends Inc.
Name : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber : 3810-1995-1654-4615-2295-2755-89
Version : VRTUAL - 4001628
Así no es como yo normalmente consulto WMI con PowerShell, pero funciona y permite migrar fácilmente los VBScript existentes a PowerShell. Al empezar a escribir un comando único de una línea para consultar WMI, yo uso la sintaxis siguiente.
Get-CimInstance -ClassName Win32_BIOS
SMBIOSBIOSVersion : 090006
Manufacturer : American Megatrends Inc.
Name : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber : 3810-1995-1654-4615-2295-2755-89
Version : VRTUAL - 4001628
Si solo quiero el número de serie, puedo canalizar la salida a Select-Object
y especificar únicamente la propiedad SerialNumber.
Get-CimInstance -ClassName Win32_BIOS | Select-Object -Property SerialNumber
SerialNumber
------------
3810-1995-1654-4615-2295-2755-89
De forma predeterminada, hay varias propiedades que se recuperan en segundo plano que nunca se usan.
Es posible que no importe mucho al consultar WMI en el equipo local. Pero una vez que se empieza a consultar equipos remotos, no solo se trata de tiempo de procesamiento adicional para devolver esa información, sino también de información innecesaria adicional que se debe extraer en la red. Get-CimInstance
tiene un parámetro Property que limita la información que se recupera. Esto hace que la consulta a WMI sea más eficaz.
Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber |
Select-Object -Property SerialNumber
SerialNumber
------------
3810-1995-1654-4615-2295-2755-89
Los resultados anteriores han devuelto un objeto. Para devolver una cadena simple, use el parámetro ExpandProperty.
Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber |
Select-Object -ExpandProperty SerialNumber
3810-1995-1654-4615-2295-2755-89
También puede usar el estilo de puntos de sintaxis para devolver una cadena simple. Así se elimina la necesidad de canalizar a Select-Object
.
(Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber).SerialNumber
3810-1995-1654-4615-2295-2755-89
Consulta a equipos remotos con los cmdlets de CIM
Sigo ejecutando PowerShell como administrador local que es usuario de dominio. Al intentar consultar información de un equipo remoto mediante el cmdlet Get-CimInstance
, aparece un mensaje de error de acceso denegado.
Get-CimInstance -ComputerName dc01 -ClassName Win32_BIOS
Get-CimInstance : Access is denied.
At line:1 char:1
+ Get-CimInstance -ComputerName dc01 -ClassName Win32_BIOS
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (root\cimv2:Win32_BIOS:String) [Get-CimI
nstance], CimException
+ FullyQualifiedErrorId : HRESULT 0x80070005,Microsoft.Management.Infrastructure.Cim
Cmdlets.GetCimInstanceCommand
+ PSComputerName : dc01
Muchas personas tienen problemas de seguridad con PowerShell, pero la verdad es que se tienen exactamente los mismos permisos en PowerShell que en la GUI. Ni más ni menos. El problema del ejemplo anterior es que el usuario que ejecuta PowerShell no tiene derechos para consultar información de WMI desde el servidor DC01. Podría volver a iniciar PowerShell como administrador de dominio, ya que Get-CimInstance
no tiene un parámetro Credential. Pero confíe en mí, no es una buena idea porque, a continuación, cualquier cosa que ejecute desde PowerShell se ejecutaría como administrador de dominio. Esto podría ser peligroso desde el punto de vista de la seguridad en función de la situación.
Con el principio de privilegios mínimos, elevo a mi cuenta de administrador de dominio por comando mediante el parámetro Credential, si un comando tiene uno. Get-CimInstance
no tiene un parámetro Credential, por lo que la solución de este escenario es crear un elemento CimSession primero. Luego uso CimSession en lugar de un nombre de equipo para consultar WMI en el equipo remoto.
$CimSession = New-CimSession -ComputerName dc01 -Credential (Get-Credential)
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential
La sesión de CIM se ha almacenado en una variable de nombre $CimSession
. Observe que también he especificado el cmdlet Get-Credential
entre paréntesis para que se ejecute primero y me pida credenciales alternativas antes de crear la nueva sesión. Más adelante en este capítulo muestro otra forma más eficaz de especificar credenciales alternativas, pero es importante entender este concepto básico antes de complicarlo más.
La sesión de CIM creada en el ejemplo anterior se puede usar ahora con el cmdlet Get-CimInstance
para consultar la información de BIOS desde WMI en el equipo remoto.
Get-CimInstance -CimSession $CimSession -ClassName Win32_BIOS
SMBIOSBIOSVersion : 090006
Manufacturer : American Megatrends Inc.
Name : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber : 0986-6980-3916-0512-6608-8243-13
Version : VRTUAL - 4001628
PSComputerName : dc01
El uso de sesiones de CIM en lugar de simplemente especificar un nombre de equipo ofrece varias ventajas adicionales. Al ejecutar varias consultas en el mismo equipo, el uso de una sesión de CIM es más eficaz que el uso del nombre de equipo para cada consulta. Al crear una sesión de CIM, solo se configura la conexión una vez. Luego, varias consultas usan esa misma sesión para recuperar información. El uso del nombre de equipo requiere los cmdlets para configurar y desmantelar la conexión con cada consulta individual.
El cmdlet Get-CimInstance
usa el protocolo WSMan de forma predeterminada, lo que significa que el equipo remoto necesita la versión 3.0 o superior de PowerShell para conectarse. En realidad, no es la versión de PowerShell lo que importa, sino la versión de la pila. La versión de la pila se puede determinar mediante el cmdlet Test-WSMan
.
Debe ser la versión 3.0. Esa es la versión que se encuentra con PowerShell versión 3.0 y superior.
Test-WSMan -ComputerName dc01
wsmid : http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd
ProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
ProductVendor : Microsoft Corporation
ProductVersion : OS: 0.0.0 SP: 0.0 Stack: 3.0
Los cmdlets de WMI anteriores usan el protocolo DCOM, que es compatible con versiones anteriores de Windows. Pero DCOM normalmente resulta bloqueado por el firewall en las versiones más recientes de Windows. El cmdlet New-CimSessionOption
permite crear una conexión de protocolo DCOM para su uso con New-CimSession
. Esto permite usar el cmdlet Get-CimInstance
para comunicarse con versiones de Windows anteriores a Windows Server 2000. Esto también significa que no se necesita PowerShell en el equipo remoto cuando se usa el cmdlet Get-CimInstance
con un elemento CimSession configurado para usar el protocolo DCOM.
Cree la opción del protocolo DCOM con el cmdlet New-CimSessionOption
y almacénela en una variable.
$DCOM = New-CimSessionOption -Protocol Dcom
Por eficacia, puede almacenar el administrador de dominio o las credenciales con privilegios elevados en una variable, de modo que no tenga que escribirlos constantemente para cada comando.
$Cred = Get-Credential
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential
Yo tengo un servidor denominado SQL03 que ejecuta Windows Server 2008 (no R2). Es el sistema operativo Windows Server más reciente sin PowerShell instalado de forma predeterminada.
Cree un elemento CimSession para SQL03 mediante el protocolo DCOM.
$CimSession = New-CimSession -ComputerName sql03 -SessionOption $DCOM -Credential $Cred
En el comando anterior, observe que esta vez he especificado la variable denominada $Cred
como valor del parámetro Credential en lugar de volver a escribirlos manualmente.
La salida de la consulta es la misma independientemente del protocolo subyacente que se use.
Get-CimInstance -CimSession $CimSession -ClassName Win32_BIOS
SMBIOSBIOSVersion : 090006
Manufacturer : American Megatrends Inc.
Name : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber : 7237-7483-8873-8926-7271-5004-86
Version : VRTUAL - 4001628
PSComputerName : sql03
El cmdlet Get-CimSession
se usa para ver qué elementos CimSession hay conectados actualmente y qué protocolos están usando.
Get-CimSession
Id : 1
Name : CimSession1
InstanceId : 80742787-e38e-41b1-a7d7-fa1369cf1402
ComputerName : dc01
Protocol : WSMAN
Id : 2
Name : CimSession2
InstanceId : 8fcabd81-43cf-4682-bd53-ccce1e24aecb
ComputerName : sql03
Protocol : DCOM
Recupere y almacene los dos elementos CimSession creados previamente en una variable denominada $CimSession
.
$CimSession = Get-CimSession
Consulte ambos equipos con un comando, uno con el protocolo WSMan y el otro con DCOM.
Get-CimInstance -CimSession $CimSession -ClassName Win32_BIOS
SMBIOSBIOSVersion : 090006
Manufacturer : American Megatrends Inc.
Name : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber : 0986-6980-3916-0512-6608-8243-13
Version : VRTUAL - 4001628
PSComputerName : dc01
SMBIOSBIOSVersion : 090006
Manufacturer : American Megatrends Inc.
Name : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber : 7237-7483-8873-8926-7271-5004-86
Version : VRTUAL - 4001628
PSComputerName : sql03
He escrito muchas entradas de blog sobre los cmdlets de WMI y CIM. Una de las más útiles trata de una función que he creado para determinar automáticamente si se debe usar WSMan o DCOM y configurar la sesión de CIM automáticamente sin tener que averiguar cuál de ellos de forma manual. Esa entrada de blog se titula Función de PowerShell para crear CimSessions en equipos remotos con reserva para DCOM.
Cuando haya terminado con las sesiones de CIM, debe quitarlas con el cmdlet Remove-CimSession
. Para quitar todas las sesiones de CIM, simplemente canalice Get-CimSession
a Remove-CimSession
.
Get-CimSession | Remove-CimSession
Resumen
En este capítulo ha aprendido a usar PowerShell para trabajar con WMI en equipos locales y remotos. También ha aprendido a usar los cmdlets de CIM para trabajar con equipos remotos con el protocolo WSMan o DCOM.
Revisar
- ¿Cuál es la diferencia entre los cmdlets de WMI y CIM?
- De forma predeterminada, ¿qué protocolo usa el cmdlet
Get-CimInstance
? - ¿Cuáles son algunas de las ventajas que aporta el uso de una sesión de CIM en lugar de especificar un nombre de equipo con
Get-CimInstance
? - ¿Cómo se especifica un protocolo alternativo distinto al predeterminado para su uso con
Get-CimInstance
? - ¿Cómo se cierran o quitan las sesiones de CIM?