DEV Community

Cover image for An easy way to provide parameters in PowerShell
Coding Bugs
Coding Bugs

Posted on

An easy way to provide parameters in PowerShell

My nickname in the networks is Coding Bugs, and I have been working as a software architect and developer from 2004. In my dashboard, you will find articles about programming languages, programming techniques, and other concepts that will help you improve.

You already know that PowerShell is the programming language that Microsoft makes available to us for "a cross-platform task automation solution composed of a command-line shell, a scripting language and a configuration management framework".

In this article I will show you a different way to provide parameters to scripts and commands. This is a simple and easy way of declaring parameters and assigning their values that will allow you to organize your scripts so that everything makes more sense.

Standard way

If you know PowerShell you already know how to provide parameters in your calls. If you don't, just type the name of the parameter preceded by a dash, then type its value.

$ Get-ChildItem -Path C:\ -Filter *.txt 
# Returns all existing text files in C:
Enter fullscreen mode Exit fullscreen mode

As you can see, the standard way is very easy and for cases where you make immediate invocations it is the best way to provide parameters.

However, imagine that you have to count the number of files of a certain type located in a specific place on your machine. In this case, we would have to repeat as many times as necessary the invocation of the above command, Get-ChildItem, providing the Filter parameter based on the requested file type.

$ Get-ChildItem -Path C:\ -Filter *.html | Measure | Select Count 
# Returns all existing HTML files in C:

$ Get-ChildItem -Path C:\ -Filter *.css | Measure | Select Count 
# Returns all existing CSS files in C:

$ Get-ChildItem -Path C:\ -Filter *.js | Measure | Select Count 
# Returns all existing JS files in C:
Enter fullscreen mode Exit fullscreen mode

To save us time each time we are asked for this information we are going to generate our own script in which we add these calls. In addition, we are going to incorporate a parameter in the script to specify the location where to count each one of the HTML, CSS and JS files.

param(
    [Parameter(Mandatory=$true)]
    [String] $Location
)

Return @{
    Html = $(Get-ChildItem -Path $Location -Filter *.html | Measure).Count
    Css = $(Get-ChildItem -Path $Location -Filter *.css | Measure).Count
    Js = $(Get-ChildItem -Path $Location -Filter *.js | Measure).Count
}
Enter fullscreen mode Exit fullscreen mode

What happens if we are now asked to include more and more file types with different extensions? The answer would be to include more and more lines to our script to fulfill the request. But what if there was another simpler and more versatile way, giving our script the ability to abstract from extension types?

A hashtable for passing parameters

We will start by adding a new parameter indicating the extensions of the files we have to count. Now we will only have to iterate over these values and pass the corresponding extension to the Get-ChildItem command.

param(
    [Parameter(Mandatory=$true)]
    [String] $Location,

    [Parameter(Mandatory=$true)]
    [String[]] $Extensions
)

Return $Extensions 
    | Foreach {
        $CurrentExtension = $_.ToLower() 
        # Transform extension to lower case
        Return @{ $_ = $(Get-ChildItem -Path $Location -Filter $CurrentExtension | Measure).Count } 
        # Return an object with the extension as the key and the count obtained as the value
}
Enter fullscreen mode Exit fullscreen mode

This would be enough for our purpose but, as a programmer, we want it to be even more abstract and allow us to keep the Get-ChildItem command call cleaner, avoiding having to modify it again with new parameters.

Being a somewhat complex command line, it is better to avoid modifying it as much as possible or to make it simpler by breaking it into simpler pieces. For the sake of this article, we choose the first option.

PowerShell allows the passing of a hashtable object to provide each of the parameters we need from the command to be executed. In our case, the command is Get-ChildItem and the parameters we are using are Path and Filter.

# The hashtable variable that we will create will look like the following one
$CmdParams = @{
    Path = "."
    Filter = "*.*"
}

# And the command call is like the following, important the use of "@" character
Get-ChildItem @CmdParams
Enter fullscreen mode Exit fullscreen mode

As in the previous case, we have to update our hashtable variable with the corresponding extension in each iteration of the Foreach.

param(
    [Parameter(Mandatory=$true)]
    [String] $Location,

    [Parameter(Mandatory=$true)]
    [String[]] $Extensions
)

$CmdParams = @{
    Path = $Location
    Filter = "*.*"
}

Return $Extensions 
    | Foreach {
        $CurrentExtension = $_.ToLower() 
        # Transform extension to lower case
        $CmdParams.Filter = "*.$CurrentExtension" 
        # Set the filter to the current extension
        Return @{ $_ = $(Get-ChildItem @CmdParams | Measure).Count } 
        # Return an object with the extension as the key and the count obtained as the value
}
Enter fullscreen mode Exit fullscreen mode

We have achieved what we were looking for, we have abstracted the call to the Get-ChildItem command with respect to the parameters we need to pass to it. This way, we can modify the CmdParams variable by adding, changing or removing any key/value pair based on the functional needs we have.

We can see here the second principle of the SOLID paradigm, Open-Closed Principle, which states that the code should be closed to any modification but open to extend its functionality. We can say that the purpose of the iteration over each of the extensions is to return the number of existing files in the indicated location. The Get-ChildItem command can be invoked with other parameters that will modify the number of files returned but its result will remain the same (closed to modification), therefore, our CmdParams variable allows that the files to be returned can be different depending on the parameters received (open to extension).

Imagine that we are asked for another new functionality. Now we need to count the files in the location provided and the files in the folders immediately inside, i.e. the first level.

Let me explain that the Get-ChildItem command has parameters that allow us to implement this type of requirements without the need to do any advanced engineering, we will use the Recurse parameters to establish that the search is performed in the indicated location and in all the ones below and, Depth to establish the maximum number of recursion that we need, in our case, the value is 1.

Surely you have already visualized the change to be made to the previous code. From my point of view, something very simple that will not take us more than 5 minutes between the change and the tests to verify that it is correct.

In our code we have to include the above two parameters in the CmdParams variable for it to be applied. It is a clean change, just add new elements in our hashtable without having to modify the command line where the command is located which, as we have said, is certainly complex.

param(
    [Parameter(Mandatory=$true)]
    [String] $Location,

    [Parameter(Mandatory=$true)]
    [String[]] $Extensions
)

$CmdParams = @{
    Path = $Location
    Filter = "*.*"
    Recurse = $true
    Depth = 1
}

Return $Extensions 
    | Foreach {
        $CurrentExtension = $_.ToLower() # Transform extension to lower case
        $CmdParams.Filter = "*.$CurrentExtension" # Set the filter to the current extension
        Return @{ $_ = $(Get-ChildItem @CmdParams | Measure).Count } # Return an object with the extension as the key and the count obtained as the value
}
Enter fullscreen mode Exit fullscreen mode

Summarizing

Passing parameters to PowerShell commands and scripts is simple. We can use the standard way for command calls or simple scripts. And, also, we can use more advanced techniques that allow us to have a cleaner code and implement modifications in a simpler way.

Using hashtables is an easy way to visualize the parameter values of the commands we invoke. In addition, it structures our code making it more readable for others or even for ourselves after a while.

The code for this article can be found in this gist.

Feedback

If you liked this article, do not forget to click on the heart or the unicorn and share it with your friends and colleagues. Leave me your comments at the bottom about what you liked or how to improve and if you want me to write about other topics send me a direct message to my Twitter account.

Credits

The header image comes from Unsplash and is courtesy of Markus Spiske.

Top comments (0)