Introduction to PowerShell for Unix people

The point of this section is to outline a few areas which I think *nix people should pay particular attention to when learning Powershell.

Resources for learning PowerShell

A full introduction to PowerShell is beyond the scope of this e-book. My recommendations for an end-to-end view of PowerShell are:

unix-like aliases

PowerShell is a friendly environment for Unix people to work in. Many of the concepts are similar, and the PowerShell team have built in a number of Powershell aliases that look like unix commands. So, you can, for example type:

1 ls

….and get this:

1     Directory: C:\temp
2 Mode                LastWriteTime     Length Name
3 ----                -------------     ------ ----
4 -a---        22/02/2015     16:51      25773 all_the_details.md
5 -a---        20/02/2015     07:31       3390 commands-summary.md

These can be quite useful when you’re switching between shells, although I found that it can be irritating when the ‘muscle-memory’ kicks in and you find yourself typing ls -ltr in PowerShell and get an error.

the pipeline

The PowerShell pipeline is much the same as the Bash shell pipeline. The output of one command is piped to another one with the ‘|’ symbol.

The big difference between piping in the two shells is that in the unix shells you are piping text, whereas in PowerShell you are piping objects.

This sounds like it’s going to be a big deal, but it’s not really.

In practice, if you wanted to get a list of process names, in bash you might do this:

1 ps -ef | cut -c 49-70

…whereas In PowerShell you would do this:

1 get-process | select ProcessName

In Bash you are working with characters, or tab-delimited fields. In PowerShell you work with field names, which are known as ‘properties’.

You can determine the properties of a Powershell object with the command get-member

get-help, get-command, get-member

get-member

When you run a PowerShell command, such as get-history only a subset of the get-history output is returned to the screen.

In the case of get-history, by default two properties are shown - ‘Id’ and ‘Commandline’…

1 $ get-history
2 
3 Id CommandLine
4 -- -----------
5 1  dir -recurse c:\temp

…but get-history has 4 other properties which you might or might not be interested in:

1 $ get-history | select *
2 
3 Id                 : 1
4 CommandLine        : dir -recurse c:\temp
5 ExecutionStatus    : Completed
6 StartExecutionTime : 06/05/2015 13:46:56
7 EndExecutionTime   : 06/05/2015 13:47:07

The disparity between what is shown and what is available is even greater for more complex entities like ‘process’. By default, on my screen, get-process shows 8 columns, but there are actually over 50 properties (as well as 20 or so methods) available.

The full range of what you can return from a PowerShell command is given by the get-member command[2].

To run get-member, you pipe the output of the command you’re interested in to it, for example:

1 get-process | get-member

….or, more typically:

1 get-process | gm

get-member is one of the ‘trinity’ of ‘help’-ful commands:

  • get-member
  • get-help
  • get-command
get-help

get-help is similar to the Unix man[3].

So if you type get-help get-process, you’ll get this:

 1 NAME
 2     Get-Process
 3 
 4 SYNOPSIS
 5     Gets the processes that are running on the local computer or a remote computer.
 6 
 7 
 8 SYNTAX
 9     Get-Process [[-Name] <String[]>] [-ComputerName <String[]>] [-FileVersionInfo] [\
10 -Module] [<CommonParameters>]
11 
12     Get-Process [-ComputerName <String[]>] [-FileVersionInfo] [-Module] -Id <Int32[]\
13 > [<CommonParameters>]
14 
15     Get-Process [-ComputerName <String[]>] [-FileVersionInfo] [-Module] -InputObject\
16  <Process[]> [<CommonParameters>]
17 
18 
19 DESCRIPTION
20     The Get-Process cmdlet gets the processes on a local or remote computer.
21 
22     Without parameters, Get-Process gets all of the processes on the local computer.\
23  You can also specify a particular
24     process by process name or process ID (PID) or pass a process object through the\
25  pipeline to Get-Process.
26 
27     By default, Get-Process returns a process object that has detailed information a\
28 bout the process and supports
29     methods that let you start and stop the process. You can also use the parameters\
30  of Get-Process to get file
31     version information for the program that runs in the process and to get the modu\
32 les that the process loaded.
33 
34 
35 RELATED LINKS
36     Online Version: http://go.microsoft.com/fwlink/?LinkID=113324
37     Debug-Process
38     Get-Process
39     Start-Process
40     Stop-Process
41     Wait-Process
42 
43 REMARKS
44     To see the examples, type: "get-help Get-Process -examples".
45     For more information, type: "get-help Get-Process -detailed".
46     For technical information, type: "get-help Get-Process -full".
47     For online help, type: "get-help Get-Process -online"

There are a couple of wrinkles which actually make the PowerShell ‘help’ even more help-ful.

  • you get basic help by typing get-help, more help by typing get-help -full and…probably the best bit as far as I’m concerned…you can cut to the chase by typing get-help -examples
  • there are lots of ‘about_’ pages. These cover concepts, new features (in for example about_Windows_Powershell_5.0) and subjects which dont just relate to one particular command. You can see a full list of the ‘about’ topics by typing get-help about
  • get-help works like man -k or apropos. If you’re not sure of the command you want to see help on, just type help process and you’ll see a list of all the help topics that talk about processes. If there was only one it would just show you that topic
  • Comment-based help. When you write your own commands you can (and should!) use the comment-based help functionality. You follow a loose template for writing a comment header block, and then this becomes part of the get-help subsystem. It’s good.
get-command

If you don’t want to go through the help system, and you’re not sure what command you need, you can use get-command.

I use this most often with wild-cards either to explore what’s available or to check on spelling.

For example, I tend to need to look up the spelling of ConvertTo-Csv on a fairly regular basis. PowerShell commands have a very good, very intuitive naming convention of a verb followed by a noun (for example, get-process, invoke-webrequest), but I’m never quite sure where ‘to’ and ‘from’ go for the conversion commands.

To quickly look it up I can type:

get-command *csv*

… which returns:

 1 $ get-command *csv*
 2 
 3 CommandType     Name                    ModuleName
 4 -----------     ----                    ----------
 5 Alias           epcsv -> Export-Csv
 6 Alias           ipcsv -> Import-Csv
 7 Cmdlet          ConvertFrom-Csv         Microsoft.PowerShell.Utility
 8 Cmdlet          ConvertTo-Csv           Microsoft.PowerShell.Utility
 9 Cmdlet          Export-Csv              Microsoft.PowerShell.Utility
10 Cmdlet          Import-Csv              Microsoft.PowerShell.Utility
11 Application     ucsvc.exe
12 Application     vmicsvc.exe

Functions

Typically PowerShell coding is done in the form of functions[4]. What you do to code and write a function is this:

Create a function in a plain text .ps1 file[5]

1 gvim say-HelloWorld.ps1
say-helloworld.png
say-helloworld.png

…then source the function when they need it

1 $ . .\say-HelloWorld.ps1

…then run it

1 $ say-helloworld
2 Hello, World

Often people autoload their functions in their $profile or other startup script, as follows:

1 write-verbose "About to load functions"
2 foreach ($FUNC in $(dir $FUNCTION_DIR\*.ps1))  
3 {
4   write-verbose "Loading $FUNC.... "
5   . $FUNC.FullName
6 }

Footnotes


[1] If you wanted the equivalent of ls -ltr you would use gci | sort lastwritetime. ‘gci’ is an alias for ‘get-childitem’, ‘sort’ is an alias for ‘sort-object’.

[2] Another way of returning all of the properties of an object is to use ‘select *‘…so in this case you could type get-process | select *

[3] There is actually a built-in alias man which tranlates to get-help, so you can just type man if you’re pining for Unix.

[4] See the following for more detail on writing functions rather than scripts: http://blogs.technet.com/b/heyscriptingguy/archive/2011/06/26/don-t-write-scripts-write-powershell-functions.aspx

[5] I’m using ‘gvim’ here, but notepad would work just as well. PowerShell has a free ‘scripting environment’ called PowerShell ISE, but you don’t have to use it if you dont want to.