Delen via


Hoofdstuk 7 - Werken met WMI

WMI en CIM

Windows PowerShell wordt standaard geleverd met cmdlets voor het werken met andere technologieën, zoals Windows Management Instrumentation (WMI). De WMI-cmdlets zijn afgeschaft en zijn niet beschikbaar in PowerShell 6+, maar worden hier besproken, omdat u ze kunt tegenkomen in oudere scripts die worden uitgevoerd in Windows PowerShell. Voor nieuwe ontwikkeling gebruikt u in plaats daarvan de CIM-cmdlets.

Er zijn verschillende systeemeigen WMI-cmdlets die aanwezig zijn in PowerShell zonder dat u extra software of modules hoeft te installeren. Get-Command kan worden gebruikt om te bepalen welke WMI-cmdlets er bestaan in Windows PowerShell. De volgende resultaten zijn afkomstig van mijn Windows 10-testomgevingcomputer waarop PowerShell versie 5.1 wordt uitgevoerd. Uw resultaten kunnen verschillen, afhankelijk van de Versie van PowerShell die u gebruikt.

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

CIM-cmdlets (Common Information Model) zijn geïntroduceerd in PowerShell versie 3.0. De CIM-cmdlets zijn ontworpen zodat ze kunnen worden gebruikt op zowel Windows- als niet-Windows-computers.

De CIM-cmdlets bevinden zich allemaal in een module. Als u een lijst met de CIM-cmdlets wilt ophalen, gebruikt Get-Command u deze met de moduleparameter , zoals wordt weergegeven in het volgende voorbeeld.

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

Met de CIM-cmdlets kunt u nog steeds met WMI werken, dus niet verwarrend wanneer iemand de instructie 'Wanneer ik een query op WMI uitvoert met de PowerShell CIM-cmdlets...'

Zoals ik eerder al zei, is WMI een afzonderlijke technologie van PowerShell en u gebruikt alleen de CIM-cmdlets voor toegang tot WMI. Mogelijk vindt u een oud VBScript dat WMI Query Language (WQL) gebruikt om een query uit te voeren op WMI, zoals in het volgende voorbeeld.

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

U kunt de WQL-query van dat VBScript gebruiken en gebruiken met de Get-CimInstance cmdlet zonder wijzigingen.

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

Dat is niet hoe ik doorgaans een query op WMI uitvoert met PowerShell. Maar het werkt wel en stelt u in staat om eenvoudig bestaande VBScripts te migreren naar PowerShell. Wanneer ik een one-liner schrijf om een query uit te voeren op WMI, gebruik ik de volgende syntaxis.

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

Als ik alleen het serienummer wil, kan ik de uitvoer doorsluisen naar Select-Object en alleen de eigenschap SerialNumber opgeven.

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

Standaard zijn er verschillende eigenschappen die achter de schermen worden opgehaald die nooit worden gebruikt. Het maakt mogelijk niet veel uit wanneer u een query uitvoert op WMI op de lokale computer. Maar zodra u externe computers gaat opvragen, is het niet alleen extra verwerkingstijd om die informatie te retourneren, maar ook extra onnodige informatie om over het netwerk te hoeven halen. Get-CimInstance heeft een eigenschapsparameter die de opgehaalde informatie beperkt. Hierdoor wordt de query efficiënter naar WMI.

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

De vorige resultaten hebben een object geretourneerd. Als u een eenvoudige tekenreeks wilt retourneren, gebruikt u de parameter ExpandProperty .

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

U kunt ook de gestippelde stijl van de syntaxis gebruiken om een eenvoudige tekenreeks te retourneren. Dit elimineert de noodzaak om door te sluizen naar Select-Object.

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

Query's uitvoeren op externe computers met de CIM-cmdlets

Ik gebruik PowerShell nog steeds als lokale beheerder die een domeingebruiker is. Wanneer ik query's wil uitvoeren op gegevens van een externe computer met behulp van de Get-CimInstance cmdlet, krijg ik een foutbericht dat de toegang is geweigerd.

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

Veel mensen hebben beveiligingsproblemen als het gaat om PowerShell, maar de waarheid is dat u precies dezelfde machtigingen hebt in PowerShell als in de GUI. Niet meer en niet minder. Het probleem in het vorige voorbeeld is dat de gebruiker met PowerShell geen rechten heeft om WMI-gegevens op te vragen van de DC01-server. Ik kan PowerShell opnieuw starten als domeinbeheerder omdat Get-CimInstance ik geen referentieparameter heb. Maar vertrouw me, dat is geen goed idee, omdat alles wat ik voer vanuit PowerShell als domeinbeheerder zou worden uitgevoerd. Dat kan gevaarlijk zijn vanuit een veiligheidsstandpunt, afhankelijk van de situatie.

Met behulp van het principe van minimale bevoegdheden kan ik per opdracht mijn domeinbeheerdersaccount uitbreiden met behulp van de parameter Referentie , als een opdracht er een heeft. Get-CimInstance heeft geen referentieparameter , dus de oplossing in dit scenario is om eerst een CimSession te maken. Vervolgens gebruik ik de CimSession in plaats van een computernaam om een query uit te voeren op WMI op de externe computer.

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

De CIM-sessie is opgeslagen in een variabele met de naam $CimSession. U ziet dat ik ook de Get-Credential cmdlet tussen haakjes heb opgegeven, zodat deze eerst wordt uitgevoerd, waarbij ik om alternatieve referenties wordt gevraagd voordat de nieuwe sessie wordt gemaakt. Ik zal u een andere efficiëntere manier laten zien om later in dit hoofdstuk alternatieve referenties op te geven, maar het is belangrijk om dit basisconcept te begrijpen voordat u het ingewikkelder maakt.

De CIM-sessie die in het vorige voorbeeld is gemaakt, kan nu worden gebruikt met de Get-CimInstance cmdlet om de BIOS-gegevens van WMI op de externe computer op te vragen.

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

Er zijn verschillende extra voordelen voor het gebruik van CIM-sessies in plaats van alleen een computernaam op te geven. Wanneer u meerdere query's uitvoert op dezelfde computer, is het gebruik van een CIM-sessie efficiënter dan het gebruik van de computernaam voor elke query. Als u een CIM-sessie maakt, wordt de verbinding slechts eenmaal ingesteld. Vervolgens gebruiken meerdere query's dezelfde sessie om informatie op te halen. Als u de computernaam gebruikt, moeten de cmdlets de verbinding met elke afzonderlijke query instellen en afbreken.

De Get-CimInstance cmdlet maakt standaard gebruik van het WSMan-protocol, wat betekent dat de externe computer PowerShell versie 3.0 of hoger nodig heeft om verbinding te maken. Het is eigenlijk niet de PowerShell-versie die belangrijk is, het is de stackversie. De stackversie kan worden bepaald met behulp van de Test-WSMan cmdlet. Dit moet versie 3.0 zijn. Dat is de versie die u vindt met PowerShell versie 3.0 en hoger.

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

De oudere WMI-cmdlets gebruiken het DCOM-protocol, dat compatibel is met oudere versies van Windows. Maar DCOM wordt doorgaans geblokkeerd door de firewall op nieuwere versies van Windows. Met de New-CimSessionOption cmdlet kunt u een DCOM-protocolverbinding maken voor gebruik met New-CimSession. Hierdoor kan de Get-CimInstance cmdlet worden gebruikt om te communiceren met versies van Windows zo oud als Windows Server 2000. Dit betekent ook dat PowerShell niet vereist is op de externe computer wanneer u de Get-CimInstance cmdlet gebruikt met een CimSession die is geconfigureerd voor het gebruik van het DCOM-protocol.

Maak de DCOM-protocoloptie met behulp van de New-CimSessionOption cmdlet en sla deze op in een variabele.

$DCOM = New-CimSessionOption -Protocol Dcom

Voor efficiëntie kunt u uw domeinbeheerder of verhoogde referenties opslaan in een variabele, zodat u deze niet voortdurend hoeft in te voeren voor elke opdracht.

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

Ik heb een server met de naam SQL03 waarop Windows Server 2008 (niet-R2) wordt uitgevoerd. Het is het nieuwste Windows Server-besturingssysteem waarop PowerShell niet standaard is geïnstalleerd.

Maak een CimSession naar SQL03 met behulp van het DCOM-protocol.

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

In de vorige opdracht heb ik deze keer de variabele met de naam $Cred opgegeven als de waarde voor de referentieparameter in plaats van ze handmatig opnieuw in te voeren.

De uitvoer van de query is hetzelfde, ongeacht het onderliggende protocol dat wordt gebruikt.

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

De Get-CimSession cmdlet wordt gebruikt om te zien welke CimSessions momenteel zijn verbonden en welke protocollen ze gebruiken.

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

Haal beide eerder gemaakte CimSessions op en sla deze op in een variabele met de naam $CimSession.

$CimSession = Get-CimSession

Voer een query uit op beide computers met één opdracht, één met behulp van het WSMan-protocol en de andere met 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

Ik heb talloze blogartikelen geschreven over de WMI- en CIM-cmdlets. Een van de handigste is over een functie die ik heb gemaakt om automatisch te bepalen of WSMan of DCOM moet worden gebruikt en de CIM-sessie automatisch moet instellen zonder dat u hoeft te achterhalen welke handmatig. Dit blogartikel heeft de titel PowerShell-functie voor het maken van CimSessions voor externe computers met terugval naar Dcom.

Wanneer u klaar bent met de CIM-sessies, moet u deze verwijderen met de Remove-CimSession cmdlet. Als u alle CIM-sessies wilt verwijderen, sluist Get-CimSession u gewoon door naar Remove-CimSession.

Get-CimSession | Remove-CimSession

Samenvatting

In dit hoofdstuk hebt u geleerd hoe u PowerShell kunt gebruiken om met WMI te werken op zowel lokale als externe computers. U hebt ook geleerd hoe u de CIM-cmdlets gebruikt om te werken met externe computers met zowel het WSMan- als DCOM-protocol.

Beoordelen

  1. Wat is het verschil in de WMI- en CIM-cmdlets?
  2. Welk protocol gebruikt de Get-CimInstance cmdlet standaard?
  3. Wat zijn enkele voordelen van het gebruik van een CIM-sessie in plaats van een computernaam op te geven met Get-CimInstance?
  4. Hoe geeft u een ander alternatief protocol op dan de standaardprotocol voor gebruik met Get-CimInstance?
  5. Hoe sluit of verwijdert u CIM-sessies?