Luna Tech

Tutorials For Dummies.

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

Install PowerShell on Mac

VS code extension: PowerShell by Microsoft

Note: on Linux system, install PowerShell (version > 7) and use pwsh to enter PowerShell.


1. PowerShell Terms

Command Types

Cmdlet

Function

Script

Alias


2. PowerShell Syntax

PowerShell cmdlet use Verb-Noun syntax, e.g., Get-Command.

PowerShell is case-insensitive, e.g., Get-Command = get-command.

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:

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:

Parameter:

WhatIf:


4. Pipeline

Usage:

A’s output becomes B’s input.

Note: Output and Input types need to match.

$PSItem

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.

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

8. References

Video Tutorial

Tech Thoughts Blog

Tech Thoughts Code Examples

PowerShell 7 Fundamentals Path | Pluralsight