Chris Davis
Chris Davis

Reputation: 31

Problems with pipeline input in PowerShell

So, hopefully someone can help me out here. I've looked for solutions in the past and have always found something before. But this one just seems to be too odd.

I have a PowerShell function that effectively duplicates the New-ADUser Cmdlet, and it accepts multiple parameters in order to do so. Most of the parameters on this function have the "ValueFromPipelineByPropertyName" parameter attribute set to True so that I can feed CSV and other pipeline data into the function without having to write a lot of "if" and assignment statements. Or at least that was the idea.

Here's an example of my function (slimed down to illustrate the point better):

[CmdletBinding()]
Param(
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [string]$FirstName,
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [string]$LastName,
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [string]$FullName
)

Process {
    if(-not $FullName) {
        $FullName = "$FirstName $LastName"
    }

    $user = "" | select FirstName,LastName,FullName
    $user.FirstName = $FirstName
    $user.LastName = $LastName
    $user.FullName = $FullName
    return $user
}

So when I run this against the CSV data:

FirstName,LastName
Bob,Smith
Dick,Jones
Sami,Davis
Ray,Charles
Jane,Doe
Keith,Johnson
Ruth,Willson
Genni,Gartner

I get:

FirstName                       LastName                        FullName
---------                       --------                        --------
Bob                             Smith                           Bob Smith
Dick                            Jones                           Bob Smith
Sami                            Davis                           Bob Smith
Ray                             Charles                         Bob Smith
Jane                            Doe                             Bob Smith
Keith                           Johnson                         Bob Smith
Ruth                            Willson                         Bob Smith
Genni                           Gartner                         Bob Smith

Now, I understand what's happening here. There isn't a specified value for FullName in the pipeline input or the function parameter, so I am setting a value in the process statement to use within that iteration. The problem is, instead of the $FullName variable then being "reset" back to a null or undefined value for the next loop iteration, it holds on to the value set.

If I change the CSV data to explicitly define a "" value for FullName, the issue goes away. But that doesn't help me when the pipeline data doesn't have the property defined.

I'm trying to avoid recoding the entire function to use different variable names or to use $_ because to add to the complexity of the function I also have parameter aliases defined so that we can take data directly from our HR program's database and pipe it into the new user function without having to massage the data manually. Which also brings me back to the inability to just add a null value parameter in the pipeline data.

I know I have been a bit long winded in my explanation, but the scenario appears to be unique (at least according to what I can dig up on the interwebs).

Upvotes: 3

Views: 1951

Answers (3)

Jackie
Jackie

Reputation: 2634

you need to set the default value of FullName, so below code will work fine:

[CmdletBinding()]
Param(
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [string]$FirstName,
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [string]$LastName,
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [string]$FullName=$null
)

Process {
    if(-not $FullName) {
        $FullName = "$FirstName $LastName"
    }

    $user = "" | select FirstName,LastName,FullName
    $user.FirstName = $FirstName
    $user.LastName = $LastName
    $user.FullName = $FullName
    return $user
}

Upvotes: 0

CB.
CB.

Reputation: 60910

why not simply 'reset' the $fullname variable?

[CmdletBinding()]
Param(
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [string]$FirstName,
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [string]$LastName,
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [string]$FullName
)

Process {  
            if([string]::IsNullOrEmpty($FullName))
                {
                    $script:Fullname =  "$FirstName $LastName"
                }        

    $user = "" | select FirstName,LastName,FullName
    $user.FirstName = $FirstName
    $user.LastName = $LastName
    $user.FullName = $FullName
    $FullName= [string]::Empty
    $user
}

Upvotes: 0

Dan Fitch
Dan Fitch

Reputation: 2529

Something tricky is going on with the variable scope here, maybe?

You could try just adding a Remove-Variable FullName at the end of the function and see if that helps.

I understand that you don't want to use different variable names, but that may make things clearer to use a different variable to store the "generated" full name inside the function; the scope will be less messy, hopefully.

if(-not $FullName) {
    $GeneratedName = "$FirstName $LastName"
} else {
    $GeneratedName = $FullName
}

Upvotes: 1

Related Questions