PowerShell Input & Output

This entry is part 8 of 9 in the series Learn PowerShell

Up to this point in the Learn PowerShell series we have covered examples using very simple PowerShell input and output. Typically we have statically provided inputs by hard coding a variable (ex. $input = ‘SomeInput’). Our outputs so far have mostly consisted of Write-Host. In this lesson we’ll look to take in more dynamic input and show you how to take more control of your output.

Video

If you prefer video format over written documentation I discuss this topic in the following TechThoughts video:

PowerShell Input

Often times your PowerShell code will need to evaluate some type of input. That input can be statically provided by you ahead of time. There are often use cases though where retrieving a dynamic input is desired.

PowerShell Input From cmdlets

You can of course use the output of cmdlets for the input of your PowerShell functionality. Depending on what a cmdlet returns, you could perform a variety of different functions based on that generated input.

  • run cmdlets (Get-Process)
    • cmdlet generates output
      • use output as your input
        • perform functionality based on dynamic input

Dynamic PowerShell input from the web

Lets explore an example where we use PowerShell to pull in dynamic results from a website. If you come from a more Linux focused background this is a bit like using curl.

#retrieve dynamic content from a website
$webResults = Invoke-WebRequest -Uri 'https://reddit.com/r/powershell.json'
$rawJSON = $webResults.Content
$objData = $rawJSON | ConvertFrom-Json
$posts = $objData.data.children.data
$posts | Select-Object Title,Score | Sort-Object Score -Descending

Here we are using Invoke-WebRequest to retrieve web content from /r/PowerShell. (A great PowerShell resource by the way!) HTML isn’t particularly useful to us as we want to work with objects in PowerShell. So note that I have visited the JSON version of this page. As a result, the output content from this cmdlet is in JSON. Because JSON is structured data, we can take control and convert it to native PowerShell objects using ConvertFrom-JSON.

Note: There are many of these convert cmdlets. This enables you to take in data from a variety of sources and continue to work with PowerShell objects!

Once in native object format, it’s a simple matter to explore the available sub-properties. We can then drill down into them and find post information. Once we have post data, we can select and sort for the inputs we are after. In this example, post title and score (upvotes) are returned.

Run the example above on your machine to see the results. Try exploring other available sub-properties in $posts.

Leveraging cmdlet output as input

How would you go about using the output from that example as input? That’s entirely up to you! You could write PowerShell code to:

  • Email yourself the top 3 PowerShell posts of the day
  • Send yourself a text message with the top post of the day
  • Display the top 10 posts of the day when you login

You’d be using PowerShell to make yourself smarter on PowerShell! We’ll be covering more how to create ps1 scripts later in the series so stay tuned!

You’d be using PowerShell to make yourself smarter on PowerShell!

Read-Host Input

Read-Host is another way to get dynamic input from yourself or your users. Leveraging the previous example again, we could only return the desired number of posts:

[int]$numPosts = Read-Host -Prompt "Enter the number of posts to read"
#retrieve dynamic content from a website
$webResults = Invoke-WebRequest -Uri 'https://reddit.com/r/powershell.json'
$rawJSON = $webResults.Content
$objData = $rawJSON | ConvertFrom-Json
$posts = $objData.data.children.data
$posts | Select-Object Title,url | Sort-Object Score -Descending | Select-Object -First $numPosts

The -First parameter of Select-Object allows us to control how many objects we return to the console. Because we are sorting by number of upvotes, we will return the number of top posts specified. Run this on your computer specifying different numbers of posts.

Here is fun example where we can retrieve web data combined with Read-Host to display the desired number of cat facts:

[int]$numFacts = Read-Host -Prompt "Enter the number of cat facts you would like"
$webResults = Invoke-RestMethod -Uri "https://catfact.ninja/facts?limit=$numFacts&max_length=140"
$webResults.data

Note that catfact.ninja is an API and not a traditional webpage. As a result, Invoke-RestMethod is the appropriate cmdlet, and not Invoke-WebRequest.

Get-Content

Another source of dynamic input that you often need comes from files on a device. Operationally, you’ll often be looking at log files. Lets take a look at an example log file:

[INFO][Date]Normal Operations
[INFO][Date]Normal Operations
[INFO][Date]Normal Operations
[ERROR][Date]192.168.1.5 unable to access
[INFO][Date]Normal Operations

Get-Content can retrieve the contents of a file for you to use as input.

$logContent = Get-Content C:\Test\SampleLog.log

# get just entries that have an IP address using regex
$regex = "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b"
$logContent | Select-String -Pattern $regex -AllMatches

# get just entries that have an IP address using Where-Object
$logContent | Where-Object {$_ -like "*.*.*.*"}

The contents of the SampleLog are stored in $logContent. Now that you have that input data you can start doing evaluations. It may be critical that PowerShell take some form of action if an IP address is discovered in the log. You can parse the data using regular expression (regex) or by using Where-Object. If an IP is discovered, you could ticket, pop a notification, or perform some other action.

You aren’t limited to just text or standard log files. Get-Content can pull in input data from a wide array of file types. Here is an example where you can get input from a csv file. Remember that there are many conversion cmdlets so you can get csv data into normal PowerShell object format easily!

$rawCSVInput = Get-Content C:\Test\SampleCSVFile.csv
$objData = $rawCSVInput | ConvertFrom-Csv

PowerShell Output

If you want to display results back to the console or generate a results file, you’ll need to generate some type of PowerShell output. There are a few ways to accomplish this, and one you should avoid!

Write-Host

Write-Host can output customized strings to the console. You can customize the output by controlling the start of a new line, or -NoNewline. A foreground and background color can also be set. Try the following examples:

# Output simple string to console
Write-Host 'Text output to console'

# Customize output to the console with colors:
Write-Host "Warning" -ForegroundColor Yellow
Write-Host "ERROR" -ForegroundColor Red
Write-Host "Works Great" -ForegroundColor Green
Write-Host "CRITICAL ERROR" -BackgroundColor Red -ForegroundColor White

Write-Host is only capable of string output, so you need to make sure you are giving it a string. If not, Write-Host will do its best to accommodate some type of output, but the results may not be what you expect.

$hostInfo = Get-Host
Write-Host $hostInfo

In the above example, you’ll get the output of: System.Management.Automation.Internal.Host.InternalHost

This is because $hostInfo is a PowerShell object, not a string. We can drill down farther into this object until we have a string that is use-able by Write-Host:

$hostInfo = Get-Host
Write-Host $hostInfo
Write-Host $hostInfo.Version

Write-Host is easy to implement, and it’s color capabilities make it an attractive choice for displaying results to users. However, you shouldn’t use it. It can be handy to use when writing new PowerShell to verify your code contains values you expect. Beyond that, its use should be avoided. Jeffrey Snover covers the reasons why in his post Write-Host Considered Harmful. In it he advocates for the use of Write-Verbose over Write-Host. We’ll be covering Write-Verbose later in the series when we begin creating PowerShell functions.

Using Write-Host is almost always wrong.

Jeffrey Snover – creator of PowerShell

Write-Output

If you’ve been following along in the series you’ve already used Write-Output quite a bit. This is because Write-Output is what PowerShell is using behind the scenes as the default output stream.

Get-Process

When you run Get-Process and see results in the PowerShell console, that was accomplished by Write-Output. All of these examples accomplish the same thing:

# Example 1
Get-Process

# Example 2
$processes = Get-Process
Write-Output $processes

# Example 3
$processes = Get-Process
$processes

As a result, you won’t often see Write-Output written in PowerShell code. It’s implied as the default output behavior.

Out-File

The console isn’t your only avenue for PowerShell output. For times when you want to output to a file, you can leverage Out-File. Out-File is capable of sending the entire output to file. This means that it’s a bit more intelligent than Write-Host, and can handle sending the entire object return from a cmdlet to file. See below for some examples:

# Example 1
$processes = Get-Process
$processes | Out-File -FilePath C:\Test\processInfo.txt

# Example 2
Get-Process | Out-File -FilePath C:\Test\processInfo.txt

Don’t forget about those conversion cmdlets! There are several for outputs as well! So, if your file needs to be in CSV format, you can leverage ConvertTo-CSV:

$processes = Get-Process
$processes | ConvertTo-Csv -NoTypeInformation | Out-File c:\test\processes.csv

There are a few parameters you’ll want to familiarize yourself with for Out-File.

  • NoClobber – prevents an existing file from being overwritten
  • Append – instead of overwriting an output file, add to it
  • Encoding – especially useful if you are running on Linux – specify the encoding type of the file
Series Navigation<< Taking Control with PowerShell LogicPowerShell Errors and Exceptions Handling >>

Leave a Reply

Your email address will not be published. Required fields are marked *