Powershell, like just about every other programming/scripting language has functions. These functions can be simple one liners or very complicated, depending on your needs.
A very simple function is show below.
function Do-PrintHelloWorld
{
Write-Host "Hello world!" -ForegroundColor Green
}
This function has a name and a code block. It has no input and will only output to the screen.
Why should I use functions.
- You can wrap up commonly used code to save space/typing and improve the readability of your scripts.
- Functions have read only access to the scripts variables. Don’t rely on this as a method to pass data to a function.
- Data can be passed to functions as parameters. parameters can be:
- Made compulsory.
- Have default values set.
- Can be forced to a certain type (string, int, object etc)
- Can validate the incoming data.
- Can return (pass back) specific data back to the calling script.
- All variables in the function are deleted when the script exits.
- Variables in a function are not accessible to the console or ISE, so can be hard to debug.
Using functions.
Below is a slightly more complex function.
function Do-PrintStuff ($line1, $Line2 ="line2")
{
Write-Host $Line1 -ForegroundColor Green
Write-Host $Line2 -ForegroundColor Green
}
Passing data in to a function like this is perfectly valid but not recommended. It will very quickly become hard to read. Also notice the $Line2 variable being set to “line2”. If the user does not pass a value for $Line2 it will default to “line2”.
The “correct” way to write the function is this.
function Do-PrintStuff
{
[CmdletBinding()]
param(
[Parameter(Mandatory = $true,ValueFromPipeline=$true)] [string]$line1,
$Line2 = "This is line 2",
[Parameter(Mandatory=$false)]$Line3,
$Line4,
[Parameter()][ValidateRange(1,10)][int]$Number,
[Parameter()][ValidateSet("jase","bob")][string]$Name,
[Parameter()][ValidateScript({test-path $_})][string]$Path
)
Process{
Write-Host $Line1 -ForegroundColor Green
Write-Host $Line2 -ForegroundColor Green
Write-Host $Line3 -ForegroundColor Green
Write-Host $Line4 -ForegroundColor Green
Write-Host $Number -ForegroundColor Green
Write-Host $Name -ForegroundColor Green
Write-Host $Path -ForegroundColor Green
}
}
I now have a Parameter block.
Listed are common validations I do.
- $Line1 is mandatory (powershell will prompt if its not set) and set to a string type, can also be piped in.
- $Line2 will default to “This is line 2” if not specified.
- $Line3 is not mandatory and not checked.
- $Line4 is not mandatory and not checked.
- $Number must be an integer and be between 1 to 10 inclusive.
- $Name must be a string and can only be “jase” or “bob” (and will tab complete)
- $Path must be a string and be a valid path. The code {test-path $_} must evaluate to true.
If any of the parameter check fails you will get a helpful error and the function will not run.
Below shows the error when the name and path parameters are invalid.
The error states the name parameter is invalid. the function has not checked the path parameter.
Fixing the name parameter and leaving path incorrect gives us:
Again, the error is quite clear as it tells us the parameter and value that failed the check.
Getting data out of a function.
Sometimes (most of the time) you will want the function to return something back to the script that called it and not output to the screen. To do that I use the return command.
Below is a function I have used i servile scripts.
I will take a test string and a number. If the length of the test string is less then the number, the function will add the required number of spaces and return a new string that is (number) charictors long. Good for column formatting.
<#
The function will take a text string and pad the end with spaces to make it $MaxSpace in length.
if the test string is to long the function will truncate it down to $MaxSpace - 3 in length and add ".. "
$testStringofLength20 = Do-FuncPadSpace $testStringOfLength10 20
#>
function Do-FuncPadSpace
{
Param(
[Parameter(Mandatory = $true)] [string]$DisplayText,
[Parameter(Mandatory = $true)] [int]$MaxSpace
)
if ($DisplayText.length -le $MaxSpace)
{
# add spaces to text to make it the correct length
# I should do it with a loop but its not very readable (and didn't work)
$spacesToAdd = $MaxSpace - $DisplayText.length
if ($spacesToAdd -eq 0){}
if ($spacesToAdd -eq 1){$Spaces = " "}
if ($spacesToAdd -eq 2){$Spaces = " "}
if ($spacesToAdd -eq 3){$Spaces = " "}
if ($spacesToAdd -eq 4){$Spaces = " "}
if ($spacesToAdd -eq 5){$Spaces = " "}
if ($spacesToAdd -eq 6){$Spaces = " "}
if ($spacesToAdd -eq 7){$Spaces = " "}
if ($spacesToAdd -eq 8){$Spaces = " "}
if ($spacesToAdd -eq 9){$Spaces = " "}
if ($spacesToAdd -eq 10){$Spaces = " "}
if ($spacesToAdd -eq 11){$Spaces = " "}
if ($spacesToAdd -eq 12){$Spaces = " "}
if ($spacesToAdd -eq 13){$Spaces = " "}
if ($spacesToAdd -eq 14){$Spaces = " "}
if ($spacesToAdd -eq 15){$Spaces = " "}
if ($spacesToAdd -eq 16){$Spaces = " "}
if ($spacesToAdd -eq 17){$Spaces = " "}
if ($spacesToAdd -eq 18){$Spaces = " "}
if ($spacesToAdd -eq 19){$Spaces = " "}
if ($spacesToAdd -eq 20){$Spaces = " "}
if ($spacesToAdd -eq 21){$Spaces = " "}
$Result = $DisplayText + $Spaces
return $Result
}else{
# text to long, error!
$Result = $DisplayText.Substring(0,$MaxSpace - 3) + ".. "
return $Result
}
}
In the above function, both if “branches” result in a string variable called $Result being populated. Once populated both “branches” end with:
return $Result
return $Result will end processing of the function and return whats after. in this case the $result variable.
I did not technically need the return command. I could have just had $Result on the line on its own. there is no code to be run after these lines so the function would exit anyway. But I like easy to read code so I always use the return command.
Calling the function would work like this.
$PaddedOutString = Do-FuncPadSpace -DisplayText $TestString -MaxSpace 20
That’s a quick look at functions.