patpitchaya - Fotolia
Cut coding corners with return values in PowerShell functions
In certain instances, a return keyword is a good option to exit the current scope of a function and to reduce the bloat from a PowerShell script.
When you want to start writing get functions that return values back to the console, you'll need to decide how to make that happen -- and make it happen efficiently.
When working with PowerShell functions, you can get far with writing functions that do not return any data. For example, many set or update functions do not provide any feedback to the console without the -Verbose parameter. A return keyword can be used to return a value or to provide an exit point in a scope, but it requires a certain level of proficiency to understand how to use the PowerShell return value from a function properly.
Method 1: Outputting a value
The easiest way to return a value from a PowerShell function is to simply output the value. The following example looks for the File Explorer process. Instead of typing the whole Where-Object expression, you can shorten it with a function:
Function Get-Explorer {
Get-Process | Where-Object Name -eq 'Explorer'
}
It might not be immediately clear the code returns anything, but you will probably recognize the Get-Process cmdlet, which typically returns the running processes on the computer. Because the return of that cmdlet is not set to a variable, it is being output straight to the pipeline. To make it more explicit, assign it to a variable and then output it:
Function Get-Explorer {
$explorer = Get-Process | Where-Object Name -eq 'Explorer'
$explorer
}
You can further refine this with the Write-Output cmdlet:
Function Get-Explorer {
$explorer = Get-Process | Where-Object Name -eq 'Explorer'
Write-Output $explorer
}
While this example may be easier to understand, it is slightly less efficient when you store that value into a variable before the pipeline output. While the third example is more readable, the first is the recommended form.
All the examples generate output in table format.
If you have used Get-Process before, that output should look familiar because it is a process object which you can validate with the GetType() method.
It might seem like this code is all you need to return output in a PowerShell function, but there is another method with its own advantages.
Method 2: Using the return keyword
If you come to PowerShell but have experience in another language, such as one based on the C programming language, then the return keyword should be familiar. The distinction between the return's implementation between C and in PowerShell is that while C only returns values passed to the return keyword, PowerShell can return values to the pipeline without a return.
Because we can return values from a PowerShell function, the value of the return keyword might not immediately be evident. The difference between returning values with Write-Output and the return keyword is using the return keyword exits the current scope. If you are inside of a function and return a value with the return keyword, the function will return that value and exit the function.
To demonstrate this, the following example uses the return keyword twice to return all the PowerShell processes running on a computer, both Windows PowerShell and open source PowerShell:
Function Get-PowerShellProcess {
return Get-Process | Where-Object Name -eq 'powershell'
return Get-Process | Where-Object Name -eq 'pwsh'
}
If this was written with Write-Output, then this would output both the powershell and pwsh processes, but since we are using the return keyword, it will return the Windows PowerShell processes and then exit. Here's the output on my computer:
To return both powershell and pwsh processes, replace return with Write-Output or remove them entirely:
Function Get-PowerShellProcess {
Get-Process | Where-Object Name -eq 'powershell'
Get-Process | Where-Object Name -eq 'pwsh'
}
PowerShell will then generate output for both processes.
To return both types of processes, avoid the use of return.
Where is the return keyword useful?
There are instances when return is more useful than Write-Object. For example, if you want to write a function that returns the first index of a character in a string and if it doesn't exist, return -1. To use Write-Output and exit the function efficiently when the character is found, it might look like the following code:
Function Find-Character {
param ([char]$Char,[string]$String)
$found = $false
for($x=0;$x -lt $String.Length;$x++) {
If($String[$x] -eq $Char) {
Write-Output $x
$found = $true
break
}
}
if (-not $found) {
Write-Output -1
}
}
The script breaks out of the for loop when it finds the character, but it also repeats this check further in the script. This is too complex for a simple operation. It is more efficient to use return with the following code.
Function Find-Character {
param ([char]$Char,[string]$String)
for($x=0;$x -lt $String.Length;$x++) {
If($String[$x] -eq $Char) {
return $x
}
}
return -1
}
This script is shorter and easier to read, and it accomplishes the same outcome. The first time the first return is run, it immediately returns $x and exits the function. If the character is not found, then the code continues to the last return and returns -1. This is just an example of using the return keyword and is not meant to show the most efficient way to find a character in a string.