Tag Archives: Write-Host

Get Multiple Percentages of Multiple Values

Before my parents decided to trade in their truck at the dealership this week, we began to discuss the possibility of me selling it for them. Back when we started the discussion, I was thinking about possible prices for the truck, and the payout for me. Go figure, but, much like other things, I was able to incorporate Windows PowerShell into this, too.

Had this actually happened, we were going to need to determine how much I was going make in this deal. Here’s how I saw the options:

– They indicate an amount they want for the truck, and everything over that amount is mine.
– They give me a set dollar amount to sell the truck, regardless of the purchase price.
– They agree to a percentage of the final purchase price.

This last option was the one that had me flip over to my PowerShell console. You see, I often use the console as my calculator. I’m faster at typing out my math problems there, than I am using the built-in calculator in Windows.

Let’s use the possible purchase prices of $12,500, $13,000, $13,500, $14,000, and $14,500. In case you’re interested, it was a 2005 F150 SuperCrew Cab with under 70,000 miles — you read that right, less than 7,000 miles per year. What I wanted to determine was how much my parents and I would each make if I received 1%, 2.5%, 5%, 7.5%, 10%, and 12% of each of the possible purchase prices. Enter PowerShell.

The first thing I did was pipe each of the possible purchase prices to the ForEach-Object cmdlet and write their values to the screen. The results indicated that each value was properly crossing the pipeline.

12500,13000,13500,14000,14500 | ForEach-Object {
    Write-Output -Verbose $_
}
12500
13000
13500
14000
14500

Next, I created a variable for each percentage, based on a calculation. On the way into the loop, it would multiply the possible purchase price, of that iteration, by the percentage amount and store it in the proper variable. Notice that I have variables with dots (or periods, or decimals) in them, such as ${7.5Percent}. In order to use something other than a letter, number, or underscore, we need to wrap the variable in curly brackets. It’s not recommend to use variable with anything other than letters and numbers, but I thought it made sense in this case.

12500,13000,13500,14000,14500 | ForEach-Object {
    $12Percent = $_ * .12
    $10Percent = $_ * .1
    ${7.5Percent} = $_ * .075
    $5Percent = $_ * .05
    ${2.5Percent} = $_ * .025
    $1Percent = $_ * .01
}

After these variables were assigned, I created a header and footer that helped to separate the results from one another. Remember, each iteration through the loop prints these two lines of asterisks. Notice that the top row will include the current possible purchase price in the middle. The colors will also help separate the different purchase prices and the percentages.

12500,13000,13500,14000,14500 | ForEach-Object {
    $12Percent = $_ * .12
    $10Percent = $_ * .1
    ${7.5Percent} = $_ * .075
    $5Percent = $_ * .05
    ${2.5Percent} = $_ * .025
    $1Percent = $_ * .01

    Write-Host -Object "*****$_*****" -ForegroundColor Green

    Write-Host -Object '***************' -ForegroundColor Green
}

Here’s how this displayed at this point.

Get-Multiple-Percentages-of-Multiple-Values00

In this next example, you can see where included the 90% value and 10% value of each possible purchase price. To determine these two values, we subtracted our 10% amount from the full purchase price (for 90%). The second value was already determined as part of setting the variable at the beginning of the loop, so we echoed what was already in the variable.

12500,13000,13500,14000,14500 | ForEach-Object {
    $12Percent = $_ * .12
    $10Percent = $_ * .1
    ${7.5Percent} = $_ * .075
    $5Percent = $_ * .05
    ${2.5Percent} = $_ * .025
    $1Percent = $_ * .01

    Write-Host -Object "*****$_*****" -ForegroundColor Green

    Write-Host -Object "90%: $($_ - $10Percent)" -ForegroundColor Yellow
    Write-Host -Object "10%: $10Percent" -ForegroundColor Gray

    Write-Host -Object '***************' -ForegroundColor Green
}

Here’s what it looked like when the code above was run.

Get-Multiple-Percentages-of-Multiple-Values01

Here’s the final code and results.

12500,13000,13500,14000,14500 | ForEach-Object {
    $12Percent = $_ * .12
    $10Percent = $_ * .1
    ${7.5Percent} = $_ * .075
    $5Percent = $_ * .05
    ${2.5Percent} = $_ * .025
    $1Percent = $_ * .01

    Write-Host -Object "*****$_*****" -ForegroundColor Green

    Write-Host -Object "87.5%: $($_ - $12Percent)" -ForegroundColor Yellow
    Write-Host -Object "12.5%: $12Percent" -ForegroundColor Gray

    Write-Host -Object "90%: $($_ - $10Percent)" -ForegroundColor Yellow
    Write-Host -Object "10%: $10Percent" -ForegroundColor Gray

    Write-Host -Object "92.5%: $($_ - ${7.5Percent})" -ForegroundColor Yellow
    Write-Host -Object "7.5%: ${7.5Percent}" -ForegroundColor Gray

    Write-Host -Object "95%: $($_ - $5Percent)" -ForegroundColor Yellow
    Write-Host -Object "5%: $5Percent" -ForegroundColor Gray

    Write-Host -Object "97.5%: $($_ - ${2.5Percent})" -ForegroundColor Yellow
    Write-Host -Object "2.5%: ${2.5Percent}" -ForegroundColor Gray

    Write-Host -Object "99%: $($_ - $1Percent)" -ForegroundColor Yellow
    Write-Host -Object "1%: $1Percent" -ForegroundColor Gray

    Write-Host -Object '***************' -ForegroundColor Green
}

Get-Multiple-Percentages-of-Multiple-Values02

In the results, above, I’ve only included the first three possible purchase prices, to save space. While all of this could have been figured out with a calculator, there’s no possible way it could have been done as quickly — at least for someone that knows PowerShell. I didn’t bother to create an object in this instance, although it would have made sense. In my mind this wasn’t going to be reused any more than it was this one time, and so I didn’t add the additional effort.

I hope this is helpful for someone. Cheers.

Write-Host, Does it Have a Place?

I’ve been working on an advanced function that I can’t wait to share (and no, it’s not the one in this post). I really think it’s something that the Windows PowerShell community has been missing. Okay fine, maybe it’s just something I’ve been missing.

I noticed in development that my Write-Output messages to the user were crossing the pipeline, when the custom object (created by the function), was passed to Select-Object (in certain manners). I have a function below that does the same thing as the one in development.

Here’s how this thing works: The function requires the user to provide the value Write-Output (or, wo), or Write-Host (or, wh) for the -Option parameter. This will determine how the message to the user is written inside the Begin block. The only other thing that’s happening in this function, is that a custom object is being created in the Process block, based on some properties of Win32_BIOS.

Function Test-TMWriteOutputVsHost {
    [CmdletBinding()]
    Param (
    [Parameter(Mandatory=$true,
        HelpMessage="Enter Write-Output or Write-Host")]
    [ValidateSet('Write-Output','wo','Write-Host','wh')]
    [string]$Option
    )

    Begin {
        If ($Option -eq 'Write-Output' -or $Option -eq 'wo') {
            Write-Output 'Inside the Begin block (using Write-Output).'

        } ElseIf ($Option -eq 'Write-Host' -or $Option -eq 'wh') {
            Write-Host 'Inside the Begin block (using Write-Host).'
        }
    } # End Begin

    Process {
        $CollectionVariable = Get-WmiObject -Class Win32_BIOS
        $Object = @()
        $Object += [pscustomobject]@{
            Manufacturer = $CollectionVariable.Manufacturer;
            Name = $CollectionVariable.Name;
            Version = $CollectionVariable.Version
        }
    } # End Process

    End {
        Write-Output $Object
    }
    # End, End
} # End Function

As we can see below, everything works great with both Write-Output or Write-Host, when we don’t pipe the function to the Select-Object cmdlet.

PS C:\> Test-TMWriteOutputVsHost -Option Write-Output
Inside the Begin block (using Write-Output).

Manufacturer                            Name                                    Version
------------                            ----                                    -------
Dell Inc.                               BIOS Date: 08/27/13 11:12:44 Ver: A1... DELL   - 1072009

PS C:\> Test-TMWriteOutputVsHost -Option Write-Host
Inside the Begin block (using Write-Host).

Manufacturer                            Name                                    Version
------------                            ----                                    -------
Dell Inc.                               BIOS Date: 08/27/13 11:12:44 Ver: A1... DELL   - 1072009

Now, let’s pipe our object to some variations of the Select-Object cmdlet and watch some things blow up (when using Write-Output).

PS C:\> # Use the horizontal scrollbar to see the results...
PS C:\> Test-TMWriteOutputVsHost -Option Write-Output | select *

                                                                                                                 Length
                                                                                                                 ------
                                                                                                                     44

PS C:\> Test-TMWriteOutputVsHost -Option Write-Output | select Name,Ver*

Name                                                        Ver*
----                                                        ----

BIOS Date: 08/27/13 11:12:44 Ver: A13.00

PS C:\> Test-TMWriteOutputVsHost -Option Write-Host | select *
Inside the Begin block (using Write-Host).

Manufacturer                            Name                                    Version
------------                            ----                                    -------
Dell Inc.                               BIOS Date: 08/27/13 11:12:44 Ver: A1... DELL   - 1072009

PS C:\> Test-TMWriteOutputVsHost -Option Write-Host | select Name,Ver*
Inside the Begin block (using Write-Host).

Name                                                        Version
----                                                        -------
BIOS Date: 08/27/13 11:12:44 Ver: A13.00                    DELL   - 1072009

The problem with Write-Output, is that the object it’s producing is crossing our pipeline and causing unpredictable behavior—something we can’t include in a function we want to distribute. Here’s the proof: When we pipe our function to Get-Member, we reveal the objects that show up on the other side, and we don’t want the string object coming over with us.

PS C:\> Test-TMWriteOutputVsHost -Option Write-Output | Get-Member | Select-Object TypeName -Unique

TypeName
--------
System.String
System.Management.Automation.PSCustomObject

PS C:\> Test-TMWriteOutputVsHost -Option Write-Host | Get-Member | Select-Object TypeName -Unique
Inside the Begin block (using Write-Host).

TypeName
--------
System.Management.Automation.PSCustomObject

I don’t profess to know it all, so if there’s a way to get around this using Write-Output, then I’d love to hear about it. While I haven’t tried it, I suspect I may be able to create an embedded function—that might be the trick I need. Perhaps I’ll play with that option at another time. Thanks for reading!

Oh, and before someone mentions it, I explained how I feel about Write-Verbose in the comments on a post by Adam Bertram: http://www.adamtheautomator.com/use-write-host-lot.