PowerShell for Windows Admins

July 24, 2018  5:38 AM

PowerShell ThreadJobs

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

PowerShell Jobs were introduced in PowerShell v2. While remoting got the attention in that release PowerShell Jobs are at least as important. PowerShell v6.1 preview 4 has introduced a new addition to the options for jobs – PowerShell ThreadJobs.

The real change is the addition of the Start-ThreadJob cmdlet. All other aspects of managing ThreadJobs are provided by the standard Jobs cmdlets.

PS>  Get-Command *Job | select name


When you use Start-Job the job is run in the background on a SEPARATE PROCESS. You can see the PowerShell processes stopping and starting if you monitor via Task manager or another instance of PowerShell.

ThreadJobs run on a separate THREAD within the same process. Apart for the cmdlet name you start a threadjob in the same way as a traditional background job.

PS>  Start-Job -ScriptBlock {Get-Service}

Id   Name   PSJobTypeName   State    HasMoreData  Location  Command
--   ----   -------------   -----    -----------  --------  -------
1    Job1   BackgroundJob   Running  True         localhost Get-Service

PS>  Start-ThreadJob -ScriptBlock {get-Service}

Id   Name  PSJobTypeName   State       HasMoreData  Location    Command
--   ----  -------------   -----       -----------  --------    -------
3    Job3  ThreadJob       NotStarted  False        PowerShell  get-Service

Notice the different job type name. The location changes from the localhost to PowerShell indicating its not a separate process.

To view jobs

PS>  Get-Job

Id     Name   PSJobTypeName   State       HasMoreData   Location     Command
--     ----   -------------   -----       -----------   --------     -------
1      Job1   BackgroundJob   Completed   True          localhost    Get-Service
3      Job3   ThreadJob       Completed   True          PowerShell   get-Service

To view results

PS>  Receive-Job -Id 3

Status   Name               DisplayName
------   ----               -----------
Running  AdobeARMservice    Adobe Acrobat Update Service
Stopped  AJRouter           AllJoyn Router Service
Stopped  ALG                Application Layer Gateway Service
Stopped  AppIDSvc           Application Identity

To clean up jobs

PS>  Get-Job | Remove-Job
PS>  Get-Job

The advantage of ThreadJobs is that they are lighter on resource consumption because they are using a thread not a process. You can therefore run more ThreadJobs simultaneously compared to standard Jobs.

The disadvantage for ThreadJobs is that all of your jobs are running in the same process. If one crashes the process will most likely crash and you’ll lose everything.

The pros and cons of using ThreadJobs vs standard jobs must be addressed on a case by case basis. The ThreadJobs project has a bit more background – https://github.com/PaulHigin/PSThreadJob

ThreadJobs look to be a useful addition to the options for running background jobs.

July 23, 2018  10:18 AM

Update-Help difference

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Between Windows PowerShell v5.1 and PowerShell v6.x I’ve noticed an Update-Help difference.

In Windows PowerShell v5.1 I can just do this:

Update-Help -Force

from an elevated prompt.

In PowerShell v6.0 and V6.1 previews I have to give the UI culture I want

Update-Help -UICulture en-US –Force

All instances – PowerShell v5.1, v6.0.3 and v6.1 preview 4 are running on a single Windows 10 machine. The UI culture is en-GB for all PowerShell instances and versions.

Not a major problem now I’ve tried using the en-US culture but it explains why I wasn’t getting help before.

July 23, 2018  6:31 AM

Measure-Object Enhancement

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

PowerShell v6.1 preview 4 brings a Measure-Object enhancement.

Measure-Object has been around since PowerShell v1. It enables you to measure the properties of an object and easily perform a number of calculations.

PS> Get-ChildItem -File | Measure-Object -Property Length

Count : 6
Average :
Sum :
Maximum :
Minimum :
StandardDeviation :
Property : Length

The original calculations were – Count, Sum, Average, Minimum and Maximum

Using Measure-Object was a very successful short cut in a number of solutions to scripting games puzzles over the years and was often the differentiator of those who really knew how to use PowerShell.

PS> Get-ChildItem -File | Measure-Object -Property Length -Average -Sum

Count : 6
Average : 2580291
Sum : 15481746
Maximum :
Minimum :
StandardDeviation :
Property : Length

PowerShell v6 added the calculation to produce the standard deviation

PS> Get-ChildItem -File | Measure-Object -Property Length -Average -StandardDeviation

Count : 6
Average : 2580291
Sum :
Maximum :
Minimum :
StandardDeviation : 5637125.25690079
Property : Length

PowerShell v6.1 preview 4 adds the –Allstats parameter so that you get get all of the calculations done in one pass

PS> Get-ChildItem -File | Measure-Object -Property Length -AllStats

Count : 6
Average : 2580291
Sum : 15481746
Maximum : 14027010
Minimum : 0
StandardDeviation : 5637125.25690079
Property : Length

A very useful addition to a very useful cmdlet.

July 20, 2018  1:17 PM

New releases of PowerShell v6.x

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

New releases of PowerShell v6.x are available.

First off v6.0.3 is available. This is a servicing release to update PowerShell v6.0 to use .Net 2.0.8. The primary point of this release is to update to fix the vulnerability discussed in Microsoft Security Advisory CVE-2018-8356: .NET Framework Security Feature Bypass Vulnerability. You ae recommended to upgrade PowerShell v6.0.x to v6.0.3

Secondly, preview 4 for Powershell v6.1 is also available. It has some breaking changes:

Visualbasic support is removed from Add-Type

PowerShell direct tries PowerShell v6.x then drops back to PowerShell v5.1

Powershell v6.1 can start in a folder with a wildcard in its name

Enable-PSRemoting produces configuration names unique for preview releases

CompatiblePSeditions check is enforced for modules from system32 module path (PowerShell v5.1 modules!)


Experimental features are supported

Markdown rendering cmdlets are available

ThreadJob module available

WMI and ADSI accelerators are back

Plus a bunch of minor updates you can see in the release notes

Both releases are available from https://github.com/PowerShell/PowerShell/releases

July 17, 2018  1:17 PM

UK PowerShell conference

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

There’s a one day PowerShell conference in October in London – https://powershell.org/2018/07/17/psdayuk-2018-the-uk-powershell-conference/

It’s rumoured I may be there and speaking

July 11, 2018  8:16 AM

Windows Server 2008 EoL

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Windows 2008, Windows 2008 R2

Windows Server 2008 EoL on 14 January 2020

Windows Server 2008 and 2008 R2 will be end of life and no longer supported from 14 January 2020 – https://cloudblogs.microsoft.com/windowsserver/2018/07/10/its-sunset-time-for-windows-server-2008-and-2008-r2/

There’s plenty of time to think about migrating off of the 2008 family but don’t leave it to the last minute.

Server 2008 had PowerShell v1 and 2008 R2 introduced PowerShell v2. They were good server products but its time to replace them if you haven’t already.

July 9, 2018  10:37 AM

Windows activation

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

enum Licensestatus {
Unlicensed = 0
Licensed = 1
OOBGrace = 2
OOTGrace = 3
NonGenuineGrace = 4
Notification = 5
ExtendedGrace = 6

Get-CimInstance -ClassName SoftwareLicensingProduct -Filter “PartialProductKey IS NOT NULL” |
select Name, ApplicationId, @{N=’LicenseStatus’; E={[LicenseStatus]$_.LicenseStatus} }

July 9, 2018  4:31 AM

CPU intensive processes

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

How do you find the most CPU intensive processes?

If you want to know the processes that are taking most CPU on your system right now then use Get-Process

PS> Get-Process | sort CPU -Descending | select -First 10

Will display the 10 processes that are running and are using the most CPU – see the CPU( s ) field.

Couple of issues with this approach. First only running processes are shown. If a process starts and runs to completion between 2 calls to Get-Process you’ll never know it happened. Especially relevant if the process runs over night. Second, Get-Process produces a lot of information you don’t necessarily need for this task.

The alternative is to use performance counters.

PS> Get-Counter -ListSet *Process* | select CounterSetName, Description

Lists possible counter sets you can use. The Process set looks like a good possibility:

PS> Get-Counter -ListSet Process | select -ExpandProperty Counter
\Process(*)\% Processor Time
\Process(*)\% User Time
\Process(*)\% Privileged Time
\Process(*)\Virtual Bytes Peak
\Process(*)\Virtual Bytes
\Process(*)\Page Faults/sec
\Process(*)\Working Set Peak
\Process(*)\Working Set
\Process(*)\Page File Bytes Peak
\Process(*)\Page File Bytes
\Process(*)\Private Bytes
\Process(*)\Thread Count
\Process(*)\Priority Base
\Process(*)\Elapsed Time
\Process(*)\ID Process
\Process(*)\Creating Process ID
\Process(*)\Pool Paged Bytes
\Process(*)\Pool Nonpaged Bytes
\Process(*)\Handle Count
\Process(*)\IO Read Operations/sec
\Process(*)\IO Write Operations/sec
\Process(*)\IO Data Operations/sec
\Process(*)\IO Other Operations/sec
\Process(*)\IO Read Bytes/sec
\Process(*)\IO Write Bytes/sec
\Process(*)\IO Data Bytes/sec
\Process(*)\IO Other Bytes/sec
\Process(*)\Working Set – Private

Of those \Process(*)\% Processor Time looks to be what we want.

If you just run

PS> Get-Counter -Counter ‘\Process(*)\% Processor Time’

You’ll get all counters. But you can’t give a process name so you’ll have to do a bit of digging into the object returned by Get-Counter

PS> Get-Counter -Counter ‘\Process(*)\% Processor Time’ | gm

TypeName: Microsoft.PowerShell.Commands.GetCounter.PerformanceCounterSampleSet

Name MemberType Definition
—- ———- ———-
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
CounterSamples Property Microsoft.PowerShell.Commands.GetCounter.PerformanceCo
Timestamp Property datetime Timestamp {get;set;}
Readings ScriptProperty System.Object Readings {get=$strPaths = “”…

Timestamp is the time that you retrieved the data. Countersamples gives the data for each process:

PS> $samples = Get-Counter -Counter ‘\Process(*)\% Processor Time’
PS> $samples.Timestamp

09 July 2018 10:58:34

PS> $samples.CounterSamples | select -First 1 | Format-List

Path : \\w510w10\process(idle)\% processor time
InstanceName : idle
CookedValue : 803.827924975895

Just selecting the top 10 processes won’t work.

PS> $samples.CounterSamples | sort CookedValue -Descending | select -f 10 | Format-List

Path : \\w510w10\process(_total)\% processor time
InstanceName : _total
CookedValue : 805.382717867531

Path : \\w510w10\process(idle)\% processor time
InstanceName : idle
CookedValue : 803.827924975895

Path : \\w510w10\process(powershell#1)\% processor time
InstanceName : powershell
CookedValue : 1.55479289163616

Because you get the _total and idle counts. So you need to skip them

PS> $samples.CounterSamples | sort CookedValue -Descending | select -Skip 2 -First 10 | Format-List

By default Get-Counter takes 1 sample. If you want to multiple samples you can use the –Continuous switch which will sample continuously. Use –SampleInterval to determine the number of seconds between samples.

Alternatively, use –MaxSamples and –SampleInterval to control the number of samples in a given period but you get a sample at each sampling interval.

However you decide to sample the data you’re going to need to preserve it for future analysis. Probably easiest is to output the top process at each sampling interval to a CSV file

$samplecount = 0

while ($true) {

$samples = Get-Counter -Counter ‘\Process(*)\% Processor Time’
$counter = $samples.CounterSamples | sort CookedValue -Descending | select -Skip 2 -First 1

$props = [ordered]@{
Time = $samples.Timestamp
Process = $counter.InstanceName
Value = $counter.CookedValue

New-Object -TypeName PSObject -Property $props |
Export-Csv -Path C:\test\counters.csv -Append -NoTypeInformation

if ($samplecount -ge 10){break}

Start-Sleep -Seconds 10

You may see error messages like this:

Get-Counter : The data in one of the performance counter samples is not valid. View the Status property for each PerformanceCounterSample object to make sure it contains valid data.
At line:6 char:14
+ $samples = Get-Counter -Counter ‘\Process(*)\% Processor Time’
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidResult: (:) [Get-Counter], Exception
+ FullyQualifiedErrorId : CounterApiError,Microsoft.PowerShell.Commands.GetCounterCommand

So you may not your data exactly 10 seconds apart.

You could use –ErrorAction to silently continue and suppress the messages. You’ll still get your 10 samples.

You can run the script from a job or put an outer loop that starts sampling every minute, 10 minutes or whatever you need.

If you see different process showing in your samples then your machine’s resources aren’t been hogged by a single process.

July 5, 2018  10:43 AM

PowerShell not equal

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

The Powershell not equal operator is –ne. This how you use it.

When dealing with numbers:

PS> $a = 3
PS> $b = 5
PS> $a -ne $b

When dealing with strings you have a bit more choice:

PS> $a = ‘abcd’
PS> $b = ‘efgh’
PS> $a -ne $b

By default PowerShell is case insensitive so

PS> $a = ‘abcd’
PS> $b = ‘ABCD’
PS> $a -ne $b

If the only difference is case then –ne reports they are the same.

If you need a case insensitive test use –cne

PS> $a = ‘abcd’
PS> $b = ‘ABCD’
PS> $a -cne $b

Because there are case differences the strings are different so you get a result of True

If you need a case insensitive test use –ine so you know you’re ignoring case

PS> $a = ‘abcd’
PS> $b = ‘ABCD’
PS> $a -ine $b

The major problem with use not equal is that you’re in double negative

if X –ne Y then it means they are the same if the result is false

PS> $a = 3
PS> $b = 3
PS> $a -ne $b

Its always easier to comprehend a test for equality rather than inequality especially if you’re nesting tests.

July 4, 2018  5:34 AM

Variable squeezing

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

When you’re developing code interactively how often do you set a variable and then display it to test the result? You can do that in one go using variable squeezing.

Normally you’d do:

PS> $test = 1
PS> $test

Set the variable and display the contents as two separate actions.

By enclosing the first statement in parentheses you accomplish both tasks

PS> ($test2 = 2)

Great for interactive work but you don’t want in in scripts as you’d be getting output every time you set a variable value!

Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to: