Reputation: 3364
I ran into a weird issue that I do not know how to explain. I hope someone could shed some light for me.
I would like to create a function which takes a parameter of an array, let's say $scriptnames and users have an option to pipe it from previous results should they prefer. I stripped away the unrelated stuff to better illustrate my confusion.
In the process of the module, I read each item from the array and just print the item.
My function:
function Get-Test
{
[CmdletBinding()]
param
(
[parameter(mandatory=$true,
ValueFromPipeline=$True,
ValueFromPipelineByPropertyName=$true)]
[string[]]$scriptNames
)
BEGIN
{
}
PROCESS
{
foreach ($scriptName in $scriptNames)
{
Write-Verbose "Executing: $scriptname"
}
}
END{}
Here was what confused me:
Scenario 1:
I used this command to get the list of the file in my directory:
get-childitem | Select-Object {$_.BaseName}
The list of file was return correctly without extension:
However, when I piped the results to my function, I got this print out:
Notice the unwanted $_.BaseName= literal was added.
Scenario 2:
However, if I issue this command:
get-childitem | Select-Object $_.BaseName
The results did not really filter out the basename only
but when piping to my function:
get-childitem | Select-Object $_.BaseName|
Get-Test -Verbose
the $_basename literal was not included:
However, the basename included the extension, which really confused me.
Can someone see something flaring up at you? and why did the following things happen:
1) Why was $_.BaseName literal tagged in the print out in scenario 1, which I did not ask for?
2) Why the select did not seem to work in scenario 2, but the print-out did not have $_.baseName with the exact same script?
3) What do I need to correct in my script to print out the filename only without the extension and without the literal $_.BaseName?
Upvotes: 2
Views: 292
Reputation: 1076
When you include Select-Object BaseName
, your returning an array of objects with 1 property, BaseName
. Switch it to Select-Object -ExpandProperty BaseName
to do what you're looking for, or you can use (Get-ChildItem).BaseName
to achieve the same result.
Whenever you see something expected as a string (i.e. Filename
) that's instead returned as an object/hashtable (i.e. @{$_.BaseName=Filename}
). If you want to have it return the extension as well, use Name
instead of BaseName
. If you want the full path to the file, use FullName
in that case.
To answer your scenario questions...
That behaved as expected, as you only specified a single property to be returned from the objects, but are still returning objects. The object property is named $_.BaseName
because you defined it that way with how you called it (usually you would just need to specify the property name without including the $_.
in front to indicate the pipeline object, i.e. Select-Object BaseName
). It's also working because of the surrounding curly braces in Scenario 1
The verbose text appears to be defaulting to the Name property, even though you're passing full objects to it. The first example in Scenario 2 returns the full object since you're calling Select-Object incorrectly.
My initial answer should cover the solution, I think
Upvotes: 3
Reputation: 6605
You did not specify how you are calling your function, so cannot really tell what's wrong with #1, it seems like you are returning an array instead of string
#2 is easy. You should have simply wrote
gci |select-object basename
instead of $_.basename.
#3 Probably related to 2.
Also, do not use Select-Object if you are trying to get Basename and do not want the header. You can instead do:
(get-childitem).basename | whatever
Here is how it prints with the example function you provided above
PS C:\> (gci).basename |get-test -ver
VERBOSE: Executing: batch
VERBOSE: Executing: DB
VERBOSE: Executing: Modules
VERBOSE: Executing: nix
VERBOSE: Executing: py
VERBOSE: Executing: utils
VERBOSE: Executing: Microsoft.PowerShellISE_profile
VERBOSE: Executing: Microsoft.PowerShell_profile
VERBOSE: Executing: PowerShellTranscripts
Oh you really should remove Mandatory, if you are expecting to pipe stuff to it or you will get a binding error:
Get-Test : Cannot bind argument to parameter 'scriptNames' because it is an empty string
Upvotes: 0