Introduction
Iron Scripter grew out of the scripting games at PowerShell Summit and the quote below comes from the introductory post on the Iron Scripter site.
The Chairman has decided that it is in the best interests of his Iron Scripters, and those that wish to attain that valued designation, that training continue year-round. To that end, he has commissioned a series of PowerShell challenges. These challenges will range in complexity and be tagged accordingly.
— Iron Scripter, Let The PowerShell Challenges Begin, June 7, 2019
I’ve completed three of the online Iron Scripter challenges and, as I finished the last one, I decided to go back through the ones that I skipped.
The beginner challenge seemed like a great opportunity to discuss some PowerShell concepts.
If you are new to PowerShell or just have a little knowledge or experience with it, please continue reading.
PowerShell Concepts
In this post, you will learn about the following PowerShell concepts.
- PowerShell Editions
- Help System
- Conceptual Help
- Get-Help
- Commands
- Verb-Noun Naming Convention
- Verb
- Noun
- Types
- Cmdlets
- Functions
- Aliases
- Verb-Noun Naming Convention
- Variables
- Environment Variables
- Parameters
- Positional
- Default Values
- Unique Names, i.e. Shortened
- Pipeline
PowerShell Beginners Have to Start Somewhere
Here is the original PowerShell Beginners Have to Start Somewhere challenge.
Challenge Directions
Get all files in a given folder including subfolders and display a result that shows the total number of files, the total size of all files, the average file size, the computer name, and the date when you ran the command.
This should not be written as a script or function. It should be one or two lines of PowerShell that you would type at the console to generate the desired result.
PowerShell Editions
PowerShell currently comes in three editions: Windows PowerShell, PowerShell Core, and PowerShell.
Edition | Operating System | Versions | PSEdition | .Net Version |
---|---|---|---|---|
Windows PowerShell | Windows only | 1.0-5.1 | Desktop | .Net Framework |
PowerShell Core | Windows, Linux, MacOS | 6.x | Core | .Net Core 2.0 |
PowerShell | Windows, Linux, MacOS | 7.x | Core | .Net Core 3.0 |
For more information on PowerShell editions, visit Microsoft Docs entry for About PowerShell Editions.
Help System
Before we start the challenge, you should know how to get help for the various commands and concepts that we will cover in this post.
The first concept is PowerShell’s Help system. You access it primarily via the Get-Help
command. It is a command that
you should know how to use as it will provide you invaluable information on your PowerShell learning path.
In a PowerShell console, enter the following statement. Note that the command is not case sensitive.
|
|
In the console, you should see details on the PowerShell Help system.
Conceptual Help
If you wanted to know more about PowerShell concepts, you can always use Get-Help
. For example, if you wanted to know
more about variables, you can type the following in the console.
|
|
The output is a list of topics that contain the word variables. In the list, you should see several entries that start with about with a category of HelpFile. This type of help is called conceptual help and can provide information on concepts or even modules. Modules, a grouping of commands for a specific task, are outside the scope for this challenge.
You can narrow your command to only search for the concept about_variables.
|
|
Get-Help
As this is a challenge walk-through for beginners, we will be using Get-Help
significantly. Let’s see what the Help
system has for this command.
|
|
Though it seems redundant, the statement is using the command to display information about itself. At the end of the output, you should see the following lines.
|
|
The words after the dashes, such as -examples
, are parameters for the Get-Help
command. More on parameters later.
Verb-Noun Naming Convention
You might be wondering about the Get-Help
command itself, specifically why is there a dash between get and help.
The names of PowerShell commands are typically (and best practice) in the form of verb-noun.
Verb
The first part of the name is a verb and identifies the type of action the command does. There are standard verbs that are allowed which are grouped based on what on the verb normally acts upon.
Use Get-Verb
to list the verbs available and their groups. Don’t worry about knowing all of the verbs.
|
|
Noun
The second part of the command name after the dash is the noun. The verb acts upon the noun. In the case of
Get-Help
, the command will get information on help. The noun could be object, item, service, path, or any
number of other things.
Command Types
There are several types of commands, such as cmdlets, functions, and aliases. Even PowerShell scripts are considered a type of command just like applications, such as notepad.exe.
Cmdlet
Get-Help
is an example of a cmdlet. PowerShell cmdlets (pronounced command-lets or command-let for singular) are
commands that are typically written in .NET (or .NET Core) C# programming language and compiled.
Function
Get-Verb
is an example of a function. PowerShell functions are self-contained PowerShell statements. Basic and
advanced functions can be written. Advanced functions provides greater control over the input, processing, and output of
the command. To learn more about functions, see the conceptual help using Get-Help about_Functions
.
Alias
A PowerShell alias is an alternate name for another command. Aliases are typically short forms of command names and save you several keystrokes at the console.
There are several default aliases. To see all aliases configured in your current session, you can use Get-Alias
. To
learn more about aliases, see the conceptual help using Get-Help about_Aliases
.
Note: When you start writing your own scripts or functions, you should always use the command’s full name, and never use aliases. Full command names are easier to read for other users of your code, or even your future self.
Walk-Through Step 1
Get all files in a given folder including subfolders.
A quick internet search, using powershell list files, should reveal that the command you would use to list files or
folders is Get-ChildItem
. For ease of use, we will assign the output to a variable, $files
.
By default, Get-ChildItem
returns the top-level folders and files. We only want files and we want to get all
subfolders.
If you are unsure how to tell Get-ChildItem
to only return files or how to get all subfolders, review the output from
Get-Help -Name Get-ChildItem -Detailed
.
The command for our first directive could look like the following.
|
|
The command explained:
- The
$files
is the name of the variable that will receive the results from the command. - The
gci
is an alias forGet-ChildItem
. - The
-r
represents the-Recurse
switch parameter forGet-ChildItem
. - The
-file
switch parameter tellsGet-ChildItem
to only return files.
Variables
Variables allow you to store the results of a command which you can reference later. There are different types of variables - user-defined, automatic, and preference. Variables are stored in memory and may be accessed during the current PowerShell console session. User-defined variables can be manually removed from memory.
For more information on the types of variables, see the conceptual help using Get-Help about_Variables
,
Get-Help about_Automatic_Variables
, and Get-Help about_Preference_Variables
.
Get-ChildItem Aliases
Let’s look at the aliases for Get-ChildItem
.
|
|
|
|
From this output, you can see that there are three aliases for Get-ChildItem
.
- The alias
dir
helps persons that are familiar with DOS commands. - The alias
ls
helps persons that are familiar with Linux commands. - And the alias
gci
is just an abbreviation for the cmdlet.
Parameters
Parameters, such as Recurse
and Definition
, allow you to provide input to PowerShell commands.
Positional Parameters
By examining help again using Get-Help -Name Get-ChildItem -Full
, we see that Path
is the only parameter with a
position of 0. This means that the first item immediately after the cmdlet name, that is not another parameter, will
be assigned to the Path
parameter. Other cmdlets and custom functions could have one or more positional parameters.
Parameter Default Values
The command for the challenge technically uses a default value for the Path
parameter. After reviewing the cmdlet help
again, we see that Path
has a default value of current directory. If you do not specify a path (or the LiteralPath
parameter), the command will automatically return results for the current directory. To learn more about default values,
see Get-Help about_Parameters_Default_Values
.
Shortened Parameter Names
With one of the directives that this solution should be entered in the PowerShell console, I have chosen to use aliases and shortened parameters.
Parameter names can be shortened, as long as they uniquely identify a parameter. For instance, -r
is sufficient since
there are no other parameters that begin with the letter r. However, for -file
, there is more than one parameter
that begins with the letter f. You can see from the cmdlet help, or from auto-completion at the prompt, that there are
three parameters that begin with the letter f, four for PowerShell Core.
- Filter
- Force
- File
- FollowSymlink (PowerShell Core)
For uniqueness, you can see that to return only files, you will need to use the full parameter name, -File
.
Parameter names are not case sensitive.
Note: As with aliases, when you start writing your own scripts or functions, you should always use the parameter’s full name, and never use shortened or rely on the parameter’s position.
Walk-Through Step 2
[D]isplay a result that shows the total number of files, the total size of all files, the average file size, the computer name, and the date when you ran the command.
The second step of the challenge is to display the following output.
- Total number of files
- Total size of all files
- Average file size
- The computer name
- Date when executed
We can satisfy the requirements at least a couple different ways, but there are two components that are identical for both.
Number, File Size, Average
When you checked out help for Get-ChildItem
, you may recall reading that file size corresponds to the length
property. A quick internet search, using powershell file length sum, should reveal the Measure-Object
cmdlet, which
has an alias of measure
.
Let’s examine help for Measure-Object
a slightly different way than we have previously.
|
|
The statement above will open your default browser to the online help version for the cmdlet. We saw the online
switch parameter when we looked at the help for Get-Help
.
Measuring $files
Let’s look at how we can get the first three items in the list using Measure-Object
.
Example 2 in the online help shows how to measure files.
This command displays the Minimum, Maximum, and Sum of the sizes of all files in the current directory, and the average size of a file in the directory.
For this challenge, we need the sum and the average of the length attribute. From the online help, we know that
Average
, Sum
, and Property
are the parameters we need to use.
Let’s use the cmdlet alias, positional parameter for Property
(position 0), and shortened form for the last two
parameters.
|
|
This results in something like the following.
|
|
Disregard the actual values, as they will be different. What is important is that we see the average and the sum of the length, along with a count property. That actually satisfies the first three requirements for output.
More Concepts
Get Computer Name
Now, how do we get name of the computer? A quick search for powershell get name of computer reveals a new type of
variable, $env:COMPUTERNAME
.
Environment Variables
The variable $env:COMPUTERNAME
holds the name of the local computer. It is just one of many environment variables and
is an automatic variable. You can see all environment variables by entering gci env:
and find more information about
them using get-help about_environment_variables
.
Get Date
Given what you have learned so far about how commands are named using verb-noun, hopefully you can take a guess the command you can use to get the date.
If you said Get-Date
, then you are absolutely right.
That Symbol Explained
The ‘|’ symbol is called a pipe. PowerShell uses it to denote the pipeline.
Pipeline
In PowerShell, multiple commands can be placed after each other, separated by the pipe, to create a pipeline. The output from the first command feeds into the next. The output for the second command feeds into the next, and so on.
Some cmdlets and functions accept output as it is received on the pipeline. There’s a lot you can learn about pipelines, but the topic is a little more advanced than what we need to cover here. For the purpose of the challenge, just knowing what the symbol is called and what it represents should be sufficient.
You can always see what the Help system has about pipelines using Get-Help about_pipelines
. If that does not return
anything, you may need to update your Help system using Update-Help
in an elevated, that is Run as Administrator,
PowerShell console session.
Solution 1
In order to fulfil the last two requirements, we need to use the Select-Object
cmdlet and create two calculated
properties for computer name and the date. Calculated properties are essentially PowerShell expressions, also called
statements, enclosed in curly braces {}
.
The Select-Object
has a named parameter of Property
which just happens to also be position 0. Furthermore, it
accepts a list of properties.
Now that we the necessary basic PowerShell concepts to complete this challenge, let’s put it all together.
This solution begins differently than the ones discussed so far. This version omits the use of the $files
variable and
is about the shortest possible.
|
|
|
|
Solution 1 was taken primarily from John Steele’s response to the challenge which you can find below.
Solution 2
This solution is very similar to Solution 1, except that we use a hashtable for the calculated properties in order to name the properties. If you just use an expression, the expression itself is used as the name for the property.
|
|
|
|
Solution 3
This was the solution that I originally wrote. It outputs the same values but as a custom object. It uses a few
advanced concepts, such as type accelerators and an array count
property, that we didn’t cover here.
|
|
This solution is also not the most efficient solution. How many inefficiencies can you spot? Feel free to leave them in the comments below.
Alternate Solutions
On the challenge’s page, three Iron Scripters submitted their own. We’ve seen one; here are the other two.
Alternate Solution 1
Alternate Solution 2
Summary
We have covered several foundational PowerShell concepts in order to complete the Iron Script’s beginner challenge.
To complete the challenge, you used the commands Get-ChildItem
, Measure-Object
, and Select-Object
, or more
accurately, their aliases.
Hopefully, you now have a better understanding of the PowerShell Help system and how to use Get-Help
to learn about
concepts and commands. You learned about the Verb-Noun naming convention, a few types of commands, and variables.
You also learned about parameters and their positions, default values, and that they can be shorted. And lastly, you
learned about the PowerShell pipeline which is one of the scripting languages greatest strengths.
I hope you’ve found this interesting or informative. If you have any comments or questions, please post them below.
Thanks for reading and good luck on the Iron Scripter challenges!