header image

Archive for PowerShell and CIM

Testing Windows activation

Posted by: | August 29, 2019 Comments Off on Testing Windows activation |

Testing Windows activation from PowerShell involves a little dive into CIM (WMI).

At its simplest a function like this

function test-activation {

$ta = Get-CimInstance -ClassName SoftwareLicensingProduct -Filter “PartialProductKey IS NOT NULL” |
Where-Object -Property Name -Like “Windows*”

if ($ta.LicenseStatus -eq 1) {$true} else {$false}
}

 

Checks the SoftwareLicensingProduct class for instances with a Partial product key. Where-Object filters on the Name of the product. It has to start with Windows.

 

If the LicenseStatus equals 1 then Windows is activated – otherwise it isn’t

under: PowerShell and CIM

Volume friendly name

Posted by: | July 24, 2019 Comments Off on Volume friendly name |

When you use Get-Volume one of the properties displayed is the friendly name

PS> Get-Volume -DriveLetter C

DriveLetter FriendlyName FileSystemType
———– ———— ————–
C NTFS

 

In this case its blank because I haven’t set a volume label.

If you try to access the FriendlyName property

PS> (Get-Volume ).FriendlyName

 

You’ll get nothing returned.

 

The actual property is FileSystemLabel

PS> (Get-Volume ).FileSystemLabel

 

FriendlyName is an alias for FileSystemLabel created in the CDXML that is used to create the storage module and in the formating system for display.

 

Use

PS> Get-Volume -DriveLetter C | Format-List *

and

PS> Get-Volume -DriveLetter C | Get-Member

 

to view the properties on the object

under: PowerShell and CIM

Logon sessions

Posted by: | July 4, 2019 Comments Off on Logon sessions |

Saw a question about logon sessions that had me looking at CIM class Win32_LogonSession. I really don’t like the example code they have – code shouldn’t posted that contains aliases especially the abominable use of ? for Where-Object (pet PowerShell peeve number 3).

 

Something like this is a better example – especially as it demonstrates using CIM associations.

Get-CimInstance -ClassName Win32_Logonsession |
Where-Object LogonType -in @(2,10) |
ForEach-Object {

switch ($_.LogonType){
2 {$type = ‘Interactive Session’}
10 {$type = ‘Remote Session’}
default {throw “Broken! Unrecognised logon type” }
}

$usr = Get-CimAssociatedInstance -InputObject $psitem -ResultClassName Win32_Account
$props = [ordered]@{
Name = $usr.Name
Domain = $usr.Domain
SessionType = $type
LogonTime = $_.StartTime
Authentication = $_.AuthenticationPackage
Local = $usr.LocalAccount
}
if ($props.Name) {New-Object -TypeName PSobject -Property $props}
}

 

Get the instances of Win32_LogonSession where the LogonType is 2 (interactive) or 10 remote (RDP type session) and for each of them find the associated instance of Win32_Account (user information). Create the output object if the Win32_Account has the name property populated. This filters out historical sessions.

 

I could have used a Filter instead of Where-Object to perform the filtering but I may want to extend the number of types of session I include and doing it this way is easier than have a massive filter statement with lots of ORs

under: PowerShell and CIM

Windows Server 2019 updates with CIM

Posted by: | May 19, 2019 Comments Off on Windows Server 2019 updates with CIM |

Windows Server 2019 updates with CIM remain the same as all server versions post Windows Server 2016. This code will check for and install any updates. Micorosft Update or WSUS will be used depending on how your system is configured

 

$au = Invoke-CimMethod -Namespace root/microsoft/windows/windowsupdate -ClassName MSFT_WUOperations -MethodName ScanForUpdates -Arguments @{SearchCriteria=”IsInstalled=0″}
$au.Updates

if ($au.Updates.Length -gt 0) {
Invoke-CimMethod -Namespace root/microsoft/windows/windowsupdate -ClassName MSFT_WUOperations -MethodName InstallUpdates -Arguments @{Updates = $au.Updates}
}
else {
Write-Warning “No updates available”
}

 

This code should work on Server 1709, 1803, 1809 and Windows Server 2019.

It won’t work on Windows Server 2016 as the CIM classes were changed post Windows Server 2016

under: PowerShell and CIM, Windows Server 2019

CIM_Component class

Posted by: | April 25, 2019 Comments Off on CIM_Component class |

I saw a question about the CIM_Component class and wondered what it was. So I tried it

 

PS> Get-CimInstance -Namespace root\CIMV2 -ClassName CIM_Component | select -f 1 | fl *

GroupComponent : Win32_Directory (Name = “<directory path>”)
PartComponent : CIM_DataFile (Name = “<file path>”)
PSComputerName :
CimClass : root/CIMV2:CIM_DirectoryContainsFile
CimInstanceProperties : {GroupComponent, PartComponent}
CimSystemProperties : Microsoft.Management.Infrastructure.CimSystemProperties

 

What you’ll get is a list of every file on your system – showing folder in the GroupComponent (parent) and File in the PartComponent (child).

The documentation is totally accurate and totally useless as it explains that you get a parent-child relationship but not what’s in it!

I’d strongly recommend against using this class – there are easier ways to get the information.

under: PowerShell and CIM

File searches with WMI

Posted by: | August 19, 2018 Comments Off on File searches with WMI |

I saw a question about file searches with WMI.

If you just know the file name it’s a very slow process. Painfully slow.

If you have an idea about the folder its much quicker.

 

function get-wmifile {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string]$path,

[string]$file

)

if ($path.IndexOf('\\') -le 0 ){
$path = $path.replace('\', '\\')
}

if ($path.IndexOf('*') -ge 0 ){
$path = $path.replace('*', '%')
}

Write-Verbose -Message "Path to search: $path"

$folders = Get-CimInstance -ClassName Win32_Directory -Filter "Name LIKE '$path'" 
foreach ($folder in $folders){

if ($file) {
Get-CimAssociatedInstance -InputObject $folder -ResultClassName CIM_DataFile |
where Name -Like "*$file" |
Select Name
}
else {
Get-CimAssociatedInstance -InputObject $folder -ResultClassName CIM_DataFile |
Select Name
}
}

}

 

Take the path and replace any single \ with \\. WMI expects c:\\test NOT c:\test.

Likewise replace the wildcard * with the WMI wildcard equivalent %

Get the folders that are like the path. Foreach folder use the WMI association between Win32_Directory and CIM_datafile to get the files. if you’ve specified a file then just return that otherwise all files in the folders matching path.

 

The WMI approach works and if you add in the computer name you can use remoting to get the answer from a remote machine.

 

As a comparison using Get-ChildItem would be

PS> Get-ChildItem -Path c:\test* -Recurse -Filter ‘p1.txt’ | select Fullname

which is much quicker.

 

Using WMI to do this is a fun exercise but the fastest approach is to use Get-ChildItem

under: PowerShell and CIM, PowerShell and WMI

user logon time

Posted by: | August 15, 2018 Comments Off on user logon time |

Saw an interesting question about user logon time. How can you tell the logged on user and when they logged on

 

$logon = Get-CimInstance -ClassName Win32_LogonSession |
sort StartTime -Descending |
select -First 1

$user = Get-CimAssociatedInstance -InputObject $logon -ResultClassName Win32_Account

$props = [ordered]@{
Name = $user.Fullname
UserId = $user.Name
Domain = $user.Domain
LocalAccount = $user.LocalAccount
LogonTime = $logon.StartTime
}

New-Object -TypeName PSobject -Property $props

 

Start by getting the last logon session using Win32_LogonSession. Use that to find the associated account using Get-CimAssociatedInstance and the Win32_Account class.

 

Pull together the output you want and create an object to display.

 

This deliberately only takes the latest logon and deals with that

under: PowerShell and CIM, PowerShell and WMI

WMI and CIM accelerators

Posted by: | May 26, 2018 Comments Off on WMI and CIM accelerators |

In PowerShell an accelerator is a shortcut to a .NET type. The WMI accelerators have been around since PowerShell v1. The WMI accelerators were heavily used in v1 fill some of the gaps in cmdlet coverage. The CIM accelerators appeared in PowerShell v3 (I think – only discovered them recently!). This is how you use the WMI and CIM accelerators.

 

There are three WMI accelerators

wmiclass is shortcut for System.Management.ManagementClass
wmi is shortcut for System.Management.ManagementObject
wmisearcher is shortcut for System.Management.ManagementObjectSearcher

 

And four CIM accelerators are

ciminstance is shortcut for Microsoft.Management.Infrastructure.CimInstance
cimclass is shortcut for Microsoft.Management.Infrastructure.CimClass
cimtype is shortcut for Microsoft.Management.Infrastructure.CimType
cimconverter is shortcut for Microsoft.Management.Infrastructure.CimConverter

plus

CimSession which is a shortcut for Microsoft.Management.Infrastructure.CimSession. Use this to set a parameter type.

 

Notice that there isn’t a direct correspondence between the WMI and CIM accelerators.

PowerShell v6 only has the CIM accelerators

 

The WMI accelerators are used like this:

WMICLASS

This can be used for creating new instances of CIM classes

PS> $p = [wmiclass]’Win32_Process’
PS> $p.Create(“notepad.exe”)

This is easily replicated using the CIM cmdlets

PS> Invoke-CimMethod -ClassName Win32_Process -MethodName create -Arguments @{CommandLine=’notepad.exe’}

 

WMI

The [wmi] accelerator is used to find an instance BUT you have to use the class key!

PS> [wmi]”root\cimv2:Win32_Process.Handle=’7264′”

NOTE the handle has to be the one reported by CIM NOT the one reported by Get-Process!

Its much easier to use Get-CimInstance and filter on the name

Get-CimInstance -ClassName Win32_Process -Filter “Name=’pwsh.exe'”

 

WMISEARCHER

This is used to find CIM instances:

PS> $query = [wmisearcher]”SELECT * FROM Win32_Process WHERE Name=’pwsh.exe'”
PS> $query.Get()

Its easier to use Get-CIMinstance these days

PS> Get-CimInstance -ClassName Win32_Process -Filter “Name=’pwsh.exe'”

 

Looking at the CIM accelerators

CIMINSTANCE

This one doesn’t seem to be usable for anything but a type decorator on a parameter.

 

CIMCLASS

Using Get-CimClass

PS> Get-CimClass -ClassName Win32_process | fl

CimSuperClassName : CIM_Process
CimSuperClass : ROOT/cimv2:CIM_Process
CimClassProperties : {Caption, Description, InstallDate, Name…}
CimClassQualifiers : {Locale, UUID, CreateBy, DeleteBy…}
CimClassMethods : {Create, Terminate, GetOwner, GetOwnerSid…}
CimSystemProperties : Microsoft.Management.Infrastructure.CimSystemProperties
CimClassName : Win32_Process

The output is of type Microsoft.Management.Infrastructure.CimClass for which cimclass is an accelerator BUT there doesn’t seem to be a way to use the accelerator to access a class. I think this one is only usable as a type on a parameter for a function where you want to pass in a CIM class object.

 

CIMTYPE

Microsoft.Management.Infrastructure.CimType is an enum that contains the CIM (and WMI) datatypes:

PS> [cimtype]::Boolean
Boolean
PS> [cimtype]::UInt32
UInt32

The full set of CIM data types is

PS> [enum]::GetNames([cimtype])
Unknown
Boolean
UInt8
SInt8
UInt16
SInt16
UInt32
SInt32
UInt64
SInt64
Real32
Real64
Char16
DateTime
String
Reference
Instance
BooleanArray
UInt8Array
SInt8Array
UInt16Array
SInt16Array
UInt32Array
SInt32Array
UInt64Array
SInt64Array
Real32Array
Real64Array
Char16Array
DateTimeArray
StringArray
ReferenceArray
InstanceArray

 

CIMCONVERTOR

Some of the CIM data types shown above don’t directly correspond to .NET types you’re used to from PowerShell. You can use [cimconvertor] which is shortcut for Microsoft.Management.Infrastructure.CimConverter to discover the corresponding .NET or CIM data type

.NET to CIM

PS> [cimconverter]::GetCimType([int32])
SInt32
PS> [cimconverter]::GetCimType([double])
Real64

CIM to .NET

PS> [cimconverter]::GetDotNetType([cimtype]::SInt32)

IsPublic IsSerial Name BaseType
——– ——– —- ——–
True True Int32 System.ValueType

PS> [cimconverter]::GetDotNetType([cimtype]::Instance)

IsPublic IsSerial Name BaseType
——– ——– —- ——–
True True CimInstance System.Object

 

For the most part I think the WMI and CIM accelerators are best ignored. Use the CIM cmdlets instead. The cimtype and cimconverter accelerators are useful when developing code to check on types between CIM and .NET

under: PowerShell and CIM, PowerShell and WMI

CIM references and associations

Posted by: | April 24, 2018 Comments Off on CIM references and associations |

Way back in 2011, when I were just a young lad, I wrote about WMI or CIM references and associations – https://wordpress.com/read/blogs/16267735/posts/1673

ASSOCIATORS show the end point of the link between CIM classes and REFERENCES shows the linking class.

I used the Win32_NetworkAdapter class in the example because it has a known association with Win32_NetworkAdapterConfiguration.

 

One thing I appear to have not made clear is that you have to use the key to the CIM class in the query for the reference or association. The key for a Win32_networkadapter class is DeviceID.

This became clear when a reader pointed out that this won’t work:

PS> Get-WmiObject -Query “REFERENCES OF {win32_printer.name = ‘fax’}”
Get-WmiObject : Invalid object path
At line:1 char:1
+ Get-WmiObject -Query “REFERENCES OF {win32_printer.name = ‘fax’}”
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], ManagementException
+ FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

 

But that

Get-WmiObject -Query “REFERENCES OF {Win32_Printer.DeviceID=’Fax’}”

works. Again DeviceId is the key to the class.

 

Usually its better to go straight to the association and bypass the reference.

A better approach than writing WQL queries is to use the CIM cmdlets

$p = Get-CimInstance -ClassName Win32_Printer -Filter “Name=’Fax'”

Get-CimAssociatedInstance -InputObject $p

will show you the data from the associated classes.

 

If you just want to see the associated class names

PS> Get-CimAssociatedInstance -InputObject $p | select CIMclass

CimClass
——–
root/cimv2:Win32_PrinterDriver
root/cimv2:Win32_PrinterConfiguration
root/cimv2:Win32_ComputerSystem
root/cimv2:CIM_DataFile

 

And if you just want the data for a particular associated class

PS> Get-CimAssociatedInstance -InputObject $p -ResultClassName Win32_PrinterDriver

Caption :
Description :
InstallDate :
Name : Microsoft Shared Fax Driver,3,Windows x64
Status :
CreationClassName : Win32_PrinterDriver
Started :
StartMode :
SystemCreationClassName : Win32_ComputerSystem
SystemName :
ConfigFile : C:\WINDOWS\system32\spool\DRIVERS\x64\3\FXSUI.DLL
DataFile : C:\WINDOWS\system32\spool\DRIVERS\x64\3\FXSUI.DLL
DefaultDataType :
DependentFiles : {C:\WINDOWS\system32\spool\DRIVERS\x64\3\FXSWZRD.DLL,
C:\WINDOWS\system32\spool\DRIVERS\x64\3\FXSTIFF.DLL,
C:\WINDOWS\system32\spool\DRIVERS\x64\3\FXSRES.DLL,
C:\WINDOWS\system32\spool\DRIVERS\x64\3\FXSAPI.DLL}
DriverPath : C:\WINDOWS\system32\spool\DRIVERS\x64\3\FXSDRV.DLL
FilePath :
HelpFile :
InfName :
MonitorName :
OEMUrl :
SupportedPlatform : Windows x64
Version : 3
PSComputerName :

under: PowerShell and CIM

CIM_ or Win32_

Posted by: | February 1, 2018 Comments Off on CIM_ or Win32_ |

If you dig into the classes available on a Windows machine you’ll see a mixture of prefixes – namely CIM_ and Win32_ used for the classes. So which should you use CIM_ or Win32_

 

Lets start by seeing whats available:

PS> Get-CimClass -ClassName *Volume*


    NameSpace: ROOT/CIMV2

CimClassName
------------
Win32_VolumeChangeEvent
Win32_VolumeQuota
Win32_VolumeQuotaSetting
Win32_VolumeUserQuota
CIM_StorageVolume
Win32_Volume
CIM_VolumeSet
Win32_ShadowVolumeSupport
CIM_LogicalDiskBasedOnVolumeSet
Win32_ShadowDiffVolumeSupport

 

The CIM_ classes follow the standard definition from the DMTF – https://www.dmtf.org/standards/cim

The Win32_ classes are Microsoft’s versions of the equivalent CIM_ class often with additional properties and methods.

 

I’ve always recommended using the Win32_ classes because they are “optimised” for Windows. The one exception that I’ve found is CIM_Datafile that doesn’t have a Win32_ equivalent.

 

A question on the forum asked why this was failing

PS> Get-CimInstance -ClassName CIM_StorageVolume -Filter "DriveLetter='C:'"
 Get-CimInstance : Invalid query
 At line:1 char:1
 + Get-CimInstance -ClassName CIM_StorageVolume -Filter "DriveLetter='C: ...
 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     + CategoryInfo          : InvalidArgument: (:) [Get-CimInstance], CimException
     + FullyQualifiedErrorId : HRESULT 0x80041017,Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand

 

When this worked

PS> Get-CimInstance -ClassName CIM_StorageVolume | select Name, DriveLetter, Capacity

Name                                              DriveLetter     Capacity
 ----                                              -----------     --------
 \\?\Volume{c1c4c5bb-0000-0000-0000-100000000000}\                366997504
 C:\                                               C:          511210610688
 \\?\Volume{c1c4c5bb-0000-0000-0000-801c77000000}\                529526784
 D:\                                               D:

 

The reason is that you’re not getting back CIM_StorageVolume:

PS> Get-CimInstance -ClassName CIM_StorageVolume | Get-Member


    TypeName: Microsoft.Management.Infrastructure.CimInstance#root/cimv2/Win32_Volume

 

You’re getting Win32_Volume which DOES have a DriveLetter property. Get-WmiObject works in the same way. Looking at the properties:

PS> (Get-CimClass -ClassName CIM_StorageVolume ).CimClassProperties | Where Name -like "D*"


Name               : Description
Value              :
CimType            : String
Flags              : Property, ReadOnly, NullValue
Qualifiers         : {read}
ReferenceClassName :

Name               : DeviceID
Value              :
CimType            : String
Flags              : Property, ReadOnly, NullValue
Qualifiers         : {CIM_Key, read}
ReferenceClassName :

 

No DriveLetter. Now try Win32_Volume

PS> (Get-CimClass -ClassName Win32_Volume ).CimClassProperties | Where Name -like "D*"


Name               : Description
Value              :
CimType            : String
Flags              : Property, ReadOnly, NullValue
Qualifiers         : {read}
ReferenceClassName :

Name               : DeviceID
Value              :
CimType            : String
Flags              : Property, Key, ReadOnly, NullValue
Qualifiers         : {CIM_Key, read, key, MappingStrings...}
ReferenceClassName :

Name               : DirtyBitSet
Value              :
CimType            : Boolean
Flags              : Property, ReadOnly, NullValue
Qualifiers         : {read}
ReferenceClassName :

Name               : DriveLetter
Value              :
CimType            : String
Flags              : Property, NullValue
Qualifiers         : {read, write}
ReferenceClassName :

Name               : DriveType
Value              :
CimType            : UInt32
Flags              : Property, ReadOnly, NullValue
Qualifiers         : {MappingStrings, read}
ReferenceClassName :

 

Win32_Volume has 2 extra properties that start with the letter D, including DriveLetter. Win32_Volume is derived from, and builds on, CIM_StorageVolume

PS> Get-WmiObject -Class Win32_Volume | select -First 1 | select -ExpandProperty __Derivation
 CIM_StorageVolume
 CIM_StorageExtent
 CIM_LogicalDevice
 CIM_LogicalElement
 CIM_ManagedSystemElement

 

If you want to get volume information on a Windows box use Win32_Volume or better still on Windows 8 and later use Get-Volume.

The only possible reason for using CIM_StorageVolume is that you’re learning more about CIM or you’re trying some cross-platform task. As I can’t think of a platform other than Windows that has implemented CIM_StorageVolume not sure how far you’ll get on the latter. If you do try CIM_StorageVolume you can filter using the Name property:

Get-CimInstance -ClassName CIM_StorageVolume -Filter "Name='C:\\'"

 

Note that you have to use C:\\ not C:\ because \ is an escape character in WQL.

Alternatively, use where-object to filter:

Get-CimInstance -ClassName CIM_StorageVolume | where DriveLetter -eq 'C:'

 

If you’re working remotely the first option is best as it reduces the amount of data being returned across the network.

 

If in doubt use the Win32_ class rather than the CIM class.

 

under: PowerShell and CIM

Older Posts »

Categories