Monthly Archive


Monthly Archives: April 2018

PowerShell v6.1 Range Operator

The PowerShell v6.1 Rang Operator has been enhanced to deal with letters as well as numbers.

The range operator has always been available in PowerShell. It can be used to generate a range of integers for example:

PS>  (1..10) -join ','
PS>  (10..1) -join ','
PS>  (-10..10) -join ','
PS>  (10..-10) -join ','


In PowerShell v6.1 the range operator can also produce sequences of letters

PS>  'a'..'z' -join ','
PS>  'z'..'a' -join ','

PS>  'A'..'Z' -join ','
PS>  'Z'..'A' -join ','


Be careful with mixing case

PS>  'Z'..'a' -join ','
PS>  'a'..'Z' -join ','
PS>  'z'..'A' -join ','
PS>  'A'..'z' -join ','


As you might get more than you wanted  🙂

-Contains or -In

PowerShell has two operators that do very similar jobs –contains and –in. So which should you use –contains or –in.

From the help file.

-Contains: Tells whether a collection of reference values includes a single test value.

-In: Tells whether a test value appears in a collection of reference values

OK – they’re subtly different.


The real difference comes in how you use them

-Contains has been available since PowerShell v1. Its used like this

<reference values> –contains <value>

for example

PS> $rb = 'Red', 'Orange', 'Yellow', 'Green', 'Blue', 'Indigo', 'Violet'
PS> $rb -contains 'yellow'
PS> $rb -contains 'black'


True or false is returned depending if the value is part of the collection or not


By contrast –In (introduced in PowerShell v3) uses this syntax

<value> –in <reference values>

for example

PS> $rb = 'Red', 'Orange', 'Yellow', 'Green', 'Blue', 'Indigo', 'Violet'
PS> 'Blue' -in $rb
PS> 'Black' -in $rb


The difference between the two is the order of the operands.

-In was introduced for use with the short hand syntax of Where-Object

where <property value> operator <value>

so try this

$rb = 'Red', 'Orange', 'Yellow', 'Green', 'Blue', 'Indigo', 'Violet'
$colours = 'Black', 'White', 'Red'

$co = foreach ($colour in $colours) {
New-Object -TypeName psobject -Property @{
Colour = $colour


Then run

$co | where Colour -in $rb

$co | where Colour -contains $rb

$co | where $rb -contains colour

$co | where {$rb -contains $_.colour}


You’ll see the correct answer from the first and fourth options and nothing from the second because the values are the wrong way round. The third option errors

Where-Object : A positional parameter cannot be found that accepts argument
At line:1 char:7
+ $co | where $rb -contains colour
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Where-Object], ParameterBi
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell

Installing PowerShell v6.1 preview 2

The MSI for installing PowerShell v6.1 preview 2 has a screen for optional actions:

Add PowerShell to Path environment variable
Register Windows Event Logging Manifest
Enable PowerShell remoting
Add 'open here' context menus to Explorer


The 6.1 preview installs side by side with PowerShell v6.0.x


Test-Connection in v6.1

PS> Get-Command Test-Connection -Syntax

Test-Connection [-TargetName] <string[]> [-Ping] [-IPv4] [-IPv6] [-ResolveDestination] [-Source <string>] [-MaxHops <int>] [-Count <int>] [-Delay <int>] [
-BufferSize <int>] [-DontFragment] [-TimeoutSeconds <int>] [-Quiet] [<CommonParameters>]

Test-Connection [-TargetName] <string[]> [-Ping] [-IPv4] [-IPv6] [-ResolveDestination] [-Source <string>] [-MaxHops <int>] [-Delay <int>] [-BufferSize <int>] [-DontFragment] [-Continues] [-TimeoutSeconds <int>] [-Quiet] [<CommonParameters>]

Test-Connection [-TargetName] <string[]> -MTUSizeDetect [-IPv4] [-IPv6] [-ResolveDestination] [-TimeoutSeconds <int>] [-Quiet] [<CommonParameters>]

Test-Connection [-TargetName] <string[]> -Traceroute [-IPv4] [-IPv6] [-ResolveDestination] [-Source <string>] [-MaxHops <int>] [-TimeoutSeconds <int>] [-Quiet] [<CommonParameters>]

Test-Connection [-TargetName] <string[]> -TCPPort <int> [-IPv4] [-IPv6] [-ResolveDestination] [-Source <string>] [-TimeoutSeconds <int>] [-Quiet] [<Common

is very different to Test-Connection in v5.1

Test-Connection [-ComputerName] <string[]> [-AsJob] [-DcomAuthentication <AuthenticationLevel>] [-WsmanAuthentication <s
tring>] [-Protocol <string>] [-BufferSize <int>] [-Count <int>] [-Impersonation <ImpersonationLevel>] [-ThrottleLimit <i
nt>] [-TimeToLive <int>] [-Delay <int>] [<CommonParameters>]

Test-Connection [-ComputerName] <string[]> [-Source] <string[]> [-AsJob] [-DcomAuthentication <AuthenticationLevel>] [-W
smanAuthentication <string>] [-Protocol <string>] [-BufferSize <int>] [-Count <int>] [-Credential <pscredential>] [-Impe
rsonation <ImpersonationLevel>] [-ThrottleLimit <int>] [-TimeToLive <int>] [-Delay <int>] [<CommonParameters>]

Test-Connection [-ComputerName] <string[]> [-DcomAuthentication <AuthenticationLevel>] [-WsmanAuthentication <string>] [
-Protocol <string>] [-BufferSize <int>] [-Count <int>] [-Impersonation <ImpersonationLevel>] [-TimeToLive <int>] [-Delay
<int>] [-Quiet] [<CommonParameters>]


You’ll need to experiment to see the differences and to determine which works best for you.


Test –json I’m not sure if its working correctly or not – it throws an exception with a JSON file I’ve used many times and also with this

PS> Get-Process p* | ConvertTo-Json | Test-Json
Test-Json : Cannot parse the JSON.
At line:1 char:35
+ Get-Process p* | ConvertTo-Json | Test-Json
+ ~~~~~~~~~
+ CategoryInfo : InvalidData: ([
]:String) [Test-Json], Exception
+ FullyQualifiedErrorId : InvalidJson,Microsoft.PowerShell.Commands.TestJsonCommand

needs some investigation.

Access module and functions

A long time ago I wrote a module for working with Access databases. I also added a couple of independent functions. The  Access module and functions are now available on github.

People have asked about getting the module and while its had a number of temporary homes its permanent home is now the github repsoitory -


The module comprises the following functions:



The independent functions are:



All of the functions are supplied as is without warranty or guarantee.

PowerShell v6.1 preview 2

PowerShell v6.1 preview 2 is now available for download from


The breaking changes shouldn’t affect your code as they’re for telemetry and installation


Test-Connection is now available in v6

Export-FormatData will pretty print the XML rather than just giving you a single string

There’s now a Test-Json cmdlet and a –Not parameter has been added to Where-Object


OpenSSH has moved to but releases are managed through

Confused? So am I.

This may be linked to the fact that OpenSSH is appearing as an optional install in Windows 10 and Windows Server (post v1709) though the server only had the option for the client last time I looked.

The OpenSSH story is becoming more confusing every time I look at it. It needs to be sorted if remoting between Linux and Windows is to become a thing.


ScriptBlocks Decoded

My second talk at the PowerShell Summit 2018 was ScriptBlocks Decoded.


Starting from the basic explanation of what is a scriptblock and why they’re important it progressed through to proxy functions at the end.


The slides and code are available at


The recording of the session should be on the youtube channel sometime in May

Troubleshooting #2

Last time I covered the PowerShell Troubleshooting pack. This time in Troubleshooting #2 I want to show you how to use Pester when troubleshooting.


When you’re troubleshooting you ideally want to follow a repeatable process so that you can do it again if necessary and teach others to do the same task.

By wrapping the troubleshooting tests as Pester tests you achieve these aims.


If you’ve not used Pester its a PowerShell module that was originally conceived for performing unit tests on your code. You can use Pester for testing your infrastructure is correctly built and configured as well.


I created a set of Pester tests for various scenarios where remoting has gone wrong. For example

Describe 'Listener' {
## tests listener available
It 'Listener is available' {
Test-Path -Path WSMan:\localhost\Listener\listener* |
Should Be $true


tests if the remoting listener is available


Describe 'Port' {
## tests listening on correct remoting port
It 'Remoting Port is 5985' {
Get-Item  "$path\Port" |
select -ExpandProperty Value |
Should Be '5985'


tests the port that remoting is using.


I wanted the troubleshooting script to stop when it hit a problem so I used a second script to execute the tests. Normally  Pester would execute all tests in a file.

$tests = 'WinRM', 'Listener', 'Listener Enabled', 'Transport', 'Address',
'Port', 'EndPoint Exists', 'EndPoint Enabled', 'Firewall Enabled', 'Firewall Allows',
'Remoting Enabled'

$data = foreach ($test in $tests) {
$result = $null
$result = Invoke-Pester -Script @{Path = '.\RemotingTests.ps1'} -PassThru -TestName "$test" -Show None #-EnableExit

$props = [ordered]@{
'Test' = $result.TestResult.Name
'Result' = $result.TestResult.Result
'Failue Message' = $result.TestResult.FailureMessage
New-Object -TypeName PSObject -Property $props

if ($result.FailedCount -gt 0) {break}

$data | Format-Table -AutoSize -Wrap


List the tests I want to run and foreach test run it. Output the results of the test and if the test failed break out of the loop and dump the results to screen.


if everything works you see something like this

PS>  .\Test-Remoting.ps1

Test                        Result Failue Message
----                        ------ --------------
WinRM should be running     Passed
Listener is available       Passed
Listener is Enabled         Passed
Transport is HTTP           Passed
Address is *                Passed
Remoting Port is 5985       Passed
End Point Exists            Passed
EndPoint is Enabled         Passed
Firewall rule is enabled    Passed
Firewall rule set to Allow  Passed
PowerShell Remoting Enabled Passed


If at any stage the test fails the testing process stops and you get a display showing the tests that passed and a message explaining the test that failed.  You can fix that and then rerun.


The code is available at


There are also a number of scripts that break remoting so you can test the methodology. For each breaking script there is the corresponding fix. The demo script I used in the talk is also available.


Its currently a proof of concept for the Summit talk but I think the approach has strong possibilities as troubleshooting methodology that could be applied to many troubleshooting scenarios.


Enjoy, use and adapt to meet your needs

Troubleshooting #1

How do you go about troubleshooting a problem?


There are two ends to the spectrum of solutions to troubleshooting a problem. At one end you have the click and pray brigade who will manically click round all the menus on all the tools they can think of using to try and find something that will fix the problem. I’ve watched people like this in action and while it looks like they’re working incredibly hard in reality they are achieving nothing  - in fact less than nothing because their manic activities get in the way of actually discovering a solution to the problem.


At the other end you have the people who have a process – usually manual – to work through solving the problem. In this case they methodically work through the process eliminating possible issues until they arrive at the cause of the problem. The classic problem solving routine for network connectivity is a classic example:

- ping the loop back adapter

- ping the local IP address

- ping the default gateway

- ping one or more routers

- ping destination address

You find out where the problem lies and can then address how to fix it.


One problem with the second approach is that it requires experience. Experience in administration and troubleshooting and  keeping calm and methodically working through the process when people are shouting at you for a solution. Junior admins usually don’t have this experience.


For a number of versions (I can’t remember when it first appeared) Windows PowerShell has carried a Troubleshooting module – its NOT available in Powershell v6.

There a number of troubleshooting packs in C:\Windows\Diagnostics\system\



You can view the individual packs – for instance

PS> Get-TroubleshootingPack -Path C:\Windows\Diagnostics\system\BITS | fl

Path              : C:\Windows\Diagnostics\system\BITS
Id                : BITSDiagnostic
Version           : 3.5
Publisher         : Microsoft Windows
Name              : Background Intelligent Transfer Service
Description       : Find and fix problems that may prevent background downloads from working
MinimumVersion    : 6.0
PrivacyLink       :
SupportsClient    : True
SupportsServer    : True
SupportsX86       : True
SupportsAmd64     : True
SupportsIA64      : True
RequiresElevation : True
Interactive       : True
RootCauses        : {Service registration is missing or corrupt, Check for missing or corrupt files, Some security
settings are missing or have been changed}
FoundRootCauses   :
Interactions      : {Check for missing or corrupt files, Restart your PC}
ExtensionPoint    : #document


And you can fire off the troubleshooting pack

PS> Get-TroubleshootingPack -Path C:\Windows\Diagnostics\system\BITS | Invoke-TroubleshootingPack
Initialising the diagnostic  -1

Check for missing or corrupt files
Checking security descriptor…  -1
Starting Bits service  -1

No problems were detected


In this case the BITS service was stopped and the troubleshooting pack restarted it to solve the problem.


The major issue with the TroubleShooting module is that there are only a very limited number of troubleshooting packs as you’ve seen. There’s no documentation that I’ve been able to find that deals with writing new packs.


One of my recent talks at the PowerShell Summit was about troubleshooting Powershell WinRM based remoting. I wanted to show how to automate troubleshooting as well as how to actually troubleshoot remoting issues.


I eventually had the idea to use Pester – the code testing module. I’ve used it to test code and infrastructure but I’d never seen anyone talk about using it as a general troubleshooting  tool.


Next time I’ll show you how to use Pester to create an expandable troubleshooting tool that can be adapted for almost any scenario.

CIM references and associations

Way back in 2011, when I were just a young lad, I wrote about WMI or CIM references and associations -

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 { = 'fax'}"
Get-WmiObject : Invalid object path
At line:1 char:1
+ Get-WmiObject -Query "REFERENCES OF { = '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



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,
DriverPath : C:\WINDOWS\system32\spool\DRIVERS\x64\3\FXSDRV.DLL
FilePath :
HelpFile :
InfName :
MonitorName :
OEMUrl :
SupportedPlatform : Windows x64
Version : 3
PSComputerName :

Change a function definition

Functions in PowerShell are based on scriptblocks and as I showed in my session at the recent PowerShell Summit its possible to change a function definition.

Let’s start with a simple function:

PS> function f1 {
>> $x = 1
>> $y = 2
>> $x + $y
>> }
PS> f1

Our function just adds two numbers and outputs the result.

Digging into functions

PS> Get-Item -Path function:\f1 | Format-List *

PSPath : Microsoft.PowerShell.Core\Function::f1
PSDrive : Function
PSProvider : Microsoft.PowerShell.Core\Function
PSIsContainer : False
HelpUri :
ScriptBlock :
$x = 1
$y = 2
$x + $y

CmdletBinding : False
DefaultParameterSet :
Definition :
$x = 1
$y = 2
$x + $y

Options : None
Description :
Verb :
Noun :
HelpFile :
OutputType : {}
Name : f1
CommandType : Function
Source :
Version :
Visibility : Public
ModuleName :
Module :
RemotingCapability : PowerShell
Parameters : {}
ParameterSets : {}

You’ll see a scriptblock property that is the equivalent of the function definition

This means you can change the function definition by changing the scriptblock

PS> $function:f1 = {
>> $x = 2
>> $y = 3
>> $x * $y
>> }
PS> f1

The function has been changed to output the product of the two numbers instead of the sum.

Just one of the many things that scriptblocks can do for you