In this tutorial, we'll be creating a fully-functional terminal application that can let us check some useful system information in one place. We'll be pulling from previous lessons and adding some new functionality as we go.

Full code can be found near the bottom of this page for the PowerShell script. I have commented the complete code as thoroughly as felt necessary to let it be a stand-alone document, but we'll still go through everything step by step as we move along.

Launching Scripts

Very frustratingly, Microsoft has decided to make PowerShell scripts pretty difficult to run! This is a security feature to keep less adept computer users from accidentally running malicious scripts that have been slipped to them, but unfortunately it has a pretty giant flaw -- we can simply use batch scripts (from the old MS-DOS days) to manually bypass all of that security.

This does require having TWO files, though. We can have a batch that that we can just click on and that will allow us to get over this little hurdle without too much issue.

However, this is NOT a batch scripting tutorial, so I am simply going to paste the code that works here, and you can find the full launcher.bat at the bottom of the page. Paste the following into a new *.bat file, being sure to modify the $scriptPath variable to reflect the correct script name to run all future practice applications without needing to modify system-wide permissions.

Getting Funky with Functions

Functions are basically used to store code that we know we'll be running repeatedly. We can create them very easily and call on them later do a long or complex task without repeating the code again. In this tutorial, we'll pass one through a new type of loop that we have not yet seen, the do loop.

Without further ado, let's get started. Fire up your editor of choice and save a new file as systemInfo.ps1. After that, enter the following code to begin our first function:

return-ing Data

When a function is called as a variable assignment (in this script,we'll be running $computerCollection = Get-UpdatedSysInfo at the beginning), you need to `return` data to it - in this case, we are returning the new collection we generated by running this function.

In this case, since we aren't setting it as a variable, return simply gives us the output in the terminal window.

When you run that script, you should get some output that looks familiar from the last lesson.


        

Parameters

Now that we have a function that collects all that data, we want something that allows us to pick which pieces of data we want to see.

Let's begin by removing the $computerCollection debugging line, since we can see that our code does in fact work, and let's add another new function to our script. Add this directly below the existing script:

param-eter Blocks

The param code block you see at the beginning of the function tells the script that in order to use the function, the user must supply additional information. Unlike functions themselves, these are contained within parentheses ("(" and ")"). Different parameters that can be supplied are separated by commas (",").

In our script, we are looking for two parameters: $infoType, which we assign the same names as the data properties in our new collection, and $dataSource, which is the collection we want to pull from. We probably don't NEED to have a parameter for $dataSource, but if we set it as a parameter now, we can easily add other data sources down the road if we decide to expand the scope of this application.

At the end of running the script now, you should get output in your terminal that looks like this:

=== WindowsVersion ===
Data updated at 5/5/2025 10:18:57 AM
            
Windows Version: Microsoft Windows 11 Pro
            
Press any key to return to main screen

Once again, let's remove the last line that calls the Show-Information function, and then move on to the next step.

User Interface

Now that we know how to collect the data, let's move on to actually creating an interface to deal with it. For now, we'll keep it simple. Add the following code to the end of script, directly after defining the Show-Information function:

And now when we run our script, we'll get an interface asking us which piece of information we want. For now, we just have a basic if statement that exits the application, no matter what we do (we'll do that next). You'll see output like this:

================ System Information Viewer ================
Data collected on 5/5/2025 10:42:20 AM

Please select an option:

0. Update system information
1. Windows Version
2. Current User
3. Computer Name
4. CPU Information
5. Time Zone
q. Exit

Enter your choice (0-5 or q): q
Quitting application

Formatting terminal text

We could have simply had a single "Write-Host" command to type out all of that information, but you need to be careful with formatting. Since text in a "Write-Host" command is considered pre-formatted, going to a new line in one command will require everything to be laid out differently.

Code that looks like this:

>    Write-Host "Testing
>    Testing Testing 1-2"

Will generate:

Testing
        Testing Testing 1-2

Because of the tab gap on the second line. I usually find it's best to simply state new lines when you know there will be one.

Do the do (loop)

Remove everything after the Show-SystemInformation function. We'll be replacing that logic with entirely new logic with the following code:

What do?

We saw a ForEach-Object loop in earlier lessons - here's another kind. Instead of going through every property of a supplied collection, a "do" loop simply repeats until it is broken.

So here we begin our do loop - it will continue to run while "q" is not selected to exit the program. Once the user selects "q", the program terminates with a parting message.

switching it up

Previously, we used an if statement to decide which selection does what. However, when we have multiple options to choose from, we can use a switch statement instead. It works much like an if statement, but instead of looping throughy every single argument using elseif and else statements, it can simply select which action to take from a pre-defined index, which is what we are doing here.

Now when you run your script, you'll see the same interface as before, but all of its functions should work. The full code with more in-depth commenting can be found below the Conclusion section below, including the ps1 and bat launcher file.

Conclusion

There was a lot to touch on today and this tutorial is likely going to be needed to refer back to from time-to-time, but we have finally written a tiny utility in PowerShell! Now we should have a decent grasp on the following:

  1. How (and why) to launch a PowerShell script from a Batch file.
  2. How to write and use functions to collect and store information for later use.
  3. Adding and using parameters in functions.
  4. Creating basic text-based user interfaces and using Read-Host to get user input.
  5. Implementing do loops to create functional programs.
  6. Using switch statements when appropriate, rather than if statements.

Final Scripts

systemInfo.ps1 launcher.bat

systemInfo.ps1

launcher.bat