Monthly Archive

Categories

Monthly Archives: February 2018

Dynamic parameters

PowerShell has always been an extensible language meaning that you can add things on, change things and even remove things if required. One way that this extensibility surfaces is dynamic parameters.

 

A dynamic parameter is a parameter that is available when certain conditions are met. Many of the core cmdlets (about_Core_Commands) have dynamic parameters that are available dependent on the PowerShell provider currently in use.

 

A PowerShell provider exposes a data store in the same way as the file system

PS> Get-PSProvider | select Name, Drives

Name        Drives
----        ------
Registry    {HKLM, HKCU}
Alias       {Alias}
Environment {Env}
FileSystem  {C, D}
Function    {Function}
Variable    {Variable}
Certificate {Cert}

 

You can view the available certificates.

Get-ChildItem -Path Cert:\CurrentUser\ –Recurse

 

Now view the syntax of Get-ChildItem

PS> Get-Command Get-ChildItem -Syntax

Get-ChildItem [[-Path] <string[]>] [[-Filter] <string>] [-Include <string[]>] [-Exclude <string[]>] [-Recurse] [-Depth <uint32>] [-Force] [-Name] [-UseTransaction] [-Attributes <FlagsExpression[FileAttributes]>] [-Directory] [-File] [-Hidden] [-ReadOnly] [-System] [<CommonParameters>]

Get-ChildItem [[-Filter] <string>] -LiteralPath <string[]> [-Include <string[]>] [-Exclude <string[]>] [-Recurse] [-Depth <uint32>] [-Force] [-Name] [-UseTransaction] [-Attributes <FlagsExpression[FileAttributes]>] [-Directory] [-File] [-Hidden] [-ReadOnly] [-System] [<CommonParameters>]

 

Move into the cert: drive and have another look at Get-ChildItem

PS> Get-Command Get-ChildItem -Syntax

Get-ChildItem [[-Path] <string[]>] [[-Filter] <string>] [-Include <string[]>] [-Exclude <string[]>] [-Recurse] [-Depth <uint32>] [-Force] [-Name] [-UseTransaction] [-CodeSigningCert] [-DocumentEncryptionCert] [-SSLServerAuthentication] [-DnsName <DnsNameRepresentation>] [-Eku <string[]>] [-ExpiringInDays <int>] [<CommonParameters>]

Get-ChildItem [[-Filter] <string>] -LiteralPath <string[]> [-Include <string[]>] [-Exclude <string[]>] [-Recurse] [-Depth <uint32>] [-Force] [-Name] [-UseTransaction] [-CodeSigningCert] [-DocumentEncryptionCert] [-SSLServerAuthentication] [-DnsName <DnsNameRepresentation>] [-Eku <string[]>] [-ExpiringInDays <int>] [<CommonParameters>]

 

Comparing the 2 syntax lists you’ll see a number of differences. These are the dynamic parameters.

You can use –Eku for instance for filter the certificates

Get-ChildItem -Path Cert:\CurrentUser\ -Recurse -Eku 'Client'

 

If you try to run that command from any drive but cert: it’ll fail.

 

You can discover the dynamic parameters that are available for a particular provider by looking at the provider’s help

Get-Help certificate

 

When you’re working with PowerShell providers and drives remember to check what dynamic parameters are available – could save you some time and effort.

 

Note these dynamic parameters don’t appear to be available in PowerShell v6

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.