---
title: "PowerShell Parameters: Unlock the Power of Scripting"
description: "Discover the importance of PowerShell parameters and how to use them effectively to create versatile and powerful scripts."
canonical: "https://adamtheautomator.com/powershell-parameter/"
---

# PowerShell Parameters: Unlock the Power of Scripting

> Discover the importance of PowerShell parameters and how to use them effectively to create versatile and powerful scripts.

Source: https://adamtheautomator.com/powershell-parameter/

---

ATA Learning

Tap to hide

[

ATA Learning

](/)

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Search for:  

*   [](https://twitter.com/adbertram)
*   [](https://github.com/Adam-the-Automator)
*   [](https://www.linkedin.com/company/adam-the-automator-llc)
*   [](/feed/)

![PowerShell Parameters: Unlock the Power of Scripting](https://adamtheautomator.com/wp-content/uploads/2019/07/photo-1498050108023-c5249f4df085.jpg)

# PowerShell Parameters: Unlock the Power of Scripting

[![](https://secure.gravatar.com/avatar/d0b9d42e21e5622713f8b693aa5c0f9244d5f7dd200ed29b8398f52dee5de337?s=192&d=mm&r=g)Adam Bertram](https://adamtheautomator.com/author/adam-bertram/)1 February 202113 min. read

Categories: [IT Ops](/category/it-ops/)

Tags:[PowerShell](/tag/powershell/)

Table of Contents

*   [Why Do You Need a Parameter?](#introduction)
*   [When to Use a PowerShell Parameter](#when-to-use-a-parameter)
*   [Creating a Simple PowerShell Parameter](#creating-a-simple-parameter)
*   [The Mandatory Parameter Attribute](#the-mandatory-parameter-attribute)
*   [PowerShell Parameter Validation Attributes](#parameter-validation-attributes)
*   [Learning by Example](#h-learning-by-example)
*   [Using the ValidateSet Parameter Validation Attribute](#h-using-the-validateset-parameter-validation-attribute)
*   [Parameter Sets](#parameter-sets)
*   [The Default Parameter Set](#h-the-default-parameter-set)
*   [Pipeline Input](#pipeline-input)
*   [The “Old” Way Using a Loop](#h-the-old-way-using-a-loop)
*   [Building Pipeline Input for Parameters](#h-building-pipeline-input-for-parameters)
*   [Don’t Forget the Process Block!](#h-don-t-forget-the-process-block)
*   [Resources](#resources)

All PowerShell commands can have one or more parameters, sometimes called arguments. If you’re not using PowerShell parameters in your PowerShell functions, you’re not writing good PowerShell code!

In this article, you’re going to learn just about every facet of creating and use PowerShell parameters or arguments!

> _This is a sample from my book PowerShell for SysAdmins. If you want to learn PowerShell or learn some tricks of the trade, [check it out](https://nostarch.com/powershellsysadmins)!_

## Why Do You Need a Parameter?

When you begin to create functions, you’ll have the option to include parameters or not and how those parameters work.

Let’s say you have a function that installs Microsoft Office. Maybe it calls the Office installer silently inside of the function. What the function does, doesn’t matter for our purposes. The basic function looks like this with the name of the function and the script block.

```powershell
function Install-Office {
    ## run the silent installer here
}
```

In this example, you just ran `Install-Office` without parameters and it does it’s thing.

It didn’t matter whether the `Install-Office` function had parameters or not. It apparently didn’t have any mandatory parameters; else, PowerShell would not have let us run it without using a parameter.

## When to Use a PowerShell Parameter

Office has lots of different versions. Perhaps you need to install Office 2013 and 2016. Currently, you have no way to specify this. You could change the function’s code every time you wanted to change the behavior.

For example, you could create two separate functions to install different versions.

```powershell
function Install-Office2013 {
    Write-Host 'I installed Office 2013. Yippee!'
}

function Install-Office2016 {
    Write-Host 'I installed Office 2016. Yippee!'
}
```

Doing this works, but it’s not scalable. It forces you to create a separate function for every single version of Office that comes out. You’re going to have to duplicate lots of code when you don’t have to.

Instead, you need a way to pass in different values at runtime to change the function’s behavior. How do you do this?

Yep! Parameters or what some people call arguments.

Since we’d like to install different versions of Office without changing the code every time, you have to add at least one parameter to this function.

Before you quickly think up a PowerShell parameter to use, it’s essential first to ask yourself a question; “What is the smallest change or changes you expect will be needed in this function?”.

Remember that you need to rerun this function without changing any of the code inside of the function. In this example, the parameter is probably clear to you; you need to add a `Version` parameter. But, when you’ve got a function with tens of lines of code, the answer won’t be too apparent. As long as you answer that question as precisely as possible, it will always help.

So you know you need a `Version` parameter. Now what? You now can add one, but like any great programming language, there are multiple ways to skin that cat.

In this tutorial, I’ll show you the “best” way to create parameters based on my nearly decade of experience with PowerShell. However, know that this isn’t the _only_ way to create a parameter.

> _There is such a thing as positional parameters. These parameters allow you to pass values to parameters without specifying the parameter name. Positional parameters work but aren’t considered “best practice.” Why? Because they are harder to read especially when you have many parameters defined on a function._

## Creating a Simple PowerShell Parameter

Creating a parameter on a function requires two primary components; a _param block_ and the parameter itself. A _param_ block is defined by the `param` keyword followed by a set of parentheses.

```powershell
function Install-Office {
    [CmdletBinding()]
    param()
    Write-Host 'I installed Office 2016. Yippee!'
}
```

At this point, the function’s actual functionality hasn’t changed a bit. We’ve just put together some plumbing, preparing us for the first parameter.

Once we’ve got the _param_ block in place, you’ll now create the parameter. The method that I’m suggesting you create a parameter includes the `Parameter` block, followed by the _type_ of parameter, it is followed by the parameter variable name below.

```powershell
function Install-Office {
    [CmdletBinding()]
    param(
        [Parameter()]
        [string]$Version
    )
    Write-Host 'I installed Office 2016. Yippee!'
}
```

We’ve now created a function parameter in PowerShell but what exactly happened here?

The `Parameter` block is an optional yet recommended piece of every parameter. Like the _param_ block, it is “function plumbing,” which prepares the parameter for adding additional functionality. The second line is where you define the type of parameter it is.

In this case, we’ve chosen to _cast_ the `Version` parameter to a string. Defining an explicit type means that any value passed to this parameter will always attempt to be “converted” to a string if it’s not already.

The type isn’t mandatory but is highly encouraged. Explicitly defining the type of parameter it is will significantly reduce many unwanted situations down the road. Trust me.

Now that you’ve got the parameter defined, you can run the `Install-Office` command with the `Version` parameter passing a version string to it like _2013_. The value passed to the `Version` parameter is sometimes referred to as parameters’ arguments or values.

```powershell
PS> Install-Office -Version 2013
I installed Office 2016. Yippee!
```

What’s going on here anyway? You told it you wanted to install version 2013, but it’s still telling you it’s installed 2016. When you add a parameter, you must then remember to change the function’s code to a variable. When the parameter is passed to the function, that variable will be expanded to be whatever value was passed.

Change the static text of _2016_ and replace it with the `Version` parameter variable and converting the single quotes to double quotes so the variable will expand.

```powershell
function Install-Office {
    [CmdletBinding()]
    param(
        [Parameter()]
        [string]$Version
    )
    Write-Host "I installed Office $Version. Yippee!"
}
```

Now you can see that whatever value you pass to the `Version` parameter will then get passed into the function as the `$Version` variable.

## The Mandatory Parameter Attribute

Recall that I mentioned the `[Parameter()]` line was just “function plumbing” and needed to prepare the function for further work? Adding parameter attributes to a parameter is the additional work I was speaking about earlier.

A parameter doesn’t have to be a placeholder for a variable. PowerShell has a concept called _parameter attributes_ and _parameter validation_. Parameter attributes change the behavior of the parameter in a lot of different ways.

For example, one of the most common parameter attributes you’ll set is the `Mandatory` keyword. By default, you could call the `Install-Office` function without using the `Version` parameter and it would execute just fine. The Version parameter would be optional. Granted, it wouldn’t expand the $Version variable inside the function because there was no value, but it would still run.

Many times when creating a parameter, you’ll want the user always to use that parameter. You’ll be depending on the value of the parameter inside of the function’s code somewhere, and if the parameter isn’t passed, the function will fail. In these cases, you want to force the user to pass this parameter value to your function. You want that parameter to become _mandatory_.

Forcing users to use a parameter is simple once you’ve got the basic framework built as you have here. You have to include the keyword `Mandatory` inside of the parameter’s parentheses. Once you have that in place, executing the function without the parameter will halt execution until a value has been input.

```powershell
function Install-Office {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Version
    )
    Write-Host "I installed Office $Version. Yippee!"
}

PS> Install-Office
cmdlet Install-Office at command pipeline position 1
Supply values for the following parameters:
Version:
```

The function will wait until you specify a value for the `Version` parameter. Once you do so and hit _Enter_, PowerShell will execute the function and move on. If you provide a value for the parameter, PowerShell will not prompt you for the parameter every time.

## PowerShell Parameter Validation Attributes

Making a parameter mandatory is one of the most common parameter attributes you can add, but you can also use _parameter validation_ attributes. In programming, it’s always essential to restrict user input as tightly as possible. Limiting the information that users (or even you!) can pass to your functions or scripts will eliminate unnecessary code inside your function that has to account for all kinds of situations.

### Learning by Example

For example, in the `Install-Office` function, I demonstrated passing the value `2013` to it because I knew it would work. I wrote the code! I’m _assuming_ (never do this in code!) that it’s obvious that anyone who knows anything would specify the version as either 2013 or 2016. Well, what’s obvious to you may not be so obvious to other people.

If you want to get technical about versions, it’d probably be more accurate to specify the 2013 version as `15.0` and 2016 as `16.0` if Microsoft were still using the versioning schema, they have in the past. But what if, since you’re assuming they’re going to specify a version of 2013 or 2016, you’ve got the code inside of the function that looks for folders with those versions in it or something else?

Below is an example of where you may be using the `$Version` string in a file path. If someone passes a value that doesn’t complete a folder name of `Office2013` or `Office2016`, it will fail or do something worse, like remove unexpected folders or change things you didn’t account for.

```powershell
function Install-Office {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Version
    )
    Get-ChildItem -Path "\\SRV1\Installers\Office$Version"
}
PS> Install-Office -Version '15.0'
Get-ChildItem : Cannot find path '\SRV1\Installers\Office15.0' because it does not exist.
At line:7 char:5

Get-ChildItem -Path "\\SRV1\Installers\Office$Version"

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

CategoryInfo          : ObjectNotFound: (\SRV1\Installers\Office15.0:String) [Get-ChildItem], ItemNotFoundExcep
tion
FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
```

To limit the user to what you expect them to input, you can add some PowerShell parameter validation.

### Using the ValidateSet Parameter Validation Attribute

There are various kinds of parameter validation you can use. For a full listing, run `[Get-Help](https://adamtheautomator.com/powershell-get-help/) about_Functions_Advanced_Parameters`. In this example, the [`ValidateSet`](https://adamtheautomator.com/powershell-validateset/ "ValidateSet") attribute would probably be the best.

The `ValidateSet` validation attribute allows you to specify a list of values that are allowed as the parameter value. Since we’re only accounting for the string _2013_ or _2016_, I’d like to ensure that the user can only specify these values. Otherwise, the function will fail immediately, notifying them of why.

You can add parameter validation attributes right under the original `Parameter` keyword. In this example, inside the parameter attribute’s parentheses, you have an array of items; _2013_ and _2016_. A parameter validation attribute tells PowerShell that the only values that are valid for `Version` are _2013_ or _2016_. If you try to pass something besides what’s in the set, you’ll receive an error notifying you that you only have a specific number of options available.

```powershell
function Install-Office {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateSet('2013','2016')]
        [string]$Version
    )
    Get-ChildItem -Path "\\SRV1\Installers\Office$Version"

}
PS> Install-Office -Version 15.0
Install-Office : Cannot validate argument on parameter 'Version'. The argument "15.0" does not belong to the set
"2013,2016" specified by the ValidateSet attribute. Supply an argument that is in the set and then try the command
again.
At line:1 char:25

Install-Office -Version 15.0

                    ~~~~

CategoryInfo          : InvalidData: (:) [Install-Office], ParameterBindingValidationException
FullyQualifiedErrorId : ParameterArgumentValidationError,Install-Office
```

The `ValidateSet` attribute is a common validation attribute to use. For a complete breakdown of all of the ways parameter values can be restricted, check out the `Functions_Advanced_Parameters` help topic by running `Get-Help about_Functions_Advanced_Parameters`.

## Parameter Sets

Let’s say you only want certain PowerShell parameters used with other parameters. Perhaps you’ve added a `Path` parameter to the `Install-Office` function. This path will install whatever version the installer is. In this case, you don’t want the user using the `Version` parameter.

You need parameter sets.

Parameters can be grouped into sets that can only be used with other parameters in the same set. Using the function below, you can now use both the `Version` parameter and the `Path` parameter to come up with the path to the installer.

```powershell
function Install-Office {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateSet('2013','2016')]
        [string]$Version,
        
        [Parameter(Mandatory)]
        [string]$Path
    )
    
    if ($Version) {
        Get-ChildItem -Path "\\SRV1\Installers\Office$Version"
    } elseif ($Path) {
        Get-ChildItem -Path $Path
    }
}
```

This poses a problem, though, because the user _could_ use both parameters. Besides, since both parameters are mandatory, they’re going to be forced to use both when that’s not what you want. To fix this, we can place each parameter in a parameter set like below.

```powershell
function Install-Office {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ParameterSetName = 'ByVersion')]
        [ValidateSet('2013','2016')]
        [string]$Version,
        
        [Parameter(Mandatory, ParameterSetName = 'ByPath')]
        [string]$Path
    )
    
    if ($Version) {
        Get-ChildItem -Path "\\SRV1\Installers\Office$Version"
    } elseif ($Path) {
        Get-ChildItem -Path $Path
    }
}
```

By defining a parameter set name on each parameter, this allows you to control groups of parameters together.

### The Default Parameter Set

What if the user tries to run `Install-Office` with no parameters? This isn’t accounted for, and you’ll see a friendly error message.

![No parameter set](/wp-content/uploads/2019/07/image-5.png)

No parameter set

To fix this, you’ll need to define a default parameter set within the `CmdletBinding()` area. This tells the function to pick a parameter set to use if no parameters were used explicitly changing `[CmdletBinding()]` to `[CmdletBinding(DefaultParameterSetName = 'ByVersion')]`

Now, whenever you run `Install-Office`, it will prompt for the `Version` parameter since it will be using that parameter set.

## Pipeline Input

In the examples so far, you’ve been creating functions with a PowerShell parameter that can only be passed using the typical -ParameterName Value syntax. But, as you’ve learned already, PowerShell has an intuitive pipeline that allows you to seamlessly pass objects from one command to another without using the “typical” syntax.

When you use the pipeline, you “chain” commands together with the pipe symbol `|` allowing a user to send the output of a command like `Get-Service` to `Start-Service` as a shortcut for passing the `Name` parameter to `Start-Service`.

### The “Old” Way Using a Loop

In the custom function you’re working with; you’re installing Office and have a `Version` parameter. Let’s say you’ve got a list of computer names in a CSV file in one row with the version of Office that needs to be installed on them in the second row. The CSV file looks something like this:

```powershell
ComputerName,Version
PC1,2016
PC2,2013
PC3,2016
```

You’d like to install the version of Office that’s next to each computer on that computer.

First, you’ll have to add a `ComputerName` parameter onto the function to pass a different computer name in for each iteration of the function. Below I’ve created some pseudocode that represents some code that may be in the fictional function and added an `Write-Host` instance to see how the variables expand inside the function.

```powershell
function Install-Office {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateSet('2013','2016')]
        [string]$Version,
    
        [Parameter()]
        [string]$ComputerName
    )

    <#
    ## Connect to the remote with some code here
    Invoke-Command -ComputerName $ComputerName -ScriptBlock {
        ## Do stuff to install the version of office on this computer
        Start-Process -FilePath 'msiexec.exe' -ArgumentList 'C:\Setup\Office{0}.msi' -f $using:Version
    }
    #>
    Write-Host "I am installing Office version [$Version] on computer [$ComputerName]"
}
```

Once you’ve got the `ComputerName` parameter added to the function; you could make this happen by reading the CSV file and passing the values for the computer name and the version to the `Install-Office` function.

```powershell
$computers = Import-Csv -Path 'C:\ComputerOfficeVersions.csv'
foreach ($pc in $computers) {
    Install-Office -Version $_.Version -ComputerName $_.ComputerName
}
```

### Building Pipeline Input for Parameters

This method of reading the CSV rows and using a loop to pass each row’s properties to the function is the “old” way of doing it. In this section, you want to forego the `foreach` loop entirely and use the pipeline instead.

As-is, the function doesn’t support the pipeline at all. It would make intuitive sense to assume that you could pass each computer name and version to the function using the pipeline. Below, we’re reading the CSV and directly passing it to `Install-Office,` but this doesn’t work.

```powershell
PS> Import-Csv -Path 'C:\ComputerOfficeVersions.csv' | Install-Office
```

You can assume all you want, but that doesn’t just make it work. We’re getting prompted for the `Version` parameter when you know that `Import-Csv` is sending it as an object property. Why isn’t it working? Because you haven’t added any pipeline support yet.

There are two kinds of pipeline input in a PowerShell function; _ByValue_ (entire object) and _ByPropertyName_ (a single object property). Which do you think is the best way to stitch together the output of `Import-Csv` to the input of `Install-Office`?

Without any refactoring at all, you could use the `ByPropertyName` method since, after all, `Import-Csv` is already returning the properties `Version` and `ComputerName` since they’re columns in the CSV.

To add pipeline support to a custom function is much simpler than you may be thinking. It’s merely a parameter attribute represented with one of two keywords; `ValueFromPipeline` or `ValueFromPipelineByPropertyName`.

In the example, you’d like to bind the `ComputerName` and `Version` properties returned from `Import-Csv` to the `Version` and `ComputerName` parameters of `Install-Office` so you’ll be using `ValueFromPipelineByPropertyName`.

Since we’d like to bind both of these parameters, you’ll add this keyword to both parameters as shown below and rerun the function using the pipeline.

```powershell
function Install-Office {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ValueFromPipelineByPropertyName)]
        [ValidateSet('2013','2016')]
        [string]$Version,
        
        [Parameter(ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [string]$ComputerName
)

    <#
    ## Connect to the remote with some code here
    Invoke-Command -ComputerName $ComputerName -ScriptBlock {
        ## Do stuff to install the version of office on this computer
        Start-Process -FilePath 'msiexec.exe' -ArgumentList 'C:\Setup\Office{0}.msi' -f $using:Version
    }
    #>
    Write-Host "I am installing Office version [$Version] on computer [$ComputerName]"
}
```

That’s weird. It only ran for the last row in the CSV. What’s going on? It just executed the function for the last row because you skipped over a concept that isn’t required when building functions without pipeline support.

### Don’t Forget the Process Block!

When you need to create a function that involves pipeline support, you must include (at a minimum) an “embedded” block inside of your function called. `process`. This process block tells PowerShell that when receiving pipeline input, to run the function for every iteration. By default, it will only execute the last one.

You could technically add other blocks like `begin` and `end` as well, but scripters don’t use them near as often.

To tell PowerShell to execute this function for every object coming in, I’ll add a `process` block that includes the code inside of that.

```powershell
function Install-Office {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ValueFromPipelineByPropertyName)]
        [ValidateSet('2013','2016')]
        [string]$Version,
        
        [Parameter(ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [string]$ComputerName
)

    process {
        <#
        ## Connect to the remote with some code here
        Invoke-Command -ComputerName $ComputerName -ScriptBlock {
            ## Do stuff to install the version of office on this computer
            Start-Process -FilePath 'msiexec.exe' -ArgumentList 'C:\Setup\Office{0}.msi' -f $using:Version
        }
        #>
        Write-Host "I am installing Office version [$Version] on computer [$ComputerName]"
    }
}
```

Now you can see that each object’s `Version` and `ComputerName` properties returned from `Import-Csv` was passed to `Install-Office` and _bound_ to the `Version` and `ComputerName` parameters.

## Resources

To dive deeper into how function parameters work, check out my [blog post on PowerShell functions](https://adamtheautomator.com/powershell-functions/).

I also encourage you to check my Pluralsight course entitled [Building Advanced PowerShell Functions and Modules](https://pluralsight.pxf.io/yPVKB) for an in-depth breakdown of everything there is to know about PowerShell functions, function parameters, and PowerShell modules.

Share this article

[Share on X](https://twitter.com/intent/tweet?url=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-parameter%2F&text=PowerShell%20Parameters%3A%20Unlock%20the%20Power%20of%20Scripting)[Share on Facebook](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-parameter%2F)[Share on LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-parameter%2F)

## Related Posts

![](https://adamtheautomator.com/wp-content/uploads/2026/06/26995-troubleshoot-dns-issues-powershell-codex.webp)

### [Troubleshoot DNS Issues with PowerShell](/troubleshoot-dns-issues-powershell/)

Troubleshoot DNS issues with PowerShell by testing name resolution, DNS client settings, cache entries, and network connectivity in a repeatable workflow.

![](https://adamtheautomator.com/wp-content/uploads/2025/10/image_2025-10-24_095322075.png)

### [Migrating from PowerShell 6 to 7.5: Breaking Changes/New Features](/migrating-powershell-6-to-7-5/)

Migrate from PowerShell Core 6 to 7.5: breaking changes, features, and testing tips.

![](https://adamtheautomator.com/wp-content/uploads/2025/06/featured-image-6.png)

### [How to Add Timeouts to Pester Tests with PowerShell Runspaces](/pester-test-timeout-runspaces/)

Prevent Pester tests from hanging indefinitely using PowerShell runspaces. Learn to handle variable scoping, module loading, TestDrive access, and stream capture challenges with timeout protection.

## Categories

*   [IT Ops](/category/it-ops/)
*   [Cloud](/category/cloud/)
*   [DevOps](/category/devops/)
*   [Home Ops](/category/home-ops/)
*   [Information Security](/category/infosec/)
*   [Software Development](/category/software-development/)

## Site

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Copyright 2026© ATA Learning | [Privacy Policy](/privacy/)
