Support for PipelineVariable in Advanced Function

I mostly use PowerShell to automate tasks with VMware PowerCLI and I have recently started working on my first advanced functions. I created one that gets virtual machines that are inside a specific folder in vCenter. The main PowerCLI cmdlet used in this function is Get-VM so the output for Get-VM and my function is basically the same as far as I can tell. However, -PipelineVariable doesn’t work for me as it does with Get-VM. When I run the following commands -which essentially do the same- the {$VM} is empty in the output of Get-SgVm (my function) but populated with the virtual machine name when using Get-Folder piped to Get-VM, everything else in the output is exactly the same.

[pre]Get-SgVm -PipelineVariable VM | Get-NetworkAdapter | select {$VM},Name,NetworkName

Get-Folder RootFolder-001 | Get-VM -PipelineVariable VM | Get-NetworkAdapter | select {$VM},Name,NetworkName[/pre]

Here is the code of the function.

[pre]

Function Get-SgVm {

[CmdletBinding()]
param ([Parameter (Mandatory=$true,Position = 0)]
[ValidateNotNullOrEmpty()]
[int]$SGNumber,
[switch]$NoRecursion,
[switch]$Legacy)

BEGIN {
[string]$SGNumber = ‘{0:000}’ -f $SGNumber
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) BEGIN ] Formatting SG Number to: $SGNumber”
}

PROCESS {

If ($Legacy){
$Folder = Get-Folder -Name (-join (‘RootFolder’,$SGNumber,’’))
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) BEGIN ] Folder found: $Folder”
}

Else {
Write-Warning ‘Legacy not selected.’
$Folder = Get-Folder -Name (-join (‘RootFolder-’,$SGNumber,’’))
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) BEGIN ] Folder found: $Folder”
} #If Legacy

If ($NoRecursion){
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) BEGIN ] Getting VMs”
$VMs = $Folder | Get-VM -NoRecursion
Write-Warning ‘NoRecursion switch used, getting VMs in root of SG folder only.’
}

Else {
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) BEGIN ] Getting VMs”
$VMs = $Folder | Get-VM
Write-Warning ‘NoRecursion switch not used, getting all VMs in SG folder.’
} #If Recursion

If ($Folder -ne $null){
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) PROCESS] Working on folder: $Folder”
}

Else {
Write-Warning ‘No folder found. Check the switches used in the command.’
} #If Folder

If ($VMs -ne $null) {
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) PROCESS] VM(s) found”
}

Else {
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) PROCESS] No VM(s) found”
} #If VMS

If (!$global:DefaultVIServer) {
Throw ‘Not connected to a vCenter server’
}

Else {
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) PROCESS] Writing output.”
Write-Output $VMs
} #If vCenter connection

} #Process

END {}

} #Function[/pre]

After some testing I have figured out that by removing the BEGIN block altogether, -PipelineVariable works. I have updated the code with a Try/Catch construct so it looks a little different, however, I can tell for sure that even an empty BEGIN block would prevent the output to include the PipelineVariable value. I surely can’t explain this behavior? Any ideas or thoughts? Thanks.

Here is the latest function code:

[pre]Function Get-SgVm {

[CmdletBinding()]
param (

[Parameter (Mandatory=$true,Position = 0)]
[ValidateNotNullOrEmpty()]
[int]$SGNumber,
[switch]$NoRecursion,
[switch]$Legacy)

Begin {
[string]$SGNumber = ‘{0:000}’ -f $SGNumber
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) BEGIN ] Formatting SG Number to: $SGNumber”

} #Begin

Process {

Try {

If ($Legacy){
$Folder = Get-Folder -Name (-join (‘sysgrp’,$SGNumber,’’))
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) BEGIN ] Folder found: $Folder”
}

Else {
Write-Warning ‘Legacy not selected.’
$Folder = Get-Folder -Name (-join (‘syrgrp-’,$SGNumber,’’))
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) BEGIN ] Folder found: $Folder”
} #If Legacy

If ($NoRecursion) {
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) BEGIN ] Getting VMs”
$VMs = $Folder | Get-VM -NoRecursion
Write-Warning ‘NoRecursion switch used, getting VMs in root of SG folder only.’
Write-Output $VMs
}

Else {
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) BEGIN ] Getting VMs”
$VMs = $Folder | Get-VM
Write-Warning ‘NoRecursion switch not used, getting all VMs in SG folder.’
Write-Output $VMs
} #If Recursion

If ($Folder -ne $null) {
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) PROCESS] Working on folder: $Folder”
}

Else {
Write-Warning ‘No folder found. Check the switches used in the command.’
} #If Folder

If ($VMs -ne $null) {
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) PROCESS] VM(s) found”
}

Else {
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) PROCESS] No VM(s) found”
} #If VMs

} #Try

Catch {

If (!$global:DefaultVIServer) {
Throw ‘Not connected to a vCenter server’
}

Else {
Write-Verbose “[$((Get-Date).TimeOfDay.ToString()) PROCESS] Writing output.”
Write-Output $VMs
} #If vCenter connection

} #Catch

} #Process

End {}

} #Function[/pre]

 

Output with BEGIN block in function.

[pre]Get-SgVm 1 -Legacy -NoRecursion | Get-NetworkAdapter | select {$VM},Name,NetworkName

$VM Name NetworkName


Network adapter 1 Isolated-VLAN23
Network adapter 2 VLAN722
Network adapter 1 Isolated-VLAN23
Network adapter 2 VLAN722
Network adapter 3 VLAN22
Network adapter 1 Isolated-VLAN23
Network adapter 2 CRSJO-VLAN722
Network adapter 3 CRSJO-VLAN722
Network adapter 1 Isolated-VLAN23
Network adapter 2 VLAN722
Network adapter 3 VLAN722[/pre]

Output without BEGIN block in function.

[pre]Get-Folder rootfolder001 | Get-VM -NoRecursion -PipelineVariable VM | Get-NetworkAdapter | select {$VM},Name,NetworkName

VM Name NetworkName


VOPPE-P001 Network adapter 1 Isolated-VLAN23
VOPPE-P001 Network adapter 2 VLAN722
VOPPE-MS001 Network adapter 1 Isolated-VLAN23
VOPPE-MS001 Network adapter 2 VLAN722
VOPPE-MS001 Network adapter 3 VLAN22
VOPPE-TS001A Network adapter 1 Isolated-VLAN23
VOPPE-TS001A Network adapter 2 VLAN722
VOPPE-TS001A Network adapter 3 VLAN722
VOPPE-TS001B Network adapter 1 Isolated-VLAN23
VOPPE-TS001B Network adapter 2 VLAN722
VOPPE-TS001B Network adapter 3 VLAN722[/pre]