Get-Help parameter syntax

Hi

About the brackets surrounding a parameter name, or rather, when they DON’T surround a parameter name.

In the MVA Powershell 3,0 Jump Start course Jason Helmick covered this but not in a way that resulted in me understanding it.

Consider the second parameter set for Get-Service:

Get-Service [-ComputerName <String>] [-DependentServices] [-Exclude <String>] [-Include <String>] [-RequiredServices] -DisplayName <String> [<CommonParameters>]

The DisplayName parameter is NOT surrounded by (aka “binkies”, bless him). Since denotes ‘optional’, the implication is that -DisplayName is not optional…but clearly it is since I can run

Get-Service -ComputerName DC
Get-Service -ComputerName DC -name bit*

and both will produce valid output. So, I don’t have to use -DisplayName.

Does it mean that if I want to use DisplayName I have to type it? Well, no, because it’s not a positional parameter like -Name, since -Name is shown in the Help with the syntax of [[-Name] <String>], and it’s those extra around the -Name parameter itself that show it’s a positional parameter so therefore you don’t have to type it in (but just enter the argument(s)).

In the course Jason said “If you’re going to use it, you’ve got to type it in and you’ve got to give me a value.”

Well, OK, but then if I’m going to use -Name I also HAVE to give it an value. But while I don’t HAVE to type it in (because it’s a positional parameter) I do HAVE to type in any of the other parameters, with arguments if they take them, if I want to use them.

So why does “-DisplayName <String>” not have the surrounding ?

My Friend, I believe you are confused with the parameter “-Name” & “DisplayName”…
e.g -

“BITS” is the Name of the Service, representing “-Name” parameter
But the Display Name for the service “Bits” is “Background Intelligent Transfer Service”

So, the below command works

PS C:&gt; Get-Service bits

Status Name DisplayName


Running bits Background Intelligent Transfer Ser…

But the below will not work ever:

PS C:&gt; Get-Service -DisplayName

It will throw the below error:

"Get-Service : Missing an argument for parameter ‘DisplayName’. Specify a parameter of type ‘System.String’ and try
again.
At line:1 char:13

  • Get-Service -DisplayName
  •         ~~~~~~~~~~~~
    
    • CategoryInfo : InvalidArgument: (:slight_smile: [Get-Service], ParameterBindingException
    • FullyQualifiedErrorId : MissingArgument,Microsoft.PowerShell.Commands.GetServiceCommand"

To make the above command work, you have to give an argument againsta “-DisplayName” parameter like below:

PS C:&gt; Get-Service -DisplayName back*

Status Name DisplayName


Running BITS Background Intelligent Transfer Ser…

In short, if you are using “-DisplayName” parameter, then you have to give arguments, or else it will not work… Don’t consider the representing the whole set of syntaxes of the command like “Get-Service”, but the individual parameters, it’s talking about like “-ComputerName” & “-DisplayName” etc… Hope it helps!

Cheers!
Surya

Actually I don’t agree about that being the point of confusion.

To understand what’s going on with required parameters, you need to be aware of all of the parameter sets for Get-Service. For instance, consider this:

PS C:\> get-command get-service -syntax

Get-Service [[-Name] <string[]>] [-ComputerName <string[]>] [-DependentServices] [-RequiredServices] [-Include <string[]>] [-Exclude <string[]>] [<CommonParameters>]

Get-Service -DisplayName <string[]> [-ComputerName <string[]>] [-DependentServices] [-RequiredServices] [-Include <string[]>] [-Exclude <string[]>] [<CommonParameters>]

Get-Service [-ComputerName <string[]>] [-DependentServices] [-RequiredServices] [-Include <string[]>] [-Exclude <string[]>] [-InputObject <ServiceController[]>] [<CommonParameters>]

The first parameter set is the default, so when you invoke Get-Service with only a computer name, that is the parameter set that is invoked. In that parameter set, the Name parameter is optional, so you can get all services when you don’t specify a name.

In the case of DisplayName however, which is only a member of the second parameter set, the DisplayName parameter is required in order to use that parameter set (or that version) of Get-Service. That is why you see it without the square brackets. It is required for that specific parameter set, but it is not required for all parameter sets.

One last thing: the help and syntax information is based on how the command is defined. That information does not always reflect how the command actually runs. For example, consider this:

PS C:\> Get-Service 'Windows Update'

Status   Name               DisplayName
------   ----               -----------
Running  wuauserv           Windows Update

In that invocation, I’ve called Get-Service without naming the first parameter, so the default parameter set (the first one in the list above) gets invoked. This uses the Name parameter. Yet I am able to look up the service using the DisplayName, not the name. This demonstrates that internally the cmdlet is looking at both Name and DisplayName. This can cause some confusion, and the help text for the Name parameter doesn’t make it any clearer. For example, if I have a service with a name of MyService and another service with a different name but with a display name of MyService, will Get-Service MyService return the first one, the second, or both? I can’t tell from the documentation, nor can I tell from the syntax, so I need to run it to see how it behaves. In a perfect world, these details would always be documented, but our world is far from perfect. The main point here is that how commands actually run internally may be somewhat different from how it may appear they will run based on how they are defined (in this case, someone may expect Get-Service to return an error because there is no service with a “Name” parameter of “Windows Update”), so be aware of that when you are trying to figure these things out.

Surya, no, I get all that. I’m not confusing -Name and -Displayname. I know that these commands will work as shown:
Get-Service -Name bit*

Status Name DisplayName


Running BITS Background Intelligent Transfer Ser…

Get-Service -DisplayName bit*

Status Name DisplayName


Stopped BDESVC BitLocker Drive Encryption Service

You said, quite rightly, that “…if you are using “-DisplayName” parameter, then you have to give arguments, or else it will not work…” but that’s also true of the -Name parameter:

Get-Service -Name
Get-Service : Missing an argument for parameter 'Name'. Specify a parameter of type 'System.String' and try again.
At line:1 char:13

  • Get-Service -Name
  •         ~~~~~
    
    • CategoryInfo : InvalidArgument: (:slight_smile: [Get-Service], ParameterBindingException
    • FullyQualifiedErrorId : MissingArgument,Microsoft.PowerShell.Commands.GetServiceCommand

Get-Service -DisplayName
Get-Service : Missing an argument for parameter 'DisplayName'. Specify a parameter of type 'System.String' and try again.
At line:1 char:13

  • Get-Service -DisplayName
  •         ~~~~~~~~~~~~
    
    • CategoryInfo : InvalidArgument: (:slight_smile: [Get-Service], ParameterBindingException
    • FullyQualifiedErrorId : MissingArgument,Microsoft.PowerShell.Commands.GetServiceCommand`

So, neither the -Name parameter nor the -DisplayName are required, but if you use either of them then both of them require an argument.

So then, the question remains, in the CmdLet syntax as shown by Get-Help, why is -Name shown enclosed in square brackets (as “[[-Name] <String>]”) but -DisplayName NOT shown enclosed in square brackets (but as “-DisplayName <String>”)?

Let me clarify that with the below example:

PS C:&gt; Get-Service -Name Bits

Status Name DisplayName


Running Bits Background Intelligent Transfer Ser…

PS C:&gt; Get-Service Bits

Status Name DisplayName


Running Bits Background Intelligent Transfer Ser…

Did you see how both the above 2 commands work… one with “-Name bits” and the other one with only “bits”, but with below it doesn’t work.

PS C:&gt; Get-Service -DisplayName back*

Status Name DisplayName


Running BITS Background Intelligent Transfer Ser…

PS C:&gt; Get-Service back*
PS C:&gt;

The above doesn’t work because “back*” tries to find “Any service whose -Name or -ComputerName starts with back*”, but not with “-DisplayName” starting with “back*”.

The default syntax shows if you do not pass any parameter to the command “Get-Service”, then “Get-Service” will take the argument, which you are passing it, and will map it to the “-Name” or “-ComputerName” parameter.

But it will never try to map it to “-DisplayName” parameter, as it requires the parameter to be mentioned first as “-DisplayName” first to take its relevant argument.

Does it make sense now… as those Square Brackets are there because those parameter names are optional and the argument will work without any parameters defined, but that’s not the same case for the particualr parameter “-DisplayName”

Hope this time it clears all your confusion!

Cheers!

That’s the difference between a parameter that can be passed by either position or name (the -ParameterName part is optional), or by name only.

If you look at the help file for get-service
£> get-help get-service -Parameter Displayname

-DisplayName <String>
Specifies the display names of services to be retrieved. Wildcards are permitted. By default, Get-Service gets all
services on the computer.

Required?                    true
Position?                    named
Default value                All services
Accept pipeline input?       false
Accept wildcard characters?  true

£> get-command get-service -Syntax

Get-Service [[-Name] <string>] [-ComputerName <string>] [-DependentServices] [-RequiredServices] [-Include
<string>] [-Exclude <string>] [<CommonParameters>]

Get-Service -DisplayName <string> [-ComputerName <string>] [-DependentServices] [-RequiredServices] [-Include
<string>] [-Exclude <string>] [<CommonParameters>]

Get-Service [-ComputerName <string>] [-DependentServices] [-RequiredServices] [-Include <string>] [-Exclude
<string>] [-InputObject <ServiceController>] [<CommonParameters>]

So as Kirk said the -Displayname parameter is the first parameter of a parameter set and if you want to search for a particular service by a Displayname you have to supply the displayname

however if you do this
Get-Service ‘Windows Search’
Get-Service -displayname ‘Windows Search’

as you pointed out they both work.

I suspect a bug in the documentation.

Isn’t the Syntax section generated automatically based on cmdlet metadata, making it impossible to have documentation bugs of that sort? Or can that be overridden in XML-based help (unlike comment-based)?

Going on the assumption that parameter binding was working fine (meaning the issue would be a quirk with how the -Name parameter is implemented), I used dotPeek to look over the Get-Service cmdlet. When you specify -DisplayName, it enumerates over all of the services on the specified computer(s) (using ServiceController.GetServices(machineName)), does a wildcard match on the display name, and outputs the matches. This is basically the same as doing Get-Service | Where-Object { $_.DisplayName -like ‘Something*’ } yourself, with similar performance penalties.

Using the Name parameter, on the other hand, only behaves that way if it contains a wildcard. If Name doesn’t contain a wildcard, presumably to improve performance, the cmdlet only creates a single ServiceController instance using this constructor: http://msdn.microsoft.com/en-us/library/ssbk2tf3.aspx

From that constructor’s documentation:

Parameters
nameType: System.String

The name that identifies the service to the system. This can also be the display name for the service.

  1. I said it was a possible documentation bug
  2. Documentation bugs do exist - we’ve been reporting them for the last 3 or 4 years as we discover them so the writers can remove them. This process has accelerated with updateable help. The fix cycle on documentation is much shorter

I know that documentation bugs exist. :slight_smile: I was just curious about the Syntax section, since I’ve only written comment-based help, and in comment-based help you can’t change that section; it’s always dynamically generated, based on the parameters and sets you’ve defined. I don’t know if that’s also true for compiled cmdlets that use XML help files, or if they have to write the Syntax section manually, introducing possible errors.

Command authors can write implementations internally that do not accurately reflect what you might expect based on a simple look at the syntax. That’s why I added the note to the end of my previous post. Get-Service has -Name and -DisplayName as separate parameters, yet the results show that internally Get-Service will look for services by DisplayName when the Name parameter is used if a service is not found. You can’t show that in Syntax alone, because it’s internal implementation details. For example:

PS C:\WINDOWS\system32> get-service z*

Status   Name               DisplayName
------   ----               -----------
Running  ZeroConfigService  Intel(R) PROSet/Wireless Zero Confi...

PS C:\WINDOWS\system32> get-service i*

Status   Name               DisplayName
------   ----               -----------
Running  IBMPMSVC           Lenovo PM Service
Stopped  IEEtwCollectorS... Internet Explorer ETW Collector Ser...
Stopped  IKEEXT             IKE and AuthIP IPsec Keying Modules
Running  iphlpsvc           IP Helper
Running  iPod Service       iPod Service

In that output you see that wildcard searching using the Name parameter actually only looks for services by name, yet if I search for a service using a DisplayName without any wildcards in the Name parameter, the cmdlet finds that service.

Drop a wildcard in there anywhere, and it won’t find the service by display name using the Name parameter.

PS C:\WINDOWS\system32> get-service 'Intel(R) PROSet/Wireless Zero Configuration Service'

Status   Name               DisplayName
------   ----               -----------
Running  ZeroConfigService  Intel(R) PROSet/Wireless Zero Confi...


PS C:\WINDOWS\system32> get-service 'Intel(R) PROSet/Wireless Zero ?onfiguration Service'
PS C:\WINDOWS\system32> get-service 'Intel(R) PROSet/Wireless Zero *Configuration Service'
PS C:\WINDOWS\system32>

Internal implementation detail, doc bug, no fault on the doc writer though because they weren’t aware of the internal implementation detail.

Surya, I think all you’ve done is confirm what I’ve already said I understand. Although I’m not sure your statement “The above doesn’t work because “back” tries to find “Any service whose -Name or -ComputerName starts with back“…” is correct, in that it won’t be looking for the ComputerName at all because in your example (PS C:&gt; Get-Service back*) the -ComputerName parameter has not been specified at all.

For example, I have a PC called UserPC01:

`PS C:\Users\jj> get-service UserPC01
get-service : Cannot find any service with service name 'UserPC01'.
At line:1 char:1

  • get-service UserPC01
  •   + CategoryInfo          : ObjectNotFound: (UserPC01:String) [Get-Service], ServiceCommandException
      + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand`</pre>
    
    

From the Help for Get-Service only the -Name parameter is positional:

`    -Name <String>
Specifies the service names of services to be retrieved. Wildcards are permitted. By default, Get-Service gets all of the services on the computer.

    Required?                    false
    Position?                    1`</pre>

And in the Syntax section that status (of it being a positional parameter) is marked by the DOUBLE square brackets:

Get-Service [[-Name] &lt;String[]&gt;]

All the other parameters are marked with SINGLE square brackets, denoting them as being optional. For example:

Get-Service [-ComputerName &lt;String[]&gt;]

…which is confirmed further below in the help file…:
`Parameters
-ComputerName <String>
Gets the services running on the specified computers. The default is the local computer.

    Required?                    false
    Position?                    named`</pre>

With regards to the -DisplayName parameter lacking these surrounding , I think what the PowerShell help is trying to tell me/us is that “I will look for services by their Service Name UNLESS YOU TELL ME I SHOULD DO SO BY THE DISPLAYNAME INSTEAD, in which you case you HAVE TO TELL ME THAT’S WHAT YOU WANT!” :slight_smile:

Or, to put it another way, it’s an override from the default behaviour…

[quote=10129]That’s the difference between a parameter that can be passed by either position or name (the -ParameterName part is optional), or by name only.
[/quote]

Surely the single denotes optional, which is what I was talking about, whereas it’s the [] which denotes a positional parameter.

To everybody/nobody-in-particular, if my interpretation that -DisplayName is an override of the default/positional -Name behaviour then I’d argue that the second parameter set…:

Get-Service [-ComputerName <String[]>] [-DependentServices ] [-Exclude <String[]>] [-Include <String[]>] [-RequiredServices ] -DisplayName <String[]> [<CommonParameters>]

…would be better written with -DisplayName placed at the beginning, rather than hidden away further down the line like a bullied little kid who’s been pushed in front of in the dinner line at school. Like this:

Get-Service -DisplayName <String[]> [-ComputerName <String[]>] [-DependentServices ] [-Exclude <String[]>] [-Include <String[]>] [-RequiredServices ] [<CommonParameters>]

Yesno?

[quote=10110]One last thing: the help and syntax information is based on how the command is defined. That information does not always reflect how the command actually runs. For example, consider this:

PS C:\> Get-Service 'Windows Update'

Status   Name               DisplayName
------   ----               -----------
Running  wuauserv           Windows Update
In that invocation, I’ve called Get-Service without naming the first parameter, so the default parameter set (the first one in the list above) gets invoked. This uses the Name parameter. Yet I am able to look up the service using the DisplayName, not the name. This demonstrates that internally the cmdlet is looking at both Name and DisplayName. This can cause some confusion...[/quote]

Wow. You’re not kidding that’s confusing!

[quote=10155]

<div class=“d4p-bbt-quote-title”>Dave Wyatt wrote:</div>That’s the difference between a parameter that can be passed by either position or name (the -ParameterName part is optional), or by name only.

Surely the single [] denotes optional, which is what I was talking about, whereas it’s the [[]] which denotes a positional parameter. [/quote]

Square brackets around the parameter name indicate a parameter that can be passed positionally. Square brackets around both the parameter name and the argument indicate a parameter that is optional. These things aren’t mutually exclusive:

[-ParameterName] <Value> # Required parameter that may be passed by name or by position
[-ParameterName <Value>] # Optional parameter that may only be passed by name
[[-ParameterName] <Value] # Optional parameter that may be passed by name or by position