PowerShell Intro
2023-01-31
0. What is PowerShell and Why it’s worth learning
PowerShell is a scripting language developed by Microsoft, it is currently an open-source project .
PowerShell is cross-platform, flexible, extensible, it is a great tool for automating tasks and managing devices.
PowerShell has pipeline concept, similar to linux bash pipe.
PowerShell is built on the .NET Common Language Runtime (CLR). All inputs and outputs are .NET objects, so it’s compiled with C# code.
Environment Setup
VS code extension: PowerShell by Microsoft
- use F8 to execute selected PowerShell code
Note: on Linux system, install PowerShell (version > 7) and use
pwsh
to enter PowerShell.
1. PowerShell Terms
Command Types
- cmdlet
- function
- script
- alias
Cmdlet
- building block
- does one thing
Function
- PowerShell script
- does one thing
Script
- a file with
.ps1
extension - run cmdlet and functions in a structured format
- automate task sequences
Alias
- an alternate name for a cmdlet, function or script
- simplifies typing
- acts as a transition aid
2. PowerShell Syntax
PowerShell cmdlet use Verb-Noun
syntax, e.g., Get-Command
.
PowerShell is case-insensitive, e.g., Get-Command = get-command
.
- Note: variable name is case sensitive
Some commands have alias, e.g., Get-Command = gcm
All parameters in PowerShell start with a dash. Get-Command -Name
Variables
Variable starts with $
.
PowerShell is not a strongly typed language, we can use Get-Member
to check current type.
Cast a variable’s type: [int]$num1 = '2'
Quotes
Single quote means literal value (all variables will not work, they are going to be treated as string).
Double quotes can recognize variables.
$literal = 'Two plus one equals: $(1 + 2)'
$escaped = "Two plus one equals: $(1 + 2)"
Write-Host '$escaped'
Write-Host $escaped
Splat
Splat can combine a collection of parameter values as a variable, it helps to simplify the script. It has two data structures, hash table and array.
$HashArguments = @{
Path = "test.txt"
Destination = "test2.txt"
WhatIf = $true
}
Copy-Item @HashArguments
$ArrayArguments = "test.txt", "test2.txt"
Copy-Item @ArrayArguments -WhatIf
3. Help System
Get Help
Navigation:
- enter: next line
- spacebar: next page
- q: quit
Examples
# You need to manually update help to stay on the latest version
Update-Help
# Search for all the command with help in the name (Regex Match)
Get-Command *help*
# Get help (documentation) of Get-Command
help Get-Command
# Get full help content
help Get-Command -Full
# Get member (properties, methods..) of Get-Command
Get-Command | Get-Member
# Get available variables
Get-Variable
# Pattern match for variables
Get-Variable *Home*
# Get all environment variables
Get-ChildItem env:
# Change the output format
Get-Command | Format-List
Read Help
NAME
Get-Command
SYNTAX
Get-Command [[-ArgumentList] <Object[]>] [-Verb <string[]>] [-Noun <string[]>] [-Module <string[]>]
[-FullyQualifiedModule <ModuleSpecification[]>] [-TotalCount <int>] [-Syntax] [-ShowCommandInfo] [-All]
[-ListImported] [-ParameterName <string[]>] [-ParameterType <PSTypeName[]>] [<CommonParameters>]
Get-Command [[-Name] <string[]>] [[-ArgumentList] <Object[]>] [-Module <string[]>] [-FullyQualifiedModule
<ModuleSpecification[]>] [-CommandType {Alias | Function | Filter | Cmdlet | ExternalScript | Application |
Script | Configuration | All}] [-TotalCount <int>] [-Syntax] [-ShowCommandInfo] [-All] [-ListImported]
[-ParameterName <string[]>] [-ParameterType <PSTypeName[]>] [-UseFuzzyMatching] [-UseAbbreviationExpansion]
[<CommonParameters>]
PARAMETERS
-Name <string[]>
Required? false
Position? 0
Accept pipeline input? true (ByValue, ByPropertyName)
Parameter set name AllCommandSet
Aliases None
Dynamic? false
Accept wildcard characters? false
Syntax:
- Different syntax means a cmdlet can accept multiple parameter sets
Parameter:
- Positional
- You don’t have to specify parameter name, the position of the value matches the positional param
- e.g.,
[[-Name] <String[]>]
is the syntax of a positional param
- Accept pipeline input
- You need to make sure the pipeline output type matches the accepted input type
- By PropertyName: if an object comes in with a property name that matches the parameter name, I’m going to hook those 2 values together.
- ByValue: pass value in parameters
WhatIf:
- Some commands accept -whatif as a true/false parameter, we can use it to test our command
Stop-Process [-Id] <int[]> [-PassThru] [-Force] [-WhatIf] [-Confirm] [<CommonParameters>]
Get-Process | Stop-Process -whatif
4. Pipeline
Usage:
cmdlet A | cmdlet B
Get-Date | Format-Table
A’s output becomes B’s input.
Note: Output and Input types need to match.
$PSItem
- an automatic variable holds the current object in the pipeline.
Get-Process | ForEach-Object {$PSItem}
If we pipe this to a ForEach-Object, it will iterate through each object.
$PSItem
is usually shorthanded as $_
Get-process | where-object {$_.CPU -gt 50} | Sort-object CPU -descending
5. Function
# basic function
function FunctionName (OptionalParameters) {
}
function FunctionName {
param (
OptionalParameters
)
}
# advanced function
function Verb-Noun {
[CmdletBinding()]
param (
)
begin {
# Begin will initialize some steps at the start
}
process {
# Process will process each object as received
}
end {
# End can perform cleanup.
}
}
CmdletBinding is an attribute of functions that enables capabilities that makes them operate more like compiled cmdlets. It gives the function additional capabilities such as Write-Verbose
, PositionalBinding
.
- Usually you want to keep this attribute
Also it’s recommended to write your function help doc, once the function is loaded in memory, people can use Get-Help <your function name>
to access the help doc.
Parameter Syntax
param (
# basic param
[string]$HomeAddress,
[switch]$Enable = true,
# Advanced param
[Parameter(
Position = 0,
Mandatory = $false
)]
[string]
$City,
# Validate set will check the input value
[Parameter(Position = 1)]
[ValidateSet('en', 'zh-cn')]
[string]
$Language
)
For advanced params, you can try to read the parameter from bottom to top, e.g., $City
is the param name, [string]
is the type.
Example
function Get-Total {
param (
[int]$Number1,
[int]$Number2
)
$total = $Number1 + $Number2
# Write-Debug $total
return $total
}
Get-Total -Number1 2 -Number2 2
<#
.SYNOPSIS
Returns your public IP address.
.DESCRIPTION
Queries the ipify Public IP Address API and returns your public IP.
.EXAMPLE
Get-PublicIP
Returns the public IP.
.OUTPUTS
System.String
.NOTES
https://github.com/rdegges/ipify-api
#>
function Get-PublicIP {
$uri = 'https://api.ipify.org'
try {
$invokeRestMethodSplat = @{
Uri = $uri
ErrorAction = 'Stop'
}
$publicIP = Invoke-RestMethod @invokeRestMethodSplat
}
catch {
Write-Error $_
}
return $publicIP
}
Get-PublicIP
6. Script Block
Script block works like an anonymous function.
A script block returns the output of all the commands in the script block, either as a single object or as an array.
A script block can be assigned to a variable.
# create a simple script block
$block = {<statement>}
# advanced script block
{
Param([type]$Parameter1 [,[type]$Parameter2])
<statement list>
}
You can also specify a return value using the return
keyword. The return
keyword does not affect or suppress other output returned from your script block. However, the return
keyword exits the script block at that line.
# Example
# Output:
# p1: First
# p2: Second
Invoke-Command -ScriptBlock { param($p1, $p2)
"p1: $p1"
"p2: $p2"
} -ArgumentList "First", "Second"
# Example
# Output:
# p1: First
# p2: Second
# Stop here
Invoke-Command -ScriptBlock { param($p1, $p2)
"p1: $p1"
"p2: $p2"
return "Stop here"
} -ArgumentList "First", "Second"
# Example
# Output:
# Stop here
# p2: Second
Invoke-Command -ScriptBlock { param($p1, $p2)
return "Stop here"
"p1: $p1"
"p2: $p2"
} -ArgumentList "First", "Second"
7. Other Topics
Debug
Write-Host $env:HOME
Write-Output $env:HOME
Write-Debug # can be used inside function to check variable details
Modules
Modules are packaged scripts that can be used in your script to extend its capability.
You can install modules and publish your own module.
All PowerShell modules have 2 main files, one psm1
file (the script), another is psd1
file, it is a module manifest file (contains version and other info).
Well maintained modules usually have CI/CD setup.
# check your remote repo connection, by default, you'll see PSGallery
Get-PSRepository | Format-List *
# search a module in your PSRepository
Find-Module -Tag Telegram
# save a module (without installing, may be useful for evaluation)
Save-Module -Name PoshGram -Path <path>
# install a module
Install-Module -Name PoshGram