PowerShell for Windows Admins


January 20, 2012  2:58 PM

SMART disks

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

A question on the forum about using WMI to work with SMART disks got my digging into the subject.  SMART disks – http://en.wikipedia.org/wiki/S.M.A.R.T – detect and report on disk problems (hopefully) before they cause a catastrophe. While vendors’ implementations vary there are some things we can access.

The WMI classes are in the root\wmi namespace

PS> Get-WmiObject -Namespace root\wmi -List MSStorageDriver_Failure* | select Name

Name
—-
MSStorageDriver_FailurePredictEvent
MSStorageDriver_FailurePredictFunction
MSStorageDriver_FailurePredictData
MSStorageDriver_FailurePredictThresholds
MSStorageDriver_FailurePredictStatus

 

The most immediate concern is – what is the status of our disks

function test-diskstatus {            
[CmdletBinding()]            
param (            
 [string]$computername = $env:COMPUTERNAME            
)            
            
Get-WmiObject -Namespace root\wmi -Class MSStorageDriver_FailurePredictStatus -ComputerName $computername |            
select InstanceName, Active, PredictFailure, Reason            
            
}

The InstanceName is long so the best display is list

PS> test-diskstatus | fl


InstanceName   : IDE\DiskST9250320AS_____________________________HP07____\5&b0fd174&0&1.0.0_0

Active         : True

PredictFailure : False

Reason         : 0

 

The PredictFailure is the the important property & we worry when it is true!

January 18, 2012  1:54 PM

WMI associations through CIM cmdlets

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

The CIM cmdlets that introduced in PowerShell v3 give us a different API for working with WMI. We can still work with associations just in a slightly different way.

 

NOTE – this done on a different machine to the previous one so the adapters are different

 

We get the instances of a WMI class like this

Get-CimInstance -ClassName Win32_NetworkAdapter

 

we can filter to a specific instance

Get-CimInstance -ClassName Win32_NetworkAdapter -Filter "DeviceId=7"

 

if we put that in a variable

$nic = Get-CimInstance -ClassName Win32_NetworkAdapter -Filter "DeviceId=7"

 

then we can see all of the associated classes like this

Get-CimAssociatedInstance -CimInstance $nic

 

You might think that we would do this to get a specific associated class

Get-CimAssociatedInstance -CimInstance $nic -Association Win32_NetworkAdapterConfiguration

 

Nope – we don’t just to be different.

We need to back track a minute. When two classes are linked there is normally a linking class (reference) the shows the links. We can see this by running

Get-CimClass -ClassName *NetworkAdapter*

which shows a class Win32_NetworkAdapterSetting

so if we try

PS> Get-CimInstance -ClassName Win32_NetworkAdapterSetting

Element                                                     Setting
——-                                                     ——-
Win32_NetworkAdapter (DeviceID = "0")                       Win32_NetworkAdapterConfiguration (Index = 0)
Win32_NetworkAdapter (DeviceID = "1")                       Win32_NetworkAdapterConfiguration (Index = 1)
Win32_NetworkAdapter (DeviceID = "2")                       Win32_NetworkAdapterConfiguration (Index = 2)
Win32_NetworkAdapter (DeviceID = "3")                       Win32_NetworkAdapterConfiguration (Index = 3)
Win32_NetworkAdapter (DeviceID = "4")                       Win32_NetworkAdapterConfiguration (Index = 4)
Win32_NetworkAdapter (DeviceID = "5")                       Win32_NetworkAdapterConfiguration (Index = 5)
Win32_NetworkAdapter (DeviceID = "6")                       Win32_NetworkAdapterConfiguration (Index = 6)
Win32_NetworkAdapter (DeviceID = "7")                       Win32_NetworkAdapterConfiguration (Index = 7)
Win32_NetworkAdapter (DeviceID = "8")                       Win32_NetworkAdapterConfiguration (Index = 8)
Win32_NetworkAdapter (DeviceID = "9")                       Win32_NetworkAdapterConfiguration (Index = 9)
Win32_NetworkAdapter (DeviceID = "10")                      Win32_NetworkAdapterConfiguration (Index = 10)
Win32_NetworkAdapter (DeviceID = "11")                      Win32_NetworkAdapterConfiguration (Index = 11)
Win32_NetworkAdapter (DeviceID = "12")                      Win32_NetworkAdapterConfiguration (Index = 12)

 

Which is cool – we can see the links

A quicker way to discover this linking class is to do

Get-CimClass -ClassName *NetworkAdapter* -Qualifier "Association"

Now how do we use this link

Get-CimAssociatedInstance -CimInstance $nic -Association Win32_NetworkAdapterSetting

ServiceName      DHCPEnabled      Index       Description
———–      ———–      —–       ———–
netvsc           False            7           Microsoft Virtual Machine Bus …

 

which we know from the output above is the correct link

Same answer as WMI using a WQL query or GetRelated – just a different route


January 18, 2012  1:29 PM

Running a function

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Most of my scripts end up being functions because I will eventually combine them into modules

My recent script

function get-logedonuser {                        
param (                        
 [string]$computername = $env:COMPUTERNAME                        
)                        
Get-WmiObject -Class Win32_LogonSession -ComputerName $computername |                        
foreach {                        
 $data = $_                        
                        
 $id = $data.__RELPATH -replace """", "'"                        
 $q = "ASSOCIATORS OF {$id} WHERE ResultClass = Win32_Account"                        
 Get-WmiObject -ComputerName $computername -Query $q |                        
 select @{N="User";E={$($_.Caption)}},                         
 @{N="LogonTime";E={$data.ConvertToDateTime($data.StartTime)}}                        
}                        
}

Prompted a comment about how could you run this script.

First off I would save it to a file – get-logedonuser.ps1

You can then either

Open PowerShell Integrated Scripting Environment (ISE) and the open the file. if you run the file the function is added into memory and you can run it as get-logedonuser

 

OR

open the PowerShell console, change to the folder where you saved the file, and run . ./get-logedonuser.ps1

This “dot sources” the script and leaves the function in memory. Then run get-logedonuser as before


January 18, 2012  1:18 PM

Associated Classes

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

If I run

Get-WmiObject -Class Win32_NetworkAdapter

I get a list of the Network Adapters in my system plus some information about the adapter.  What I don’t get is the IP addressing and other configuration information because it is stored on the Win32_NetworkAdapterConfiguration class.

 

The key property on Win32_NetworkAdapter is DeviceId.  My wireless card is DeviceId 11.

 

There is an association between the Win32_NetworkAdapter class and the corresponding Win32_NetworkAdapterConfiguration class. The Win32_NetworkAdapterConfiguration  class uses Index to identify the card and

Win32_NetworkAdapter.DeviceId = Win32_NetworkAdapterConfiguration.Index

So I could  do this

Get-WmiObject -Class Win32_NetworkAdapter -Filter "DeviceID=11"

Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "Index=11"

 

A better way is work through the association

$nic = Get-WmiObject -Class Win32_NetworkAdapter -Filter "DeviceID=11"
$nic
$q = "ASSOCIATORS OF {Win32_NetworkAdapter.DeviceID=$($nic.DeviceID)} WHERE ResultClass = Win32_NetworkAdapterConfiguration"
Get-WmiObject -Query $q

 

I tend to use WQL but there is an alternative

$nic = Get-WmiObject -Class Win32_NetworkAdapter -Filter "DeviceID=11"
$nic
$nic.GetRelated("Win32_NetworkAdapterConfiguration")

 

The WMI object has a GetRelated() method

if you just do

$nic.GetRelated()

you will get all associations – its the equivalent of

$q = "ASSOCIATORS OF {Win32_NetworkAdapter.DeviceID=$($nic.DeviceID)} "
Get-WmiObject -Query $q

 

One slight problem is that if you do

$nic | Get-Member

you won’t see the method – you will need to do this

$nic | Get-Member -View base

 

Which one should you use?  Its your choice. I tend to use WQL out of habit but GetRelated() is less typing.


January 17, 2012  3:00 PM

Get the logged on users

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Do you know which users are logged on to your systems?

Want to find out?

function get-logedonuser {            
param (            
 [string]$computername = $env:COMPUTERNAME            
)            
Get-WmiObject -Class Win32_LogonSession -ComputerName $computername |            
foreach {            
 $data = $_            
            
 $id = $data.__RELPATH -replace """", "'"            
 $q = "ASSOCIATORS OF {$id} WHERE ResultClass = Win32_Account"            
 Get-WmiObject -ComputerName $computername -Query $q |            
 select @{N="User";E={$($_.Caption)}},             
 @{N="LogonTime";E={$data.ConvertToDateTime($data.StartTime)}}            
}            
}

 

Use the Win32_LogonSession class and then find the associated Win32_Account classes.  It does work for domain and local accounts


January 16, 2012  2:43 PM

CIM sessions

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

When we last looked at the CIM cmdlets we saw that by default they use WSMAN to access remote computers but this only works if the remote computer is running PowerShell v3 with version 3.0 of the WSMAN stack.

We can force the CIM cmdlets to use DCOM by configuring a CIM session. These are analogous to PSsessions we create when using PowerShell remoting.

CIM sessions default to WSMAN – everything with CIM defaults to WSMAN unless you are accessing the local machine

PS> $sw = New-CimSession -ComputerName webr201
PS> $sw

Id           : 1
Name         : CimSession1
InstanceId   : 91ad5f5e-d5a9-4776-9965-3c520f8bb9a0
ComputerName : webr201
Protocol     : WSMAN

 

Get-CimInstance -CimSession $sw -ClassName Win32_ComputerSystem

 

Now returns the result over the session. Using a session or using

Get-CimInstance -ClassName Win32_ComputerSystem -computername webr201

 

both return an object of type

Microsoft.Management.Infrastructure.CimInstance#root/cimv2/Win32_ComputerSystem

 

So how do we create a session using DCOM?

 

PS> $opt = New-CimSessionOption -Protocol DCOM
PS> $sd = New-CimSession -ComputerName server02 -SessionOption $opt
PS> $sd

Id           : 2
Name         : CimSession2
InstanceId   : 3066aa29-7062-423d-a0ab-13b29cd86013
ComputerName : server02
Protocol     : DCOM

 

This session is used in the same way as a WSMAN session

Get-CimInstance -CimSession $sd -ClassName Win32_ComputerSystem

 

and returns the same object type.

We can even mix and match CIMsessions over WSMAN and DCOM

 

PS> Get-CimInstance -CimSession $sw, $sd -ClassName Win32_ComputerSystem | Format-Table Name, TotalPhysicalMemory –AutoSize

Name     TotalPhysicalMemory
—-     ——————-
SERVER02         17108066304
WEBR201            536403968

 

The CimSession parameter takes pipeline input so we can do this

Get-CimSession | Get-CimInstance -ClassName Win32_ComputerSystem | Format-Table Name, TotalPhysicalMemory –AutoSize

 

which has to be a cool way to access remote machines.


January 15, 2012  3:43 PM

Boot partition

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Do you know which disk partition your system boots from?

Its easy to find out

function get-bootpartition {            
[CmdletBinding()]            
param (            
 [parameter(ValueFromPipeline=$true,            
   ValueFromPipelineByPropertyName=$true)]            
 [string]$computername="$env:COMPUTERNAME"            
)            
PROCESS{                
              
  Get-WmiObject -Class Win32_DiskPartition -Filter "BootPartition = $true" -ComputerName $computername            
              
}            
}

 

The filter only returns the partition where BootPartition is set to True


January 14, 2012  12:44 PM

CIM cmdlets and remote machines

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

To access a remote machine using WMI we use

Get-WmiObject -Class Win32_ComputerSystem -ComputerName webr201

 

This is replicated using the CIM cmdlets
Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName webr201

 

No lets repeat with another server
Get-WmiObject  -Class Win32_ComputerSystem -ComputerName server02

and with CIM
Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName server02

Get-CimInstance : The WS-Management service cannot process the request. A DMTF resource URI was used to access a
non-DMTF class. Try again using a non-DMTF resource URI.
At line:1 char:1
+ Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName server02
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Win7Test.Manticore.org:) [Get-CimInstance], CimException
    + FullyQualifiedErrorId : 2150859065,Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand

 

We get an error.  Huh! What’s going on?

The problem is that the WMI cmdlets use DCOM to access remote machines. By default the CIM cmdlets use WSMAN. In fact the only time they use DCOM is to access the local machine IF a machine name such as “.”, “localhost” or “$env:COMPUTERNAME” isn’t used i.e. no use of the –Computername parameter to access local machines.

My webr201 server is using PowerShell v3 but server02 is still on PowerShell v2. We can see the difference

PS> Test-WSMan -ComputerName webr201 -Authentication default

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: 6.1.7601 SP: 1.0 Stack: 3.0

 

PS> Test-WSMan -ComputerName server02 -Authentication default

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: 6.1.7601 SP: 1.0 Stack: 2.0

 

Webr201 is using WSMAN 3 from PowerShell v3 so it works with the CIM cmdlets but server02 is using WSMAN 2 so doesn’t work.   Does that mean that we can’t use the CIM cmdlets against systems running PowerShell v2? NO it doesn’t – it means we need to use CIM sessions but that is a topic for next time


January 12, 2012  3:25 PM

Friday 13th

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Tomorrow is Friday 13th and Manning are offering $13 off any purchase at manning.com.

This would be a good time to get a copy of PowerShell in Practice or PowerShell and WMI

use code “fri1312” at checkout


January 9, 2012  2:15 PM

CIM instances

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

We are use to using Get-WmiObject to retrieve information from WMI. if you have been following this blog for any length of time you will have see lots of examples of that particular cmdlet. The CIM equivalent is Get-CIMInstance. It might appear that Get-CIMClass would be used but that is used to get information about the WMI class itself. think Get-WmiObject –List  on steroids.

This should be familiar

Get-WmiObject -Class Win32_ComputerSystem

The direct comparison is

Get-CimInstance -ClassName Win32_ComputerSystem

 

We can run WQL queries

$q = "SELECT * FROM Win32_ComputerSystem"
Get-WmiObject -Query $q

 

Get-CimInstance -Query $q

 

And we can filter

Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3"

Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3"

 

Another difference is that CIM cmdlets tend to default to a table output but WMI cmdlets tend to default to a list

 

We can even select properties

Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3" -Property DeviceID, FreeSpace, Size

Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" -SelectProperties DeviceID, FreeSpace, Size

 

Here we get a big difference

WMI returns the properties we asked for plus the System properties (those starting with __) for the class. CIM returns the whole object but only the select properties and the system type properties are populated.

 

So far you could be forgiven for thinking these are very similar and we don’t need both. The big differences come when we look at access remote machines next time.


Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to: