Monthly Archive


Monthly Archives: July 2013

Pure PowerShell–the great debate

One of the outcomes of the Scripting Games is a series of debates on regarding things that were noticed during the games. The latest is on using “pure” powershell as opposed to adding .NET, COM, utilities and whatever comes to hand

PowerShell Jump Start recordings

The records of the PowerShell Jump Start from two weeks ago are now available.

9 sessions on PowerShell 3.0 delivered by Jason Helmick and Jeffrey Snover.

It doesn’t get any better than this.

drive letter functions

Have you ever looked at the functions available to you in PowerShell?

Get-ChildItem function:

shows the list of functions currently available in your PowerShell session.

function: is a PowerShell drive.  Other drives are available:

£ Get-PSDrive

Name           Used (GB)     Free (GB) Provider      Root
----           ---------     --------- --------      ----
Alias                                  Alias
C                 103.58        129.21 FileSystem    C:\
Cert                                   Certificate   \
D                    .03           .06 FileSystem    D:\
E                                      FileSystem    E:\
Env                                    Environment
F                                      FileSystem    F:\
Function                               Function
HKCU                                   Registry      HKEY_CURRENT_USER
HKLM                                   Registry      HKEY_LOCAL_MACHINE
Variable                               Variable
WSMan                                  WSMan

These drives are created by PowerShell providers – functionality that exposes data stores as if they were file systems.  Other providers include AD, SQL Server and IIS if you have those installed.

The function drive enables you to work directly with functions. You can view their details:

£ get-command c: | fl *

PSPath              : Microsoft.PowerShell.Core\Function::C:
PSDrive             : Function
PSProvider          : Microsoft.PowerShell.Core\Function
PSIsContainer       : False
HelpUri             :
ScriptBlock         : Set-Location C:
CmdletBinding       : False
DefaultParameterSet :
Definition          : Set-Location C:
Options             : None
Description         :
Verb                :
Noun                :
HelpFile            : System.Management.Automation.dll-Help.xml
OutputType          : {}
Name                : C:
CommandType         : Function
Visibility          : Public
ModuleName          :
Module              :
RemotingCapability  : PowerShell
Parameters          : {}
ParameterSets       : {}

In this case the information is minimal because all the function does is set your location to the c: drive.

The important part is that you can investigate functions as you will see later

Is PowerShell too big?

I was thinking the other day about the differences between PowerShell v1 and the new v4 we’ll be getting soon. There is so much in PowerShell that its very difficult to be an expert in aspects.

Think about these topics for a moment:

  • PowerShell pipeline
  • Error handling and debugging
  • Objects
  • Scope
  • Formatting
  • Extensible type System
  • PowerShell remoting
  • PowerShell jobs
  • Advanced functions
  • Modules
  • Splatting
  • CIM sessions
  • Workflows
  • Scheduled jobs
  • Internationalization
  • Desired State Configuration

And all of that is before you start adding in the cmdlets for administering specific parts of your environment – AD, Exchange, SQL Server, SharePoint, DNS, DHCP, networks, backup etc etc etc.

PowerShell has got to the point where you can’t expect to be an expert in every facet. Have a working knowledge of as much as possible but specialise where it will help you do your job.

That’s why it took three of us to write PowerShell in Depth!

off with his head

CSV files are great for passing information around and are very easy to use in your PowerShell scripts. Sometimes, your CSV may have a problem – for instance it doesn’t have a header row. At that point the data becomes a bit difficult to use:

£ Import-Csv .\htest.csv | Format-Table -AutoSize

2  Red   23.8 47.6
-  ---   ---- ----
7  Blue  24.0 168.0
15 Green 2.5  37.5

Luckily there is an answer.  Create your own headers:

£ Import-Csv .\htest.csv -Header "Number", "Colour", "Price", "Total" | Format-Table -AutoSize

Number Colour Price Total
------ ------ ----- -----
2      Red    23.8  47.6
7      Blue   24.0  168.0
15     Green  2.5   37.5

Makes much more sense now.

You can also override existing headers

£ Import-Csv .\htest.csv -Header "Number", "Colour", "Price", "Total"  |
>> select -Skip 1 | Format-Table -AutoSize

Number Colour Price Total
------ ------ ----- -----
2      Red    23.8  47.6
7      Blue   24.0  168.0
15     Green  2.5   37.5

The select call is used to skip the old header row.

If you run queries in SQL Studio Management Studio and export the results to a CSV file you will get a file without headers. This technique comes in useful at that point.

PowerShell remoting book

I mentioned several times during the Q&A for the PowerShell jump start that a free PowerShell remoting book was available from

The book can be found here -

Scroll down the list to see lots of free books

Fun with prompts

At the PowerShell Jumpstart event there were a lot questions asking how Jeffrey Snover managed to get a dollar sign – $ – as his prompt. A lot of them centred on asking if this was a PowerShell v4 thing.

Its not a V4 thing. You have been able to change the prompt since v1. 

The PowerShell prompt is by default the path of your current folder. This can easily take half the width if the screen if if you are several layers deep

You can change the PowerShell prompt by running a prompt function. For instance to change the prompt to a dollar sign

PS C:\Windows\system32> function prompt {
>> "$ "
>> }

I move the folder information into the header

$ function prompt {
>> "$ "
>> $host.ui.RawUI.WindowTitle = $(get-location)
>> }

Other useful tricks – are you running 32 bit or 64 bit PowerShell?  Its easy to forget if you have numerous consoles open.

PS>function prompt {
>> if ([System.IntPtr]::Size -eq 8) {$size = '64 bit'}
>> else {$size = '32 bit'}
>> $host.ui.RawUI.WindowTitle = "$size $(get-location)"
>> "$ "
>> }

This adds 64 bit or 32 bit to the console header.  As well as the location.

One final option is to show if you are running that console elevated or not.

function prompt {
if ([System.IntPtr]::Size -eq 8) {$size = '64 bit'}
else {$size = '32 bit'}

$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
$secprin = New-Object Security.Principal.WindowsPrincipal $currentUser
if ($secprin.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator))
{$admin = 'Administrator'}
else {$admin = 'non-Administrator'}

$host.ui.RawUI.WindowTitle = "$admin $size $(get-location)"
"$ "

The Windows identity of the current user is retrieved and used to create a security principal object. This is used to test is the security principal is in the Administrator role.

Add this prompt function to your profile and you get some useful reminders for while you are working and a minimalist prompt.

PowerShell Deep Dives is published

PowerShell Deep Dives is a collection of chapters from PowerShell authorities world wide. The book is now published

The royalties from the book all go to Save the Children

If you’ve bought a copy thank you for your support – your book will be with you soon. If you haven’t got a copy please buy one. You will be supporting a very good cause and getting your hands on PowerShell material you won’t find elsewhere.

Internet Connection

Can you find the network adapter on your machine that’s connected to the Internet?  On a Windows 8/2012 machine its fairly simple:

PS> Get-NetConnectionProfile -IPv4Connectivity Internet

Name             : NetworkName
InterfaceAlias   : AdapterName
InterfaceIndex   : 12
NetworkCategory  : Private
IPv4Connectivity : Internet
IPv6Connectivity : LocalNetwork

What else can you discover?

The important information is the InterfaceIndex

Get-NetAdapter -InterfaceIndex 12

shows the NIC information such as name, MAC address and speed (similar to Win32_NetworkAdapter)

Get-NetAdapterAdvancedProperty -Name name

shows buffer data

Get-NetAdapterStatistics -Name name

shows transmitted data

Get-NetIPConfiguration -InterfaceIndex 12

pulls the IP configuration

This just scratches the surface to the networking modules in Windows 8/2012

The modules are based on new WMI classes for the most part so you won’t find them on legacy operating systems even with WMF 3 loaded.

CSV fields with spaces in the field name

CSV files are one way we can get data into our scripts – but sometimes when we get given a CSV file it has spaces in the field name e.g.

"Area Number"

Dealing with this can be a bit awkward but you can access the field like this:

Import-Csv area.csv |
foreach {
$_.'Area Number'

Double quotes work as well

The trick comes if you need to add the field into a string

Import-Csv area.csv |
foreach {
"Area = " + $_.'Area Number' + " is available"

String concatenation works. Alternatively, if you want to use string substitution:

Import-Csv area.csv |
foreach {
"Area = $($_.'Area Number') is available"