Windows PowerShell

This is a disorganized collection of information about PowerShell that I personally found useful.

PowerShell Basics

PowerShell is an open source shell developed for Microsoft Windows. It is the default shell on Windows 10. You can install PowerShell on most other systems, including OSX and Gnu/Linux.

Basic Commands

Many PowerShell commands have aliases chosen to match similar bash commands. Despite this superficial correspondence, options are handled very differently. For example, a directory listing ls -dir in PowerShell but ls -d */ in bash.

clear (Clear-Host)

clear the terminal display

man (Help)

display help manual for a command (e.g., man man)

cd (Set-Location)

change the working directory

pwd (Get-Location)

display present working directory

ls (Get-ChildItem)

list all files and directories

cat (Get-Content)

display file contents

date (Get-Date)

display the current date

File Manipulation Commands

cp (Copy-Item)

copy file

mv (Move-Item)

move file to new location (or rename)

rm (Remove-Item)

remove file

rmdir (Remove-Item)

remove directory

PowerShell does not include the equivalent of bash’s touch, which creates an empty file with no bytes. However you can accomplish this as follows:

New-Item -ItemType File <filename>

Finding and Renaming Files

Use Get-ChildItem to find files. (This has the bash-like alias ls.) Use Rename-Item to rename them. Use Sort-Object to sort them.

Get-ChildItem -File -Filter oldName*.*

find files using OS-specific wild card filtering

Get-ChildItem -File | Where-Object {$_.name -match "^oldName.*"}

find file names using regex filtering (via Where-Object)

Get-ChildItem -File -Filter oldName*.* | Rename-Item -NewName {$_.name -Replace 'regex','str' }

rename files using wild card filtering

Get-ChildItem oldname.* | %{Rename-Item $_ -NewName ('newname', $_.extension)}

change the basename but keep the extension

Get-ChildItem -File | Sort-Object LastWriteTime -Descending | Select-Object -first 10

get most recent 10 files

Note: % is an alias for ForEach-Object.

Finding Executables

PowerShell does not have the equivalent of which, but the following can find executables in your path. (Replace <myprog> with the program name.)

($Env:Path).Split(";") | Get-ChildItem -filter <myprog>*

Using CMD

If you have experience with DOS commands, many of these are available as aliases in PowerShell. However, some are not. You can then invoke cmd in PowerShell. E.g.,

#find the association for an extension
cmd /c assoc .xhtml

Version

In PowerShell, find your version with $PSVersionTable.PSVersion or the related (Get-Host).Version.

Console Colors

Get your current color settings with Get-PSReadlineOption. View the keys and values by entering Get-PSReadLineOption. Change each option separately or multiple options at one go. E.g.,

Set-PSReadLineOption -colors @{Command = "Black"}

You can also set console colors in your profile. (See below.) For example:

$console = $host.ui.rawui
$console.backgroundcolor = "black"
$console.foregroundcolor = "white"
$colors = $host.privatedata
$colors.verbosebackgroundcolor = "Magenta"
$colors.verboseforegroundcolor = "Green"
$colors.warningbackgroundcolor = "Red"
$colors.warningforegroundcolor = "white"
$colors.ErrorBackgroundColor = "DarkCyan"
$colors.ErrorForegroundColor = "Yellow"

Basic Resources

PowerShell Basics

http://social.technet.microsoft.com/wiki/contents/articles/4307.powershell-for-beginners.aspx

Command Comparison with Other Shells

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

PowerShell Scripting Intro

https://technet.microsoft.com/en-us/magazine/hh551144.aspx

PowerShell Scripting

https://msdn.microsoft.com/en-us/powershell/scripting/powershell-scripting

PowerShell Punctuation

https://www.red-gate.com/simple-talk/wp-content/uploads/2015/09/PSPunctuationWallChart_1_0_4.pdf

PowerShell Programming

Arithmetic and Assignment

Five standard basic arithmetic operators (+, -, *, /, and %)

with augmented assignment for all of those (+=, -=, *=, /=, and %= )

auto-increment (++) and auto-decrement (--).

For anything more, you need the [math] System class.

Basic Punctuation

;

use to separate statements; optional at end of line

() grouping operator

grouping for a single statement, returning result ($msg = "try this")

$() subexpression operator

grouping for semicolon separated statements; outputting all non-null expressions

@() array subexpression operator

like subexpression operator but returns array

@{} hash initializer

@{a='test',b='this'}

? alias

Where-Object

% alias

ForEach-Object

.. range operator

$($a=1..10; $a[2..5])

[math]

See the available methods:

[math].GetMethods() | Select -Property Name -Unique

E.g.,

[math]::pow(2,3)
[math]::log([math]::e)

Be careful with comparison: type matters! For example, the following is False.

[math]::equals(1, 1.0)

The comparison 1 -eq 1.0 is useful more often.

Comments

Single-line comments begin with an octothorpe (#)

Block comments that span multiple lines are bracketed with <# and #>.

Quotes for Strings

Within double-quoted strings, expressions are evaluated and dollar-variables are substituted.

$name = 'HAL'
"${name} says that summing 2 + 3 produces $(2+3)."

So, use double quotes to provide variable substitution or expression evaluation. Use single quotes to produces literal strings; even escape characters are not recognized!

So-called “here strings” use two-character delimiters, additionally bracketing the string with atmarks.

Documentation:

Arrays of Strings

The atmark is also use to create fixed-length arrays. The type of the array items can be specified at creation.

[String[]] $a = @('this','that') #create string array
$a.GetType()                     #String[]

Call Operator (&)

Use the ampersand call operator to treat a string as a command.

& 'path\to\docs\Test Document.docx'

The call operator can be used with script blocks. Unlike Invoke-Expression (which works with strings), the call operator creates a separate scope. (Note that the semicolon separates commands.)

& {$i=5;echo i}

Hash Tables

Separate key-value pairs with semicolons or end of lines. E.g., $myhash = @{key1 = "value1"; key2 = "value2"}. or

$myhash = @{
  key1 = "value1"
  key2 = "value2"
}

foreach ($key in $myhash.Keys) {
  Write-Output $myhash[$key]
}

Cmdlets

Powershell includes many special purpose cmdlets. This category is actually a command type, so we can get a list of them (and their location) using the Get-Command cmdlet.

Get-Command -CommandType cmdlet

That is a long list, so you may want to pipe it through a paging utility:

Get-Command -CommandType cmdlet | Out-Host -Paging

Get-Help

Use Get-Help to get help for a cmdlet:

Get-Help Get-Help

Online help display is provided:

Get-Help Get-Help -Online

Get-ChildItem (folder and file listing)

bash-like alias: ls

Examples:

ls
ls -File       #only files
ls -Directory  #only folders
ls -name       #only names (as strings)
ls -dir
ls -dir | Measure-Object
ls -dir | Measure-Object -Sum Length
ls | sort LastWriteTime -Descending
ls | where {$_.extension -eq ".tex"}
ls | where {$_.LastWriteTime -gt (Get-Date).AddDays(-1)}
ls | where {$_.Name -like "*1000*"}
(ls *.nb -r).fullname |out-file c:\temp\temp99.txt

Important details:

  • use -Recurse (or -r) option to explore subfolders:

    get-childitem -dir | foreach-object {write-host $_.name; get-childitem $_ -recurse | measure-object -property length -sum }

    Get-ChildItem -Recurse . | Measure-Object -Sum Length

    ls -recurse *.py | sls "mystr"

    ls -recurse *.py | sls "mystr" -Context 5

By default Get-ChildItem lists the mode (currently, six key Attributes) of listed files. If you see an r in the third position of this listing, the file is read-only.

Piping

Note that piping uses the vertical bar, as in many other shells. In contrast to many shells, however, Powershell passes objects rather than strings.

Documentation resource:

https://msdn.microsoft.com/en-us/powershell/scripting/getting-started/fundamental/understanding-the-windows-powershell-pipeline

Useful video:

https://www.youtube.com/watch?v=QKmyf6c83Rs

Get-Content

Get-Content has aliases gc and cat. Use it to read a text file by printing it to screen. You can then filter further.

cat -head 10 log.txt     # head
cat -tail 10 log.txt     # tail (since PSv3)
cat log.txt | more       # or less if you have it installed
cat log.txt | %{ $_ -replace '\d+', '($0)' }         # sed

Note: % is an alias for ForEach-Object.

Select-Object

Select-Object has alias select. To select or skip the first lines of a string result, use the -skip option.

Output Redirection

Pipe through Out-File, e.g.

python39 myscript.py | Out-File -encoding ASCII -width 120 c:\temp\temp.txt

Filtering with where

Let us list the running processes:

get-service | where-object {$PSItem.status -eq "Running"}

Shorter version of the same thing:

get-service | where {$_.status -eq "Running"}

Even shorter version of the same thing, using a special version of where that works without braces:

get-service | where status -eq "Running"

Profiles

https://technet.microsoft.com/en-us/library/bb613488%28v=vs.85%29.aspx

https://technet.microsoft.com/en-us/magazine/2008.10.windowspowershell.aspx

This one is for the current user (all shells).

$Home\Documents\WindowsPowerShell\Profile.ps1     #PowerShell 5
$Home\Documents\PowerShell\Profile.ps1            #PowerShell 6+

You may have to create the WindowsPowerShell folder. Here is one way to change the profile.

http://www.howtogeek.com/50236/customizing-your-powershell-profile/

If you try to email yourself your profile from another computer, it will be consider insecure. You will need to unblock it.

Unblock-File -Path $Home\Documents\WindowsPowerShell\Profile.ps1

Disk Info

View information about your logical disk drives.

Get-WmiObject -Class Win32_logicaldisk

Existing Aliases

C:WindowsSystem32WindowsPowershellv1.0Examplesprofile.ps1

A collection of predefined aliases give you access to an imitation of the DOS cmd commands:

http://ilovepowershell.com/2011/11/03/list-of-top-powershell-alias/ https://msdn.microsoft.com/en-us/powershell/scripting/getting-started/fundamental/using-familiar-command-names

Use Get-Alias to the cmdlet definition of the alias:

Get-Alias ls

Existing aliases include cat, cd, chdir, clear, cls, copy, del, diff, dir, echo, erase, h, history, kill, lp, ls, mount, move, popd, ps, pushd, pwd, r, ren, rm, rmdir, sleep, sort, tee, type, write

New-Alias

Use the Set-Alias cmdlet to create new aliases:

https://technet.microsoft.com/en-us/library/Ee176913.aspx

If you want these to persist, put them in your profile:

Access to Environment Variables

Environmental variables are stored on the ENV “drive”. For example,

Get-ChildItem Env:
ls $ENV:PYTHONPATH
$ENV:PYTHONPATH = ";"
create process specific enviromental variable

$env:testvar = "My test environment variable."

create permanent user-specific enviromental variable (using .Net framework)

[Environment]::SetEnvironmentVariable("TestVariable", "Test value.", "User")

remove process specific enviromental variable

Remove-Item Env:\testvar

remove process specific enviromental variable (using .Net)

[Environment]::SetEnvironmentVariable("TestVariable",$null,"User")

USERPROFILE example (or %userprofile% under cmd):

$env:USERPROFILE
cd ENV:
cat USERPROFILE

For more details: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables

Variable Expansion in Double-Quoted Strings

$myvar = "in"
echo "put $myvar ${myvar}side with optional braces"

Arrays

Create an empty array:

$a = @()

Create an array:

$a = @(1,2,3)

Create an array (shortcut with commas):

$a = 1,2,3

Create an array (shortcut for range):

$a = 1..3

Use arrays to swap values:

$var1, $var2 = $var2, $var1

Create a typed array:

[int[]] $a = 1,2,3

Append to an array:

$a = $a + 4

Catenate arrays:

$c = $a + $b

Access array item:

$a[0]

Access array items:

$a[0,1,-1]
$a[0..3]

Arrays vs Lists

Arrays are fixed length. For dynamic sizing, use lists.

$processedItems = New-Object System.Collections.Generic.List[String]
$processedItems.Add('thisItem')
$processedItems.Add('thatItem')
$processedItems -Join "`n"

Replacing missing Unix utilities

ls

alias for Get-ChildItem

E.g., ls | where {$_.extension -eq ".tex"}

Important details:

  • use -Recurse (or -r) option to explore subfolders,

  • use -Directory (or -dir) option to explore only folders.

  • use -File option to explore only files.

  • use -force -dir to see hidden directories.

cat

(now exists)

diff

now exists, sort of:

diff (cat file1) (cat file2)

is short for

Compare-Object (Get-Content file1) (Get-Content file2)

http://ss64.com/ps/compare-object.html

grep (or sls)

alias for Select-String https://communary.wordpress.com/2014/11/10/grep-the-powershell-way/

Ordinarily, put a regular expression in single quotes (to produce a literal string);

Use -CaseSensitive as needed.

pushd

alias for Push-Location

popd

alias for Pop-Location

zip

Use Compress-Archive

Compressed folder (with folder as root):

Compress-Archive -Path C:\Reference -DestinationPath C:\Archives\Draft.zip

Compressed files from folder (without root), with subdirectories:

Compress-Archive -Path C:\Reference\* -DestinationPath C:\Archives\Draft.zip

Compressed files from folder, without subdirectories:

Compress-Archive -Path C:\Reference\*.* -DestinationPath C:\Archives\Draft.zip

Compressed files from list:

$compress = @{
  Path = "file01.tex", `
         "file01.pdf", `
         "images\visit-visit(verylow)-boxplotT.pdf"
  CompressionLevel = "Fastest"
  DestinationPath = "myfiles.zip"
}
Compress-Archive -Force @compress

Regular Expressions

PowerShell uses the .NET implementation, which in turn essentially uses Perl 5’s regular expression syntax. There are a few added features, including named captures. Basic matches are not case senstitive.

$greeting = "Hello World!"
$greeting -match "World"
$greeting -match "world"

Use cmatch for case sensitive matches:

$greeting -cmatch "world"

After a match PowerShell creates an array named $matches, where $matches[n] corresponds to Perl’s $n.

.

matches any character except newline

escape character

w

word character [a-zA-Z_0-9]

W

non-word character [^a-zA-Z_0-9]

d

Digit [0-9]

D

non-digit [^0-9]

n

new line

r

carriage return

t

tabulation

s

white space

S

non-white space

^

beginning of a line

$

end of a line

A

beginning of the string (multi-line match)

Z

end of the string (multi-line match)

b

word boundary, boundary between w and W

B

not a word boundary

<

beginning of a word

>

end of a word

{n}

matches exaclty n times

{n,}

matches a minimum of n times

{x,y}

matches a min of x and max of y

(a|b)

‘a’ or ‘b’

  • matches 0 or more times

  • matches 1 or more times

?

matches 1 or 0 times

*?

matches 0 or more times, but as few as possible

+?

matches 1 or more times, but as few as possible

??

matches 0 or 1 time

Set-Location (cd)

cd ~

change to home directory

Scripts

PowerShell scripts use the extension .ps1.

Script running is disabled by default.

https://technet.microsoft.com/en-us/library/Ee176961.aspx

Starting Powershell from Explorer

Alt-d (to get to address bar) and enter powershell -executionpolicy bypass

On Windows 8, or later, can use the built-in File » "Open Windows Powershell" (or Alt-f,r).

Looping: For Loop

for($a = 1 ; $a -le 10; $a++) {$a}
for($a = 1 ; $a -le 10; $a++) {"`$a = $a"}

Looping: Foreach Loop

Example from documentation:

Get-Process | ForEach-Object {Write-Host $_.name -foregroundcolor cyan}

In this context, the percent sign (%) is an alias, as is foreach:

Get-Alias -Definition ForEach-Object

Cool example:

1..9|%{"$_"*$_}

But be alert: % is also the modulus operator.

Documentation:

https://technet.microsoft.com/en-us/library/ee176828.aspx

Functions

Function addTwo {
  Param($intOne, $intTwo)
  $intOne + $intTwo
}

Dot-Source

Dot-source a script by creating a line starting with a period and a space, and then the path to the script. This will add the functions in the script to the "function drive":

dir function:\

Running Python Scripts

To run Python scripts in your PowerShell, you must enable the extension in your profile:

$env:PATHEXT += ";.py"

Importing CSV Data

http://stackoverflow.com/questions/21030086/using-powershell-set-the-ad-home-directory-for-a-user-given-the-display-name

Booleans

There are no language-level literals for booleans.

The boolean constants are $false and $true.

Comparison

The equals sign (=) is used for assignment. Equality comparison is performed with -eq.

Caution: an assignment effectively evaluates to the assigned value, and most values cast to boolean $true. (Similar to Python.)

[string]$mystr = "foobar"

Type declarations are optional. If a variable is typed, assignment with force casting (if possible).

$mystr = 123
$mystr -is [string]

Branching

if (condition1) {"ok1"} elseif (condition2) {"ok2"} else {"default"}

Parentheses are require around the condition. Braces are required around the script block.

if ($true) {"it's true"} else {"it's false"}

Variables

Variable names can include spaces, but then they must be braces-enclosed.

A raw variable name refers to the entire object, not just the attribute considered to be its value. To reference the value, add a dollar sign: $var or ${var}. Change the value by assignment: ${var}=5 or $var=1,2,3.

Zero-Based Indexing

$myarray = 1,2,3
echo $array[0]

Quotation Marks

  • generally, use single quotes to delimit a string

  • use double quotes to create a string containing single quotes

  • use double quotes to do string substitution (PowerShell will look for the $, and will treat everything afterwards as part of a name, up to the first character that is illegal in a variable name

$name = 'Alan'
echo "My name is $name" #or "My name is ${name}"

will echo My name is Alan, without requiring explict string concatnation.

Within double quotes, the escape character is the backtick. Escape the dollar sign if you want a literal dollar sign. Escaping a letter can produce a special meaning (e.g., an escaped t is a tab).

Catenate Files, Adding Filename Headers

$fout = 'C:\temp\temp.txt'
Get-ChildItem . -Filter *.m | % {Out-File -encoding ASCII -InputObject "`n`n%FILE: $_`n" -Append -FilePath "${fout}";  Out-File -encoding ASCII -Append  -InputObject (Get-Content $_) "${fout}" }

Key Manipulation

On Windows 10, PowerToys includes a keyboard remapper, but it must be reloaded at reboot. Check whether CAPSLOCK is on with:

[console]::CapsLock

To change the staus of the CapsLock key:

$wsh = New-Object -ComObject WScript.Shell
$wsh.SendKeys('{CAPSLOCK}')

Network Statistics

netstat

PowerShell still recognizes the old netstat command, which displays active TCP connections. (That's because netstat is part of .Net Core.) Start with the -n option, which displays the protocol, local address, foreign address, and state. The protocol is TCP or UDP. The local address is the local IP address and port number. The foreign address is the remote IP (or FQDN) address and port number. (Use the -f option if you prefer to see the fully qualified domain name, FQDN.) Common states of the connection inlcude ESTABLISHED (i.e., active), TIME_WAIT (i.e. local port closed), and CLOSE_WAIT (i.e., not yet closed).

Use the -a option to also display the TCP and UDP ports on which the computer is listening. Use the -b option to also display the associated executable (that created each connection or listening port).

Docs:

https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/netstat

Get-NetTCPConnection

For examining TCP connections, Get-NetTCPConnection is the newer replacement for netstat. (Similary, use Get-NetUDPConnection for UDP connections.) For example, to get all the TCP connections in the LISTEN state, try the following. (Use the :code:-LocalPort` option to Get-NetTCPConnection to examine only one port.)

Get-NetTCPConnection | ? {$_.State -eq "Listen"}

Profiles and Policies

Execution Policy

Since your profile is a script file, you must enable script running for this to work. One way is to edit the PowerShell icon to include an execution policy paramater:

powershell -ExecutionPolicy ByPass

A slightly better way is to change the execution policy to allow you to run script. At the PowerShell command line:

Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

Profile Locations

To find all profile locations, do this:

$PROFILE | Format-List -Force