Powershell Cheatsheet

Garen Ikezian published on Updated on
7 min, 1322 words

Categories: Programming

This article teaches the fundamentals of Powershell scripting. It can serve people as a refresher for those who don't touch Powershell too often. It assumes the reader has basic knowledge of Bash scripting.

As of writing, Powershell 7.5 is the latest version used in this article.

Introduction: Getting a Taste of PowerShell

Both Powershell and other scripting languages have common command aliases (e.g. ls, dir, cd, echo). However, one aspect that stands out is Powershell's slightly more verbose and descriptive syntax.

Powershell commands are called "cmdlets" (pronounced "command-lets"). They primarily use a verb-noun pair and are case-insensitive (get-help is the same as Get-Help).

Note:

  • As specified in this manual, PowerShell uses the term verb to describe a word that implies an action even if that word isn't a standard verb in the English language. For example, the term "New" is a valid PowerShell verb name because it implies an action even though it isn't a verb in the English language.
  • Both parameters and cmdlets are case-insensitive.

Alongisde cmdlet, Powershell comes bundled with cmd.exe (Command Prompt) commands. They are legacy DOS commands integrated into Powershell for backwards compatibility. Such commands include dir, ping, copy, and net.

Examples of cmdlets include:

  • Get-Alias
  • Get-Command
  • Get-Help
  • Select-String
  • Start-Process
  • End-Process
  • Get-Date
  • Clear-Session
  • Get-Process

Note: If you're on Ubuntu Linux, you can install and use the command pwsh as an experiment. Do note that some features are not consistent or are limited.

The first three most important important Powershell cmdlets to acquaint are Get-Help, Get-Alias and Get-Command.

Get-Help

Like man or info in Linux, Get-Help is your best friend. It will help you gather information about a specified command. Although Get-Help can accept cmd.exe commands, it is generally better to use /? instead.

Get-Help additionally offers three different options. When we type get-help get-help and read under the the REMARKS section, we will see this:

    To see the examples, type: "get-help Get-Help -examples".
    For more information, type: "get-help Get-Help -detailed".
    For technical information, type: "get-help Get-Help -full".

Furthermore, you can use help or man which displays one screen of text at a time. Do note however that the navigation is limited and you cannot scroll one line up like like in less.

<cmdlet-name> -? is also an option (-? is dentical to Get-Help), but it only works for cmdlets.

Get-Alias

For Get-Alias, both dir and ls actually run Get-ChildItem. We can check by typing Get-Alias ls or Get-Alias dir:

They give:

PS C:\Users\garen> get-alias dir

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           dir -> Get-ChildItem


PS C:\Users\garen> get-alias ls

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           ls -> Get-ChildItem

If Powershell reports that the leading alias does not exist, we can verify all the aliases like so:

PS C:\Users\garen> get-alias

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           % -> ForEach-Object
Alias           ? -> Where-Object
Alias           ac -> Add-Content
Alias           asnp -> Add-PSSnapin
Alias           cat -> Get-Content
Alias           cd -> Set-Location
Alias           CFS -> ConvertFrom-String                          3.1.0.0    Microsoft.PowerShell.Utility

Ideally, grep will come in handy for this situation. But since we're using Powershell, the alternative is Select-String (its alias is sls).

PS C:\Users\garen> get-alias | sls ls

cls
ls
sls

Well that's disappointing (insert "mom, can we have" meme).

To remedy this, we'll need Out-String with the passing -Stream argument.

If you didn't understand, it's not something to worry too much for now, but it's here to stay for grep lovers like me:

PS C:\Users\garen> get-alias | out-string -stream | sls ls

Alias           cls -> Clear-Host
Alias           gcs -> Get-PSCallStack
Alias           ls -> Get-ChildItem
Alias           sls -> Select-String

Get-Command

Typing Get-Command without arguments will provide you a list of cmdlets, aliases, and functions available in your current session.

If you include the asterisk, it will show everything including the executable applications (e.g. notepad.exe, 7z.exe, python.exe) set in the PATH environment variable ($Env:PATH).

I/O in PowerShell

Output Streams in Powershell

An important clarification needs to be said about Powershell ouput streams...

Both Powershell and Bash share stdin, stdout and stderr streams. However, unlike Bash, Powershell handles the output stream differently because it doesn't process texts like its Bash counterpart. Instead, it processes and outputs .NET objects.

This is because Powershell is an object-oriented scripting language. Everything is an object in Powershell. In fact, when you call any cmdlet, it will always return one or more .NET objects. You can verify cmdlets returning an object by typing Get-Member after a pipe opreator |:

Note: Recall... Pipeline: A sequence of one or more commands separated by a |.

get-alias | get-member
   TypeName: System.Management.Automation.AliasInfo

Name                MemberType     Definition
----                ----------     ----------
Equals              Method         bool Equals(System.Object obj)
GetHashCode         Method         int GetHashCode()
...
emotingCapability  Property       System.Management.Automation.RemotingCapability RemotingCapability {get;}
Version             Property       version Version {get;}
...

Powershell has six output streams and each has its dedicated write cmdlet. Both "Success Stream" and "Error Stream" are mapped to *nix's stdout and stderr respectively.

Stream #DescriptionWrite Cmdlet
1Success StreamWrite-Output (alias: echo)
2Error StreamWrite-Error
3Warning StreamWrite-Warning
4Verbose StreamWrite-Verbose
5Debug StreamWrite-Debug
6Information StreamWrite-Information, Write-Host
n/aProgress StreamWrite-Progress
*All Streamsn/a

Redirecting Outputs in Powershell

Both Bash and Powershell share the same feature for redirecting output (> for overwrite, >> for append). Still, there are two other ways:

Out-File

Like >, it sends output to a file. If there are no parameters, it is no different to using >. There are several ways to use it.

The parameter -FilePath is kind of like -o in *nix-based systems. Although it is optional, it is better to include it in your scripts for legibility purposes. For example:

get-process | out-file -filepath .\Process.txt

Will create a txt file with all running processes information. We can also pass the argument -Encoding ascii to ensure in our scripts that the file is written using ASCII encoding:

get-process | out-file -encoding ascii -filepath .\Process.txt

By default, each line will hold 80 characters when writing. If you expect an output with a line exceeding that limit, it will truncate unless you specify using the -Width parameter:

get-process | out-file -encoding ascii -filepath .\Process.txt -Width 100

Now that you have an existing file, you might not want to overwrite it. With -NoClubber, it will prompt the user that the file cannot be overwritten.

PS C:\Users\garen\Documents\Surplus> get-process | out-file -filepath process.txt -encoding ascii -noclobber
out-file : The file 'C:\Users\garen\Documents\Surplus\process.txt' already exists.
At line:1 char:15
+ ... t-process | out-file -filepath process.txt -encoding ascii -noclobber ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceExists: (C:\Users\garen\...lus\process.txt:String) [Out-File], IOException
    + FullyQualifiedErrorId : NoClobber,Microsoft.PowerShell.Commands.OutFileCommand

To append an existing file, we type -Append:

PS C:\Users\garen\Documents\Surplus> echo "last line" | out-file -filepath .\Process.txt -append
PS C:\Users\garen\Documents\Surplus> tail .\Process.txt
    175      12     1788       4384              1200   0 wininit
    278      12     2388      16092             17244  15 winlogon
    217      11     2440      12936             26248  14 winlogon
    239      13     3224       5672              7016   0 wlanext
    512      24     6596      14300              5092   0 wslservice
    424      20    15812      39024             22132   0 WUDFHost


last line

Tee-Object

The Tee-Object cmdlet is very similar to Out-File. The only difference is that it will send the output of a command in two directions (like the letter "T"). It stores the output to a file or variable AND sends it down the pipeline:

PS C:\Users\garen\Documents\Surplus> echo "content of hello.txt" | tee-object -filepath .\hello.txt
content of hello.txt

Both Tee-Object and Out-File share -FilePath, -Encoding, and -Append parameters.