PowerShell if not

When you’re using an if statement you’re usually testing for a positive so how do you do a PowerShell if not

There a few scenarios to cover. The simplest is if you’re testing a boolean:

PS> $x = $true

if ($x) {‘Yes’} else {‘No’}

In an if statement the test ($x) is evaluated and must give a true or false answer. If true then Yes else No

Let’s make turn the test into a not test. You can use ! or –not as you prefer

PS> $x = $true

if (!$x) {‘Yes’} else {‘No’}
if (-not $x) {‘Yes’} else {‘No’}

If the value is already false

PS> $x = $false

if (!$x) {‘Yes’} else {‘No’}
if (-not $x) {‘Yes’} else {‘No’}

Be careful as you’re getting into double negative territory which is always a headache when you come to review the code at some time in the future.

If you’re dealing with numeric values

PS> $x = 5

if ($x -ne 5) {‘Yes’} else {‘No’}
if ($x -lt 5) {‘Yes’} else {‘No’}
if ($x -gt 5) {‘Yes’} else {‘No’}

Be careful with the first one as you’ll only get Yes if $x –ne 5. Back to double negative thinking.

Notice you can’t do this

if ($x -not -lt 5) {‘Yes’} else {‘No’}

Double operators don’t work. You get an error about

At line:1 char:8
+ if ($x -not -lt 5) {‘Yes’} else {‘No’}
+        ~~~~
Unexpected token ‘-not’ in expression or statement.
At line:1 char:8

among other things.

Nulls can be tricky

PS> $x = $null

if ($x) {‘Yes’} else {‘No’}
if (!$x) {‘Yes’} else {‘No’}


A null value will evaluate as false unless you –not it – another double negative situation.

Using if not is relatively straight forward. Just make sure you have the logic thought through to deal with double negatives correctly.

Posted in Powershell | Leave a comment

PowerShell sleep

Getting PowerShell to sleep or pause during execution can sometimes be useful. This is how you can do a PowerShell sleep.

The starting point is Start-Sleep

PS> Get-Command Start-Sleep -Syntax

Start-Sleep [-Seconds] <int> [<CommonParameters>]

Start-Sleep -Milliseconds <int> [<CommonParameters>]

You can set a time in seconds or milliseconds that you want PowerShell to pause

PS> 1..5 | foreach {
   Start-Sleep -Seconds 30

30 June 2018 20:08:02
30 June 2018 20:08:32
30 June 2018 20:09:02
30 June 2018 20:09:32
30 June 2018 20:10:02

If you need your script to sleep for more than a minute you still need to use seconds. So to sleep for 3 minutes use:

Start-Sleep -Seconds 180

If you want the pause to be under manual control use the pause function:

PS> 1..5 | foreach {

30 June 2018 20:17:57
Press Enter to continue…:
30 June 2018 20:18:01
Press Enter to continue…:
30 June 2018 20:18:16
Press Enter to continue…:
30 June 2018 20:18:33
Press Enter to continue…:
30 June 2018 20:18:43
Press Enter to continue…:

The drawback is that it’s a manual process so not good for soemthing running in the middle of the night and you get the display contaminated with “press enter to continue…” statements.

Pause is a function that PowerShell automatically creates. It has a simple definition:

$null = Read-Host ‘Press Enter to continue…’

Posted in Powershell | Leave a comment

PowerShell string concatenation

PowerShell string concatenation is performed using the concatenation operator which is +

PS> $a = ‘1234’
PS> $b = ‘5678’
PS> $c = $a + $b
PS> $c

When you concatenate 2 strings you’re creating a new string not adding extra characters to the end of the first string.

My preference is to use variable substitution rather than straight concatenation

PS> $d = “$a$b”
PS> $d

If your string has double quote delimiters you can substitute the value of variables as shown. Be careful though because substitution doesn’t work if you use single quotes:

PS> $e = ‘$a$b’
PS> $e

One last trick with strings is the ability to use the multiply operator to generate strings

PS> ‘123’ * 5

PS> 1..10 | foreach {‘*’ * $_}

Posted in Powershell | Leave a comment


Write-Host has had a bad press over the years culminating in the infamous saying “if you use Write-Host a puppy will die” or words to that effect.

So what’s the fuss about?

Let’s take some code

Write-Host -Object “starting”

function t1 {
Write-Host -Object “In the function”



Write-Host -Object “pre-function”


Write-Host -Object “post-function”

It’s not quite the world’s most fantastic piece of code but it’ll do for now

When you run this code you see output like this:



In the function



The problem is that you can’t easily separate the code output from the Write-Host messages as Write-Host does what it says and writes your message direct to the host.

What you should be doing is using one of the more specific Write cmdlets:








Maybe in this case Write-Information

Write-Information -MessageData “starting”  -InformationAction Continue

function t1 {
Write-Information -MessageData “In the function” -InformationAction Continue


Write-Information -MessageData “pre-function” -InformationAction Continue


Write-Information -MessageData “post-function” -InformationAction Continue

with output of



In the function



But this looks just like Write-Host.  In PowerShell v5 and later Write-Host is a wrapper for Write-Information

To see the difference remove the –InformationAction parameter and use this horribly contrived code

$inf = @()

Write-Information -MessageData “starting” -InformationVariable a

$inf += $a

function t1 {
Write-Information -MessageData “In the function” -InformationVariable a

$inf += $a



Write-Information -MessageData “pre-function” -InformationVariable a

$inf += $a


Write-Information -MessageData “post-function” -InformationVariable a

$inf += $a

If you look at the contents of $inf you see the messages




Notice you’ve lost the message from within the function – we’ll come back to that another time

You have a record with some interesting data

PS> $inf | gm

    TypeName: System.Management.Automation.InformationRecord

Name            MemberType Definition                                         
----            ---------- ----------                                         
Equals          Method     bool Equals(System.Object obj)                     
GetHashCode     Method     int GetHashCode()                                  
GetType         Method     type GetType()                                     
ToString        Method     string ToString()                                  
Computer        Property   string Computer {get;set;}                         
ManagedThreadId Property   uint32 ManagedThreadId {get;set;}                  
MessageData     Property   System.Object MessageData {get;}                   
NativeThreadId  Property   uint32 NativeThreadId {get;set;}                   
ProcessId       Property   uint32 ProcessId {get;set;}                        
Source          Property   string Source {get;set;}                           
Tags            Property   System.Collections.Generic.List[string] Tags {get;}
TimeGenerated   Property   datetime TimeGenerated {get;set;}                  
User            Property   string User {get;set;}

For instance

PS> $inf | select TimeGenerated, MessageData

TimeGenerated       MessageData  
-------------       -----------  
29/06/2018 20:25:44 starting     
29/06/2018 20:25:44 pre-function 
29/06/2018 20:25:44 post-function

could be useful for tracing progress

There’s a lot more in the write cmdlets that we’ll come back to another time

Posted in Powershell | Leave a comment

Hyper-V switches

I need to do some work on the Hyper-V switches in my lab so need to see which VMs are on which switch.

Easier than I thought:

Get-VM |
Get-VMNetworkAdapter |
select VMname, Name, Switchname

Posted in Hyper-V, Powershell | Leave a comment

PowerShell versions

PowerShell has gone through a number of versions since it was first released in November 2006. These are the major features of the PowerShell versions:

PowerShell v1 – initial release with 137 cmdlets. (released with Windows Vista / Server 2008 – not Server Core). Only way to work remotely was Get-WmiObject. no longer available.

PowerShell v2 (Windows 7 / Server 2008 R2) – introduced PowerShell remoting, PowerShell jobs and extended WMI cmdlets. Deprecated.

PowerShell v3 (Windows 8 / Server 2012) – Workflows, CIM cmdlets

PowerShell v4 (Windows 8.1 / server 2012 r2) – DSC

PowerShell v5 (Windows 10) – PowerShell classes

PowerShell v5.1 (Windows 10 Update / Server 2016) – mainly bug fixes for v5

PowerShell v6.0 (open source) – SSH remoting, installs for Linux and mac

PowerShell v6.1 (in development) – mainly fixes and updates to v6.0

Documentation has become weaker over time and is currently available from – https://docs.microsoft.com/en-gb/powershell/scripting/powershell-scripting?view=powershell-6

Which version should you use?

If you’re on Windows use the version installed OR download and install the latest WMF package for your version of Windows. PowerShell v6 is useful for non-domain remoting or remoting to Linux servers.

If you’re on Linux or mac the your only choice in v6.x

Posted in Powershell | Leave a comment

PowerShell v6.1 preview 3

PowerShell v6.1 preview 3 became available a couple of weeks ago.


To the user its a minor set of fixes from preview 2 though if you read the release notes there’s a lot of work going on in the background.

If the 6 months between releases idea holds we can expect to see the v6.1 release within the next month.

OpenSSH is still a bit of a mess with options to install some, or all, as Windows optional features or install from the github project. This needs to be sorted with definitive guidelines a preferably a roadmap.

Posted in PowerShell v6 | Leave a comment