none
[powershell] how to make use of the get-command 'description' property

    Pregunta

  • I ran across this by accident:

    PS C:\> function zzz {"this is just a test"}
    PS C:\> zzz
    this is just a test
    PS C:\> get-command zzz | ft -autosize
    
    CommandType Name Definition
    ----------- ---- ----------
    Function    zzz  "this is just a test"
    
    
    PS C:\> get-command zzz | select *
    
    
    HelpUri             :
    ScriptBlock         : "this is just a test"
    CmdletBinding       : False
    DefaultParameterSet :
    Definition          : "this is just a test"
    Options             : None
    Description         : 
    OutputType          : {}
    Name                : zzz
    CommandType         : Function
    Visibility          : Public
    ModuleName          :
    Module              :
    Parameters          : {}
    ParameterSets       : {}
    
    
    
    PS C:\> (get-command zzz).description = 'a custom description'
    PS C:\> (get-command zzz).description
    a custom description
    PS C:\> get-command zzz | select name,description | ft -autosize
    
    Name Description
    ---- -----------
    zzz  a custom description
    
    
    PS C:\>

    Interestingly, substituting a "*" wildcard for "ZZZ" indicates that no other commands of any type seem to have the description property populated.

    I tried setting the description property for one of my functions in the .psm1 file in which it was defined, but that did not survive. I suspect some issue of scope might be the culprit.

    Is there a way to populate the description field in one's module functions in a way that is persistent?

    I posted this first in the powershell forum, but thought perhaps it would be a good question for the Scripting Guys.

    It would be nice if this property was populated from the .synopsis or .description field of the comment-based help, but this does not seem to be the case.

    jueves, 09 de febrero de 2012 0:53

Respuestas

  • Good part about it is that in v3 ctp 2 importing module does not clean description field (for functions):

    New-Module {
        function test {
            "zzzz"
        }
        (get-command test).Description = 'foo'
    } | Import-Module
    (get-command test).Description
    
    foo

    Obviously, something have been changed between the version to make it happen... It looks like it's removed from all commands when command is exported from module, both from functions and aliases. And I do not see a way to prevent PowerShell from doing so in v2, even adding -Global to import-module is not helping with that. The only suggestion I have is to vote up bug on connect that is kind of related to the issue you have:

    http://connect.microsoft.com/PowerShell/feedback/details/576223/missing-alias-description-after-using-import-module

    Functions are fixed in v3, but aliases aren't as far as I can tell....

    viernes, 17 de febrero de 2012 8:36
  • ls function: |
     select -expand name |
     % {(gcm $_).description = (get-help $_).synopsis}

    ?

    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

    jueves, 23 de febrero de 2012 3:59

Todas las respuestas

  • I ran across this by accident:

    PS C:\> function zzz {"this is just a test"} PS C:\> zzz this is just a test PS C:\> get-command zzz | ft -autosize CommandType Name Definition ----------- ---- ---------- Function zzz "this is just a test" PS C:\> get-command zzz | select * HelpUri : ScriptBlock : "this is just a test" CmdletBinding : False DefaultParameterSet : Definition : "this is just a test" Options : None Description : OutputType : {} Name : zzz CommandType : Function Visibility : Public ModuleName : Module : Parameters : {} ParameterSets : {} PS C:\> (get-command zzz).description = 'a custom description' PS C:\> (get-command zzz).description a custom description PS C:\> get-command zzz | select name,description | ft -autosize Name Description ---- ----------- zzz a custom description PS C:\>

    Interestingly, substituting a "*" wildcard for "ZZZ" indicates that no other commands of any type seem to have the description property populated.

    I tried setting the description property for one of my functions in the .psm1 file in which it was defined, but that did not survive. I suspect some issue of scope might be the culprit.

    Is there a way to populate the description field in one's module functions in a way that is persistent?

    I posted this first in the powershell forum, but thought perhaps it would be a good question for the Scripting Guys.

    It would be nice if this property was populated from the .synopsis or .description field of the comment-based help, but this does not seem to be the case.

    Yes - it would be nice.  Do you have a solution?  We would like to hear your solution...

    Seriously  - this has been brought up before,

    Try this -> get-command cat|select definition

    I seems to disprove your thesis.


    ¯\_(ツ)_/¯

    jueves, 09 de febrero de 2012 3:25
  • What did that disprove?


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

    jueves, 09 de febrero de 2012 3:45
  • Yes - it would be nice.  Do you have a solution?  We would like to hear your solution...

    Seriously  - this has been brought up before,

    Try this -> get-command cat|select definition

    I seems to disprove your thesis.


    ¯\_(ツ)_/¯

    Do I have a solution? No, this is why I'm looking for one. If I had one I would have given it by now.

    So, this was brought up before? Did someone eventually give some reason why it was not possible?

    jueves, 09 de febrero de 2012 5:12
  • Yes - it would be nice.  Do you have a solution?  We would like to hear your solution...

    Seriously  - this has been brought up before,

    Try this -> get-command cat|select definition

    I seems to disprove your thesis.


    ¯\_(ツ)_/¯

    Do I have a solution? No, this is why I'm looking for one. If I had one I would have given it by now.

    So, this was brought up before? Did someone eventually give some reason why it was not possible?

    @Al - do you have a solution? No!  Life is like that.

    Here we specialize in non-binding solutions.

    Seriously -  When I run this I find a lot of definitions - as I posted earlier.

    It is a non-issue on my machine but I do understand your complaint.  I agree that more definition would be better,

    We have examples.  We should also have a link to 'best usage'.


    ¯\_(ツ)_/¯

    jueves, 09 de febrero de 2012 5:23
  • What did that disprove?


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

    Everything.

    I have invalidated the universe and all who hang onto it.

    When we select the definition in this case it is not empty as was claimed.

    Of course you didn't eventru the  command:

    00:27 PS>get-command cat|select definition
    Definition
    ----------
    Get-Content

    Not a great definition but it is not blank.


    ¯\_(ツ)_/¯

    jueves, 09 de febrero de 2012 5:27
  • Actually, I now have a "solution"; it's just not optimal.

    I found that a command following the import-module command in the profile script can add the description property. Best would be to put these commands into a module function that is then dot-sourced from the profile. That function could easily enumerate the functions to have their .description property set; the difficulty would be in determining the content for the property. And whatever method was used for that could be used by a similar function whose purpose was to display the description of each function. And, in that case, there would be no need to store that information in the .description property... ;-(

    So, I guess the question becomes: what is the actual purpose of the .description property and how was it intended to be used? Seems to me like a question for the Powershell development team.

    jueves, 09 de febrero de 2012 5:47
  • What did that disprove?


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

    Everything.

    I have invalidated the universe and all who hang onto it.

    When we select the definition in this case it is not empty as was claimed.

    Of course you didn't eventru the  command:

    00:27 PS>get-command cat|select definition
    Definition
    ----------
    Get-Content

    Not a great definition but it is not blank.


    ¯\_(ツ)_/¯

    I never claimed that the .definition property was available for general use. I was talking about the .description property. try this command:

         get-command * | select name,description,definition

    and tell us which command has a non-blank .description property.

    jueves, 09 de febrero de 2012 5:53
  • Honestly, I think description in CommandInfo objects is meant to be used with aliases.

    New-Alias -Name foo -Value bar -Description 'Foo is Bar' -PassThru | get-command | fl *

    For functions? I would rather use comment based help:

    function bar {
    
    # .Description
    # Foo is Bar
    
    }
    
    (Get-Help bar).Description
    Not sure if that answers your question...
    jueves, 09 de febrero de 2012 11:04
  • Don't know if it helps or not, but only functions and aliases seem to have it.  There isn't really a description property on cmdlets that I can find.  Maybe it's being added by the providers?

    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

    jueves, 09 de febrero de 2012 11:21
  • Honestly, I think description in CommandInfo objects is meant to be used with aliases.

    New-Alias -Name foo -Value bar -Description 'Foo is Bar' -PassThru | get-command | fl *

    For functions? I would rather use comment based help:

    function bar {
    
    # .Description
    # Foo is Bar
    
    }
    
    (Get-Help bar).Description
    Not sure if that answers your question...

    not completely, but very useful nonetheless. I was unaware of the -description parameter on the set-alias and new-alias cmdlets. Makes sense.

    I still think it would be nice if the property was as easy to set for functions as for parameters. Why would they have one if there was no expectation of it being used?

    As I indicated in the original thread (http://social.technet.microsoft.com/Forums/en-US/winserverpowershell/thread/39263fa6-3904-4c40-8ab6-6f1854410181), comment-based help is only useful if you already know which function does what you are wanting to do. If you could display in ft format the names and descriptions of all your functions (and aliases), I think that would be helpful.

    jueves, 09 de febrero de 2012 14:15
  • Don't know if it helps or not, but only functions and aliases seem to have it.  There isn't really a description property on cmdlets that I can find.  Maybe it's being added by the providers?

    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

    An interesting observation. Not significant to me, as I will not be creating any of my own cmdlets, and do not plan on adding descriptions to anyone elses.

    Thanks to your suggestion in the other thread I have an idea how to accomplish what I'm after. It not being a deal-breaker, I'm not sure how long it will take to put together. I'll post the solution when (and if) I get it working...

    jueves, 09 de febrero de 2012 18:17
  • Good part about it is that in v3 ctp 2 importing module does not clean description field (for functions):

    New-Module {
        function test {
            "zzzz"
        }
        (get-command test).Description = 'foo'
    } | Import-Module
    (get-command test).Description
    
    foo

    Obviously, something have been changed between the version to make it happen... It looks like it's removed from all commands when command is exported from module, both from functions and aliases. And I do not see a way to prevent PowerShell from doing so in v2, even adding -Global to import-module is not helping with that. The only suggestion I have is to vote up bug on connect that is kind of related to the issue you have:

    http://connect.microsoft.com/PowerShell/feedback/details/576223/missing-alias-description-after-using-import-module

    Functions are fixed in v3, but aliases aren't as far as I can tell....

    viernes, 17 de febrero de 2012 8:36
  • I tried setting the description of aliases in my .psm1 files with commands such as:

        set-alias -name ping -value test-connection -description 'this space for rent'

    but found that, although the alias is available in my session, the description property did not survive that long. Thinking that this could be a scope issue, I tried this:

        set-alias -scope global -name ping -value test-connection -description 'this space for rent'

    and found that that works. Since aliases set in a script module are, effectively, global in scope, I cannot think of any downsides to making aliases explicitly global.

    And, since the same goes for functions, I found the same thing works there as well, just not quite so neatly. If I define function in a module script like this:

        function global:doobedoobedoo {
        <#
        .SYNOPSIS
            it ain't what it ain't
        #>
            (get-command doobedoobedoo).description = (get-help doobedoobedoo).synopsis
            "it is what it is"
        }

    I can see the description from my session, i.e.:

       PS C:\>
       PS C:\> doobedoobedoo
       it is what it is
       PS C:\> (get-command doobedoobedoo).description
       it ain't what it ain't
       PS C:\>

    I used .synopsis instead of .description because my intent is that this be a brief, one-liner. I also tried just leaving out the command to set the description and adding a .DESCRIPTION entry instead to see if that would become the description parameter automatically, but that doesn't work - too bad.

    Now all that remains is to find a way to do this:

        (get-command doobedoobedoo).description = (get-help doobedoobedoo).synopsis

    or this:

       (gcm doobedoobedoo).description = (get-help doobedoobedoo).synopsis

    with even less of the extra verbiage. Or with more verbiage but without having to include the literal name of the function. I made a few attempts using iex, but so far no luck. Any ideas?


    Al Dunbar

    miércoles, 22 de febrero de 2012 21:13
  • Aaaarrgh, my apologies. In all the testing I did, I did not actually display the function's description property until AFTER I actually ran it. I have since determined that the above DOES NOT WORK. And further, it would be counterintuitive to have to execute a function in order to see a description of what it will do.

    Fortunately, that same command:

        (get-command doo).description = (get-help doo).synopsis

    can be moved from within the function to just after it. This would seem to make it less likely to be able to simplify the command by not having to include the literal name of the function. About the best I think we could do would be to embed the logic in a function and call it like this:

        Set-FunctionDescription doo

    or, with an alias:

        SFD foo

    Of course, this function would need to be the first one created...


    Al Dunbar

    miércoles, 22 de febrero de 2012 21:31
  • Maybe

    (gi function:doobedoobedoo).description = (get-help doobedoobedoo).synopsis

    miércoles, 22 de febrero de 2012 21:35
  • Maybe

    (gi function:doobedoobedoo).description = (get-help doobedoobedoo).synopsis

    get-item, good one. Unfortunately, it only gets functions if you qualify them with the function: prefix. This works and is eight characters shorter:

        (gcm doobedoobedoo).description = (get-help doobedoobedoo).synopsis


    Al Dunbar

    jueves, 23 de febrero de 2012 3:38
  • ls function: |
     select -expand name |
     % {(gcm $_).description = (get-help $_).synopsis}

    ?

    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "

    jueves, 23 de febrero de 2012 3:59
  • Nice one. Unfortunately it does more that I want it to. There is no need to display this info for many of the standard functions, as some are obvious ("Z:" is "Set-Location Z:"? really, I would never have guessed), or the .synopsis provided is not useful ("importsystemmodules" is "..."? how illuminating).

    Also, running the code a second time gives a different result: "Z:" is now "Z: ...", and "ImportSystemModules" is now "ImportSystemModules ...".

    Since I basically want to do this only for my own module functions, I will probably use this function, defined in the first of my modules to be imported:

       function global:Set-FunctionDescription {
       
       param (
           # the name of the function whose description is to be set
           $FunctionName
       )
       
           # does the parameter refer to a function?
           if ( test-path function:$FunctionName ) {
        
               # parameter is a function, set its description property
               iex @"
               (get-command $FunctionName).description = (get-help $FunctionName).synopsis
       "@
           } else {
               write-error -Message "The value of parameter -FunctionName is not the name of a function"
           }
       
       }

    I have a similar one to define aliases, giving their -description property as the .synopsis of the function they are aliased to, or a literal string parameter for aliases that reference functions other than mine, cmdlets, or anything not having a useful .synopsis value.


    Al Dunbar

    viernes, 24 de febrero de 2012 16:15
  • So, I'm (still) a bit confused. I import my modules from the profile script, and they are available to me interactively, from a script, from a function, so, I consider them global, or at least global to my "session". Why then cannot the description property added by the same module script take on the same scope, i.e. and be visible at any scope in my session?

    If I define the function as explicitly global, that effectively makes the description property stick.

    I then thought of tacking on the -global qualifier to the import-module in my profile script, as noted in the help:

    -Global [<SwitchParameter>]
           When used in a script module (.psm1), this parameter imports modules into the global session state.

           This parameter is effective only when it appears in a script module. Otherwise, it is ignored.

           By default, the commands in a script module, including commands from nested modules, are imported into the caller's session state. To restrict the commands that a module exports, use an Export-ModuleMember command in the script module.

    Then I noticed the bit I emphasized above: To do this I'd need to have the profile script import a module containing a script that imported all the other modules. seems a bit extreme, so what I'll probably do is define all my module functions (and aliases) as global.

    Can anyone suggest any downside in doing so?


    Al Dunbar

    sábado, 25 de febrero de 2012 21:17