In part 2 of powershell basic Mike say if a parameter is not provided the command goes by position. What exactly does that mean? Is there an example of this?
-
Powershell parameter/position question
-
I hope all is well. What Mike is talking about is the following behavior in PowerShell.
The Position argument determines whether the parameter name is required when the parameter is used in a command. When a parameter declaration includes the Position argument, the parameter name can be omitted and PowerShell identifies the unnamed parameter value by its position, or order, in the list of unnamed parameter values in the command.
If the Position argument is not specified, the parameter name, or a parameter name alias or abbreviation, must precede the parameter value whenever the parameter is used in a command.
By default, all function parameters are positional. PowerShell assigns position numbers to parameters in the order in which the parameters are declared in the function. To disable this feature, set the value of the PositionalBinding argument of the CmdletBinding attribute to $False.
The Position argument takes precedence over the value of the PositionalBinding argument of the CmdletBinding attribute.
The value of the Position argument is specified as an integer. A position value of 0 represents the first position in the command, a position value of 1 represents the second position in the command, and so on.
If a function has no positional parameters, PowerShell assigns positions to each parameter based on the order in which the parameters are declared. However, as a best practice, do not rely on this assignment. When you want parameters to be positional, you should use the Position argument.
You can take a look here for a quick explanation and some samples:
https://powershellstation.com/2017/10/04/specifying-powershell-parameter-position/
I hope that helps out !!
Please let us know if you have any other questions...
Cheers,
Adam
-
Adam, Thank you, Unfortunately, the terminology used in the link you gave me is not making anything clear. Would it be possible to use the the two examples from the site to clarify what the positional concept is?
Whether you know it or not, if you’ve used PowerShell, you’ve used positional parameters. In the following command the argument (c:\temp) is passed to the -Path parameter by position.
?
1
cd c:\temp
The other option for passing a parameter would be to pass it by name like this:?
1
cd -path c:\temp
It makes sense for some commands to allow you to pass things by position rather than by name, especially in cases where there would be little confusion if the names of the parameters are left out (as in this example).What confuses me, however, is code that looks like this:
?
1
2
3
4
5
6
7
function Test-Position{
[CmdletBinding()]
Param([parameter(Position=0)]$parm1,
[parameter(Position=1)]$parm2,
[parameter(Position=2)]$parm3,
[parameter(Position=3)]$parm4)
}
In this parameter declaration, we’ve explicitly assigned positions to the first four parameters, in order.Why is that confusing? Well, by default, all parameters are available by position and the default order is the order the parameters are defined. So assigning the Position like this makes no difference (or sense, for that matter).
-
For an example, think of the cmdlet
copy-item
Using named parameters, you would type
Copy-Item -Path <sourcepath> -Destination <destinationpath>
To shorten the command, you can take advantage of positional parameters,
You can type
Copy-Item <sourcepath> <destinationpath>
PowerShell can determine that the first parameter passed is the
-Path
, and the second parameter passed is the-Destination
. It can do this because in the definition ofCopy-Item
, the-Path
parameter is defined first, and the-Destination
parameter is defined secondCopy-Item [-Path] <String[]> [[-Destination] <String>] [-Container] [-Force] [-Filter <String>] [-Include <String[]>] [-Exclude <String[]>] [-Recurse] [-PassThru] [-Credential <PSCredential>] [-WhatIf] [-Confirm] [-FromSession <PSSession>] [-ToSession <PSSession>] [<CommonParameters>]
I just saw your follow-up question as I was typing this response, I will answer that after all of our morning meetings.
Mike Rodrick
Edutainer, ITProTV**if the post above has answered the question, please mark the topic as solved.
-
If you tell me which episode you are referring to, I can clarify that specific example.
When those shows were filmed, all parameters were not available by position by default. Many cmdlets required the use of naming the parameters being passed. If you did not specify the parameter name, the cmdlet would fail.
If you wanted a function to accept positional parameters, you had to define the position order. I would assign the position number in the order that I defined the parameters. It wouldn't make sense to me to define the parameters, but assign positions is a different order like:
function Test-Position{ [CmdletBinding()] Param([parameter(Position=0)]$parm1, [parameter(Position=3)]$parm2, [parameter(Position=1)]$parm3, [parameter(Position=2)]$parm4) }
Mike Rodrick
Edutainer, ITProTV**if the post above has answered the question, please mark the topic as solved.
-
PowerShell Basics for Administrators Command History and Aliases part 2 about the 9:50-56 time mark is where you give an explanation. I'm sure this is a simple concept, but the terminology is making a monster out of it for me at the moment. Functions, tables, parameters, and postional parameters, and whatever else awaits me is a little overwhelming. I have to go look up the big words and try to apply them. It's all good, but that's where i'm coming from at the moment.
Thank you!!
-
It can definitely be overwhelming at times. Keep at it!
When you think about positional parameters or named parameters, understand that it's all the same parameter, you are just describing how you are providing the parameter.
Lets say we want to copy a file named sales.xls from c:\reports to d:\archive.
The Copy-Item cmdlet needs two parameters, what you are going to copy, and where you want to put the copy. The -Path parameter is used to specify the item to copy, and the -Destination parameter is used to specify where to put the copy.
If you use named parameters, that means you will specify the name of the parameter in the command. This is the recommended way to run commands.
Copy-Item -Path c:\reports\sales.xls -Destination d:\archive\sales.xls
There are two main reasons this is the preferred and recommended way. One is readability, anyone reading this in a script will know exactly what is going on. Two, you can put them in any order and the command will still work. Granted there are only two parameters is this command, but think about New-ADUser, where you might have to specify dozens of parameters. You don't want to have to worry about what order to put them in. So this command would work as well.
Copy-Item -Destination d:\archive\sales.xls -Path c:\reports\sales.xls
For short commands, and when we get a little lazy, we can take advantage of positional parameters. Remember, it's not a different type of parameter, it's just how we are going to provide the parameter. Using positional parameters means we are going to let PowerShell figure out what parameters we are providing, based on the order that we provide them it.
Copy-Item c:\reports\sales.xls d:\archive\sales.xls
Since we didn't name the parameters we passed with the command, we are using positional parameters. PowerShell has to interpret the best it can what we mean. It does this by looking at the order that we typed the parameters.
The first thing after the cmdlet name is
c:\reports\sales.xls
. So this is position 0. The second thing after the cmdlet name isd:\archive\sales.xls
, this is position 1. Positions start with 0.Let's take a look at the definition for Copy-Item.
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/copy-item?view=powershell-7In the list of parameters, find -Path.
-Path Specifies, as a string array, the path to the items to copy. Wildcard characters are permitted. TABLE 12 Type: String[] Position: 0 Default value: None Accept pipeline input: True Accept wildcard characters: True
Notice the Position: 0
And for -Destination-Destination Specifies the path to the new location. The default is the current directory. To rename the item being copied, specify a new name in the value of the Destination parameter. TABLE 4 Type: String Position: 1 Default value: Current directory Accept pipeline input: True Accept wildcard characters: False
You'll see Position: 1
So PowerShell says, since we didn't name our parameters, whatever is in position 0 (the first thing after the cmdlet name) is the -Path, or what we want to copy. Whatever is in position 1 (the second thing after the cmdlet name) is the -Destination, or where we want to put the copy.
So the shortened version of this command, using positional parameters works fine, the downside is the parameters have to be listed in the right order. With the named parameters we were able to reverse the parameter order and the command worked fine. Not so with positional parameters. If we tried
Copy-Item d:\archive\sales.xls c:\reports\sales.xls
PowerShell would try to copy sales.xls from d:\archive to c:\reports, which is not what we wanted.
Named parameters is the better way to go, especially is scripts, but sometimes when I just need to run a cmdlet real quick, especially with simple cmdlets, I will use positional parameters. Just to confuse you event more, you can use both! For example:
Copy-Item c:\reports\sales.xls -Destination d:\archive\sales.xls
The first parameter is passed as a positional parameter, the second as a named parameter. Definitely not recommended, but you will see this now and again on some blog sites, etc.
Hope this helps with named parameters vs positional parameters,
Mike Rodrick
Edutainer, ITProTV**if the post above has answered the question, please mark the topic as solved.
-
To clear up some terminology, there is a difference between cmdlets and functions. A cmdlet is a .NET class written in C# or other .NET language and contained in a .dll (i.e. in a binary module). A function is specified directly in PowerShell in a script, script module or at the command line.
So when you read "by default, all parameters are available by position and the default order is the order the parameters are defined", understand this does not refer to cmdlets like
Copy-Item
If we go back to the docs page in my previous post, look at the
-Include
parameter.-Include Specifies, as a string array, an item or items that this cmdlet includes in the operation. The value of this parameter qualifies the Path parameter. Enter a path element or pattern, such as "*.txt". Wildcard characters are permitted. The Include parameter is effective only when the command includes the contents of an item, such as C:\Windows\*, where the wildcard character specifies the contents of the C:\Windows directory. TABLE 9 Type: String[] Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: True
Notice the
Position: Named
This means you have to use -Include and cannot rely on position.
If you wanted to copy all .xls files from c:\reports to d:\archive, you might try
Copy-Item c:\reports\* d:\archive "*.xls"
The first two parameters are fine, because they can be specified either by name or position. but not -Include, it must be named. You would get the error:
Copy-Item: A positional parameter cannot be found that accepts argument '*.xls'.
You would need to run this:
Copy-Item c:\reports\* d:\archive -Include "*.xls"
Mike Rodrick
Edutainer, ITProTV**if the post above has answered the question, please mark the topic as solved.
-
Mike first thank you very much for the position explanation. It's sort of clearing up.
But you have lost me in the explanation of the terminology. I'm not making the connection you are explaining in the recurse example.
Is the way the command is written making the difference?
If this worked worked Copy-Item c:\reports\sales.xls d:\archive\sales.xls, why wouldn't this Copy-Item c:\reports* d:\archive "*.xls" also work?
-
@John-DeWilde I think you updated Recurse to Include in the example.. If the syntax was copy-item c:\reports*.xls d:\archive would that work without the -include?
-
I did edit the post. Initially I was going to use
-Recurse
as the example, but that is more of a switch than a parameter. (With a switch, you are just turning something on, you don't provide any additinal info.)Copy-Item c:\reports\* d:\archive "*.xls"
will not work. You have to type-Include "*.xls"
Without the
-Include
, PowerShell has no idea what"*.xls"
is. Do you want to include .xls files or exclude .xls files, or is .xls a filter?When you look at https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/copy-item?view=powershell-7 for the
-Include parameter,Position = Named
This means you must use the name to use this parameter.
Mike Rodrick
Edutainer, ITProTV**if the post above has answered the question, please mark the topic as solved.