An easy way to provide parameters in PowerShell
Tags: powershell, programing, script
Published: 2022-04-04 07:10:13

> _My nickname in the networks is [__Coding Bugs__][Dashboard], and I have been working as a software architect and developer from 2004. In my [dashboard][Dashboard], you will find articles about programming languages, programming techniques, and other concepts that will help you improve._

You already know that [PowerShell][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][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.

```PowerShell
$ Get-ChildItem -Path C:\ -Filter *.txt 
# Returns all existing text files in C:
```

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.

```PowerShell
$ 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:
```

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.

```PowerShell
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
}
```


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.

```PowerShell
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
}
```

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](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`.

```PowerShell
# 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
```

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

```PowerShell
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
}
```

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__](https://dev.to/codbugs/learning-open-closed-principle-by-example-1628), 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.

```PowerShell
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
}
```


__Summarizing__

Passing parameters to [PowerShell](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_](https://gist.github.com/codbugs/d18b9b2d958c48d94f253535bb3896fe).

__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][Twitter] account.

__Credits__

The header image comes from [Unsplash][Unsplash] and is courtesy of [Markus Spiske](https://unsplash.com/@markusspiske).

[PowerShell]: https://docs.microsoft.com/es-es/powershell/scripting/overview?view=powershell-7.2 "PowerShell"
[GitHub Profile]: https://github.com/codbugs "Mi perfil en GitHub"
[Unsplash]: https://unsplash.com/ "Unsplash"
[Twitter]: https://twitter.com/BugsCoding
[Dashboard]: https://dev.to/codbugs "Dashboard"