Help with PowerShell $PSBoundParameters

My script below works and that should satisfy it's purpose, however, I am trying to learn more about what is happening.

In doing so I have put Write-Verbose within an If/Then process so that if the computer name is passed as a parameter it should Write-Verbose that it is passed as a parameter. However, if passed as a script, it should Write-Verbose that it is passed through pipeline.

Why in every example does the computer name(s) pass through as parameter??
Get-Content .\list.txt | Start-ReportPSCompliant -Verbose

Open in new window


That should pass the computer names through the cmdlet as pipeline and the Write-Verbose "$_ is going through pipeline" should be printed, but no matter how I use the cmdlet it always passes through as parameter.

Why is it not using the pipeline Else{} script??

function Start-ReportPSCompliant {
<#
.Synopsis
   This reports on computers as to whether or not they have policy ready for PSRemoting by invoking a command to return the environment computer name. If it doesn't return then PSRemoting is not enabled or the device is unavailable.
.DESCRIPTION
   Enter in a single computer name or multiple computer names. Value from pipeline is also
   acceptable.
.EXAMPLE
   Start-ReportPSCompliant Server1

.EXAMPLE
   Start-ReportPSCompliant -Computer 'computer1','computer2'

.EXAMPLE
   Get-Content C:\Scripts\list.txt | Start-ReportPSCompliant 

.EXAMPLE
   Start-ReportPSCompliant (Get-Content C:\Scripts\list.txt)
#>

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$true,ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [String[]]$Computer = 'localhost'
    )
    Begin {
        Write-Verbose 'Looking for existing reports and removing files if found'
        $Pa = Test-Path C:\Scripts\temp\compliant.txt

            if ($Pa) {Remove-Item C:\Scripts\temp\compliant.txt; Write-Verbose 'compliant.txt list was removed'}
            else {Write-Verbose 'compliant.txt list does not exist'}

        $Pa = Test-Path C:\Scripts\temp\noncompliant.txt

            if ($Pa) {Remove-Item C:\Scripts\temp\noncompliant.txt; Write-Verbose 'noncompliant.txt list was removed'}
            else {Write-Verbose 'noncompliant.txt list does not exist'}

    }
    Process {
        if ($PSBoundParameters.ContainsKey('computer')) {
             # we have parameter input
        Write-Verbose "$Computer is going through as parameter input"
             foreach ($c in $Computer) {
                CompliantWorker $c
             }
        }else{
             # we have pipeline input
        Write-Verbose "$_ is going through pipeline"
             CompliantWorker $_
        }
    }
    End {
        Write-Verbose 'The operation is complete'
        $Pa = Test-Path C:\Scripts\temp\compliant.txt

            if ($Pa) {notepad C:\Scripts\temp\compliant.txt}
            else {Write-Warning 'No computers in list were compliant!'}

        $Pa = Test-Path C:\Scripts\temp\noncompliant.txt
        
            if ($Pa) {notepad C:\Scripts\temp\noncompliant.txt}
            else {Write-Verbose 'All computers in list were compliant!'}
    }
}
function CompliantWorker {
    param (
        $Computer
    )
        Write-Verbose "Attempting to send a remote command to $Computer"
        Invoke-Command $Computer {$env:COMPUTERNAME} -ErrorAction SilentlyContinue -ErrorVariable err
        
            if($err.count -gt 0) {
                Write-Output $Computer | Out-File C:\Scripts\temp\noncompliant.txt -Append
            }
            else {
               $Computer | Out-File C:\Scripts\temp\compliant.txt -Append
            }
}

Open in new window

ryanmavesAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

footechCommented:
The parameter is defined to take pipeline input, so it is being used either way.  If you want you can examine $MyInvocation (or $PsCmdlet.MyInvocation) and look at the PipelineLength property.  If it's greater than 1 then you're using the pipeline.  This is true of you're using something like
Get-Content .\list.txt | Start-ReportPSCompliant -Verbose
but not something like
"server1","server2" | Start-ReportPSCompliant -Verbose

You've written your script to handle pipeline input.  It shouldn't matter whether you're actually using the pipeline or not.
ryanmavesAuthor Commented:
Thanks for the response footech. You're right, it shouldn't matter, but I don't understand why I'm not seeing my Verbose message that says my input is going through pipeline as opposed to parameter when I do in fact use the line

Get-Content .\list.txt | Start-ReportPSCompliant -Verbose

Should I not expect to see the Verbose message from the Else{} block?

if ($PSBoundParameters.ContainsKey('computer')) {
             # we have parameter input
        Write-Verbose "$Computer is going through as parameter input"
             foreach ($c in $Computer) {
                CompliantWorker $c
             }
        }else{
             # we have pipeline input
        Write-Verbose "$_ is going through pipeline"
             CompliantWorker $_
        }

Open in new window

footechCommented:
Nope.  As I mentioned, the parameter is being used either way.  So whether you feed it values via the command line directly or the pipeline, $Computer is the receptacle.
Discover the Answer to Productive IT

Discover app within WatchGuard's Wi-Fi Cloud helps you optimize W-Fi user experience with the most complete set of visibility, troubleshooting, and network health features. Quickly pinpointing network problems will lead to more happy users and most importantly, productive IT.

ryanmavesAuthor Commented:
Okay, I see what you are saying. My question then would be, what about my script has caused the parameter to handle pipeline input as well?

FYI. I got this script trick of $PSBoundParameters from Don Jones at 3:19:00 time frame in this youtube video below:
https://www.youtube.com/watch?v=7fFEV8xawx0

I guess I am trying to understand, do I have unnecessary lines in my script. I can't wrap my head around why the correct Verbose message isn't being used here. Unless, that means it's unnecessary script that can be removed, but why did Don Jones use it?

Thanks for entertaining my curiosity.
footechCommented:
Where you have ValueFromPipeline=$true and ValueFromPipelineByPropertyName=$true (more the former in this case).

I haven't used $PSBoundParameters a lot, but I can see just by outputting it what it contains and it doesn't matter whether I'm using the pipeline or not, so I don't know why he would have that in the video.  Go ahead and insert this between lines 41 and 42.  I include the "====" lines just to make it easy to see in the output.
"====="
$PsBoundParameters
"====="

Open in new window


From what I see if ($PSBoundParameters.ContainsKey('computer')) will always be true, so the else block will never be used.  I'm not aware of any change with $PsBoundParameters with different PS versions, so I can't think of any reason why he used it, other than a faulty assumption on his part (which I find a bit odd as well).

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ryanmavesAuthor Commented:
Thanks for being thorough footech. You are right, turns out I didn't even need the If/Then statement in my code. The process simply is a foreach and sends it to my worker process. Everything still works the same.

Thanks for the lesson.

    Process {
        foreach ($c in $Computer) { CompliantWorker $c }
        }

Open in new window

ryanmavesAuthor Commented:
Note, without the foreach statement having it send to my worker, there does rise a problem when calling computernames into the parameter such as it doesn't process them individually, but tries to do it all at once. This causes all the computernames to be added to my non-compliant list because they are all considered to have an ($err.count -gt 0).

Thanks again!
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Powershell

From novice to tech pro — start learning today.