Richard Siddaway's Blog

Archive for May, 2018

Splitting into pairs

without comments

During my session on scriptblocks at Summit 2018 I showed how to split a string into pairs of values

Start with this string

PS> $str = ‘Jack,Jill,Bill,Ben,Eric,Ernie,Cagney,Lacey’


You want the string split in the commas – but every other comma so you get pairs if values separated by a comma.

You need to set a counter
PS> $count=@(0)
PS> $count


Then use a scriptblock to control the split
PS> $str -split {$_ -eq ‘,’ -AND ++$count[0] % 2 -eq 0}
PS> $count


You need to use an array because the scriptblock executes in its own context and a scalar value wouldn’t be updated as you need.


PS> $count2 = 0
PS> $str -split {$_ -eq ‘,’ -AND ++$count2 % 2 -eq 0}
PS> $count2

and nothing happens.

Written by richardsiddaway

May 31st, 2018 at 9:45 am

Posted in PowerShell

Summit 2018 sessions

without comments

Written by richardsiddaway

May 31st, 2018 at 9:30 am

Posted in PowerShell,Summit

PowerShell functionality

without comments

PowerShell functionality – in the form of modules – comes from a number of different sources.

These are:

Powershell itself including the Microsoft.PowerShell.* modules and CIM cmdlets

Windows Team – this includes the modules such as NetAdapter, NetTCPIP, Storage that were first introduced with Windows 8 and have been part of all subsequent Windows client and server versions. These modules are often CDXML (CIM based) which means they won’t be found, and can’t be installed, on versions of Windows earlier than Windows 8

Windows feature installs – these modules are installed when you install a windows feature or role such as DNS, AD, IIS or Hyper-V. Many of then are also available as part the RSAT tools. Their presence on your system is dependent on what features are installed.

Modules you have written – totally unique to you

Modules you’ve down loaded from the PowerShell gallery or other repository. Again the presence of a particular module depends on what you’ve downloaded.

Modules from third party vendors – such as NetApp or VMWare. Their presence depends on what you’ve bought and installed.

If you can’t find a cmdlet or module on your system check that its available for that version of windows then check to see where it comes from. You may, depending on the source, be able to download and/or install it.

Written by richardsiddaway

May 31st, 2018 at 9:15 am

Posted in PowerShell

Hyper-V book

without comments

The Month of Lunches Hyper-V book I was working on was cancelled by the publisher.

The good news is that it’s most likely going to be resurrected with another publisher and will hopefully be available later this year.

More to follow when the details are finalised

Written by richardsiddaway

May 28th, 2018 at 3:50 pm

Posted in Hyper-V

WMI and CIM accelerators

without comments

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


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:


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’}



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'”



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


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



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.



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

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

The full set of CIM data types is

PS> [enum]::GetNames([cimtype])



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


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


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

Written by richardsiddaway

May 26th, 2018 at 4:15 pm

PowerShell parameter sets

without comments

PowerShell parameter sets allow you to control which parameters can be used together. If a parameter isn’t in the parameter set you’re trying to use you’ll get an error message.

PS> Get-VM -Name XYZ -id (New-Guid)
 Get-VM : Parameter set cannot be resolved using the specified named parameters.
 At line:1 char:1
 + Get-VM -Name XYZ -id (New-Guid)
 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 + CategoryInfo : InvalidArgument: (:) [Get-VM], ParameterBindingException
 + FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.HyperV.PowerShell.Commands.GetVM


You can also use parameter sets to help control the processing within your function as this example shows:

function Convert-Temperature {
param (



$temps = New-Object -TypeName psobject -Property @{
'Temperature-Celsius' = 0.0
'Temperature-Fahrenheit' = 0.0
'Temperature-Kelvin' = 0.0

switch ($psCmdlet.ParameterSetName) {
"Celsius" {
$temps.'Temperature-Celsius' = $degreeC
$temps.'Temperature-Fahrenheit' = [math]::Round((32 + ($degreeC * 1.8)), 2)
$temps.'Temperature-Kelvin' = $degreeC + 273.15

"Fahrenheit" {
$temps.'Temperature-Celsius' = [math]::Round((($degreeF - 32) / 1.8), 2)
$temps.'Temperature-Fahrenheit' = $degreeF
$temps.'Temperature-Kelvin' = $temps.'Temperature-Celsius' + 273.15

"Kelvin" {
$temps.'Temperature-Celsius' = $degreeK - 273.15
$temps.'Temperature-Fahrenheit' = [math]::Round((32 + ($temps.'Temperature-Celsius' * 1.8)), 2)
$temps.'Temperature-Kelvin' = $degreeK

default {Write-Error -Message "Error!!! Should not be here" }



Each of the input parameters is in its own parameter set meaning that they are mutually exclusive – you can only use one of them!

The switch statement uses the active parameter set name to decide how to perform the relevant conversions – the output object contains the temperature in Celsius, Fahrenheit and Kelvin

Written by richardsiddaway

May 22nd, 2018 at 7:04 pm

Posted in PowerShell

PowerShell version

without comments

Discovering the PowerShell version you’re using can be an interesting task.

The automatic variable $PSVersionTable was introduced in PowerShell v2. On my Windows 10 version 1803 machine for Windows PowerShell I get

PS> $PSVersionTable

Name Value
—- —–
PSVersion 5.1.17134.48
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
BuildVersion 10.0.17134.48
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3


$PSVersionTable is a hashtable so the order in which items are displayed may vary. The contents of the hashtable have changed over time as well.


The important parts of $PsversionTable include:

The version of PowerShell itself

PS> $PSVersionTable.PSVersion

Major Minor Build Revision
—– —– —– ——–
5 1 17134 48

PS> $PSVersionTable.PSVersion.Major

This a simple test for version.


The edition is also important

PS> $PSVersionTable.PSEdition

Desktop means its full CLR – in other words Windows PowerShell


The WSMAN version is also important

PS> $PSVersionTable.WSManStackVersion

Major Minor Build Revision
—– —– —– ——–
3 0 -1 -1

You need v3 to use CIM sessions.


With PowerShell v6 you get a few more options

PS> $PSVersionTable

Name Value
—- —–
PSVersion 6.0.1
PSEdition Core
GitCommitId v6.0.1
OS Microsoft Windows 10.0.17134
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
WSManStackVersion 3.0


Notice PSEdition is set to Core.

The OS and Platform data are v6 only

The PSRemotingProtocolVersion, SerializationVersion and WSManStackVersion are the same for Windows PowerShell v5.1 and PowerShell v6.


PowerShell v6 runs on Windows, Linux and macOS. You can test which OS you’re on from $PSVersionTable or more simply using the following automatic variables:

PS> ls variable:\is*

Name Value
—- —–
IsLinux False
IsMacOS False
IsWindows True
IsCoreCLR True

Using these you could create branching logic to perform a task by calling the appropriate command based on the underlying operating system.

Written by richardsiddaway

May 22nd, 2018 at 2:54 pm

Format Data

without comments

PowerShell will format the output of objects that it knows about. For instance Get-Process shows different sets of properties depending on whether you choose a table or list view. The format data is stored in files named *.format.ps1xml.

In Windows PowerShell the format files are found in C:\Windows\System32\WindowsPowerShell\v1.0. In PowerShell v6 the format files are stored with the appropriate module.


If you want to create formatting for a new object, or change the formatting for an existing object the best place to start is to export the format data for an existing object

Get-FormatData -TypeName System.Diagnostics.Process | Export-FormatData -Path f5.txt

gets the format data for the object used in Get-Process.

The drawback is that is presented a long string

<?xml version=”1.0″ encoding=”utf-8″?><Configuration><ViewDefinitions><View><Name>process</Name><ViewSelectedBy><TypeNam
th><Alignment>Right</Alignment></TableColumnHeader><TableColumnHeader /></TableHeaders><TableRowEntries><TableRowEntry><


And you have to manage the pretty printing yourself.

In PowerShell v6.1 the output is automatically pretty printed

Get-FormatData -TypeName System.Diagnostics.Process | Export-FormatData -Path f6.txt

<?xml version=”1.0″ encoding=”utf-8″?>
<TableColumnHeader />


which makes it much easier to work with

Written by richardsiddaway

May 18th, 2018 at 5:41 pm

Posted in PowerShell v6

where –not

without comments

PowerShell v6.1 preview 2 has added the where –not option.

The option adds another parameter to the syntax

where-object <property name> <operator like parameter> <value>


Couple of examples of using the syntax

Get-Process | where CPU -gt 12

Get-Service | where Status -like ‘Stop*’


Use –Not when you’re looking for properties that aren’t set. For example

Get-Service | where -Not DependentServices


Get-Process | where -Not StartTime

Written by richardsiddaway

May 15th, 2018 at 2:13 pm

Posted in PowerShell v6

Calculating standard deviation

without comments

Calculating a standard deviation isn’t a difficult exercise but PowerShell v6.1 offers an easier method.


In Windows PowerShell v5.1 and PowerShell v6.0 the Measure-Object cmdlet has this syntax

PS> Get-Command Measure-Object -Syntax

Measure-Object [[-Property] <string[]>] [-InputObject <psobject>] [-Sum] [-Average] [-Maximum] [-Minimum] [<CommonParameters>]

Measure-Object [[-Property] <string[]>] [-InputObject <psobject>] [-Line] [-Word] [-Character] [-IgnoreWhiteSpace] [<CommonParameters>]


In PowerShell v6.1.0-preview.2 this changes to

PS> Get-Command Measure-Object -Syntax

Measure-Object [[-Property] <string[]>] [-InputObject <psobject>] [-StandardDeviation] [-Sum] [-Average] [-Maximum] [-Minimum] [<CommonParameters>]

Measure-Object [[-Property] <string[]>] [-InputObject <psobject>] [-Line] [-Word] [-Character] [-IgnoreWhiteSpace] [<CommonParameters>]


You’ve now got a standard deviation option.

How do you use it?

PS> 1..517 | Measure-Object -Sum -Average -StandardDeviation

Count : 517
Average : 259
Sum : 133903
Maximum :
Minimum :
StandardDeviation : 149.389312424506
Property :


There’s probably a few other calculations that would be useful to add to Measure-Object

Written by richardsiddaway

May 11th, 2018 at 2:57 pm

Posted in PowerShell v6