PowerShell: The basics – Part 4 – Strings, Arrays, Hashtables, Conditional Statements, and Loops

This blog series will teach you the basics of PowerShell. You’ll learn common concepts such as variables, loops, functions and scripts in this series, along with PowerShell unique concepts such as cmdlets and the pipeline.

In this post we will take a brief look at strings, arrays, hashtables, conditional statements, and loops.

Strings

Strings are more than just text when dealing with PowerShell. Just take a look at all the stuff string objects contain with Get-Member.

Here’s how you work with strings:

$text = "PowerShell rocks!"

# Append text
$text += " Bye. "

# Prepend text
$text = " Hello, $text"

# Get length of string
$text.Length

# Get position of first occurence of the word 'rock'
$text.IndexOf('rock')

# Get all text up until first occurence of the word 'rock'
$text.Substring(0, $text.IndexOf('rock'))

# Get all text from first occurence of the word 'rock'
$text.Substring($text.IndexOf('rock'))

# Check if string contains substring, returns boolean
$text.contains('rock')

# Convert the string to uppercase
$text.ToUpper()

# Convert the string to lowercase
$text.ToLower()

# Remove whitespace from both sides
$text.Trim()

# Remove only trailing whitespace
$text.TrimEnd()

# Replace text
$text -replace 'rocks', 'sucks'

# Remove text
$text -replace ' rocks'

# Check if string starts with 'Hello', returns boolean
$text.StartsWith('Hello')

# Check if string starts with 'bye', returns boolean
$text.EndsWith('bye')

# Convert string to an array of characters
$text.ToCharArray()

# Split string into array by a specified delimiter
$text -Split 'Shell'

When performance is important, as is with looping operations on large arrays, it’s advised to utilize the .NET StringBuilder object to build large strings.

$sb = New-Object -TypeName System.Text.StringBuilder
1..10000 | ForEach-Object {
    [Void]$sb.AppendLine("Hello, PowerShell rocks! Bye.")
}
$sb.ToString()

Note: The ToString() method is implemented by most objects and will return a string representiation of the object.
Note: [Void] is used to prevent output from being written to the screen. It’s functionality is eqvuivalen to piping to Out-Null, but it’s quite a bit faster.

Arrays

Arrays are objects containing multiple values.

# Different ways to create arrays
$fruits = 'apple', 'banana', 'grapes', 'orange'
$fruits = @('apple', 'banana', 'grapes', 'orange')
$numbers = 1..4
$numbers = [Int[]]('1', '2', '3', 4)

# Get item count of array
$numbers.Count

# Retrieve an item from an array by specifying index
$fruits[0] # First item
$fruits[2] # Third item
$fruits[0..2] # Three first items
$fruits[-1] # Last item

# Check if array contains value 'grapes'
$fruits.Contains('grapes')

# Check if value is present in array
'banana' -in $fruits

# Add item to array (this fails, because once arrays are created, they are of a fixed size)
$fruits.Add('pineapple')

# PowerShell however works around it when you do the following (it recreates the whole array)
$fruits += 'pineapple'

# For better performance you can use an arraylist object when you have to add/remove items in large arrays
$thousand = New-Object -TypeName System.Collections.ArrayList
1..1000 | ForEach-Object {
    [Void]$thousand.Add($_)
}

# Removing items from an arraylist by value
$thousand.Remove(1000)
$thousand[-1] # Last item should now be 999

# Removing items from an arraylist by position
$thousand.RemoveAt(5)
$thousand[0..5] # Should now not contain value 6

# Creat multi dimensional arrays
$food = 'meat', 'bread', $fruits
$food[1] # Outputs bread
$food[2][2] # Outputs grapes

Hashtables

Hashtables are arrays of key-value pairs.

# Create a hashtable
$person = @{
    name = 'Martin'
    age = 12
    height = 150
}

$person.name # Returns Martin
$person.age # Returns 12

$person['age'] # Also returns 12

# You can easily add more key-value pairs to a hashtable
$person.canCode = $true

# Note that hashtable items do not appear in the same order you specify them
# If order is important, use the following to create an ordered dictionary
$personOrdered = [Ordered]@{
    name = 'Martin'
    age = 12
    height = 150
}

# You can use hashtables to specify parameters to a cmdlet by splatting it
$param = @{
    Path = 'C:\Users'
    Recurse = $true
    Filter = "*.txt"
}
Get-ChildItem @param

Conditional Statements

Conditional statements are used to execute certain code only if a specified statement evaluates to true.

If statement

if (Test-Path -Path C:\)
{
    Write-Output "Found C drive!"
}
else
{
    Write-Output "Hmm.. Where's the C drive?"
}

$dayOfWeek = [Int](Get-Date).DayOfWeek

if ($dayOfWeek -eq 0) { $day = 'Sunday' }
elseif ($dayOfWeek -eq 1) { $day = 'Monday' }
elseif ($dayOfWeek -eq 2) { $day = 'Tuesday' }
elseif ($dayOfWeek -eq 3) { $day = 'Wednesday' }
elseif ($dayOfWeek -eq 4) { $day = 'Thursday' }
elseif ($dayOfWeek -eq 5) { $day = 'Friday' }
elseif ($dayOfWeek -eq 6) { $day = 'Saturday' }

Write-Output $day

Switch Statement

The switch structure is great when only dealing with evaluating one variable. It will run all blocks where the statements evaluate to true. If it should only run one block, then you should end the block with a break keyword to stop the switch structure from executing more blocks. The output from a switch statement can be assigned directly to a variable.

$dayOfWeek = [Int](Get-Date).DayOfWeek

$day = switch ($dayOfWeek)
{
    0 { 'Sunday' }
    1 { 'Monday' }
    2 { 'Tuesday' }
    3 { 'Wednesday' }
    4 { 'Thursday' }
    5 { 'Friday' }
    6 { 'Saturday' }
    Default { 'Unknown' } # Will run if none of the above is true
}

Write-Output "It's $day"

switch ($day)
{
    { $_ -in 'Saturday', 'Sunday' } { "It's Weekend!" }
    Default { 'Time to work..' }
}

The switch statement also supports arrays, where it will evaluate each item in the array in turn. You can turn on wildcard matching for strings, to reduce the code you needto write.

# Evaluate each item in an array, and use wildcard matching on the strings
$transport = 'bus', 'train', 'car', 'tram'
switch -Wildcard ($transport)
{
    'tr*' { "$_ runs on tracks" }
    Default { "$_ has tires" }
}

Loops

Looping structures are handy for running the same code multiple times, but with different input values.

For

The for loop is a compact way to deal with incrementing counters, or to loop through a subset of an array.

$numbers = 1..100
for ($counter = 0; $counter -lt 10; $counter++)
{
    Write-Output $numbers[$counter]
}

Foreach

The foreach structure will loop through an array, and assign each item to a variable you choose.

$numbers = 10, 22, 30, 44, 50
foreach ($number in $numbers)
{
    if ($number -gt 25)
    {
        Write-Output "$number is greater than 25"
    }
    else
    {
        Write-Output "$number is less than or equal 25"
    }
}

Foreach-object

The foreach-object structure gets it’s input from the pipeline, and runs it’s code on each of the input items. This structure can be shorthanded like this: % { }, and the $_ variable refers to the current object being processed.

10, 22, 30, 44, 50 | ForEach-Object {
    if ($number -gt 25)
    {
        Write-Output "$_ is greater than 25"
    }
    else
    {
        Write-Output "$number is less than or equal 25"
    }
}

While

The while structure executes the code block while a statement holds true. The statement is re-evaluated after every block execution.

$counter = 0
while ($counter -lt 10)
{
    Write-Output $counter
    $counter++
} 

Do-Until

Do-until is like the while structure, but here the code block will be executed once, before the statement is even evaluated, and will stop looping when the statement holds true.

$counter = 0
Do
{
    Write-Output $counter
    $counter++
} Until ($counter -ge 10)

Do-While

Same as Do-Until, but will execute as long as the statement holds true.

$counter = 0
Do
{
    Write-Output $counter
    $counter++
} While ($counter -lt 10)

Continue and Break

All the loops supports the Continue and Break keywords.
Continue skips to the next item to evaluate.
Break stops the loop from executing any more.

# Continue, does not output 5
$counter = 0
Do
{
    $counter++
    if ($counter -eq 5) { continue }
    else { Write-Output $counter }
    
} Until ($counter -ge 10)

# break, last output is 5
$counter = 0
Do
{
    Write-Output $counter
    if ($counter -eq 5) { break }
    $counter++
} Until ($counter -ge 10)

Further reading

In the next post we’ll take a look at filtering and formatting output. If you want more detailed reading on the topics of this post I suggest the following resources:

Leave a Reply