Luna Tech

Tutorials For Dummies.

PowerShell Intro


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





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


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'


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 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



# You need to manually update help to stay on the latest version

# 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

# Pattern match for variables
Get-Variable *Home*

# Get all environment variables
Get-ChildItem env:

# Change the output format
Get-Command | Format-List

Read Help


    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]

    -Name <string[]>
        Required?                    false
        Position?                    0
        Accept pipeline input?       true (ByValue, ByPropertyName)
        Parameter set name           AllCommandSet
        Aliases                      None
        Dynamic?                     false
        Accept wildcard characters?  false




4. Pipeline


A’s output becomes B’s input.

Note: Output and Input types need to match.


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 (

# advanced function
function Verb-Noun {
    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
    [switch]$Enable = true,

		# Advanced param
        Position = 0,
        Mandatory = $false

 		# Validate set will check the input value
    [Parameter(Position = 1)]
    [ValidateSet('en', 'zh-cn')]

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.


function Get-Total {
    param (
    $total = $Number1 + $Number2
    # Write-Debug $total
    return $total
Get-Total -Number1 2 -Number2 2

    Returns your public IP address.
    Queries the ipify Public IP Address API and returns your public IP.

    Returns the public IP.
function Get-PublicIP {
    $uri = ''
    try {
        $invokeRestMethodSplat = @{
            Uri         = $uri
            ErrorAction = 'Stop'
        $publicIP = Invoke-RestMethod @invokeRestMethodSplat
    catch {
        Write-Error $_

    return $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


Write-Host $env:HOME
Write-Output $env:HOME
Write-Debug # can be used inside function to check variable details


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