I hope the description was clear enough to understand what i mean 🙂

As a programmer or “scripter” you really want to copy/paste as less as possible and keep the code clean. This reduces the chance of failures/bugs and much more readable. For this reason you have to use functions when code is used more than once.

I was creating an installation script for some servers at work. For every step I noticed that I was copy/pasting actions that I was using before and after every installation step. For example, I keep track of the status in a json file, logging information to a log file and showing it to the screen. For this reason I was looking for a way to simplify this and came up with the following simple way. To keep the concept clear I removed all unnecessary code.

First I created a log function which outputs to the screen and a log file:

Clear-Host
#--------------------------------
# Variables
#--------------------------------
$LogFile = "C:\temp\LogFile.txt"

#--------------------------------
# This function outputs to screen and logfile at once
#--------------------------------
Function Out-Log {
    Param(
        [parameter(mandatory = $true)][string]$Text,
        [parameter(mandatory = $true)][string]$File
    )
    $Date = Get-Date -Format "dd MM yyyy HH:mm:ss"
    $LogMessage = "$Date | $Text"
    Write-Host $LogMessage -ForegroundColor Yellow
    Out-file -FilePath $File -InputObject $LogMessage -Append
}

The following function is used for the repetitive tasks! It uses a scriptblock as parameter.
The purpose of this function is:

  1. Pre scriptblock code
  2. Execute the code given as scriptblock parameter ($Script.Invoke())
  3. Post scriptblock code
#--------------------------------
# This function uses a scriptblock as parameter and performs actions before and after this script
#--------------------------------
Function Invoke-ScriptBlock {
    Param(
        [Parameter(Mandatory = $true)][string]$Description,
        [Parameter(Mandatory = $true)][scriptblock]$Script
    )
    Try {
        Out-Log "Performing Installationstep: $Description" -File $LogFile
        # -------------------------
        # Process scriptblock here:
        # -------------------------
        $Script.Invoke()
        # -------------------------
        # Post scriptblock actions:
        # -------------------------
        Out-log "Installationstep: $Description has Finished" -File $LogFile
    }
    Catch {
        Out-Log $_.Exception.Message -File $LogFile
        Out-Log "Installationstep: $Description has failed!" -File $LogFile
        Throw $_.Exception.Message
    }
    finally {
        Write-Host "-------------------------------------------------------"
    }
}

When using this function, you can see that you only see the code which is unique, not repetitive. And very clean. Not “try catch”, no “Out-Log”, this is all handled in the Invoke-Scriptblock function, what makes this a very readable piece of code I think.

#--------------------------------
# Practical example:
#--------------------------------
Invoke-ScriptBlock -Description "Install software package 01" -Script {
    Write-host "Installing software package 01"
}

Invoke-ScriptBlock -Description "Install software package 02" -Script {
    Write-host "Installing software package 02"
}

Result: