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
- 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.
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.
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.
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
Symbolic Links
Powershell 5 can create symbolic links via the New-Item
cmdlet.
You will need to run this command as administrator.
Suppose you are in C:\temp
and want a link to tgt.txt
in another folder.
New-Item -ItemType SymbolicLink -Name mylinkname.txt -Value $tgtDir\tgt.txt
(You can also use the alias Target
for Value
.)
See https://msdn.microsoft.com/en-us/powershell/wmf/5.0/feedback_symbolic for details.
You can accomplish the same thing from other folders.
New-Item -ItemType SymbolicLink -Path C:\Temp -Name mylinkname.txt -Value $tgtDir\tgt.txt New-Item -ItemType SymbolicLink -Path C:\Temp\mylinkname.txt -Value $tgtDir\tgt.txt
You can also create symlinks to directories:
New-Item -ItemType SymbolicLink -Path C:\linkDir -Value D:\realDir
Removing the symlink is not so obvious.
(Get-Item C:\linkDir).Delete()
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)
- 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.
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:
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
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).
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
Comments
Single-line comments begin with an octothorpe (
#
)Block comments that span multiple lines are bracketed with
<#
and#>
.