Windows PowerShell Tutorial 4 - Input and Output

Controlling Input and Output using Redirection and/or Pipes



  1. Regedit32
    Just as in any other programming language, there comes a time where the Programmer may wish to access information from an external file, or they may wish to save information (i.e. Write information) to an external file.

    PowerShell has three special characters that can be used for this in combination with Cmdlets either built-in to PowerShell or created by the programmer.

    These characters are as follows:
    • > The greater than symbol
    • < The less than symbol
    • | The pipe symbol (located on key just below Backspace)

    The > symbol will write information to an external file from a Cmdlet instruction. The default is to write to the console if you do not redirect.

    The
    < symbol will read information from an external file for use by a Cmdlet.

    The | symbol sits between two Cmdlets. Information read from the left hand Cmdlet is passed as an Object to the right hand Cmdlet, which uses that Object as its input, then generates its own Object for output. Most often this is done between just two Cmdlets, however it is possible to pipeline multiple Cmdlets one after the other.

    For those of you who all ready are familiar with using pipelines in other Shell environments like the Command prompt, you would more than likely find this easy enough to do, however there is a major difference between the older Shell environments and PowerShell, which makes using PowerShell a lot more effective and efficient in my view.

    In the older Shell environments piped Commands produced a single result set, so as a result the entire result set needed to be generated before it could be passed down the pipeline, which meant the first result was returned at the same time as the last result.

    In PowerShell though, individual results are streamed live down the pipeline as soon as they are generated, and this means a result is instantly available to be used as input by the second Cmdlet which in turn will generate a new object instantly which too can be used by yet another Cmdlet for use immediately. So, as a result there is no waiting for the last result before the preceding results can be actioned and made use of.

    Confused yet? Trust me, it's a lot easier to get to grips with these tools by applying them to real life scenarios. So let's get to that now!

    • Press your Windows key + S
    • In the search field type powershell
    • In the search results select Windows PowerShell ISE
    This will open the application Microsoft provide to help you write your own Scripts, Functions, etcetera., for PowerShell. The great thing about this tool is that it comes with Intellisense technology which means if activated it will from time to time predict what you are likely to type next and offer a context menu to quickly choose an option. It can also help spot quickly an incorrect Parameter choice you might make.

    The Windows PowerShell ISE
    PS25.png

    You can see by default its split into a Script pane at the top, and a console at the bottom, with a list of Cmdlets on the right side to refer to. You can adjust the size of the panes to your preference or use only one pane.
    As you are more than likely aware you can quickly view Services in Windows by typing Services.msc in a run dialog then clicking OK, or by right-clicking on the Taskbar and selecting Task Manager then the Services tab.

    In PowerShell you can retrieve this information using a single Cmdlet.

    Type Get-Service in the console pane (bottom pane) of your Windows PowerShell ISE then press Enter key.

    PS26.png You can now see a complete list of Services. Their Status (i.e. Running or Stopped), the Service name (i.e. what you would type to use the Service), and their Display Name (i.e. a User Friendly name so you know what Service it is).

    Did intellisense pop up for you as you typed Get-Service? I'm sure it did and you can now see how easy it is to get assistance from this tool which can save a lot of typing, as you then only need to select the item you intended to type then press Enter or click it with your mouse to select it.

    I'm sure you'll agree this is useful, but what if you only want a list of Services that are currently running on your computer? That is where using a pipeline comes in handy.

    Type cls or clear in your console then press Enter to clear the console screen.

    Now type the following command using a pipeline:

    Code (PowerShell):
    Get-Service | Where-Object {$_.status -eq ‘running’}
    Press Enter key to execute.
    PS27.png
    Using a pipeline we are able to view running Services only

    So how did that work precisely?

    Well the Cmdlet Get-Service produced an Object which included all the information about Services. You may recall in a previous tutorial how I mentioned that an Object can store multiple pieces of information.

    Once the object was created, as we are using PowerShell, this was instantly passed down the pipeline to the second Cmdlet Where-Object which took the object created by Get-Service as input to generate its own Object.

    Where-Object's new object was filtered using a parameter which is enclosed inside { } braces: {$_.status -eq ‘running’}.

    • $_ is a built-in dynamic variable in PowerShell, For those familiar with programming languages like Java, $_ is a symbolic representation of This. In the example above, $_ literally means This Object (i.e. the object created by Get_service and passed via the pipeline to become input for Where-Object.
    • .status I hope is self explanatory. It's a method to return the Status of the Services in this example.
    • -eq acts as a switch. Switches test an object's values to see whether it contains something. In this example, -eq is testing the object's values to see whether or not it equates / equals running. If it does then it will be included in a new object being created which will be displayed to the console.
    • 'running' is the argument the Switch -eq is testing for.
    Now as I mentioned you can use multiple Cmdlets with pipelines.

    Let's expand the above command by passing it through yet another pipeline:

    Code (PowerShell):
    Get-Service | where {$_.status -eq ‘running’} | select name
    What do you think this additional pipeline will do? Not sure, well try it and see.

    PS28.png
    If you guessed it would display the Service name of any running Service well done!

    Now arguably it would make a lot more sense to display the User friendly Display Name as this would help you identify the running Services more easily. To do that you'd simply replace select name with select displayname. The benefit though, of accessing the actual Service name is that you can use these in additional commands within a Script to control their status. For example, you might wish to change its Startup type from automatic to manual, or you may wish to execute a command to stop a particular running Service, which is very handy should you need to perform an action that requires the Service not to be running, for example, to be able to delete the contents of the SoftwareDistribution directory in Windows you need to stop two running Services: Bits and WUAUSRV (i.e. Bits Intelligent Service, & Windows Update Service).

    T I P !!!

    You would have noticed in this example you needed to do a bit of scrolling to see all the results. While that is hardly the end of the world, it can be a little tiresome at times. You can increase the size of the console by left-clicking & dragging the horizontal bar which separates the upper Script pane from the lower console pane. Drag it up to increase the size, or down to decrease the size. You can also click an arrow to close or make the Script pane reappear.

    PS29.png

    Another thing to note, is that using pipes can get rather lengthy if you write it all on a single line. PowerShell recognizes if you choose to go to a multi-line approach, so for example, if we take the command we just used, you could write it in a multi-line format like so:

    Code (PowerShell):
    Get-Service |
      where {$_.status -eq ‘running’} |
      select name
    You may find this easier to read later should you need to debug the script.

    Note to: You do not need the escape new line `n like when writing multi-line Strings.


    Moving on now to the
    > and < symbols which can be used to write to or read from an external file.

    Before we start showing an example, we will want a simple test file to work with.

    In your Windows PowerShell ISE console, type cls or clear and press Enter to clear the console screen.

    Now type notepad and press Enter.

    A new notepad will have opened. In this type some text, then click File > Save as, and name the file Test then save to your Desktop.

    OK, assuming you've done the above let's see how we can read the content of our Test.txt file, then write that content to a new variable, and from there how to read the variable and write its content to a new file.

    For this we will use two Cmdlets:

    • Get-Content (Which can read the contents of an object/file)
    • Out-File (Which is used to write data to a file)

    So now in your Windows PowerShell ISE console, type the following:

    Code (PowerShell):
    $contentsOfTestFile = Get-Content "$env:UserProfile\Desktop\Test.txt
    Press Enter key to execute.

    Now in the console type:

    Code (PowerShell):
    Write-Host "`n",$contentsOfTextFile
    Press Enter key to execute


    PS30.png
    All going well, you ought to see the content of what you typed into your Test.txt file

    You can see that we successfully read the content of the Test file and stored that into our new variable $contentsOfTestFile, then by calling our variable we were able to read the contents in our console.

    You would also have noticed how intellisense helped in two ways as you typed these commands:

    1. As you typed the $env:UserProfile\Desktop\Test.txt the intellisense would have popped up and you could select Desktop then select Test.txt rather than have to type them in.
    2. When calling our new variable, as you began to type it, intellisense would have popped up and again, you could select it rather than type in that long variable name.

      You can see now I hope how useful intellisense can be.

    Now let's read the contents of our variable and write it to a new file.

    Type the following into your Windows PowerShell ISE console:

    Code (PowerShell):
    $contentsOfTextFile > "$env:UserProfile\Desktop\Test2.txt"
    Press Enter key

    PS31.png

    Notice you just used the > redirection symbol to write output from your Variable to an external file.

    Note: Another way of creating this file is via a pipe and using the Cmdlet Out-File:

    Code (PowerShell):
    $contentsOfTextFile | Out-File "$env:UserProfile\Desktop\Test2.txt"


    Now press Windows key + D and you ought to see on your Desktop your new file named Test2.txt — open it, and it ought to contain what you had previously typed into Test.txt

    What is that? Did I hear someone in the back row mumble, 'I thought this was a PowerShell tutorial, not a Windows Shortcut Keys tutorial!' Great point!

    Type the following into your console:

    Code (PowerShell):
    Notepad.exe "$env:UserProfile\Desktop\Test2.txt"
    Press Enter key

    PS32.png
    PowerShell can easily be used to open any file — in this case our newly created Test2.txt

    That brings me to the redirection of file content back to the console by using the < redirection symbol. Alas, at this time Microsoft have chosen to redact this option which you were able to use in older Shell environments to echo information back to your console. However, its not impossible to achieve this, as we can instead make use of the Get-Content Cmdlet coupled with piping.

    So in an old Shell environment you could code something like this:

    Code (PowerShell):
    GPUPDATE /Force < C:\SomeFile.txt
    This would redirect the content of the chosen external file and allow you to update Group Policies. Very handy for the IT Administrator.

    To do this in PowerShell though, given the < redirection option is not available for the time being, you would have to code your script like this instead:

    Code (PowerShell):
    Get-Content "C:\SomeFile.txt" | GPUPDATE /FORCE
    Credit to Microsoft PowerShell MVP Sean Kearney
    https://blogs.technet.microsoft.com...nd-legacy-redirection-issues-with-powershell/


    Well that brings me to the end of this tutorial.

    What's that? Did I hear a collective sigh of relief :mad:

    Just for that, the next tutorial will deal with more advanced redirections!

    Oh by the way, you can delete those files on your Desktop now if you wish to.


    Regards,

    Regedit32
    ClickOK and Ian like this.