Monthly Archive


PowerShell for loop

PowerShell has a number of looping mechanisms – do-while; do-until; foreach; while and for loops. In this post I’ll show you how to use the PowerShell for loop.

A for loop iterates a predefined number 0f times. A basic for loop looks like this:

for ($i=0; $i -lt 10; $i++) {


In the () you have 3 statements – they can be pipelines rather than simple assignments though most people just use assignments.

$i=0; - means set the counting variable $i to zero as the starting point

$i -lt 10; – means loop while the counting variable is less than 10

$i++ – means increment the counting variable by 1 after each loop

If you run the code you’ll see the numbers 0-9 displayed.

$i is traditionally used as the loop counting variable but it doesn’t have to be $i. It can be any arbitrary variable

for ($somevar=0; $somevar -lt 10; $somevar++) {


The reason for using $i is traditional. It traces back to one of the early programming languages – Fortran – in which variables starting with i,j,k,l,m or n were integers by default. The variable i became the counter variable because of its position in the alphabet. The tradition has progressed down through programming languages since that day.

The loop count can be decremented

for ($i=0; $i -gt -10; $i--) {

This loop will output 0 to –9


If you want to break out of a for loop use break

for ($i=0; $i -lt 10; $i++) {
if ($i -eq 5){break}
Write-Host "I now equals $i"

which outputs

I now equals 5


Alternatively, to force the loop to skip further processing and move to the next iteration

for ($i=0; $i -lt 10; $i++) {
if ($i -eq 5){continue}

which outputs 0-4 then 6-9


The for loop is a basic loop that’s best used when you want to iterate over a set of code a number of times.

You can use variables when assigning the start and endpoints

$x = 1
$y = 10
for ($i=$x; $i -lt $y; $i++) {


Also, the loop counter doesn’t have to change by 1 each time

for ($i=0; $i -lt 10; $i+=2) {

outputs 0,2,4,6,8

PowerShell v6 and PowerShell Direct

Not seen this reported anywhere so thought I post.


PowerShell v6 went to GA in January 2018. PowerShell Direct is a feature of Windows 10/Windows Server 2016. By accident I found that PowerShell v6 and PowerShell Direct work together.


PowerShell v6 is based on .NET core which is basically a subset of the full .NET CLR (that powers Windows PowerShell )


PowerShell Direct is a technology by which a PowerShell v5.1 session on a Windows 10/Windows Server 2016 Hyper-V host can establish a remoting session to a Windows 10/Windows Server 2016 virtual machine over the VM bus rather than using WSMAN.


By default PowerShell v6 can’t access the Hyper-V module but if you add the PowerShell v5.1 module path to the PowerShell v6 module path:

$env:PSModulePath = 'C:\Windows\System32\WindowsPowerShell\v1.0\Modules\;' + $env:PSModulePath


You can then create a credential

$cred = Get-Credential manticore\richard


This is required because you’re not relying on Kerberos to authenticate as you do in standard remoting within the domain.

You can then create your session:

$s = New-PSSession -VMName W10PRV01 -Credential $cred


And use it

Invoke-Command -Session $s -ScriptBlock {Get-Service}


The session has a ComputerType of VirtualMachine

PS> $s | fl

ComputerType : VirtualMachine
ComputerName : W10PRV01
ContainerId :
VMName : W10PRV01
VMId : 374d0569-3b22-441d-84dc-802aed67dea9
ConfigurationName :
InstanceId : c6e6b1c1-8ed5-409f-be4c-0a1262342cb7
Id : 1
Name : WinRM1
Availability : Available
ApplicationPrivateData : {DebugMode, DebugStop, UnhandledBreakpointMode, PSVersionTable...}
Runspace : System.Management.Automation.RemoteRunspace
State : Opened
IdleTimeout : -1
OutputBufferingMode :
DisconnectedOn :
ExpiresOn :


You can also enter the session

PS> Enter-PSSession $s
[W10PRV01]: PS C:\Users\Richard.MANTICORE\Documents>


I’ve not tried all the Hyper-V cmdlets but the Get* cmdlets that I have tried all work.

Putting on the style

PowerShell is all about getting things done but how you do things can be as important as what you do. I’ll explain what I mean so you be able to be putting on the style.


While PowerShell is used by a number of developers its predominantly an administrators tool. Most administrators aren’t taught to code so they pick things up as they go along -  including coding styles.


Back when PowerShell first appeared Jeffrey Snover talked about administrators having an ad hoc development methodology. They’d use single cmdlets to get things done. Then progress to using multiple cmdlets in a pipeline. They’d then realise that if they saved that pipeline in a script they wouldn’t have to retype it every time they wanted to use it and so save so time and errors.


What happens once you’ve got those first scripts?


You’ll realise that scripting enables you to generate tools that make your life easier and that others can also use. By then you’ve probably discovered the PowerShell community and seen what others are doing – so you learn a bit more about coding.


You adopt some standards – no aliases in scripts etc., etc. And you think about creating modules of advanced functions.


At this point you need to think about your coding style. I’m deliberately separating coding standards from coding style. Standards are what you do – style is how you do it.


We’ve used this style concept as the basis of the Iron Scripter competition at PowerShell Summit 2018. To help people divide themselves into teams we have three factions defined - The factions split on coding styles as much as anything. You can regard the differences between the factions as philosophical discussions if you prefer.


The factions can be summarised as:

  • Daybreak Faction - beautiful code
  • Flawless Faction - flawless code
  • Battle Faction - good enough to get the job done


Battle faction is the easiest to understand. You have a solution to your problem. It works and gives the correct result in a reasonable time frame. Job done. Next task. if it breaks at some time in the future you’ll fix it then but in the meantime there’s a stack of other problems to solve.


This is the way many administrators work, at least to begin with. Working code doesn’t mean that the code is easy to maintain. If it breaks in the future you may not be the one to fix it – so the code needs to be readable and understandable. Daybreak faction with their view that code should be beautiful take this to the extreme.


Ideally, your code shouldn’t break. The idea of flawless code is at the heart of Flawless faction who believe in doing everything possible to ensure that the code will run. Beauty has its place but beautiful code that doesn’t work is wasted time and effort.


The three factions are stereotypes and extremes but there is an extremely valid point to them. Imagine an equilateral triangle that has a faction at each point.  Your code will sit somewhere in that triangle with varying influences of battle, flawless and daybreak factions.


Does all your code sit at the same place in the triangle? Sometimes good enough will do and you can move on to the next task. Sometimes the code just has to run so you need a lot of flawless influence.


All the code you produce doesn’t have to have the same influences but knowing when to be putting on the style – and more importantly which style – could arguably make you a better coder and make your life easier.

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



The CIM_ classes follow the standard definition from the DMTF -

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


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.



Every so often I find a new cmdlet in PowerShell. This was the case with Clear-RecycleBin that I’ve just found.

It appears to have been introduced with PowerShell 5.0 BUT isn’t available in PowerShell 6.0

With pretty simple syntax

PS> Get-Command Clear-RecycleBin -Syntax

Clear-RecycleBin [[-DriveLetter] <string[]>] [-Force] [-WhatIf] [-Confirm] [<CommonParameters>]

Its easy to use

PS> Clear-RecycleBin -DriveLetter C -Force

use –Force to avoid the question to confirm the action

Documentation can be wrong!

We rely on vendor documentation to help us solve problems. Documentation is produced by people and people make mistakes so Documentation can be wrong!


As an example:

The CIM class Win32_OperatingSystem has a Description property. According to the documentation the Description property is

“ Description of the Windows operating system. Some user interfaces for example, those that allow editing of this description, limit its length to 48 characters.”


if you take this to mean the description describes something about the OS you’d be wrong.

PS> Get-CimInstance Win32_OperatingSystem | Format-List Caption, Description

Caption : Microsoft Windows 10 Enterprise
Description : Richards Laptop


The caption property gives a description of the OS. The Description property is what you’ll find at

Control Panel –> System –> Advanced system settings –> Computer Name tab –> Computer description field


If you find something that doesn’t match with the documentation double check as you may find the documentation is wrong!

PowerShell sleep

PowerShell use tends to be very interactive. You run a command at the console and get some results. You run a script and get some results. How do you make PowerShell sleep?

There’s a few ways you can make PowerShell code sleep.


First there’s Start-Sleep

PS> for ($i=0; $i -le 10; $i++){
>> if ($i -eq 5) {
>> Get-Date
>> Start-Sleep -Seconds 30
>> Get-Date
>> }
>> }

30 January 2018 14:06:21
30 January 2018 14:06:51

I use Start-Sleep when starting a bunch of virtual machines to ensure one is fully up and running before attempting to start the next.


You can use the pause function to add a manually controlled delay

PS> for ($i=0; $i -le 10; $i++){
>> if ($i -eq 5) {
>> Get-Date
>> pause
>> Get-Date
>> }
>> }

30 January 2018 14:08:57
Press Enter to continue...:
30 January 2018 14:09:44


Pause is a function created when you start PowerShell

PS> Get-Command pause | select definition

$null = Read-Host 'Press Enter to continue...'

so if you prefer you can use Read-Host


You could also use a workflow and suspend the job

PS> workflow w1 {
>> for ($i=0; $i -le 10; $i++){
>> if ($i -eq 5) {
>> Get-Date
>> Suspend-Workflow
>> Get-Date
>> }
>> }
>> }
PS> w1 -AsJob

Id Name PSJobTypeName   State HasMoreData  Location  Command
-- ---- -------------   ----- -----------  --------  -------
3  Job3 PSWorkflowJob Running        True  localhost      w1

PS> Get-Job

Id Name PSJobTypeName     State HasMoreData  Location Command
-- ---- -------------     ----- -----------  -------- -------
3  Job3 PSWorkflowJob Suspended        True localhost      w1

PS> Resume-Job -Id 3

Id Name PSJobTypeName   State HasMoreData  Location Command
-- ---- -------------   ----- -----------  -------- -------
3  Job3 PSWorkflowJob Running        True localhost      w1

PS> Get-Job

Id Name PSJobTypeName     State HasMoreData  Location Command
-- ---- -------------     ----- -----------  -------- -------
3  Job3 PSWorkflowJob Completed        True localhost      w1

PS> Receive-Job -Id 3

30 January 2018 18:39:25
30 January 2018 18:40:39


Remember that workflows aren’t available on PowerShell v6

PowerShell –f string

A PowerShell –f string is used to format the data inside a string. –f is usually referred to as the format operator.


The operation of the format operator is best explained by examples. At its simplest you create fields in the string using {} and the arguments to the right of the –f operator are assigned to those fields in numeric order:

PS> "{0} is  {1}" –f  'A', 'a'
A is  a


‘A’ is the first argument (so is assigned to field {0} and so on.


You can format the contents of the fields. The full syntax is

{index[,alignment][:format string]}

index is the zero based index of the arguments after the format operator as you’ve seen.

alignment takes a positive number and aligns the item to the right of a field of that length. A negative number produces a left alignment.

PS> "{0,5} is  {1,5}!" -f 'A', 'a'
A is      a!
PS> "{0,-5} is  {1,5}!" -f 'A', 'a'
A     is      a!
PS> "{0,5} is  {1,-5}!" -f 'A', 'a'
A is  a    !
PS> "{0,-5} is  {1,-5}!" -f 'A', 'a'
A     is  a    !


The format strings cover numeric and date time formatting

will get you started and provide links to other formatting information


A few more examples.

To control the total number of digits displayed

PS> "{0:D3} {1:D3} {2:D3}" -f 2, 20, 200
002 020 200


for hexadecimal – case matches case in string

PS> "{0:X4} {1:x8} " -f  1234, 1234
04D2 000004d2


Truncating the digits after decimal point

PS> "{0:F3} {1:F2} {2:F1}" -f 2.1234, 3.1234, 4.1234
2.123 3.12 4.1


Dates can be manipulated as well

PS> "{0:yyyy} {0:MM} {0:dd} {0:hh} {0:mm} {0:ss}" -f (Get-Date)
2018 01 28 02 24 03

Note that I’m referring to a single object for all of the fields

DSC update

The PowerShell team have posted an update on what’s happening with DSC.


The interesting thing is the decoupling of the Local Configuration Manager from Windows. A new LCM that can use resources written in multiple languages sounds good – DSC on Linux can finally have custom written resources.


LCM will be open source


No comments on pull server in the post though – ideally pull server should be open source as well