Partilhar via


Capítulo 7 - Trabalhando com WMI

WMI e CIM

O Windows PowerShell é fornecido por padrão com cmdlets para trabalhar com outras tecnologias, como o WMI (Instrumentação de Gerenciamento do Windows). Os cmdlets WMI foram preteridos e não estão disponíveis no PowerShell 6+, mas são abordados aqui, pois você pode encontrá-los em scripts mais antigos em execução no Windows PowerShell. Para novos desenvolvimentos, use os cmdlets CIM.

Há vários cmdlets WMI nativos que existem no PowerShell sem a necessidade de instalar nenhum software ou módulo adicional. Get-Command pode ser usado para determinar quais cmdlets WMI existem no Windows PowerShell. Os resultados a seguir são do meu computador de ambiente de laboratório do Windows 10 que está executando o PowerShell versão 5.1. Seus resultados podem diferir dependendo da versão do PowerShell que você está executando.

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...

Os cmdlets CIM (Common Information Model) foram introduzidos no PowerShell versão 3.0. Os cmdlets CIM foram projetados para que possam ser usados em máquinas Windows e não Windows.

Os cmdlets CIM estão todos contidos em um módulo. Para obter uma lista dos cmdlets CIM, use Get-Command com o parâmetro Module , conforme mostrado no exemplo a seguir.

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

Os cmdlets CIM ainda permitem que você trabalhe com o WMI, portanto, não se confunda quando alguém fizer a instrução "Quando eu consultar o WMI com os cmdlets CIM do PowerShell..."

Como mencionei anteriormente, o WMI é uma tecnologia separada do PowerShell e você está apenas usando os cmdlets CIM para acessar o WMI. Você pode encontrar um VBScript antigo que usa WMI Query Language (WQL) para consultar WMI, como no exemplo a seguir.

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

Você pode pegar a consulta WQL desse VBScript e usá-la com o Get-CimInstance cmdlet sem modificações.

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

Não é assim que normalmente consulto o WMI com o PowerShell. Mas ele funciona e permite migrar facilmente VBScripts existentes para o PowerShell. Quando começo a escrever uma linha única para consultar o WMI, utilizo a sintaxe a seguir.

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

Se eu quiser apenas o número de série, posso canalizar a saída e Select-Object especificar apenas a propriedade SerialNumber .

Get-CimInstance -ClassName Win32_BIOS | Select-Object -Property SerialNumber
SerialNumber
------------
3810-1995-1654-4615-2295-2755-89

Por padrão, há várias propriedades recuperadas nos bastidores que nunca são usadas. Pode não importar muito ao consultar o WMI no computador local. Mas uma vez que você começa a consultar computadores remotos, não é apenas tempo de processamento adicional para retornar essas informações, mas também informações adicionais desnecessárias para ter que puxar pela rede. Get-CimInstance tem um parâmetro Property que limita as informações recuperadas. Isso torna a consulta ao WMI mais eficiente.

Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber |
Select-Object -Property SerialNumber
SerialNumber
------------
3810-1995-1654-4615-2295-2755-89

Os resultados anteriores retornaram um objeto. Para retornar uma cadeia de caracteres simples, use o parâmetro ExpandProperty .

Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber |
Select-Object -ExpandProperty SerialNumber
3810-1995-1654-4615-2295-2755-89

Você também pode usar o estilo pontilhado de sintaxe para retornar uma cadeia de caracteres simples. Isso elimina a necessidade de canalizar para Select-Object.

(Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber).SerialNumber
3810-1995-1654-4615-2295-2755-89

Consultar computadores remotos com os cmdlets CIM

Ainda estou executando o PowerShell como um administrador local que é um usuário de domínio. Quando tento consultar informações de um computador remoto usando o cmdlet, recebo Get-CimInstance uma mensagem de erro de acesso negado.

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

Muitas pessoas têm preocupações de segurança quando se trata do PowerShell, mas a verdade é que você tem exatamente as mesmas permissões no PowerShell que na GUI. Nem mais, nem menos. O problema no exemplo anterior é que o usuário que executa o PowerShell não tem direitos para consultar informações WMI do servidor DC01. Eu poderia reiniciar o PowerShell como administrador de domínio, pois Get-CimInstance não tem um parâmetro Credential . Mas, acredite, isso não é uma boa ideia, porque então qualquer coisa que eu execute a partir do PowerShell estaria sendo executada como um administrador de domínio. Isso pode ser perigoso do ponto de vista da segurança, dependendo da situação.

Usando o princípio de menor privilégio, elevo para minha conta de administrador de domínio por comando usando o parâmetro Credential , se um comando tiver um. Get-CimInstance não tem um parâmetro Credential , portanto, a solução neste cenário é criar um CimSession primeiro. Em seguida, uso o CimSession em vez de um nome de computador para consultar o WMI no computador remoto.

$CimSession = New-CimSession -ComputerName dc01 -Credential (Get-Credential)
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential

A sessão CIM foi armazenada em uma variável chamada $CimSession. Observe que também especifiquei o Get-Credential cmdlet entre parênteses para que ele seja executado primeiro, solicitando credenciais alternativas, antes de criar a nova sessão. Mostrarei outra maneira mais eficiente de especificar credenciais alternativas mais adiante neste capítulo, mas é importante entender esse conceito básico antes de torná-lo mais complicado.

A sessão CIM criada no exemplo anterior agora pode ser usada com o Get-CimInstance cmdlet para consultar as informações do BIOS do WMI no computador 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

Há vários benefícios adicionais em usar sessões CIM em vez de apenas especificar um nome de computador. Ao executar várias consultas no mesmo computador, usar uma sessão CIM é mais eficiente do que usar o nome do computador para cada consulta. Criar uma sessão CIM só configura a conexão uma vez. Em seguida, várias consultas usam essa mesma sessão para recuperar informações. O uso do nome do computador requer que os cmdlets configurem e destruam a conexão com cada consulta individual.

O Get-CimInstance cmdlet usa o protocolo WSMan por padrão, o que significa que o computador remoto precisa do PowerShell versão 3.0 ou superior para se conectar. Na verdade, não é a versão do PowerShell que importa, é a versão da pilha. A versão da pilha pode ser determinada usando o Test-WSMan cmdlet. Precisa ser a versão 3.0. Essa é a versão que você encontrará com o PowerShell versão 3.0 e 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

Os cmdlets WMI mais antigos usam o protocolo DCOM, que é compatível com versões mais antigas do Windows. Mas o DCOM normalmente é bloqueado pelo firewall em versões mais recentes do Windows. O New-CimSessionOption cmdlet permite criar uma conexão de protocolo DCOM para uso com New-CimSessiono . Isso permite que o cmdlet seja usado para se comunicar com versões do Windows tão antigas quanto o Get-CimInstance Windows Server 2000. Isso também significa que o PowerShell não é necessário no computador remoto ao usar o Get-CimInstance cmdlet com um CimSession configurado para usar o protocolo DCOM.

Crie a opção de protocolo DCOM usando o New-CimSessionOption cmdlet e armazene-a em uma variável.

$DCOM = New-CimSessionOption -Protocol Dcom

Para maior eficiência, você pode armazenar suas credenciais de administrador de domínio ou elevadas em uma variável para não precisar inseri-las constantemente para cada comando.

$Cred = Get-Credential
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential

Tenho um servidor chamado SQL03 que executa o Windows Server 2008 (não R2). É o mais novo sistema operacional Windows Server que não tem o PowerShell instalado por padrão.

Crie um CimSession para SQL03 usando o protocolo DCOM.

$CimSession = New-CimSession -ComputerName sql03 -SessionOption $DCOM -Credential $Cred

Observe que no comando anterior, desta vez especifiquei a variável nomeada $Cred como o valor para o parâmetro Credential em vez de ter que inseri-los manualmente novamente.

A saída da consulta é a mesma, independentemente do protocolo subjacente que está sendo usado.

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

O Get-CimSession cmdlet é usado para ver quais CimSessions estão conectados atualmente e quais protocolos eles estão 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 e armazene ambos os CimSessions criados anteriormente em uma variável chamada $CimSession.

$CimSession = Get-CimSession

Consulte ambos os computadores com um comando, um usando o protocolo WSMan e o outro com 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

Escrevi vários artigos de blog sobre os cmdlets WMI e CIM. Uma das mais úteis é sobre uma função que criei para determinar automaticamente se o WSMan ou DCOM deve ser usado e configurar a sessão CIM automaticamente sem ter que descobrir qual manualmente. Esse artigo do blog é intitulado Função do PowerShell para criar CimSessions para computadores remotos com fallback para Dcom.

Quando terminar as sessões CIM, você deve removê-las com o Remove-CimSession cmdlet. Para remover todas as sessões CIM, basta canalizar Get-CimSession para Remove-CimSession.

Get-CimSession | Remove-CimSession

Resumo

Neste capítulo, você aprendeu sobre como usar o PowerShell para trabalhar com WMI em computadores locais e remotos. Você também aprendeu como usar os cmdlets CIM para trabalhar com computadores remotos com o protocolo WSMan ou DCOM.

Rever

  1. Qual é a diferença nos cmdlets WMI e CIM?
  2. Por padrão, qual protocolo o Get-CimInstance cmdlet usa?
  3. Quais são alguns dos benefícios de usar uma sessão CIM em vez de especificar um nome de computador com Get-CimInstance?
  4. Como você especifica um protocolo alternativo diferente do padrão para uso com Get-CimInstance?
  5. Como fechar ou remover sessões CIM?