positional parameters and parameter sets

This topic contains 3 replies, has 2 voices, and was last updated by  Dave Wyatt 3 years, 7 months ago.

  • Author
    Posts
  • #12780

    Nick Parlow
    Participant

    Hi All,

    why does running get-service 'background intelligent transfer service' work?

    We're doing a book club in work, based on "powershell in a month of lunches" for powershell v2 (yes, i know it's old, but none of our customers have gone to windows 2012 yet) and we've noticed that something we don't think should work, works.

    if we run "help get-service" we see:

    SYNTAX
    Get-Service [[-Name] ] [-ComputerName ] [-DependentServices] [-Exclude ] [-Include ] [-RequiredServices] []

    Get-Service -DisplayName [-ComputerName ] [-DependentServices] [-Exclude ] [-Include
    ] [-RequiredServices] []

    so we take that to mean that if we type "get-service " then "" will be taken as input for the -Name parameter, not the display name parameter. the -DisplayName parameter isn't in square brackets, so must be typed if you are going to use a displayname value...

    now, consider the BITS service:

    Name : BITS
    DisplayName : Background Intelligent Transfer Service
    Status : Running
    DependentServices : {}
    ServicesDependedOn : {EventSystem, RpcSs}
    CanPauseAndContinue : False
    CanShutdown : True
    CanStop : True
    ServiceType : Win32ShareProcess

    and if i run get-service BITS | gm i see:

    Name MemberType Definition
    —- ———- ———-
    Name AliasProperty Name = ServiceName

    DisplayName Property System.String DisplayName {get;set;}
    MachineName Property System.String MachineName {get;set;}
    ServiceHandle Property System.Runtime.InteropServices.SafeHandle ServiceHandle {get;}
    ServiceName Property System.String ServiceName {get;set;}
    ServicesDependedOn Property System.ServiceProcess.ServiceController[] ServicesDependedOn {get;}
    ServiceType Property System.ServiceProcess.ServiceType ServiceType {get;}
    Site Property System.ComponentModel.ISite Site {get;set;}
    Status Property System.ServiceProcess.ServiceControllerStatus Status {get;}

    so it looks like "Name" is definitely distinct from "DisplayName"; it's an alias for "ServiceName".

    so, my original question... why does this work?
    get-service bits

  • #12781

    Dave Wyatt
    Moderator

    Nice catch, but it's not quite what you think. When you call get-service 'background intelligent transfer service' , it really is binding to the Name parameter, not the DisplayName (which you can verify with Trace-Command, as shown below).

    Trace-Command -Name ParameterBinding -PSHost -Expression { Get-Service 'Background Intelligent Transfer Service' }
    
    DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Get-Service]
    DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Get-Service]
    DEBUG: ParameterBinding Information: 0 :     BIND arg [Background Intelligent Transfer Service] to parameter [Name]
    DEBUG: ParameterBinding Information: 0 :         Binding collection parameter Name: argument type [String], parameter type [System.String[]], collection type Array, element type [System.String], no coerceElementType
    DEBUG: ParameterBinding Information: 0 :         Creating array with element type [System.String] and 1 elements
    DEBUG: ParameterBinding Information: 0 :         Argument type String is not IList, treating this as scalar
    DEBUG: ParameterBinding Information: 0 :         Adding scalar element of type String to array position 0
    DEBUG: ParameterBinding Information: 0 :         BIND arg [System.String[]] to param [Name] SUCCESSFUL
    DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Get-Service]
    DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
    DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing
    

    It's just that the Get-Service cmdlet is written to work with either value passed to the Name argument, for some reason, but only if the Name argument does not contain any wildcards. You won't find that in the documentation anywhere, and it may not have even been a conscious design choice by the PowerShell team, as it's actually behavior from the underlying ServiceController class. See http://msdn.microsoft.com/en-us/library/ssbk2tf3(v=vs.110).aspx; you'll see that the "name" parameter can be either the name or display name of the service, and this is the constructor that Get-Service calls if you pass it a Name without wildcards.

  • #12782

    Nick Parlow
    Participant

    ah, i see:

    name
    Type: System.String
    The name that identifies the service to the system. This can also be the display name for the service.

    thanks a lot Dave, that's really helpful!

  • #12783

    Dave Wyatt
    Moderator

    If you are really curious, download a copy of dotPeek sometime. It's free, and it's what I use to investigate how PowerShell's various bits actually work. You can run this command to identify the DLL and class name of a particular cmdlet:

    Get-Command Get-Service | Format-Table DLL, ImplementingType -Wrap
    
    DLL                                                                                                              ImplementingType                                                                                               
    ---                                                                                                              ----------------                                                                                               
    C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.PowerShell.Commands.Management\v4.0_3.0.0.0__31bf3856ad364e Microsoft.PowerShell.Commands.GetServiceCommand                                                                
    35\Microsoft.PowerShell.Commands.Management.dll
    

    So I just load up dotPeek, choose the "Open from GAC" option, point it at Microsoft.PowerShell.Commands.Management.dll, and look for the Microsoft.PowerShell.Commands.GetServiceCommand class.

    This does require some understanding of C#, and the decompiled code isn't always the clearest to read, but it's very handy for this type of investigation.

You must be logged in to reply to this topic.