I am currently trying to get a command that I know works in CLI to run through a PowerShell Ise script but it will not allow me to run it as it is picking up a part of the command as a parameter.
Start-Process ssh -o KexAlgorithms=diffie-hellman-group14-sha1 Username@IP
Start-Process : Parameter cannot be processed because the parameter name 'o' is ambiguous. Possible matches include: -OutVariable -OutBuffer.
At line:1 char:30
+ Start-Process ssh -o KexAlgorithms=diffie-hellman-group14- ...
+ ~~
+ CategoryInfo : InvalidArgument: (:) [Start-Process], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameter,Microsoft.PowerShell.Commands.StartProcessCommand
What is supposed to happen is the cli should pop up and allow me to access a switch which as i have stated earlier works when I manually input it into Cli.
68 gold badges673 silver badges862 bronze badges
asked Aug 7, 2023 at 10:47
As Mathias notes, you must quote the list of arguments to pass through to ssh
:
# Note the '...' around the entire list of pass-through arguments.
# Use "..." if you need string interpolation.
# Use *embedded* "..." quoting for arguments that contain spaces, for instance.
Start-Process ssh '-o KexAlgorithms=diffie-hellman-group14-sha1 Username@IP'
There are two problems with your approach:
Because
-o
is unquoted,Start-Process
interprets it as one of its parameter names.Thus, pass-through arguments that happen to look like PowerShell parameters, must be quoted, e.g. – if passed individually (which isn’t advisable; see next point) –
'-o'
.As for the error you saw:
PowerShell’s “elastic syntax” allows you to use parameter-name prefixes for brevity, so you don’t have to type / tab-complete the full parameter name.
However, such a prefix must be unambiguous; if it isn’t, PowerShell complains and lists the candidate parameter names, such as
-OutVariable
and-OutBuffer
for-o
in this case. Thus, prefix-outv
would have avoided the ambiguity, for instance. Also note that some parameters have unambiguous short aliases, such as-ov
for-OutVariable
.
More fundamentally, trying to pass multiple pass-through arguments individually to
Start-Process
causes a syntax error:It is best to specify all pass-through arguments as a single, quoted string, using embedded double-quoting, if necessary.
- This answer explains the syntax problem in detail, but the short of it is that
Start-Process
expects pass-through arguments via a single argument, passed to its-ArgumentList
(-Args
) parameter, which is the 2nd positional parameter. - This answer explains why – even though you can specify the pass-through arguments individually as the elements of an array (
,
-separated), a long-standing bug makes the single-string approach preferable.
- This answer explains the syntax problem in detail, but the short of it is that
answered Aug 7, 2023 at 14:07
68 gold badges673 silver badges862 bronze badges
SYNOPSIS
Updates the environment variables for the current PowerShell session with any environment variable changes that may have occurred during script execution.
SYNTAX
DESCRIPTION
Environment variable changes that take place during script execution are not visible to the current PowerShell session.
Use this function to refresh the current PowerShell session with all environment variable settings.
EXAMPLES
EXAMPLE 1
PARAMETERS
-LoadLoggedOnUserEnvironmentVariables
Accept pipeline input
Accept wildcard characters
-ContinueOnError
Continue if an error is encountered.
Default is: $true.
Accept pipeline input
Accept wildcard characters
CommonParameters
INPUTS
None
You cannot pipe objects to this function.
OUTPUTS
None. This function does not return objects.
NOTES
This function has an alias: Refresh-SessionEnvironmentVariables
Syntax Basics
Get-MgTeam [-TeamId <String>] [-All] [-Filter <String>] [-Search <String>] [-Property <String[]>] [<CommonParameters>]
Parameters Explanation
- -TeamId <String>: Specifies the ID of the Team you want to retrieve. If you know the specific Team ID, you can use this parameter to get details about that particular Team.
- -All: Retrieves all Teams in the organization. This parameter is useful when you need to get information about every Team.
- -Filter <String>: Filters the Teams based on specific criteria. The filter must follow the OData query standards.
- -Search <String>: Searches for Teams based on a specified string. This is useful for finding Teams that match a certain keyword in their display name or other searchable properties.
- -Property <String[]>: Specifies which properties to include in the results. By default, the cmdlet returns a standard set of properties, but you can use this parameter to request specific properties.
- <CommonParameters>: Supports common parameters used by all PowerShell cmdlets, such as -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, and -Verbose. These parameters help in controlling the cmdlet’s behavior and output.
Usage Examples
Example 1: Retrieve All Teams
Get-MgTeam -All
This command retrieves all Teams in the organization.
Example 2: Retrieve a Specific Team by Team ID
Get-MgTeam -TeamId "team-id"
Replace “team-id” with the actual ID of the Team you want to retrieve.
Example 3: Filter Teams Based on a Property
Get-MgTeam -Filter "displayName eq 'MSFT'"
This command retrieves Teams with the display name “MSFT”.
Example 4: Retrieve Specific Properties of All Teams
Get-MgTeam -All -Property "id", "displayName"
This command retrieves only the ID, display name, and description properties of all Teams.
Simple Scripts Illustrating Get-MgTeam Cmdlet Usage
Script to List All Teams and Display Their Names and Descriptions
$teams = Get-MgTeam -All -Property "displayName", "description"
$teams | ForEach-Object {
"Team Name: $($_.displayName) Description: $($_.description)"
}
This script fetches all the Teams within the tenant, loops through them, and displays the team name and description.
Script to Find Teams Containing “Sales” in Their Display Name
$teams = Get-MgTeam -All | Where-Object { $_.displayName -like '*Sales*' }
$teams | ForEach-Object {
"Team ID: $($_.Id) Team Name: $($_.displayName)"
}
This script fetches all the Teams that contain ‘Sales’ in the display name, loops through them, and displays their team ID and name.
Possible Errors
Authentication Error
Get-MgTeam : Authorization_RequestDenied
Invalid Team ID
Get-MgTeam : Resource 'team-id' does not exist or one of its queried reference-property objects are not present.
Verify that the Team ID is correct and that the Team exists in your organization.
Filter Syntax Error
Get-MgTeam : Invalid filter clause
Ensure that your filter syntax adheres to the OData query standards. Refer to the Microsoft Graph documentation for valid filter options.
Cmdlet Tips
- Use the -All Parameter: When you need to retrieve information about all Teams, use the
-All
parameter to ensure you get a complete list. - Optimize Filters and Searches: Using filters and search parameters can significantly reduce the amount of data returned, making your scripts more efficient.
- Select Specific Properties: When you only need certain properties, use the
-Property
parameter to specify which ones. This reduces the amount of data processed and can improve performance. - Error Handling: Always include error handling in your scripts to manage common issues like authentication problems or invalid input.
Conclusion
Related Articles:
Parameters
When viewing help for a command, several different conventions are used to describe when a parameter is required and how it should be used. These conventions include:
- Optional parameters, where parameter names and arguments are enclosed in a single pair of square brackets.
- Optional positional parameters – the same as an optional parameter but with the parameter name also enclosed in square brackets.
- Mandatory parameters, where the parameter name and argument are not bracketed.
- Mandatory positional parameters, where the parameter name is in square brackets, but the argument is not.
Optional parameters
Optional parameters are surrounded by square brackets. If a parameter is used, a value (or argument) must be supplied. A fragment of the syntax for Get-Help
is shown below. It shows that a Category
parameter is available and that the parameter is optional.
SYNTAX
... [- <[]>] ...
HelpFile
The command above filters help documents to help files, the “about” documents.
Optional positional parameters
An optional positional parameter is surrounded by square brackets, like an optional parameter. In addition, the parameter name itself is enclosed in square brackets. This indicates that the parameter is optional and that if it is used, the parameter and value can be supplied, or just the value without the parameter name.
It is not uncommon to see an optional positional parameter as the first parameter:
SYNTAX
[[-] <[]>] ...
pwsh
pwsh
The output from the two commands is identical. This includes the parameter name, which, even when it is optional, is less ambiguous and therefore a recommended practice.
Mandatory parameters
SYNTAX
<string> ...
In this case, the Filter
parameter name must be used, and it must be given a value. For example, to supply a Filter
for the command, the Filter
parameter must be explicitly written:
'sAMAccountName -eq "SomeName"'
Mandatory positional parameters
Mandatory parameters must always be supplied, but in some cases, it is possible to supply the value without using the parameter name. The parameter the value applies to is based on position.
Parameters that are mandatory and accept values based on position are written with the parameter name only in square brackets, as shown here:
SYNTAX
[-] <ADUser> ...
useridentity
useridentity
In both cases, the supplied value fills the Identity
parameter.
The Add-Content
command has a parameter set that uses more than one mandatory positional parameter. The first part of the syntax for the parameter set is shown here:
[-] <string[]> [-] <object[]>
c:\temp\file.txt
c:\temp\file.txt
c:\temp\file.txt
c:\temp\file.txt
c:\temp\file.txt
The first of these is easiest to read as both parameters are explicitly named and tends to be the better style to use.
Each of the parameters so far has required an argument, a value. PowerShell also allows parameters that do not require arguments.
Switch parameters
A switch parameter does not require an argument. If the switch is present, the value is equivalent to true, while if the switch parameter is absent, it is equivalent to false.
As with the other types of parameters, optional use is denoted by using square brackets around the parameter.
Switch parameters are typically used to toggle a behavior on. For example, Recurse
is a switch parameter for Get-ChildItem
:
SYNTAX
... [-] ...
Using the switch instructs Get-ChildItem
to recurse when listing the content of a directory, as shown here:
c:\windows
It is possible to supply a value for a switch parameter from a variable. This might be desirable when writing a script where the presence of a switch parameter is based on another variable. As switch parameters do not normally expect a value, a syntax change is required:
# Code which determines if Recurse is required
=
c:\windows :
In some cases, a switch parameter will default to present, and it may be desirable to stop the parameter from applying. The most common example is the Confirm
parameter, which will be explored later in this chapter.
Parameter values
[-] <String>
Win32_Service
ClassName
must always be a single value. If more than one value is supplied, an error will be displayed:
> Win32_Service, Win32_Process
: Cannot convert to the required by . Specified method is not supported.
[[-] <[]>]
In this case, the parameter type is an array of strings. An array may consist of one or more strings separated by a comma:
PS> Get-Service -Name WinDefend, WlanSvc
Status Name DisplayName
------ ---- -----------
Running WinDefend Windows Defender Antivirus Service
Running WlanSvc WLAN AutoConfig
PowerShell will attempt to coerce any value supplied into the required type. A single string can be used as an argument for the parameter. PowerShell will convert the single value into an array of strings with one element. For example:
WinDefend
Each of the commands used in this section will allow the value to be entered without the parameter name. For example, for Get-Service
, the Name
parameter can be omitted:
WinDefend
WinDefend, WlanSvc
When using positional parameters, PowerShell can use the type to determine which parameter (and which parameter set) should be used.
Parameter sets
In PowerShell, a parameter set is a set of parameters that may be used together when running a command.
Many of the commands in PowerShell have more than one parameter set. This was seen when looking at the Syntax
section when using Get-Help
.
For example, the Stop-Process
command has three parameter sets:
SYNTAX
[-] <Int32[]> [-] [-] [-] [-] [<>]
[-] <[]> [-] [-] [-] [-] [<>]
[-] [-] <String[]> [-] [-] [<>]
PowerShell will attempt to find a matching parameter set based on the parameters and values it is given.
The parameter sets for Stop-Process
have two different sets that will accept a value by position:
[-] <Int32[]>
[-] <[]>
The first expects an ID as an integer. The second expects a Process
object, an object returned by the Get-Process
command.
= notepad
|
Get-Help Stop-Process -Parameter *
Get-Help Stop-Process -Full
Examples are likely to show how to use the parameters with a pipeline.
If Get-Help
is incomplete, Get-Command
can be used to explore parameters:
Each of the parameter sets here also shows that the command supports common parameters.
Common parameters
Common parameters are used to control some of the standardized functionality PowerShell provides, such as verbose output and actions to take when errors occur.
When looking at the syntax, most commands will end with a CommonParameters
item:
SYNTAX
... [<>]
Debug
ErrorAction
ErrorVariable
InformationAction
InformationVariable
OutBuffer
OutVariable
PipelineVariable
Verbose
WarningAction
WarningVariable
Each is described in the about_CommonParameters
document:
about_CommonParameters
The help document is also available online: .
For example, Stop-Process
does not explicitly state that it has a Verbose
switch parameter, but since Verbose
is a common parameter, it may be used. This can be seen if notepad
is started and immediately stopped:
Start-Process notepad -Verbose -PassThru | Stop-Process -Verbose
VERBOSE: Performing the operation "Stop-Process" on target "notepad (5592)".
Not so verbose
Just because a command supports common parameters does not mean it uses them. For example, Get-Process
supports the Verbose
parameter, yet it does not write any verbose output when Verbose
is specified.
In addition to common parameters, PowerShell also offers specialized parameters for commands that make changes.
Confirm and WhatIf
Confirm
and WhatIf
can be used with commands that make changes to files, variables, data, and so on. These parameters are often used with commands that use the verbs New
, Set
, or Remove
, but the parameters are not limited to specific verbs.
about_Preference_Variables
The Confirm
switch parameter is used to control automatic prompting for high impact operations by default.
Confirm and ConfirmPreference
The Confirm
switch parameter and the ConfirmPreference
variable can be used to decide if a command should prompt. The decision to prompt is based on a comparison of ConfirmPreference
with ConfirmImpact
when set by a command author.
ConfirmPreference
has four possible values:
High
: Prompts when command impact isHigh
(default)Medium
: Prompts when command impact isMedium
orHigh
Low
: Prompts when command impact isLow
,Medium
, orHigh
None
: Never prompts
ConfirmImpact
uses the same four values.
In Windows PowerShell, the default value for ConfirmImpact
is Medium
.
Finding commands with a specific impact
$metadata.ConfirmImpact -eq 'High'
The Confirm
switch parameter therefore causes a command to prompt before an action is taken; for example, the Confirm
switch parameter forces Remove-Item
to prompt when a file is to be removed:
Set-Location :TEMP
New-Item FileName.txt -Force
Remove-Item FileName.txt -Confirm
Confirm
Are you sure you want to perform this action?
Performing the operation "Remove File" on target "C:\Users\whoami\AppData\Local\Temp\FileName.txt".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):
In the previous example, a confirmation prompt was explicitly requested. In a similar manner, confirmation prompts may be suppressed. For example, the value of the Confirm
parameter may be explicitly set to false
:
FileName.txt
FileName.txt :
The ability to provide a value for the Confirm
parameter is useful for commands that prompt by default; for example, Clear-RecycleBin
prompts by default:
Clear-RecycleBin
Confirm
Are you sure you want to perform this action?
Performing the operation "Clear-RecycleBin" on target " All of the contents of the Recycle Bin".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):
Setting the Confirm
parameter to false
for Clear-RecycleBin
bypasses the prompt and immediately empties the recycle bin:
:
If the Confirm
parameter is not set, whether a prompt is shown is determined by PowerShell. The value of the ConfirmPreference
variable is compared with ConfirmImpact
on a command.
There is more than one way to prompt
ShouldProcess
is affected by the Confirm
parameter and ConfirmPreference
variable.
ShouldContinue
is a forced prompt and is unaffected by the Confirm
parameter and ConfirmPreference
variable.
For example, Remove-Item
will always prompt when attempting to delete a directory that is not empty without supplying the Recurse
parameter.
It is not possible to easily discover commands using forced prompts. Reviewing documentation and testing is vital.
High
In scripts and functions, the ConfirmImpact
setting is part of the CmdletBinding
attribute:
If CmdletBinding
or ConfirmImpact
is not present, the impact is Medium
in Windows PowerShell and None
in PowerShell 7.
The impact of a function or cmdlet may be viewed using the ConfirmImpact
property of a command’s metadata:
A new value for ConfirmPreference
may be set by assigning it in the console; for example, it can be set to Low
. When the preference variable is set to Low
, prompts may be raised by all commands where ConfirmImpact
is Low
, Medium
, or High
:
=
ConfirmPreference and the Confirm parameter
When ConfirmPreference
is set to None
to suppress confirmation prompts, confirmation may still be explicitly requested using the Confirm
parameter; for example:
$ConfirmPreference = 'None'
New-Item NewFile.txt -Confirm
Support for confirmation also provides support for WhatIf
.
WhatIf and WhatIfPreference
WhatIf
is typically used when testing a command. If implemented correctly by a command author, WhatIf
should allow a state-changing command to be run without it making the change.
WhatIf is not always implemented as expected
WhatIf
support for a command is defined by a command author. If the author does not correctly handle the preference, an undesirable change may be made.
The Set-ADAccountPassword
had a bug for a while where WhatIf
was ignored.
Even if a command supports WhatIf
, test it on small sets of data before using the parameter to verify a large change.
The WhatIf
parameter has an associated preference variable, WhatIfPreference
, which may be set to either true
or false
. The default value is false
.
The WhatIf
parameter replaces the confirmation prompt with a simple statement describing the action the command would have taken. Using Remove-Item
as an example again, a message will be displayed, and the file will not be deleted:
Set-Location :TEMP
New-Item FileName.txt -Force
Remove-Item FileName.txt -WhatIf
What if: Performing the operation "Remove File" on target "C:\Users\whoami\AppData\Local\Temp\FileName.txt".
WhatIf
can be explicitly set on a per-command basis by supplying a value in the same manner as the Confirm
parameter. For example, WhatIf
might be explicitly set to false
:
| \test.txt :
Setting WhatIf
in the manner used here might, for instance, be useful if a log file should be written even if other state-changing commands are ignored.
=
=
New-Item NewFile.txt -Confirm
What if: Performing the operation "Create File" on target "Destination: C:\Users\whoami\AppData\Local\Temp\NewFile.txt".
Restarting the console will restore preference variables to their default values.
The behavior of Confirm
and WhatIf
is prescribed by PowerShell. Parameters such as Force
and PassThru
are commonly used in PowerShell but have less well-defined behavior.
Force parameter
The Force
parameter is not one of the common parameters with behavior defined by PowerShell itself, but the parameter is frequently used.
Force
has no fixed usage; the effect of using Force
is a choice a command author must make. Help documentation should state the effect of using Force
with a command. For example, the use of Force
with Remove-Item
is available:
Force
With the Force
parameter, New-Item
overwrites any existing file with the same path. When used with Remove-Item
, the Force
parameter allows the removal of files with Hidden
or System
attributes.
FileName.txt
FileName.txt Attributes
FileName.txt
: You do not have sufficient access rights to perform this operation or the item is hidden, system, or read only. RemoveFileSystemItemUnAuthorizedAccess,Microsoft.PowerShell.Commands.RemoveItemCommand
Adding the Force
parameter allows the operation to continue:
FileName.txt
The Force
parameter may be worth exploring if a command is prompting, and the prompts cannot be suppressed using the Confirm
parameter or the ConfirmPreference
variable.
PassThru parameter
The PassThru
parameter, like Force
, is frequently used, but the behavior of the parameter is not defined by PowerShell. However, PassThru
tends to have predictable behavior.
The PassThru
parameter is typically used with commands that do not normally generate output and is used to force the command to return the object it was working with.
For example, the Start-Process
command does not normally return any output. If PassThru
is used, it will return the process it created:
Start-Process notepad -PassThru
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
9 1.98 6.70 0.05 22636 1 notepad
The PassThru
parameter is therefore useful if more work is to be done with the object after the first command has finished.
For example, PassThru
might be used with Set-Service
, which ordinarily does not return output, allowing a service to be started immediately after another change:
Audiosrv |
Automatic |
Parameters in PowerShell are a complex topic but are a vital part of working with the language.
In my last article, I introduced the Practical PowerShell series. When working on PowerShell scripts, there might come a point where a set of instructions repeats code elsewhere in the script. It is also possible that you might want to incorporate code from elsewhere into your script so that you can easily call the code.
This description might remind you about cmdlets, which have names and, optionally, one or more parameters to control their operation. But what if you want the same thing for your code, like some code with a high reusability factor? Welcome to the world of PowerShell functions. Before we get too deep, let’s define exactly what we are talking about.
Scripts
A script is a text file with a .ps1 extension containing PowerShell code. The code consists of cmdlets and (optionally) functions. You can call scripts in various ways:
- Using the ampersand (& .\Process-Something.ps1). The code runs in a child session with its scope. This means any definitions, such as variables or functions in the script, disappear when the script terminates. When you run interactive PowerShell scripts, you usually omit the ampersand, but when you want to run code pointed to in a variable, you must use this invocation method, e.g., & { Get-ChildItem }
Make sure to understand the difference between using the ampersand at the start and end of a command. Using an ampersand at the end instructs PowerShell to run the code in a background job.
- Using dot-sourcing (e.g. .\Helper-Functions.ps1)., the code runs in the current PowerShell session. This means that any variables or functions you define in the script become available in the session. If these definitions existed before, they would simply be overwritten.
The ability to run PowerShell scripts depends on the local machine’s current execution policy. This is a security measure to prevent malicious scripts from running. Scripts from Microsoft are generally signed, but many community-sourced scripts downloaded from the internet are usually not. You may need to run Set-ExecutionPolicy unrestricted before you can run scripts created by others, provided company policies do not prevent you from modifying the execution policy.
Reusable Code
Function Get-MyReport { #reusable code }
If you create a function that redefines an existing command, the existing definition is overwritten in the current session. The code’s output will be returned to the caller, and you can output the result to the screen or assign it to a variable for further processing.
In addition to the function itself, you can also define parameters for the code contained in the function. The code within the function can then perform its task using information passed through the parameters, as the parameters become variables usable in the context of the function’s code.
Function Get-DistributionGroupInfo( $Identity, $MemberCount) { Get-DistributionGroup $Identity | Select-Object Identity,PrimarySmtpAddress, @{n='MemberCount';e={ If( $MemberCount) { (Get-DistributionGroupMember -Identity $_ | Measure-Object).Count } }}} }
This code is acceptable when drafting a script or working on a proof of concept. However, issues might become apparent when using the function later or somebody else who is less familiar with the use case takes responsibility for the code.
Among the issues with this function are:
- The distribution group passed in the variable $Identity can be unspecified ($null). This can lead to unintended side effects, as many Get cmdlets happily return all objects when you specify $null as a value. Take the following code:
Function Process-Mailbox( $Id) { Get-Mailbox -Identity $Id | Set-Mailbox -HiddenFromAddressListEnabled $True }
Can you guess what happens if you do not pass the ID parameter or when the ID is empty? All mailboxes are returned and Set-Mailbox will happily hide all the mailboxes from address lists. It is probably not something you intended.
- In the example above, Identity and Members can be anything; they do not need to be a distribution group or switch, respectively. You might add code that checks if $Identity is a distribution group and if Members is a Boolean ($true or $false), but that would require additional code. The code might become quite complex if it must process multiple parameters.
Function Get-DistributionGroupInfo { [CmdletBinding()] Param( [Parameter(Position= 0, Mandatory= $true, ValueFromPipeline= $true, ValueFromPipelineByPropertyName=$true, HelpMessage= 'Please provide a Distribution Group')] [String]$Identity, [Parameter(HelpMessage= 'Output member count')] [Switch]$MemberCount ) Process { Write-Verbose ('Fetching Distribution Group {0}' -f $Identity) Get-DistributionGroup $Identity | Select-Object Identity,PrimarySmtpAddress, @{n='MemberCount';e={ If( $MemberCount) { (Get-DistributionGroupMember -Identity $_ | Measure-Object).Count } }} } }
- [CmdletBinding()] before the first parameter definition tells PowerShell that the function supports common parameters. Examples of common parameters are Verbose and Confirm. You can then include code in your function to support this. For example, if you pass -Verbose and your function contains Write-Verbose commands, verbose output will be displayed. When you omit -Verbose, the output is not displayed.
- Position=0 in the first parameter specification instructs PowerShell that the first unnamed parameter passed to Get-DistributionGroupInfo is treated as the Identity. So, the following two commands are the same:
Get-DistributionGroupInfo -Identity 'DG-X'
Get-DistributionGroupInfo 'DG-X'
Additional unnamed parameters can be specified as Position=1, etc.
- Mandatory=$true tells PowerShell that this parameter is mandatory. When a user omits the Identity when running the script, PowerShell will ask for it. Parameters can be optional by setting Mandatory to $false or omitting the condition.
- We want to be able to pass the Identity when the function is called in a pipeline. You can enable pipeline usage for this parameter by specifying ValueFromPipeline. You can use the property of passed objects by specifying ValueFromPipelineByPropertyName. Calling the function in a pipeline can then look like this:
Get-DistributionGroup -Identity 'DG-X' | Get-DistributionGroupInfo
- When you omit a mandatory parameter, HelpMessage defines help information. This help information is displayed when you enter !? when PowerShell asks you for input, and it is also displayed when you use:
Get-Help Get-DistributionGroupInfo -Full
I do not know anyone who uses !?, but you can if you want.
- After specifying the constraints, you define the parameter itself. You do this by giving it a name or, in this case, an identity. This name contains the value passed as a parameter when the function is called, making it available within its scope. You can optionally define the type of object the parameter will accept. In this case, we specify [String], which equals [System.String], but PowerShell has some type accelerators (short aliases) for built-in types.
Function Test { param( [int]$A ) Write-Output ($A) } ❯ test -A 123 123 ❯ test -A 'string' Test: Cannot process argument transformation on parameter 'A'. Cannot convert value "string" to type "System.Int32". Error: "The input string 'string' was not in a correct format."
I recommend using strict typing with parameters whenever possible. Typing helps with troubleshooting usage and also helps to document the code, as explained later. One thing to consider is that values might get converted through interpretation. For example, if you pass a parameter value 123, and a string is expected, PowerShell will happily convert this to a string representation, ‘123’.
- The second parameter (note the comma after Identity) is a Switch named MemberCount. Since this parameter is not mandatory and pipeline usage is unnecessary, these are not specified in the definition. The nice thing with switches is that you can use them just by mentioning, e.g. –MemberCount ; will set the MemberCount variable to $true. When you do not, it will be $false. You cannot use -MemberCount $true, as PowerShell will interpret $true as the next parameter since MemberCount is a switch. If needed, for example when $true or $false is stored in a variable, you can set it using a variable by specifying <Switch>:<value>, e.g. -MemberCount:$false. You might already be using this syntax when avoiding having to confirm certain commands, e.g. Set-Mailbox … -Confirm:$False
- By putting the code performing the actual task in a Process script block {}, we make the function work for objects passed through the pipeline. If we omit this and leave the code as-is, it will not support pipelining, and the code will only execute once for the last object received through the pipeline. Note that the current object in the pipeline is available through the automatic variable $_, if needed, within the Process script block.
When we put the code for this function in a script file, for example, MyDemo.ps1, it becomes available within our PowerShell session. To accomplish this, we need to dot source it to define it in our session. We can then call it – provided the Exchange Online Management Shell is loaded and connected – and inspect its definition by calling Get-Help, which also includes documentation.
PS❯ . .\MyDemo.ps1 PS❯ Get-DistributionGroupInfo -Identity MyDG -MemberCount -Verbose VERBOSE: Fetching Distribution Group MyDG Identity PrimarySmtpAddress MemberCount -------- ------------------ ----------- MyDG MyDG@contoso.com 2 PS❯ Get-DistributionGroup | Get-DistributionGroupInfo -MemberCount Identity PrimarySmtpAddress MemberCount -------- ------------------ ----------- MyDG MyDG@contoso.com 2 OtherDG OtherDG@contoso.com 8 PS❯ Get-Help Get-DistributionGroupInfo -Full NAME Get-DistributionGroupInfo SYNTAX Get-DistributionGroupInfo [-Identity] <string> [-MemberCount] [<CommonParameters>] PARAMETERS -Identity <string> Please provide a Distribution Group. Required? True Position? 0 Accept pipeline input? true (ByValue) Parameter set name (All) Aliases None Dynamic? False Accept wildcard characters? False -MemberCount Output member count Required? False Position? Named Accept pipeline input? False Parameter set name (All) Aliases None Dynamic? False Accept wildcard characters? False <CommonParameters> This cmdlet supports the common parameters: Verbose, Debug, ErrorAction, ErrorVariable, WarningAction, WarningVariable, OutBuffer, PipelineVariable, and OutVariable. For more information, see about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216).
Begin, Process, End
Begin { # Initialize $Items=0 } Process { # Do Something $Items++ } End { # Cleanup Write-Host ('We processed {0} object(s)' -f $Items) }
An example is when you want to count how many objects you have processed, as the number of objects passed through a pipeline is unknown upfront. Another example of this would be the Sort-Object command, which can only sort objects when all objects have been passed to it.
Script Parameters
[CmdletBinding()] Param( [parameter( Mandatory= $true) [ValidateScript({ Test-Path -Path $_ -PathType Leaf})] [String]$CSVFile, [ValidateSet(',', ';')] [string]$Delimiter=',', [System.Security.SecureString]$Password ) Function X { # … } #etc.
- Ask to provide a value for $CSVFile when one has not been given (Mandatory= $true). You will notice a ValidateScript line as part of the CSVFile parameter definition. When specifying parameters, you can have PowerShell perform certain validations against the values provided. Some of the possible tests are:
- ValidateScript is used to execute a script block that needs to result in $true for the parameter value to be accepted. In the example, we check if the filename is valid using Test-Path specifying the automatic variable $_ (the actual filename).
- ValidateSet to test the value against a set of predefined values. In the example, we use ValidateSet only to allow a comma or semi-colon for the $Delimiter parameter.
- The delimiter parameter can be specified. If it is not specified (not mandatory), we set it to a default value of ‘,.’
- A $Password parameter can be provided. When specified, it needs to be of the type [System.Security.SecureString]. You are not limited to PowerShell’s built-in types; you can also use other (.NET) types, such as SecureString or a credential of the type [PSCredential].
Make PowerShell Work for You
It is ambitious to discuss functions and parameters in PowerShell in one article. I have not touched on other subjects, such as command sets and dynamic parameters. These might be topics for another article.
I hope that I have encouraged you to write reusable code, not only to leverage scripts and functions but also to correctly define code. Make PowerShell work for you when possible, letting it handle parameter validation and checking other constraints such as types. This enables you to focus on the task while making code less complex and improving readability.
If you have questions or comments, feel free to reach out in the comments. If not, wait until the next article, where I will discuss flow control.