简体   繁体   中英

How to list all installed, runnable cmdlets in powershell?

I want to list all installed, runable cmdlets and functions in powershell but Get-Command is listing cmdlets which are somehow "there" but not loaded and not runnable.

As an example, Get-Command lists New-IseSnippet :

PS W:\> get-command "*-*" -CommandType Function,Cmdlet | where name -like "New-IseSnippet" | select name,module,path

Name           Module path
----           ------ ----
New-IseSnippet ISE

So it looks like we have a New-IseSnippet command - let's inspect it:

PS W:\> get-command New-IseSnippet
get-command : The term 'New-IseSnippet' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that 
the path is correct and try again.
At line:1 char:1
+ get-command New-IseSnippet
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (New-IseSnippet:String) [Get-Command], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand

Nope, can we run it?:

PS W:\> New-IseSnippet
New-IseSnippet : The 'New-IseSnippet' command was found in the module 'ISE', but the module could not be loaded. For more information, run 'Import-Module ISE'.
At line:1 char:1
+ New-IseSnippet
+ ~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (New-IseSnippet:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CouldNotAutoloadMatchingModule

Nope.

How do we get only installed, runnable commands?

As for this root query ...

I want to list all installed, runable cmdlets and functions in powershell

... In my personal library, here is part of a snippet I created/put-together, a long time ago and update as needed, for exactly this kind of use case. There is far more in my snippet , but this should get you what you are after as per your post. This being my my snippet library in ISE / VSCode, I bring it up anytime as need using CTRL + J and selecting it in the ISE and just typing Help in VSCode and selecting it.

# Get parameters, examples, full and Online help for a cmdlet or function

# Get a list of all Modules
Get-Module -ListAvailable | 
Out-GridView -PassThru -Title 'Available modules'

# Get a list of all functions
Get-Command -CommandType Function | 
Out-GridView -PassThru -Title 'Available functions'

# Get a list of all commandlets
Get-Command -CommandType Cmdlet | 
Out-GridView -PassThru -Title 'Available cmdlets'

# Get a list of all functions for the specified name
Get-Command -Name '*ADGroup*' -CommandType Function | 
Out-GridView -PassThru -Title 'Available named functions'

# Get a list of all commandlets for the specified name
Get-Command -Name '*ADGroup**'  -CommandType Cmdlet | 
Out-GridView -PassThru -Title 'Available named cmdlet'

# get function / cmdlet details
Get-Command -Name Get-ADUser -Syntax
(Get-Command -Name Get-ADUser).Parameters.Keys
Get-help -Name Get-ADUser -Full
Get-help -Name Get-ADUser -Online
Get-help -Name Get-ADUser -Examples

# Get parameter that accepts pipeline input
Get-Help Get-ADUser -Parameter * | 
Where-Object {$_.pipelineInput -match 'true'} | 
Select * 

# List of all parameters that a given cmdlet supports along with a short description:
Get-Help dir -para * | 
Format-Table Name, { $_.Description[0].Text } -wrap


# Find all cmdlets / functions with a target parameter
Get-Command -CommandType Function | 
Where-Object { $_.parameters.keys -match 'credential'} | 
Out-GridView -PassThru -Title 'Available functions which has a specific parameter'

Get-Command -CommandType Cmdlet | 
Where-Object { $_.parameters.keys -match 'credential'} | 
Out-GridView -PassThru -Title 'Results for cmdlets which has a specific parameter'

# Get named aliases 
Get-Alias | 
Out-GridView -PassThru -Title 'Available aliases'

# Get cmdlet / function parameter aliases
(Get-Command Get-ADUser).Parameters.Values | 
where aliases | 
select Name, Aliases | 
Out-GridView -PassThru -Title 'Alias results for a given cmdlet or function.'

### Query Powershell Data Types
[AppDomain]::CurrentDomain.GetAssemblies() | 
Foreach-Object { $_.GetExportedTypes() }

# Or 

[psobject].Assembly.GetType(“System.Management.Automation.TypeAccelerators”)::get

# Or

[psobject].Assembly.GetType("System.Management.Automation.TypeAccelerators")::Get.GetEnumerator() `
| Sort-Object -Property Key

<#
 Get any .NET types and their static methods from PowerShell. 
 Enumerate all that are currently loaded into your AppDomain.
#>  
[AppDomain]::CurrentDomain.GetAssemblies() | 
foreach { $_.GetTypes() } | 
foreach { $_.GetMethods() } | 
where { $_.IsStatic } | 
select DeclaringType, Name | 
Out-GridView -PassThru -Title '.NET types and their static methods'

As already noted, there are things (not necessarily modules / cmdlets always) that are ISE only (that's anything in the ISE module or the like of course) depending on what you are after / doing, such as lots form stuff, but as long as you add the appropriate form classes / types to your code, they should run just fine in the consolehost as well.

Yet, it is not correct to think that anything that is marked as ISE would ever run anywhere else. There are lots of ISE addons as well. You can get to them via the ISE Add-Ons menu. Anything in that menu should never be expected in the consolehost. For example, that is a built in tool to open a text-based files in an ISE editor tab directly, psEdit.

Get-Help -Name psedit

NAME
    psEdit
    
SYNTAX
    psEdit [-filenames] <Object>  [<CommonParameters>]
    

ALIASES
    None
    

REMARKS
    None

Trying to use that in the console host will fail, since the console host does not have such an editor.

You can programmatically do things in the ISE as well, and of course this sort of thing would never work in the consolehost.

See details here: The ISE Object Model Hierarchy

To make sure stuff is where it should be when you need it, adjust you PowerShell profiles. For example here is a sample of what mine has in it to deal with when I am in the ISE vs the consolehost.

# Validate if in the ISE or not

If ($Host.Name -match 'ISE')
{
    Import-Module -Name PsISEProjectExplorer
    Import-Module -Name PSharp
    Import-Module -Name ClassExplorer

}

If ($Host.Name -notmatch 'ISE')
{ Import-Module -Name PSReadline }

Import-Module -Name PSScriptAnalyzer
Import-Module -Name Posh-SSH
Import-Module -Name ModuleLibrary -DisableNameChecking
Import-Module -Name Pester
Import-Module -Name PSKoans


If ($Host.Name -match 'ISE')
{
    #Script Browser Begin
    #Version: 1.3.2
    Add-Type -Path 'C:\Program Files (x86)\Microsoft Corporation\Microsoft Script Browser\System.Windows.Interactivity.dll'
    Add-Type -Path 'C:\Program Files (x86)\Microsoft Corporation\Microsoft Script Browser\ScriptBrowser.dll'
    Add-Type -Path 'C:\Program Files (x86)\Microsoft Corporation\Microsoft Script Browser\BestPractices.dll'
    $scriptBrowser = $psISE.CurrentPowerShellTab.VerticalAddOnTools.Add('Script Browser', [ScriptExplorer.Views.MainView], $true)
    $scriptAnalyzer = $psISE.CurrentPowerShellTab.VerticalAddOnTools.Add('Script Analyzer', [BestPractices.Views.BestPracticesView], $true)
    $psISE.CurrentPowerShellTab.VisibleVerticalAddOnTools.SelectedAddOnTool = $scriptBrowser
    #Script Browser End

    Set-StrictMode  -Version Latest 
}

Update for the OP

As for …

So, is there a way to query commands which are actually loaded and runnable in the powershell.exe (or pwsh.exe) console?

Not in the sense I take you are thinking. You seem to have a concept of what cmdlets are loaded on startup. That's not a thing. cmdlets are exposed by module loading, and paths. What you are expecting is for PowerShell to only display modules / cmdlets / functions based on what PowerShell version / environment you are in. That is not a thing either. PowerShell will have access to all of .Net on your system and anything in the defined paths. Whether you load and use them or not, is a different matter.

Get-Module                # will show you all currently loaded ones.
Get-Module -ListAvailable # Will show all modules installed on your system.

If you are on PSv3 and higher, anything is your system environment and PowerShell paths are always available, as anything you call in the path would be auto-loaded when you try and use it.

Again Get-Command will list all available, they are only loaded when you call one, and gone when the call or session is done / closed of course.

If you have modules, cmdlets / functions not in the expected (environment or PS paths) places, then you either have to add that path or use the use the UNC path to them to run them. So, anything in the paths, dot-sourced from any UNC, are always available. If you are in the ISE, you can see this in the Commands tab, or in the console by using Get-Command.

You can add paths temporarily on the fly or using your PowerShell profiles or permanently on the fly, via your PowerShell profile, or using the Windows Environment variable dialog.

The consolehost and the ISE will always list any module, cmdlet, function in the expected paths. They does not mean that are all usable. As noted the ISe specific modules, cmdlets, functions will only work in the ISE for obvious reasons. Yet, the ISE will run any module, cmdlet , function the console host will, except for PSReadline. Well it will load it, but it won't do anything in the ISE console. The ISE console is really an output windows not a the same thing as the consolehost. Well, you can do consolehost like stuff in it, but it's not the same thing.

So, modules are loaded, modules expose the cmdlets / functions in them. Not all modules are loaded by default, hence the reason for the two command above, this is why Import-Module and auto load on call, exists. Standalone personal module / cmdlets / functions / scripts are not something PS will know about until you tell it where they should be imported / loaded / used from.

If you are really curious about this sort of thing you can leverage the Trace-Command cmdlet ...

Trace-Command

$A = "i*"
Trace-Command ParameterBinding {Get-Alias $Input} -PSHost -InputObject $A

DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Get-Alias]
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Get-Alias]
DEBUG: ParameterBinding Information: 0 :     BIND arg [System.Object[]] to parameter [Name]
DEBUG: ParameterBinding Information: 0 :         Binding collection parameter Name: argument type [Object[]], parameter type [System.String[]], collection type 
Array, element type [System.String], no coerceElementType
DEBUG: ParameterBinding Information: 0 :         Arg is IList with 1 elements
DEBUG: ParameterBinding Information: 0 :         Creating array with element type [System.String] and 1 elements
DEBUG: ParameterBinding Information: 0 :         Argument type System.Object[] is IList
DEBUG: ParameterBinding Information: 0 :         Adding 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-Alias]
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing

... with your code to see what is actually being called and you will see that it is called each time you run the code.

The more modules you install, the moire cmdlets / functions become available. If you really think about this for a moment, their are hundreds of modules out their, and thus thousands of exposed cmdlets / functions. Why would you want all that loaded in memory. Your system would just fail due to resource exhaustion. So, only load what you really need, PowerShell will only call what it needs when it needs it. Know what is ISE specific and ignore all of that if you intend to live in the console host, or live in the ISE / VSCode, and shell out to the consolehost only when needed. This is how I do things. I rarely, if ever need to go to the console host for anything. ISE is my default, VSCode is my secondary (for now). There are those who poo-poo the ISE, I am not one of those types.

Update for OP

As for...

My use case is not a user sitting at a PC but a NodeJS application which runs the powershell.exe (PS5) or pwsh.exe (PS6/Core) host. I totally get that modules may be "available" but not loaded and that's what I want to query: which cmdlets/functions are loaded (ie available to be run now without loading a module). I find it weird/buggy that Get-Command * will list Cmdlet X but Get-Command X wil crap out. How do I query a command: are you loaded runnable? PS: Google "powowshell" to see my project.

It would have helped just to put the link to your project vs making me search for it. 8-} and the fact that it only shows in in Google and not other engine like DuckDuckGo or Bing is a bit odd, but oh well.

So, you mean this collection ---

http://cawoodm.blogspot.com https://github.com/cawoodm/powowshell .

I'll take a look. Yet, for what you are after, don't use Get-Command by itself. Use Get-Module in concert with Get-Command to list the cmdlets / functions from those loaded modules, to get closer to what you are after. By doing it this way, only the loaded modules and the associated cmdlets / functions for that session are listed.

# List all loaded session modules and the exposed cmdlets / functions in them
Get-Module -Name '*' | 
ForEach-Object { Get-Command -Module $PSItem }

# Results

 # List all loaded modules and the exposed cmdlets / functions in them
Get-Module -Name '*' | 
ForEach-Object { Get-Command -Module $PSItem }

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
... 
Cmdlet          Export-BinaryMiLog                                 1.0.0.0    CimCmdlets
Cmdlet          Get-CimAssociatedInstance                          1.0.0.0    CimCmdlets
Cmdlet          Get-CimClass                                       1.0.0.0    CimCmdlets
...
Cmdlet          Find-Member                                        1.1.0      ClassExplorer
Cmdlet          Find-Namespace                                     1.1.0      ClassExplorer
Cmdlet          Find-Type                                          1.1.0      ClassExplorer
...
Function        Get-IseSnippet                                     1.0.0.0    ISE
Function        Import-IseSnippet                                  1.0.0.0    ISE
Function        New-IseSnippet                                     1.0.0.0    ISE
Cmdlet          Add-Computer                                       3.1.0.0    Microsoft.PowerShell.Management
Cmdlet          Add-Content                                        3.1.0.0    Microsoft.PowerShell.Management
Cmdlet          Checkpoint-Computer                                3.1.0.0    Microsoft.PowerShell.Management                                   
...

Update for OP

As for ...

Your solution wil fail to list cmdlets/functions (eg ForEach-Object or Stop-Job) which have no module association (64 on my system). Also, how sure are you Get-Module returns only loaded modules?

PowerShell gets cmdlets and functions from PowerShell sources and Modules.

If you do a lookup on the cmdlets / functions you are pointing to, you will see where they come from here :

'ForEach-Object','Start-Job' | 
    ForEach{
                Get-Command -CommandType Cmdlet -Name $PSItem | 
                Format-Table -AutoSize
           }

<#
CommandType Name           Version Source                   
----------- ----           ------- ------                   
Cmdlet      ForEach-Object 3.0.0.0 Microsoft.PowerShell.Core



CommandType Name      Version Source                   
----------- ----      ------- ------                   
Cmdlet      Start-Job 3.0.0.0 Microsoft.PowerShell.Core
#>

So, the base cmdlets / functions are not from an Import-Module effort. There are just there by design in the OS/.Net install.

So, my solution is not a fail and I never said it would get you 100% by using that. It was a way of showing you what modules load for use what cmdlets / functions and that has little to nothing to do with what Microsoft.PowerShell.Core, .Net holistically and/or what the OS version allows (Cmdlets/Functions/Modules are also OS and $PSVersion specific as we all know).

So, again, your use case for what you are trying to devise is not valid. Cmdlets and functions, regardless of source are not loaded and ready for use. They are installed or exposed and available for use when you need to call them via the aforementioned. They are not ever loaded (sitting in memory) until you call them, no more that anything in the GAC is.

So, looking at you project, I see what you are trying to do, but you are trying to think for the user. Just as you as a developer have to reference an assembly from the GAC (which has thousands of things that are there, but are not loaded until you reference them), and you have to know where it is and which one you want to use and why. So, goes the same mindset for what PowerShell can have access to. Note, I said access to, not whether you can use it or not in a PowerShell session.

So, if we step into this, we get...

Cmdlets / Function come from. The OS (DLLs), [.Net][4], [Core module][3], and those exported from the modules you Import.

So, again, you thought has to be, what is available, or made available when modules or DLLs are imported. Imported modules and their associated cmdlets / function may not work, depending on what type of session you in. Meaning, ISE vs consolhost.

FYI, you have to widen you view of this...

In the ISE

# Total host available commands cmdlet / Functions regadless where the come from
(Get-Command).Count
8750
# Total host avaialble cmdlets
(Get-Command -CommandType Cmdlet).Count
4772
# Total host available functions
(Get-Command -CommandType Function).Count
3035

# Difference of host available cmdlets / functions not shown that are part of the previous two calls.
(Get-Command).Count - ((Get-Command -CommandType Cmdlet).Count + (Get-Command -CommandType Function).Count)
943

# Further breakdown
(Get-Command -CommandType Alias).Count
1446
(Get-Command -CommandType Application).Count
937
(Get-Command -CommandType Configuration).Count
# The property 'Count' cannot be found on this object. Verify that the property exists.
(Get-Command -CommandType ExternalScript).Count
2
(Get-Command -CommandType Script).Count
# The property 'Count' cannot be found on this object. Verify that the property exists.
(Get-Command -CommandType Filter).Count
2
(Get-Command -CommandType Workflow).Count
# The property 'Count' cannot be found on this object. Verify that the property exists.
(Get-Command -CommandType All).Count
10219


# Get a list of all Modules
(Get-Module -ListAvailable).Count
387

# Get a list of all loaded Modules
(Get-Module).Count
12

# List all loaded session modules and the exposed cmdlets / functions in them
(Get-Module -Name '*' | 
ForEach-Object { Get-Command -Module $PSItem }).Count
505

(Get-Module -ListAvailable | 
ForEach {
    Get-Module -Name $PSItem.Name | 
    ForEach-Object { Get-Command -Module $PSItem }
}).Count
669



# If I Import another 3rdP module I installed from the gallery, things will change of course

Import-Module -Name ShowUI

# Get a list of all Modules
(Get-Module -ListAvailable).Count
387

# Get a list of all loaded Modules
(Get-Module).Count
13

# List all loaded session modules and the exposed cmdlets / functions in them
(Get-Module -Name '*' | 
ForEach-Object { Get-Command -Module $PSItem }).Count
937

(Get-Module -ListAvailable | 
ForEach {
    Get-Module -Name $PSItem.Name | 
    ForEach-Object { Get-Command -Module $PSItem }
}).Count
1101

In the consolehost - note the differences

# Total host available commands cmdlet / Functions regadless where the come from
(Get-Command).Count
9191

# Total host avaialble cmdlets
(Get-Command -CommandType Cmdlet).Count
4772

# Total host available functions
(Get-Command -CommandType Function).Count
3472

# Difference of host available cmdlets / functions not shown that are part of the previous two calls.
(Get-Command).Count - ((Get-Command -CommandType Cmdlet).Count + (Get-Command -CommandType Function).Count)
947


# Further breakdown
(Get-Command -CommandType Alias).Count
1809

(Get-Command -CommandType Application).Count
937

(Get-Command -CommandType Configuration).Count
0
# The property 'Count' cannot be found on this object. Verify that the property exists.
(Get-Command -CommandType ExternalScript).Count
2

(Get-Command -CommandType Script).Count
0
# The property 'Count' cannot be found on this object. Verify that the property exists.
(Get-Command -CommandType Filter).Count
1

(Get-Command -CommandType Workflow).Count
1
# The property 'Count' cannot be found on this object. Verify that the property exists.
(Get-Command -CommandType All).Count
10994




# Get a list of all Modules
(Get-Module -ListAvailable).Count
387

# Get a list of all loaded Modules
(Get-Module).Count
8

# List all loaded session modules and the exposed cmdlets / functions in them
(Get-Module -Name '*' | 
ForEach-Object { Get-Command -Module $PSItem }).Count
467

(Get-Module -ListAvailable | 
ForEach {
    Get-Module -Name $PSItem.Name | 
    ForEach-Object { Get-Command -Module $PSItem }
}).Count
623



# If I Import another 3rdP module I installed from the gallery, things will change of course

Import-Module -Name ShowUI

# Get a list of all Modules
(Get-Module -ListAvailable).Count
387


# Get a list of all loaded Modules
(Get-Module).Count
9


# List all loaded session modules and the exposed cmdlets / functions in them
(Get-Module -Name '*' |
ForEach-Object { Get-Command -Module $PSItem }).Count
899


(Get-Module -ListAvailable |
ForEach {
    Get-Module -Name $PSItem.Name |
    ForEach-Object { Get-Command -Module $PSItem }
}).Count
1055

Unfortunately, as you've discovered, PowerShell's command discovery, as surfaced by Get-Command , may also include commands that you cannot actually run in your session .

There are good reasons for that, and not so good reasons:

  • (a) Commands from modules that - do or may - require a different PowerShell edition are still included, the only exception being the ones on Windows in $PSHOME/Modules - modules in other directories on Windows and on Unix-like platforms all modules in $env:PSModulePath are invariably considered compatible - the PSCompatibleEdition module-manifest entry is NOT consulted as of PowerShell Core 6.2.1.

  • (b) As of PowerShell Core 6.2.1 / Windows PowerShell v5.1, there is NO way to restrict modules by supported platform(s) (OS)

  • (c) The PowerShellHostName and PowerShellHostVersion module-manifest entries are NOT checked for compatibility during command discovery to ensure PowerShell host compatibility - only at module-import time .

(a) is a design decision (at least for now), (b) is not implemented yet, but (c) - the issue you ran into - should arguably be fixed, because it is an easy check to perform. I encourage you to request a change at https://github.com/PowerShell/PowerShell/issues .

Generally speaking, command discovery must be limited to examining module manifests to determine compatibility; anything beyond that - trying to actually load each module - would be too time- and resource-intensive.


What adds to the confusion is that Get-Command with a literal command name reports a misleading error message as of PowerShell Core 6.2.1 / Windows PowerShell v5.1:

Unlike with a wildcard expression (eg, *-* ), a literal command name (eg, New-IseSnippet ) causes Get-Command to implicitly import the command's module, which is the ultimate tests of the command's availability in the current session - and that may fail .

Unfortunately, the way it fails misleadingly suggests that no such command is defined , whereas the real problem is the inability to import the module that contains the command.

Direct invocation of the same command more helpfully indicates that the real problem is the inability to import the module (though, arguably, it shouldn't just tell you to run Import-Module yourself in order to learn the specific reason, and instead do that for you and then report that reason).

I've written you two functions that will help you to enumerate all installed commands that can be run on your system.

Get-CommandsByModule : enumerates every available command in a module, by type (defined by all of the available types in the -CommandType switch). This will also display the count of items by type per module, and after enumarating all commands in all modules will display a summary of the total commands per type that are installed on your system. It's easy to extend this function to test each command to see if the command is valid as it collects them (though that will slow down the function a lot). To just view commands of a certain type you can run with the function with arguments, eg

Get-CommandsByModule     # Will output all types of command found in each Module
Get-CommandsByModule function,cmdlet,alias   # Just display functions, cmdlets and aliases

def : Primarily for Functions and Aliases (though will show information for all command types), this will show you the contents/definition of that function/alias and what Module it resides in.

def <any-command>   # command can be cmdlet, function, alias, etc

Function Get-CommandsByModule:

function Get-CommandsByModule ($usertype) {
    function Write-Wrap {
        [CmdletBinding()]
        Param ( 
            [parameter (Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
            [Object[]] $chunk
        )
        PROCESS {
            $Lines = @()
            foreach ($line in $chunk) {
                $str = ''
                $counter = 0
                $line -split '\s+' | %{
                    $counter += $_.Length + 1
                    if ($counter -gt $Host.UI.RawUI.BufferSize.Width) {
                        $Lines += ,$str.trim()
                        $str = ''
                        $counter = $_.Length + 1
                    }
                    $str = "$str$_ "
                }
                $Lines += ,$str.trim()
            }
            $Lines
        }
    }
    
    $types = @("Alias", "Function", "Filter", "Cmdlet", "ExternalScript", "Application", "Script", "Workflow", "Configuration")
    if ($null -ne $usertype) { $types = @($usertype)}
    foreach ($type in $types) { New-Variable -Name $type -Value 0 }   # Dynamically generated variables
    foreach ($mod in Get-Module -ListAvailable) {
        "`n`n####################`n#`n# Module: $mod`n#`n####################`n"
        foreach ($type in $types) {
            $out = ""
            $commands = gcm -Module $mod -CommandType $type | sort
            foreach ($i in $commands) {
                $out = "$out, $i"
            }
            $count = ($out.ToCharArray() | Where-Object { $_ -eq ',' } | Measure-Object).Count   # Could just count $i but this is 

            if ($count -ne 0) {
                $out = $out.trimstart(", ")
                $out = "`n$($type.ToUpper()) objects [ $count ] >>> $out"
                Write-Wrap $out
                # Example of using New-, Set-, Get-Variable for dynamically generated variables
                Set-Variable -Name $type -Value $((Get-Variable -Name $type).Value + $count)
                # https://powershell.org/forums/topic/two-variables-into-on-variable/
                # "$type Total = $total"
                ""
            }
        }
    }
    ""
    "`n`n####################`n#`n# Commands by type installed on this system`n#`n####################`n"
    foreach ($type in $types) { "Total of type '$type' = $((Get-Variable -Name $type).Value)" }
}

Function def:

function def {   
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [ArgumentCompleter({ [Management.Automation.CompletionResult]::Command })]
        [string]$cmd,
        [switch]$Examples
    )

    function Write-Wrap {
        [CmdletBinding()]Param( [parameter(Mandatory=1, ValueFromPipeline=1, ValueFromPipelineByPropertyName=1)] [Object[]]$chunk )
        $Lines = @()
        foreach ($line in $chunk) {
            $str = ''; $counter = 0
            $line -split '\s+' | % {
                $counter += $_.Length + 1
                if ($counter -gt $Host.UI.RawUI.BufferSize.Width) {
                    $Lines += ,$str.trim()
                    $str = ''
                    $counter = $_.Length + 1
                }
                $str = "$str$_ "
            }
            $Lines += ,$str.trim()
        }
        $Lines
    }

    $deferr = 0; $type = ""
    try { $type = ((gcm $cmd -EA silent).CommandType); if ($null -eq $type) { $deferr = 1 } } catch { $deferr = 1 }

    if ($deferr -eq 1) {
        if ($cmd -eq $null) { Write-Host "Object is `$null" ; return } 
        Write-Host "`$object | Convert-Json:" -F Cyan
        $cmd | ConvertTo-Json
        ""
        Write-Host "(`$object).GetType()" -F Cyan -NoNewline ; Write-Host " :: [BaseType|Name|IsPublic|IsSerial|Module]"
        ($cmd).GetType() | % { "$($_.BaseType), $($_.Name), $($_.IsPublic), $($_.IsSerializable), $($_.Module)" }
        ""
        Write-Host "`$object | Get-Member -Force" -F Cyan
        $m = "" ; $cm = "" ; $sm = ""; $p = "" ; $ap = "" ; $cp = "" ; $np = "" ; $pp = "" ; $sp = "" ; $ms = ""
        $msum = 0 ; $cmsum = 0 ; $smsum = 0 ; $psum = 0 ; $cpsum = 0 ; $apsum = 0 ; $spsum = 0 ; $ppsum = 0 ; $npsum = 0 ; $spsum = 0 ; $mssum = 0
        $($cmd | Get-Member -Force) | % {
            if ($_.MemberType -eq "Method") { if(!($m -like "*$($_.Name),*")) { $m += "$($_.Name), " ; $msum++ } }
            if ($_.MemberType -eq "CodeMethod") { if(!($cm -like "*$($_.Name),*")) { $cm += "$($_.Name), " ; $cmsum++ } }
            if ($_.MemberType -eq "ScriptMethod") { if(!($sm -like "*$($_.Name),*")) { $sm += "$($_.Name), " ; $smsum++ } }
            if ($_.MemberType -eq "Property") { if(!($p -like "*$($_.Name),*")) { $p += "$($_.Name), " ; $psum++ } }
            if ($_.MemberType -eq "AliasProperty") { if(!($ap -like "*$($_.Name),*")) { $ap += "$($_.Name), " ; $apsum++ } }
            if ($_.MemberType -eq "CodeProperty") { if(!($cp -like "*$($_.Name),*")) { $cp += "$($_.Name), " ; $cpsum++ } }
            if ($_.MemberType -eq "NoteProperty") { if(!($np -like "*$($_.Name),*")) { $np += "$($_.Name), " ; $npsum++ } }
            if ($_.MemberType -eq "ParameterizedProperty") { if(!($pp -like "*$($_.Name),*")) { $pp += "$($_.Name), " ; $ppsum++} }
            if ($_.MemberType -eq "ScriptProperty") { if(!($sp -like "*$($_.Name),*")) { $sp += "$($_.Name), " ; $npsum++ } }
            if ($_.MemberType -eq "MemberSet") { if(!($ms -like "*$($_.Name),*")) { $ms += "$($_.Name), " ; $mssum++ } }
            # AliasProperty, CodeMethod, CodeProperty, Method, NoteProperty, ParameterizedProperty, Property, ScriptMethod, ScriptProperty
            # All, Methods, MemberSet, Properties, PropertySet
        }
        if($msum -ne 0) { Write-Wrap ":: Method [$msum] => $($m.TrimEnd(", "))" }
        if($msum -ne 0) { Write-Wrap ":: CodeMethod [$cmsum] => $($cm.TrimEnd(", "))" }
        if($msum -ne 0) { Write-Wrap ":: ScriptMethod [$smsum] => $($sm.TrimEnd(", "))" }
        if($psum -ne 0) { Write-Wrap ":: Property [$psum] => $($p.TrimEnd(", "))" }
        if($npsum -ne 0) { Write-Wrap ":: AliasProperty [$apsum] => $($ap.TrimEnd(", "))" }
        if($npsum -ne 0) { Write-Wrap ":: CodeProperty [$cpsum] => $($cp.TrimEnd(", "))" }
        if($npsum -ne 0) { Write-Wrap ":: NoteProperty [$npsum] => $($np.TrimEnd(", "))" }
        if($ppsum -ne 0) { Write-Wrap ":: ParameterizedProperty [$ppsum] => $($pp.TrimEnd(", "))" }
        if($spsum -ne 0) { Write-Wrap ":: ScriptProperty [$spsum] => $($sp.TrimEnd(", "))" }
        if($mssum -ne 0) { Write-Wrap ":: ScriptProperty [$mssum] => $($ms.TrimEnd(", "))" }
        ""
        Write-Host "`$object | Measure-Object" -F Cyan
        $cmd | Measure-Object | % { "Count [$($_.Count)], Average [$($_.Average)], Sum [$($_.Sum)], Maximum [$($_.Maximum)], Minimum [$($_.Minimum)], Property [$($_.Property)]" }
    }

    if ($deferr -eq 0) {

        if ($cmd -like '*`**') { Get-Command $cmd ; break }   # If $cmd contains a *, then just check for commands, don't find definitions

        if ($type -eq 'Cmdlet') {
            Write-Host "`n'$cmd' is a Cmdlet:`n" -F Green
            Write-Host "SYNOPSIS, DESCRIPTION, SYNTAX for '$cmd'.   " -F Green
            Write-Host "------------"
            Write-Host ""
            Write-Host "(Get-Help $cmd).Synopsis" -F Cyan 
            Write-Host "$((Get-Help $cmd).Synopsis)"
            Write-Host ""
            Write-Host "(Get-Help $cmd).Description.Text" -F Cyan
            try {
                $arrdescription = (Get-Help $cmd).Description.Text.split("`n")
                foreach ($i in $arrdescription) { Write-Wrap $i }
            } catch { "Could not resolve description for $cmd" }
            Write-Host ""
            Write-Host "(Get-Command $cmd -Syntax)" -F Cyan
            $arrsyntax = (Get-Command $cmd -syntax).TrimStart("").Split("`n")  # Trim empty first line then split by line breaks
            foreach ($i in $arrsyntax) { Write-Wrap $i }   # Wrap lines properly to console width
            Get-Alias -definition $cmd -EA silent          # Show all defined aliases
            Write-Host "`nThis Cmdlet is in the '$((Get-Command -type cmdlet $cmd).Source)' Module." -F Green
            Write-Host ""
            Write-Host ""
        }
        elseif ($type -eq 'Alias') {
            Write-Host "`n'$cmd' is an Alias.  " -F Green -NoNewLine ; Write-Host "This Alias is in the '$((get-command -type alias $cmd).ModuleName).' Module"
            Write-Host ""
            Write-Host "Get-Alias '$cmd'   *or*    cat alias:\$cmd" -F Cyan
            cat alias:\$cmd   # Write-Host "$(cat alias:\$cmd)"   # "$((Get-Alias $cmd -EA silent).definition)"
            if ($cmd -eq '?') { $cmd = '`?' }   # To deal correctly with the wildcard '?'
            "`n'$((Get-Alias $cmd).Name)' is an alias of '$((Get-Alias $cmd).ReferencedCommand)'"
            $fulldef = (Get-Alias $cmd -EA silent).definition   # Rerun def but using the full cmdlet or function name.
            def $fulldef
            if ($Examples -eq $true) { $null = Read-Host 'Press any key to view command examples' ; get-help $fulldef -examples }
        }
        elseif ($type -eq 'Function') {
            Write-Host "`n'$cmd' is a Function.  " -F Green -NoNewline
            Write-Host "`ncat function:\$cmd   (show contents of function)`n" -F Cyan ; cat function:\$cmd ; Write-Host ""
            Write-Host "cat function:\$cmd`n" -F Cyan
            Write-Host ""
            Write-Host "SYNOPSIS, SYNTAX for '$cmd'.   " -F Green
            Write-Host "------------"
            $arrsynopsis = ((Get-Help $cmd).Synopsis).TrimStart("").Split("`n")  # Trim empty first line then split by line breaks
            $arrsyntax = (Get-Command $cmd -syntax).TrimStart("").Split("`n")    # Often synopsis=syntax for function so use Compare-Object
            if ($null -eq $(Compare-Object $arrsynopsis $arrsyntax -SyncWindow 0)) { 
                Write-Host "'(Get-Help $cmd).Synopsis'" -F Cyan -N
                Write-Host " and " -N
                Write-Host "'Get-Command $cmd -Syntax'" -F Cyan -N
                Write-Host " have the same output for this function:`n"
                foreach ($i in $arrsynopsis) { Write-Wrap $i }   # Wrap lines properly to console width
            } else { 
                Write-Host "(Get-Help $cmd).Synopsis" -F Cyan
                foreach ($i in $arrsynopsis) { Write-Wrap $i }   # Wrap lines properly to console width
                Write-Host ""
                Write-Host "Get-Command $cmd -Syntax" -F Cyan
                foreach ($i in $arrsyntax) { Write-Wrap $i }     # Wrap lines properly to console width
            }
            Write-Host "The '$cmd' Function is in the '$((get-command -type function $cmd).Source)' Module." -F Green
            Write-Host ""
            if ($Examples -eq $true) { $null = Read-Host "Press any key to view command examples" ; get-help $cmd -examples }
            Write-Host ""
        }
        elseif ($type -eq 'ExternalScript') {   # For .ps1 scripts on path
            $x = gcm $cmd
            Write-Host "`n'$cmd' is an ExternalScript (i.e. a .ps1 file on the path)." -F Green
            Write-Host "`n$($x.Path)`n" -F Green
            Write-Host "`n$($x.ScriptContents)"
            Write-Host ""
            if ($Examples -eq $true) { $null = Read-Host "Press any key to view command examples" ; get-help $cmd -Examples }
            elseif ($Synopsis -eq $true) { $null = Read-Host "Press any key to view command examples" ; (get-help $cmd).Synopsis }
            elseif ($Syntax -eq $true) { $null = Read-Host "Press any key to view command examples" ; Get-Command $cmd -Syntax }
            Write-Host ""
        }
        elseif ($type -eq 'Application') {      # For .exe etc on path
            Write-Host "`n'$cmd' was found. It is an Application (i.e. a .exe or similar located on the path)." -F Green
            Write-Host "`n$(where.exe $cmd)" -F Green
            Write-Host ""
            Read-Host "Press any key to open cmd.exe and try '$cmd /?'" ; cmd.exe /c $cmd /? | more
            Write-Host ""
        }
    } elseif ((get-module -ListAvailable -Name $cmd) -ne $null) {
        # https://stackoverflow.com/questions/28740320/how-do-i-check-if-a-powershell-module-is-installed
        ""
        (get-module $cmd).path
        (get-module $cmd).ExportedFunctions
        "ExportedCommands (also note: get-command -Module $cmd)"
        (get-module custom-tools).ExportedCommands
        ""
        echo "get-module $cmd | get-member  # Just show the members"
        echo "get-module $cmd | fl *        # Show the contents of every member"
    }
    else {
        if ($cmd.length -eq 0) { "`n'$cmd': No command definition found. The command may require to be surround by ' or `"`nif it contains special characters (such as 'def `"&`"').`n" }
        else { "`nInput is not a command, so no command definition search.`n" }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM