Dela via


Kapitel 7 – Arbeta med WMI

WMI och CIM

Windows PowerShell levereras som standard med cmdletar för att arbeta med andra tekniker, till exempel Windows Management Instrumentation (WMI). WMI-cmdletarna är inaktuella och är inte tillgängliga i PowerShell 6+, men beskrivs här eftersom du kan stöta på dem i äldre skript som körs i Windows PowerShell. För ny utveckling använder du CIM-cmdletarna i stället.

Det finns flera interna WMI-cmdletar i PowerShell utan att behöva installera ytterligare programvara eller moduler. Get-Command kan användas för att avgöra vilka WMI-cmdletar som finns i Windows PowerShell. Följande resultat kommer från min Windows 10-labbmiljödator som kör PowerShell version 5.1. Dina resultat kan variera beroende på vilken PowerShell-version du kör.

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

Cmdletar för Common Information Model (CIM) introducerades i PowerShell version 3.0. CIM-cmdletarna är utformade så att de kan användas på både Windows- och icke-Windows-datorer.

CIM-cmdletarna finns alla i en modul. Om du vill hämta en lista över CIM-cmdletar använder du Get-Command med parametern Modul enligt följande exempel.

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

Med CIM-cmdletarna kan du fortfarande arbeta med WMI så bli inte förvirrad när någon gör instruktionen "När jag frågar WMI med PowerShell CIM-cmdletar..."

Som jag tidigare nämnt är WMI en separat teknik från PowerShell och du använder bara CIM-cmdletarna för att komma åt WMI. Du kan hitta ett gammalt VBScript som använder WMI Query Language (WQL) för att fråga WMI, till exempel i följande exempel.

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

Du kan ta WQL-frågan från VBScript och använda den med cmdleten Get-CimInstance utan några ändringar.

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

Det är inte så jag vanligtvis frågar WMI med PowerShell. Men det fungerar och gör att du enkelt kan migrera befintliga VBScripts till PowerShell. När jag börjar skriva en enradare för att fråga WMI använder jag följande syntax.

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

Om jag bara vill ha serienumret kan jag skicka utdata till Select-Object och endast ange egenskapen SerialNumber .

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

Som standard finns det flera egenskaper som hämtas i bakgrunden som aldrig används. Det spelar kanske ingen roll när du kör frågor mot WMI på den lokala datorn. Men när du börjar fråga fjärrdatorer är det inte bara ytterligare bearbetningstid för att returnera den informationen, utan även ytterligare onödig information som måste hämtas i nätverket. Get-CimInstance har en egenskapsparameter som begränsar den information som hämtas. Detta gör frågan till WMI mer effektiv.

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

Föregående resultat returnerade ett objekt. Om du vill returnera en enkel sträng använder du parametern ExpandProperty .

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

Du kan också använda det streckade syntaxformatet för att returnera en enkel sträng. Detta eliminerar behovet av att leda till Select-Object.

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

Fråga fjärrdatorer med CIM-cmdletar

Jag kör fortfarande PowerShell som lokal administratör som är en domänanvändare. När jag försöker fråga efter information från en fjärrdator med hjälp av cmdleten Get-CimInstance får jag ett felmeddelande om nekad åtkomst.

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

Många människor har säkerhetsproblem när det gäller PowerShell, men sanningen är att du har exakt samma behörigheter i PowerShell som du gör i GUI. Varken mer eller mindre. Problemet i föregående exempel är att användaren som kör PowerShell inte har behörighet att fråga WMI-information från DC01-servern. Jag kan starta om PowerShell som domänadministratör eftersom Get-CimInstance det inte finns någon parameter för autentiseringsuppgifter . Men tro mig, det är inte en bra idé eftersom allt som jag kör från PowerShell skulle köras som domänadministratör. Det kan vara farligt ur säkerhetssynpunkt beroende på situationen.

Med principen om minsta behörighet höjer jag till mitt domänadministratörskonto per kommando med hjälp av parametern Credential , om ett kommando har ett. Get-CimInstance har ingen parameter för autentiseringsuppgifter , så lösningen i det här scenariot är att skapa en CimSession först. Sedan använder jag CimSession i stället för ett datornamn för att fråga WMI på fjärrdatorn.

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

CIM-sessionen lagrades i en variabel med namnet $CimSession. Observera att jag också har angett cmdleten Get-Credential inom parenteser så att den körs först och frågar efter alternativa autentiseringsuppgifter innan den nya sessionen skapas. Jag ska visa dig ett annat mer effektivt sätt att ange alternativa autentiseringsuppgifter senare i det här kapitlet, men det är viktigt att förstå detta grundläggande begrepp innan det blir mer komplicerat.

CIM-sessionen som skapades i föregående exempel kan nu användas med cmdleten Get-CimInstance för att köra frågor mot BIOS-informationen från WMI på fjärrdatorn.

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

Det finns flera ytterligare fördelar med att använda CIM-sessioner i stället för att bara ange ett datornamn. När du kör flera frågor till samma dator är det effektivare att använda en CIM-session än att använda datornamnet för varje fråga. Om du skapar en CIM-session konfigureras bara anslutningen en gång. Sedan använder flera frågor samma session för att hämta information. Med hjälp av datornamnet måste cmdletarna konfigurera och ta bort anslutningen med varje enskild fråga.

Cmdleten Get-CimInstance använder WSMan-protokollet som standard, vilket innebär att fjärrdatorn behöver PowerShell version 3.0 eller senare för att ansluta. Det är faktiskt inte PowerShell-versionen som spelar roll, det är stackversionen. Stackversionen kan fastställas med hjälp av cmdleten Test-WSMan . Det måste vara version 3.0. Det är den version som du hittar med PowerShell version 3.0 och senare.

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 äldre WMI-cmdletarna använder DCOM-protokollet, som är kompatibelt med äldre versioner av Windows. Men DCOM blockeras vanligtvis av brandväggen i nyare versioner av Windows. Med New-CimSessionOption cmdleten kan du skapa en DCOM-protokollanslutning för användning med New-CimSession. Detta gör att cmdleten Get-CimInstance kan användas för att kommunicera med versioner av Windows så gamla som Windows Server 2000. Det innebär också att PowerShell inte krävs på fjärrdatorn när du använder cmdleten Get-CimInstance med en CimSession som är konfigurerad för att använda DCOM-protokollet.

Skapa alternativet DCOM-protokoll med hjälp av cmdleten New-CimSessionOption och lagra det i en variabel.

$DCOM = New-CimSessionOption -Protocol Dcom

För effektivitet kan du lagra domänadministratören eller förhöjda autentiseringsuppgifter i en variabel så att du inte ständigt behöver ange dem för varje kommando.

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

Jag har en server med namnet SQL03 som kör Windows Server 2008 (icke-R2). Det är det senaste Windows Server-operativsystemet som inte har PowerShell installerat som standard.

Skapa en CimSession till SQL03 med hjälp av DCOM-protokollet.

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

Observera i föregående kommando att den här gången angav jag variabeln med namnet $Cred som värde för parametern Credential i stället för att behöva ange dem manuellt igen.

Frågans utdata är desamma oavsett vilket underliggande protokoll som används.

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

Cmdleten Get-CimSession används för att se vilka CimSessioner som för närvarande är anslutna och vilka protokoll de använder.

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

Hämta och lagra båda de tidigare skapade CimSessions i en variabel med namnet $CimSession.

$CimSession = Get-CimSession

Fråga båda datorerna med ett kommando, ett med hjälp av WSMan-protokollet och det andra med 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

Jag har skrivit många bloggartiklar om WMI- och CIM-cmdletar. En av de mest användbara handlar om en funktion som jag skapade för att automatiskt avgöra om WSMan eller DCOM ska användas och konfigurera CIM-sessionen automatiskt utan att behöva ta reda på vilken manuellt. Den bloggartikeln heter PowerShell-funktion för att skapa CimSessions till fjärrdatorer med återställning till Dcom.

När du är klar med CIM-sessionerna bör du ta bort dem med cmdleten Remove-CimSession . Ta bort alla CIM-sessioner genom att bara skicka till Get-CimSession Remove-CimSession.

Get-CimSession | Remove-CimSession

Sammanfattning

I det här kapitlet har du lärt dig hur du använder PowerShell för att arbeta med WMI på både lokala datorer och fjärrdatorer. Du har också lärt dig hur du använder CIM-cmdletarna för att arbeta med fjärrdatorer med både WSMan- eller DCOM-protokollet.

Granskning

  1. Vad är skillnaden i WMI- och CIM-cmdletarna?
  2. Vilket protokoll använder cmdleten Get-CimInstance som standard?
  3. Vilka är några av fördelarna med att använda en CIM-session i stället för att ange ett datornamn med Get-CimInstance?
  4. Hur anger du ett annat protokoll än standardprotokollet för användning med Get-CimInstance?
  5. Hur stänger eller tar du bort CIM-sessioner?