PowerShell for Windows Admins

August 14, 2014  2:01 PM


Richard Siddaway Richard Siddaway Profile: Richard Siddaway

I was asked about foreach today and responded with a description of who foreach-object works. Thinking about it I should have realized that part of the issue with foreach is the confusion that arises between foreach and foreach – –  that is the difference between the foreach PowerShell statement and the foreach alias of the foreach-object cmdlet.

To unravel the confusion there are two different things referred to as foreach. The confusion is that they do very similar things but are used in different ways.

The first is the PowerShell statement which is used to step through each value in a collection of values:

$procs = Get-Process

foreach ($proc in $procs) {

New-Object -TypeName PSObject -Property @{
Name = $proc.Name
SysMen =  $proc.NonpagedSystemMemorySize + $proc.PagedSystemMemorySize64


You create your collection of objects and then use foreach to step through them. It is convention to make the collection plural and the individual member of the collection its singular.  Within the script block you can define what happens to the object.

I know I could have a performed this action is a simpler way but I wanted to demonstrate how foreach works. The simpler way would be:

Get-Process |
select Name,
@{Name = ‘SysMen’;
Expression = {$_.NonpagedSystemMemorySize + $_.PagedSystemMemorySize64}}

Now we’ve got that out of the way what about the other foreach which is the alias of foreach-object.  This can be use to iterate over a collection of objects. The main difference is that the objects are usually piped into foreach:

Get-Process |
foreach {

New-Object -TypeName PSObject -Property @{
Name = $_.Name
SysMen =  $_.NonpagedSystemMemorySize + $_.PagedSystemMemorySize64


If you don’t like using $_ to represent the object on the pipeline try

Get-Process |
foreach {

New-Object -TypeName PSObject -Property @{
Name = $psitem.Name
SysMen =  $psitem.NonpagedSystemMemorySize + $psitem.PagedSystemMemorySize64


which is exactly equivalent to

Get-Process |
ForEach-Object {

New-Object -TypeName PSObject -Property @{
Name = $psitem.Name
SysMen =  $psitem.NonpagedSystemMemorySize + $psitem.PagedSystemMemorySize64


Using the cmdlet or its alias you can set up script blocks to process once when the first object reaches foreach (BEGIN), once per object on the pipeline (PROCESS) and once when the last object has been processed (END)

Get-Process |
ForEach-Object `
Write-Host “First object about to be processed”
} `
New-Object -TypeName PSObject -Property @{
Name = $psitem.Name
SysMen =  $psitem.NonpagedSystemMemorySize + $psitem.PagedSystemMemorySize64
-END {
Write-Host “Last object processed”

Your ouput looks like this:

First object about to be processed

Name                                                                      SysMen
—-                                                                      ——
armsvc                                                                    164096
concentr                                                                  200400
conhost                                                                   119104
csrss                                                                     153664
csrss                                                                     407760

WUDFHost                                                                  103696
WWAHost                                                                   778816
WWAHost                                                                   785120
Yammer.Notifier                                                           566304
Last object processed

More info is available in the help files for foreach-object and about_foreach

August 12, 2014  10:29 AM

Can it -whatif

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

One of the nice things about PowerShell is that it can help you prevent mistakes. Many of the cmdlets that make changes to you system have a –whatif parameter that allows you to test your actions:

£> Get-Process | Stop-Process -WhatIf
What if: Performing the operation “Stop-Process” on target “armsvc (1564)”.
What if: Performing the operation “Stop-Process” on target “audiodg (3004)”.
What if: Performing the operation “Stop-Process” on target “concentr (7080)”.
What if: Performing the operation “Stop-Process” on target “conhost (3628)”.


The –whatif parameter is only present on cmdlets that make changes and then only if the team writing the cmdlet implemented it – they should but you can’t guarantee it happened. So how can you find out which cmdlets implement –whatif?

Use Get-Command

Compare these 2 commands.

£> Get-Command -Module CimCmdlets | select Name


shows the cmdlets in a module

£> Get-Command -Module CimCmdlets -ParameterName Whatif | select Name


Now you can test a module to see which cmdlets have –whatif enabled.  You can also test at just the cmdlet level:

£> Get-Command *process -ParameterName Whatif  -CommandType cmdlet | select Name

£> Get-Command *wmi* -ParameterName Whatif  -CommandType cmdlet | select Name


August 11, 2014  1:44 PM

Select-Object or Where-Object

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Both Select-Object and Where-Object (referred to by their aliases of select and where from now on) are both used to filter data.

It is important to know the way these 2 cmdlets are used.

Where is used to restrict the objects on the pipeline to those where one or more properties satisfy the filter criteria e.g.

Get-Process | where CPU -gt 20

You get a reminder of this if you you use the full syntax

Get-Process | where -FilterScript {$_.CPU -gt 20}

As a matter of style you very rarely see anyone using the parameter name –FilterScript.

Select is used to cut the number of properties on an object to just those you want to work with e.g.

Get-Process | select Name, Id, CPU

If you want just those properties for the processes where CPU time is greater than 20 seconds you need to combine them on the pipeline:

Get-Process | where CPU -gt 20 | select Name, Id, CPU

There isn’t a way to embed a where type filter in a select or vice versa. Keep it simple. Use the pipeline and let the cmdlets do the job for which they were designed.

August 10, 2014  6:07 AM

Installing Centos in Windows 2012 R2 Hyper-V

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Hyper-V 2012 R2, Virtualization

I need to create a virtual machine with CentOS 6.5 as the guest OS.

I clicked through creating the VM and discovered that the install wouldn’t work. Eventually tracked down the issues.

Keep the following points in mind as you create your VM:

  1. Create the VM as a generation 1 virtual machine
  2. Ensure the virtual disk controller and disk are IDE
  3. Ensure a legacy network adapter is used – may need to create the VM without a network adapter and add the adapter before the install
  4. If asked to test the install media (iso image) be aware that it will be ejected after the test so you’ll need to open it again
  5. keep it simple and only have 1 network adapter
  6. Use the map to find the nearest city to get the time zone – scrolling though the list is boring

August 10, 2014  2:51 AM

WMI troubleshooting

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

A WMI troubleshooting series has been started on the Ask the Performance Team Blog.

The overview article is:


The first article is about common symptoms and errors:


followed by an article on dealing with WMI repository corruption:


Very useful information in both articles. If the rest of the series is at this level you’ll want to book mark these posts

August 10, 2014  2:34 AM

Euorpean PowerShell Summit 2014 registration details

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

The European PowerShell Summit, organised by PowerShell.org, will be in Amsterdam September 29 – October 1 2014 at the Park Hotel. Details at http://powershell.org/wp/community-events/summit/

The Summit will feature 3 days of PowerShell sessions from PowerShell team members, PowerShell MVPs and other PowerShell experts. It’s the in-person gathering place for PowerShell enthusiasts and PowerShell users. It’s a place to make new connections, learn new techniques, and offer something to your peers and colleagues.  If you can’t get your PowerShell questions answered at the PowerShell Summit you’ll never get an answer.

The Summit agenda is available to view at: http://eventmgr.azurewebsites.net/event/agenda/PSEU14

Registration is now open via http://eventmgr.azurewebsites.net/event/home/PSEU14.

August 6, 2014  2:18 PM

Invoke-Item tips

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Invoke-Item is another cmdlet that you don’t see used that often but there is one place where its invaluable – opening files. If you give Invoke-Item the path to a file

Invoke-Item -Path .\procs.txt

The file will be opened with the default application associated with that extension. In this case Notepad.

If you use a PowerShell script file

Invoke-Item .\t1.ps1

It will be opened in Notepad for you to examine.  CSV files automatically open in Excel and other Office files are opened in the correct application.

Using the alias ii for Invoke-item makes it even easier.

August 5, 2014  12:42 PM

ServerManagerTasks module – – Get-SMServerFeature

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Finding the Windows features installed on a remote machine can be an interesting task. You could use Get-WindowsFeature but that gives you a “graphical” display:

£> Get-WindowsFeature | where DisplayName -like ‘*DNS*’

Display Name         Name             Install State
————         —-             ————-
[X] DNS Server       DNS              Installed
[X] DNS Server Tools RSAT-DNS-Server  Installed

Or you could use Get-SMServerFeature from the ServerManagerTasks module:

£> Get-SMServerFeature -BatchSize 1000  | where DisplayName -like ‘*DNS*’ | sort Displayname | ft -a Displayname, State, Type, ConfigurationStatus

Displayname      State Type ConfigurationStatus
———–      —– —- ——————-
DNS Server           1    0                   3
DNS Server Tools     1    2                   3

Which is CIM based and uses a new class: root/microsoft/windows/servermanager/MSFT_ServerFeature

Following the tradition firmly established since the introduction of WMI the data from this class is represented by integer values AND just for giggles its not documented. To be fair most of the WMI classes aren’t documented.


We need documentation for these classes


In an effort to work out which are the important values I compared the outputs from

Get-SMServerFeature -BatchSize 1000  | where DisplayName -like ‘*PowerShell*’ | sort Displayname | ft -a Displayname, State, Type, ConfigurationStatus


Get-WindowsFeature | where DisplayName -like ‘*PowerShell*’ | sort Displayname

The important property from  Get-SMServerFeature  seems to be State which takes a 0 or 1. O corresponds to Available in Get-WindowsFeature and 1 corresponds to Installed.

You can use the trick I show in PowerShell and WMI (www.manning.com/siddaway2)

$state = DATA {ConvertFrom-StringData -StringData @’
0 = Available
1 = Installed

Get-SMServerFeature -BatchSize 1000  |
where DisplayName -like ‘*PowerShell*’ |
sort Displayname |
select DisplayName, UniqueName,
@{N=’State’; E={$state[“$($_.State)”]}

$state = DATA {ConvertFrom-StringData -StringData @’
0 = Available
1 = Installed

Create a hash table for the integer values and their meaning and use that hash table in a calculated field to get the meaning from the integer value.

The output will look like this:

DisplayName : Windows PowerShell Web Access
UniqueName  : WindowsPowerShellWebAccess
State       : Available

Its now easy to compare the data between different machines.  Get-SMServerFeature has a CimSession parameter for working with remote machines

August 4, 2014  2:09 PM

European Summit – – update 6

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

As pointed out on PowerShell.org – http://powershell.org/wp/2014/08/03/powershell-summit-europe-2014-status/ – we’re around the 50% of capacity for registrations at the moment.

We need at least 45 attendees to be able to afford to put on a European Summit in 2015. Its not that we don’t want to do a European Summit – its we can’t afford to unless we get the support needed to ensure the event is financially viable

There are about 6 weeks until registration closes in mid-September.

Now is the time to start pestering your boss about going. There’s a great speaker line up plus some excellent evening activities. Amsterdam is a wonderful city that’s well worth a visit.

If you want to hear top line PowerShell speakers, including the PowerShell team, at an annual PowerShell summit then we need your support and I’d urge you to attend.

Registration is via the link at http://powershell.org/wp/community-events/summit/

It would be a sad position if we can’t get enough attendees from across Europe to make this work

July 24, 2014  2:22 PM

History cmdlets

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

There are 4 cmdlets for working with the history in a PowerShell session:

Add-History – adds an entry to the history
Clear-History – clears the history
Get-History -enables you see the current history
Invoke-History – enables you to run a line in your history

Get-History is the one I use the most.  You can use the UP arrow key to cycle back to an old command or use Invoke-History.

I’d only use Clear-History if I had a long running session and I was changing what I was working on.

Add-History is the odd one. I’ve never used it but it could be useful if you have a command you run often and you want to push it into the history when you start a session.

Be aware of  a  variable that controls history:

$MaximumHistoryCount  defaults to  4096 and is the maximum number of commands saved in the command history.

You can increase this up to 32768 if you desire but unless you put the command in your profile your next session will drop back to the default.

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: