by James Earnshaw on September 12, 2024
PowerShell is one of the tools I use everyday as a data professional. Like SQL Server Management Studio (SSMS) it's just there on my desktop, always open, ready when I need it.
My adoption was gradual, though. For a long time before I properly understood it, I kind of knew it would come in handy, but I just couldn't quite grok it. When I eventually sat down and tried to learn a bit of PowerShell it was hard and progress was slow. But, with a good book (Windows PowerShell in Action), it finally started to make sense. Now I use it all the time.
The number of uses I've found for PowerShell has grown steadily over the years and I keep finding new ones. This happens naturally. I'll discover a new trick by searching around for solutions to a problem I'm facing until I find a solution that roughly solves it (usually on Stack Overflow). Then I'll add the solution to my list of hacks.
I say hacks because I don't use PowerShell like a sysadmin. I basically just pick stuff up here and there. The scripts I write are (mostly) for me and are basically what I'd describe as hacks. There's no error handling and I use aliases (e.g., cd
instead of Set-Location
) But it doesn't matter because it works for me.
It's not within the scope of this post to explain what PowerShell is in any detail. I'm assuming the reader has a vague idea of the following concepts: command lines, terminals, and shells. Basically you can control a computer by typing commands using a command line interface (CLI) that is displayed in a terminal program. The commands are interpreted by a shell program (e.g. PowerShell, Bash) that talks to the operating system and performs the work specified by the commands (e.g. system calls, etc.). Read a good explanation here.
PowerShell is a shell program for automating tasks on a Windows machine (it's actually cross platform but I've only ever used Windows). It comes installed on Windows and can be opened by searching for it, or with the shortcut: Windows Key + X, I.
The commands understood by PowerShell are called cmdlets (pronounced command-lets). The names of cmdlets are Verb-Noun pairs. For example, Set-Location
, the cmdlet to change the current directory. Cmdlets can take parameters, e.g., -Path
, a very common parameter, is the path to a file.
I use PowerShell from within a terminal program called Windows Terminal. I like Windows Terminal because of the multiple tabs and panes feature. If you're using Windows 11 then it's now the default. I make sure Windows Terminal is ready on start-up by enabling it in the settings.
Now I'll list the PowerShell patterns and tips I use regularly. I start out with the basic stuff and progress to more advanced usage.
A PowerShell session will be at a location, known as the current directory. For example:
PS C:\Windows>
PS
means the terminal program is running a PowerShell session. This session is currently at the location C:\Windows
. The >
symbol is the prompt and indicates that the session is ready to receive commands.
The GUI equivalent would be having File Explorer open at C:\Windows
. But, unlike File Explorer, you can't visually inspect the folder's contents. In a shell program, like PowerShell, that uses a command line interface (CLI), you have to enter the command that lists the folder's contents. In PowerShell the cmdlet (i.e. command) is Get-ChildItem
:
After hitting enter the cmdlet is executed, the operating system handles the call, and output is returned to the terminal on the lines below the cmdlet. As you can see it returns all the files and directories in C:\Windows
.
I rarely write out the full command Get-ChildItem
. I use aliases, shortform ways of writing commands. The alias for Get-ChildItem
is gci
, or, the one I use, dir
, which is used in lots of other operating systems.
You can see all the aliases with: Get-Alias
. Or the alias for Get-Alias
: gal
Note: I use the full version of the command when the script is part of a process and will be seen by other people, for maintainability's sake. It's helpful to see the full command for those unfamiliar with the alias.
If you see an alias in a script and don't know what it does you can find out with gal
followed by the alias in question. E.g. you see spps
and wonder what cmdlet that is. You can do gal spps
:
As can be seen spps
is the alias for Stop-Process
.
The Get-ChildItem
(or gci
or dir
) command from earlier has a -Path
parameter which narrows the search. It's a good way to find a file or files within a directory, or sub-directory if you use the -Recursive
parameter. It's flexible because you can use wildcards (*
).
This example finds all the JSON files in the current directory and any subdirectories:
gci *.json -Recurse
Notice I didn't explicitly use the Path
parameter because Path
is a positional parameter and, because it's the first parameter of Get-ChildItem
, it can be set by placing it right after Get-ChildItem
.
Set-Location
changes the current working directory. It's analogous to clicking around in File Explorer until you get to the folder containing the file you need. You will find yourself doing this a lot. The alias I use is cd
, for current directory. Remember that paths in Windows use a backslash:
PS C:\Windows> cd C:
PS C:\>
So now the current directory is at C:
(the root).
The terminal window can quickly get crowded with cmdlets and their output. Clear it with Clear-Host
. I actually had to look this up because I never write Clear-Host
, I always use the alias cls
. Another option for clearing the terminal is Ctrl + l
. It's not a shortcut for Clear-Host
, what it does is move the window down. If you scroll up to can see previous commands.
cls
clears the screen but the history is still in memory and can be displayed with Get-History
or simply h
:
Notice how previously run cmdlets are numbered. Lets say you wanted to rerun a command. You can with #
followed by the number, and then tab complete (i.e. hit the tab key).
mkdir
creates a new directory (or folder, I find myself using those words interchangeably):
# Creates directory "foo"
mkdir foo
You can also use New-Item
:
New-Item -Type Directory foobar
But mkdir
is one of those commands found in a lot of operating systems. It's one you "just know".
Create files with New-Item
or its alias ni
. It takes a Path
parameter, the name of the new file.
# Creates bar.txt
New-Item -Path bar.txt
# Creates somefile.txt, -Path omitted
ni somefile.txt
It's a common practice in shell languages to "pipe" the output of one command to another command. This is done with the pipeline ("|") operator.
A common use case is sending the output of one cmdlet to a file. This is achieved with the Out-File
cmdlet.
'This is some content' | Out-File out.txt
In the above example the text string "This is some content" is sent to a file. Another example is piping the output of Get-Date
to a file.
Get-Date | Out-File date.txt
# a more concise way of doing it
Get-Date > date.txt
Display a file's contents with Get-Content
or its alias gc
.
Get-Content .\date.txt
# output
# 10 September 2024 12:38:54
A useful pattern is copying and pasting a file's contents without opening it. Imagine you have a SQL script saved in a file (e.g., select.sql
):
SELECT
*
FROM Sales.SalesOrderDetail
You can get its contents and pipe it to the clipboard (i.e. copy it) with:
Get-Content .\select.sql | clip
The script can now be pasted.
All the file system tasks you've always done in File Explorer (i.e., a GUI), like copying files from one folder to another, can be done in PowerShell, but they can be done much more powerfully. Not always, sometimes it's just quicker to use the File Explorer GUI, but I mostly use PowerShell for file system tasks. Working in File Explorer usually involves positioning two windows side by side, and dragging files across with the mouse, or something equally tedious.
Lets say you've got two directories foo
and bar
. foo
contains the file date.txt
and you need to either copy it or move it to the bar
directory. Use Copy-Item
(cp
) or Move-Item
(mv
) respectively:
# Assuming foo and bar are located at the root of the C drive
# Copying
Copy-Item -Path C:\foo\date.txt -Destination C:\bar
# Moving
Move-Item -Path C:\foo\date.txt -Destination C:\bar
When scripting it's useful to check a file or directory exists. Do that with Test-Path
:
PS C:\> Test-Path .\foo\
True
Often Test-Path
is used with the conditional command if
. For example:
if (Test-Path C:\config.json) {
# Parse the config
}
This one sometimes comes in handy:
PS C:\> Join-Path C: work
C:\work
You can't do anything non-trivial without being able to store and manipulate values in variables. Declare and assign variables with the syntax:
# an integer
$myInteger = 123
# a string
$myString = 'hello world'
Prefixing a string with $
declares a variable.
You can store the output of cmdlets in variables:
$content = Get-Content -Path date.txt
I use this pattern a lot. And it's a game changer. Seriously.
Say you've got a directory full of text files and you need to know which file(s) contain a pattern. The cmdlet for doing this is Select-String
.
Use this to set up the demo:
cd C:
mkdir somefiles
cd somefiles
1..10 | ForEach-Object {
$file = $_.ToString() + ".txt"
'Hello, World!' | Out-File $file
}
This snippet creates a directory called C:\somefiles
and then creates 10 files (1.txt
, 2.txt
,..., 10.txt
) inside it each containing the text "Hello, World!".
The first example of Select-String
finds the pattern "hello" inside one file.
PS C:\work\somefiles> Select-String -Path .\1.txt -Pattern 'hello'
# output
# 1.txt:1:Hello, World!
This output indicates that a match was found. If you want to search every file in the directory then you would do this (sls
being the alias of Select-String
):
PS C:\somefiles> dir | sls -Pattern 'hello'
1.txt:1:Hello, World!
10.txt:1:Hello, World!
2.txt:1:Hello, World!
3.txt:1:Hello, World!
4.txt:1:Hello, World!
5.txt:1:Hello, World!
6.txt:1:Hello, World!
7.txt:1:Hello, World!
8.txt:1:Hello, World!
9.txt:1:Hello, World!
That's a quick run through of some of the ways I use PowerShell regularly, the ones I can remember anyway. But I'm always finding new patterns and tricks.
PowerShell is really useful skill to learn. It's basically a Swiss Army Knife for Windows.