15 Apr 2020

An Introduction to Powershell

I’ve been using Powershell for a couple of years and it is a useful skill to have in your toolbox. In can be far easier to write a script to complete a task, than to build an exe.

As a flavour of the kinds of things you can do, these are some that I use it for:

  • Working with files.
  • Running exes / containers.
  • Creating Menus.
  • Running installers.
  • Extracting files.
  • Steps in CI / CD.
  • Any repetative set of actions.

What is Powershell

Powershell is a task automation and configuration management framework from Microsoft, consisting of a command-line shell and associated scripting language. It is Cross-platform (Windows, macOS, CentOS and Ubuntu), so your skill is useful outside of windows. It was first released in 2006, the current version is 7 (released December 2019).

In PowerShell, administrative tasks are generally performed by what’s known as cmdlets which are specialized .NET classes implementing a particular operation. For example ‘Rename-Item’ allows you to rename a file. The cmdlets work by accessing data in different data stores, like the file system or registry, which are made available to PowerShell via providers. Third-party developers can add cmdlets and providers to PowerShell. Cmdlets may also be used by scripts and scripts may be packaged into modules.

In windows everything is an API which returns structured data in the form of objects. These objects can be passed to other cmdlets to allow for a pipeline of commands.

Windows PowerShell can execute four kinds of named commands:

  • cmdlets (.NET Framework programs designed to interact with PowerShell) - Cmdlets are specialized .NET classes.
  • PowerShell scripts (files suffixed by .ps1).
  • PowerShell functions.
  • standalone executable programs.

https://en.wikipedia.org/wiki/PowerShell

https://docs.microsoft.com/en-us/powershell

Running Powershell Interactively

There are 2 ways I run powershell interactively.

  • Powershell CLI - a command line window where commands can be executed.
  • Windows PowerShell ISE - ISE stands for Integrated Scripting Environment, it is a graphical user interface that allows you to run commands and create, modify and test scripts without having to type all the commands in the command line. ISE also has a helpful list of commands you can search.

Powershell command line and ISE screenshot

Where do I get it ?

On Windows 10 version 5.1 “Window Powershell” should already be an installed. Go to the start menu and launch it.

To find out what version you have installed type:

    > Get-Host | Select-Object Version

Version 7 can be installed from: https://github.com/PowerShell/PowerShell#get-powershell

More information about the Select-Object cmdlet can be seen here: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/select-object?view=powershell-5.1

How do I use Commands ?

So what is “Get-Host” that we just called ? When you run it then an object will be returned of type “Windows PowerShell ISE Host” or “ConsoleHost” (depending upon where you run it from). The result of the cmdlet is an object which has properties which you can work with, or pass the whole object onto another command using a pipe symbol ‘|’.

    PS C:\windows\system32> Get-Host
    Name             : Windows PowerShell ISE Host
    Version          : 5.1.17763.1007
    InstanceId       : c38d1071-df2a-45a3-b03a-e42d47156137
    UI               : System.Management.Automation.Internal.Host.InternalHostUserInterface
    CurrentCulture   : en-GB
    CurrentUICulture : en-GB
    PrivateData      : Microsoft.PowerShell.Host.ISE.ISEOptions
    DebuggerEnabled  : True
    IsRunspacePushed : False
    Runspace         : System.Management.Automation.Runspaces.LocalRunspace

Referencing the Properties of an Object

A dot allows you to reference properties of an object and call methods associated with those properties, you must wrap the cmdlet in brackets so it has been evaluated first. ‘Version’ is an object of type System.Version which has a ToString() method, so it combines all it’s version values into one string.

    > (Get-Host).Version.ToString()  
     5.1.17763.1007    

You can also use Select-Object to get a property from an object. ‘|’ is a pipe which passes the result of one command into the next.

Note: The Select-Object cmdlet selects specified properties of an object or set of objects. It can also select unique objects, a specified number of objects, or objects in a specified position in an array.

    > Get-Host | Select-Object -Property Version
    Version       
    -------       
    5.1.17763.1007

using Select with -ExpandProperty allows access to the properties of an object in the pipeline.

    > Get-Host | Select-Object -ExpandProperty Version
    
    Major  Minor  Build  Revision
    -----  -----  -----  --------
    5      1      17763  1007    

Learning about the Properties of an Object

The cmdlet Get-Member will list the members of an object. This can be useful to discover what you can do with an object.

    > PS C:\windows\system32> (Get-Host).Version | Get-Member
    
       TypeName: System.Version

    Name          MemberType Definition                                                                                                                                                         
    ----          ---------- ----------                                                                                                                                                         
    ToString      Method     string ToString(), string ToString(int fieldCount)                                                                                                                 
    Build         Property   int Build {get;}                                                                                                                                                   
    Major         Property   int Major {get;}                                                                                                                                                   
    MajorRevision Property   int16 MajorRevision {get;}                                                                                                                                         
    Minor         Property   int Minor {get;}                                                                                                                                                   
    MinorRevision Property   int16 MinorRevision {get;}                                                                                                                                         
    Revision      Property   int Revision {get;}         

Exercise 1

If you would like to try to apply what you have read so far, fire up powershell. “Find out only the build number of powershell using ‘Get-Host’”. The answer can be found at the end of this blog.

    > ?
    Build
    -----
    17763

Using Variables

Variables can be created and they hold objects. These variable are defined using the $ symbol.

In the code below I am assigning some variables which are strings and integers. A string can be defined using either single or double quotes. Next I write them to the output using Write-Host.

    > $player1 = "julian"; $player2 = 'jane';$player1Score=23; $player2Score=98;
    > Write-Host "$player1 $player1Score, $player2 $player2Score. Total score: ("($player1Score+$player2Score)")"
    julian 23, jane 98. Total score: ( 121 )

Variables can be used in if statements:

    > if ($player1Score > $player2Score) { Write-Host "$player1 wins" } else { Write-Host "$player2 wins"}
    jane wins

Working with Files

Cmdlet Get-ChildItem allows you to view file details. If we set up a folder location we can pass that into the cmdlet so search for files using a filter.

    > $folder="c:\windows\system32"
    > Get-ChildItem $folder -filter *.dll

        Directory: C:\windows\system32
    Mode                LastWriteTime         Length Name                                                                                                                                         
    ----                -------------         ------ ----                                                                                                                                         
    -a----       15/09/2018     08:28         196608 aadauthhelper.dll                                                                                                                            
    -a----       05/04/2020     15:56         692736 aadcloudap.dll                                                                                                                               
    -a----       15/09/2018     08:28          68096 aadjcsp.dll                                                                                                                                  
    -a----       05/04/2020     15:56        1824768 aadtb.dll                                                                                                                                    
    -a----       15/09/2018     08:28         145720 aadWamExtension.dll
    ... etc

https://docs.microsoft.com/en-us/powershell/scripting/samples/working-with-files-and-folders?view=powershell-5.1

Exercise 2

Find all png files starting with ’S’ in c:\windows\system32 and then put the result into a variable (Use a modified version of the above Get-ChildItem example). The answer can be found at the end of this blog.

    > $files = ?

Working with arrays

We often need to work with sets of objects. We can refer to an element in a list / array using square brackets [ ] and passing an index.

Lets investigate element 0 in our array:

    > $files[0]
    Directory: C:\windows\system32
    Mode                LastWriteTime         Length Name                                                                                                                                         
    ----                -------------         ------ ----                                                                                                                                         
    -a----       15/09/2018     08:28            232 @AppHelpToast.png    

We can see that different properties for the item are shown. It is more than just a string, it is an object. We can see which properties it has using ‘Get-Member’.

    > $files[0] | Get-Member
    Name                      MemberType     Definition                                                                                                                                           
    ----                      ----------     ----------                                                                                                                                           
    ... (not all members shown)
    Directory                 Property       System.IO.DirectoryInfo Directory {get;}                                                                                                             
    DirectoryName             Property       string DirectoryName {get;}                                                                                                                          
    Exists                    Property       bool Exists {get;}     
    FullName                  Property       string FullName {get;}                                                                                                                               
    IsReadOnly                Property       bool IsReadOnly {get;set;}                                                                                                                           
    LastWriteTime             Property       datetime LastWriteTime {get;set;}                                                                                                                    
    Length                    Property       long Length {get;}                                                                                                                                   

We can also access the properties of the object for example FullName.

    > $files[0].FullName
    C:\windows\system32\@AppHelpToast.png

We can also work with the whole set of files and do something with each element for example. In this example I am going to launch the first 5 in chrome:

    > $files | Select-Object -First 5 | ForEach-Object { $file=$_.FullName; Start-Process "chrome.exe" "file:///$file" }
or 

    > Get-ChildItem -Path "c:\windows\system32" -Filter s*.png | Select-Object -First 5 | ForEach-Object {  $file=$_.FullName; Start-Process "chrome.exe" "file:///$file"}

Powershell images launched in Chrome

Files can be deleted using cmdlet “Remove-Item” or viewed using Get-Content.

    > Get-Content (Get-ChildItem -Path *  -filter *.txt)[0]
    
    Third Party Legal Notices 
    This product contains software licensed under terms which require Microsoft to display the following notice(s): 
    •   For LibTif only: 
    o   Note: While Microsoft is not the author of this file, Microsoft is offering you a license subject to the terms of the end user license agreement for LIBTIF. Microsoft reserves all other rig
    hts. The notices below are provided for informational purposes only and are not the license terms under which Microsoft distributed this file.
    o   Copyright (c) 1988-1997 Sam Leffler 
    o   Copyright (c) 1991-1997 Silicon Graphics, Inc. 

Working with Windows Services

Scripting the management of services can be very useful. There are commands to view, stop, start and manage the properties of a service. You can find out what service are in a particular state.

    > (Get-Service)[0] | Get-Member
    > Get-Service | Where-Object {$_.Status -eq 'Stopped'}

https://docs.microsoft.com/en-us/powershell/scripting/samples/managing-services?view=powershell-7

Cmdlet Aliases

Certain commands have aliases which have shortened names for example the alias for ‘Get-Content’ is ‘cat’.

   > Get-ChildItem -Path "c:\windows\system32" -Filter *.txt | ForEach-Object { cat $_.FullName }

https://ilovepowershell.com/2011/11/03/list-of-top-powershell-alias/ https://docs.microsoft.com/en-us/powershell/scripting/developer/cmdlet/cmdlet-aliases?view=powershell-7

Creating a Script

Creating scripts is where the real power of Powershell is achieved. Allowing automation to save time and increase quality.

Scripts can accept parameters either via being passed as parameters, being input by the user or from pre-set host variables.

We are going to create a script to do the following:

  1. Get a city from the user.
  2. Find out the time for that City: (Invoke-WebRequest “http://worldtimeapi.org/api/timezone/Europe/London").Content
  3. Format the result.

The command to accept input from the user is Read-Host. If we put the following into a file and name it timezone.ps1 we can executed it using .\timezone.ps1

    $city = Read-Host "What city ?"
    $content = (Invoke-WebRequest "http://worldtimeapi.org/api/timezone/Europe/$city").Content
    Write-Host (ConvertFrom-Json $content).datetime

Note: the script is not digitally signed so you will need to allow it to run by running: Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine

    > Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine
    > .\timezone.ps1
    What city ?: London
    2020-04-14T19:28:09.588199+01:00

We can improve the script by showing just the time in a nicer message. We can also pass a value into the script using the param keyword.

    param ([string]$city)
    $content = (Invoke-WebRequest "http://worldtimeapi.org/api/timezone/Europe/$city").Content
    $time=((ConvertFrom-Json $content).datetime).SubString(11,5)
    Write-Host "In $city it is $time"

    > .\timezone.ps1 "London"
    In London it is 19:33

Functions

Functions allow libaries of defined in files and then loaded and used as needed.

    function getCityTime
    {
        param ([string]$city)
        $content = (Invoke-WebRequest "http://worldtimeapi.org/api/timezone/Europe/$city").Content
        Write-Host (ConvertFrom-Json $content).datetime
    }
We can place this in a file called getCityTime.ps1 and then load it read for use.
    > . .\getCityTime.ps1
    
    > getCityTime "london"
    2020-04-14T19:39:03.094545+01:00

    > getCityTime "Paris"
    2020-04-14T20:39:09.142408+02:00

Miscellaneous Tidbits

Tailing a file

You can tail a text file to watch for changes using the -wait argument on the Get-Content cmdlet.

    > Add-Content dealer.txt "Hello from PS1"
    > cat dealer.txt -wait
    Hello from PS1
    Hello from PS2

From another powershell enter the following command to append a line to the text file. The line will appear in the firest powershell session.

    > Add-Content dealer.txt "Hello from PS2"

Unzipping Archives

To extract an archive use the “expand-archive” cmdlet.

    > $name = "myzipfile.zip"
    > expand-archive -Path "$name" -DestinationPath . -force        

Exercise Answers

Exercise 1: Find out the build number of powershell using ‘Get-Host’

    (Get-Host).Version.Build
    Get-Host | Select -ExpandProperty Version | Select Build

Exercise 2: Find all png files starting with ’S’ in c:\windows\system32 and then put the result into a variable.

    $folder="c:\windows\system32"
    $files = Get-ChildItem $folder -filter *.png
blog comments powered by Disqus

About Me


My first computer was a Commodore VIC-20, I had great fun trying to code text adventures and side scrolling shoot ‘em ups in BASIC. This helped me lead the way as the first in my school to pass a computer exam.

Currently I work as a Senior Software Engineer in Bedford for a FTSE 100 Company. Coding daily in C#, JavaScript and SQL. Outside of work I work on whatever is interesting me at that time.