Powershell how to use Get-command to display specific columns? - powershell

I need to use 'Get-Command" to display three specific columns of information. Name, CommandType, and Module. I am new to PowerShell and have been searching for hours to find an answer but have not been able to find any documentation that explains how to do this specifically.

I need to use 'Get-Command" to display three specific columns of information. Name, CommandType, and Module
Since your intent is to display the columns of interest, in tabular format, you can use Format-Table:
Get-Command | Format-Table -Property Name, CommandType, Module
For quick interactive use, you can shorten the command, by using aliases and positional parameter binding:
gcm | ft name, commandtype, module
However, note that Format-* cmdlets are only suited to for-display formatting, not for outputting data suitable for later programmatic processing - see this answer and the Select-Object solution below.
By contrast, if you need to construct new objects that have only a subset of the properties of the input objects (while possibly adding new properties / transforming or renaming existing ones via calculated properties[1]), you can use the Select-Object cmdlet:
Get-Command | Select-Object -Property Name, CommandType, Module
Note: If you print this command's output to the console (host), it will result in the same display output as the Format-Table call above, because PowerShell implicitly uses Format-Table formatting for objects that have 4 or fewer (public) properties.[2]
However, for explicit control of display formatting - such as if you want 5-property objects to be shown in tabular format too - Format-* cmdlets must be used.
[1] You may also use calculated properties with Format-Table, among other cmdlets.
[2] 5 or more properties result in Format-List formatting; Generally, this implicit formatting applies only to .NET types that do not have predefined formatting data associated with them; if they do, that data controls the default view and other aspects - see this answer.

Try piping it to select object
get-command|select-object -expandpoperty Name, CommandType, and Module

Related

Powershell - Get object properties displayed in console

The point is to populate a variable with a Powershell object's property name displayed in a console.
Meaning, if I run Get-Process, I only want the eight object's properties returned in the console which are 'Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName'.
Get-Member command is not helpful here.
Can anyone help me with that?
Thank you all!
To get the column names - which may or may not be property names - of the table view that is presented for a given .NET type if it has predefined formatting data (that includes a table view) associated with it:
Note:
The following is a proper, but nontrivial and limited solution that derives the column names from the formatting data, using the first table-view definition found. It also has conceptual background information.
See the bottom section for a quick-and-dirty solution for getting the column names only, which uses text parsing to extract the column names directly from a given command's formatted output.
The middle section builds on this first section and extracts a list of property names and calculated properties mirroring the column definitions, which can be used with Select-Object, in order to create custom objects that have properties with the same values that the formatting data produces.
# Determine the .NET type of interest.
$type = (Get-Process)[0].GetType()
# Extract the names of the column headers from the *first* table-view definition.
Get-FormatData $type -PowerShellVersion $PSVersionTable.PSVersion |
ForEach-Object FormatViewDefinition |
Where-Object Control -is [System.Management.Automation.TableControl] |
Select-Object -First 1 |
ForEach-Object {
$i = 0
$rows = $_.Control.Rows
foreach ($colLabel in $_.Control.Headers.Label) {
if ($colLabel) { $colLabel } # Explicit label, with a calculated column value or renamed property
else { $rows.Columns[$i].DisplayEntry.Value } # Property name, with its value as the column value.
++$i
}
}
Caveat: The above limits output to the first table-view definition found - which may or may not apply to a given command. Which definition is chosen by default is potentially governed by criteria associated with the definitions that select based on runtime conditions, including selecting by specific input type, given that a single instance of formatting data can cover multiple types.
Also note that views may involve grouping (as you see in Get-ChildItem's formatted output, for instance), and the grouping criterion isn't covered by the command above.
Note that even for a single type multiple views may be defined, and in order to use a non-default one you must request it explicitly, via Format-Table's -View parameter, assuming you know the name,[1] e.g. Get-Process | Format-Table -View StartTime).
See also:
This answer for how to inspect formatting data in full.
You can alternatively pipe Get-FormatData output to Export-FormatData in order to export formatting data to an XML file, which has the disadvantage of being hard to read, but has the advantage of matching the XML schema used for authoring formatting data - see next point - whereas the in-memory types used to represent formatting data partially use property names that don't match the underlying XML elements.
As for authoring formatting data, which as of PowerShell 7.2.2 requires XML files (*.Format.ps1xml):
See this answer for an example of how to define your own table view.
Formatting File Overview and the Format Schema XML Reference
Note:
Using -PowerShellVersion $PSVersionTable.PSVersion with Get-FormatData is only needed in Windows PowerShell, for certain types, to work around a bug that is no longer present in PowerShell (Core) 7.1+
While column names typically correspond to the property names of the type instances being formatted, that isn't always the case, such as with the [System.Diagnostics.Process] instances output by Get-Process.
A general caveat, as zett42 notes, is that display formatting of types isn't part of the public contract regarding breaking changes, so formatting definitions are allowed to change over time.
If a given type has no predefined formatting data associated with it (in which case Get-FormatData is a quiet no-op):
The names of its (public) instance properties are used as column
names.
You only get a table view by default if there are 4 or fewer properties but you can request it explicitly with Format-Table (With 5 or more properties, Format-List is applied by default).
To get the names of all (public) instance properties of a given object, use the intrinsic .psobject property, which is a rich source of reflection; e.g.:
(Get-Process | Select-Object -First 1).psobject.Properties.Name
To create a list of property names and calculated properties usable with Select-Object that mirror the formatting-data's column definition:
# Determine the .NET type of interest.
$type = (Get-Process)[0].GetType()
# Get an array of property names / calculated properties from the
# formatting data, for later use with Select-Object
$props =
Get-FormatData $type -PowerShellVersion $PSVersionTable.PSVersion |
ForEach-Object FormatViewDefinition |
Where-Object Control -Is [System.Management.Automation.TableControl] |
Select-Object -First 1 |
ForEach-Object {
$i = 0
$rows = $_.Control.Rows
foreach ($colLabel in $_.Control.Headers.Label) {
if ($colLabel) { # Explicit label, with a calculated column value or renamed property
#{
Name = $colLabel
Expression = if ('ScriptBlock' -eq $rows.Columns[$i].DisplayEntry.ValueType) {
[scriptblock]::Create($rows.Columns[$i].DisplayEntry.Value)
} else {
$rows.Columns[$i].DisplayEntry.Value
}
}
}
else { # Property name, with its value as the column value.
$rows.Columns[$i].DisplayEntry.Value
}
++$i
}
}
# Sample call
Get-Process | Select-Object -Property $props | Format-Table | more
The sample call produces similar output to just Get-Process alone, as it uses the column definitions as (calculated) properties - albeit with default values for formatting attributes such as column width and alignment.
Note the explicit use of Format-Table to ensure tabular output; without it - given that the [pscustomobject] instances created by Select-Object have no formatting data associated with them - list formatting (implied Format-List) would result.
As Mathias points out, the calculated properties will be string-typed even for columns based on numeric properties, because their purpose in the formatting data is to created formatted string representations.
Quick-and-dirty solution for getting the column names only:
The following uses Out-String -Stream in conjunction with Select-String to extract the column names from a given command's formatted output, which relies on two assumptions:
The column names have no embedded spaces
The command actually produces table-formatted output by default; however, you can insert a Format-Table call before Out-String, if desired.
Get-Process | Out-String -Stream | Select-String -List '^\s*--+' -Context 1, 0 |
ForEach-Object { -split $_.Context.PreContext[0] }
Output:
NPM(K)
PM(M)
WS(M)
CPU(s)
Id
SI
ProcessName
Note: In Windows PowerShell an additional property shows, as the first one: Handles.
[1] While tab-completion does offer view names, they appear to be out of sync with the actually available ones, as of PowerShell 7.2.2. To see the latter, provoke an error with a dummy name, and the error message will list the available ones; e.g. Get-Process | Format-Table -View NoSuch lists the following available views in the resulting error message: process, Priority, StartTime

How do I run multiple lines of code in PowerShell? [duplicate]

I'm getting unexpected results when executing two PowerShell commands separated by a semicolon. The output of the second command changes. If I run them in reverse order, I don't see the second command output.
Here I'm simply trying to get a time stamp and a list of groups a user belongs to in AD, as a one-liner.
If I run this line, i get the following output:
Get-ADPrincipalGroupMembership username | Select-Object name
name
----
Domain Users
CL-Inventory-Group
...
However if I run the following, this behavior changes:
get-date; Get-ADPrincipalGroupMembership username | Select-Object name
Wednesday, April 3, 2019 2:31:35 PM
name : Domain Users
name : CL-Inventory-Group
...
Stranger yet, If i run the in reverse, meaning i say get-date after the first command, the date stamp never shows up after the groups are listed.
Am I improperly separating commands?
tl;dr:
Submitting multiple ;-separated commands at the prompt (interactively) still sends their output to a single pipeline (you can think of each command line submitted as an implicit script file).
In short: in your case, the first command output's automatic display formatting also determined the display formatting for the 2nd command, so which command comes first matters:
get-date; Get-ADPrincipalGroupMembership username | Select-Object name
locked in implicit use of Format-List for all output following Get-Date, which explains the each-property-on-its-own line output from the Get-ADPrincipalGroupMembership ... command.
If i run the reverse, meaning i say get-date after the first command, the date stamp never shows up after the groups are listed.
Select-Object output instances of type [pscustomobject], which, due to their having just 1 property in this case, locked in tabular display, i.e., implicit use of Format-Table, with the selected property as the only column, i.e., just Name here. Since the [datetime] type output by Get-Date doesn't have a Name property, Get-Date's output was effectively invisible.
Read on for background information and the complete rules.
PowerShell's default display formatting is optimized for objects of the same type, as that is the typical case.
If a pipeline contains a mix of types, the specific formatting that results by default depends on:
the order of objects in the pipeline
and their default formatting behavior
See the next section for details.
You can use explicit Format-* calls to control the formatting; in your case, you can use Format-Table on your 2nd command to force tabular output:
Get-Date; Get-ADPrincipalGroupMembership username | Select name | Format-Table
Caveat: The output from Format-* cmdlets are formatting instructions rather than the original data, which makes this output unsuitable for further programmatic processing.
How PowerShell formats objects of different types in the same pipeline for display:
In the absence of explicit formatting commands (Format-Table, Format-List, ...), PowerShell automatically chooses a suitable display format, based on a given object's type:
If present for a given type, PowerShell uses predefined formatting instructions (see Get-Help about_Format.ps1xml)
In their absence:
If the type is a primitive type (see below): the object's .ToString() representation is output.
Otherwise: the format style is chosen based on the following simple rules: 4 or fewer properties? -> Format-Table; 5 or more? -> Format-List.
Note: Primitive is used loosely here to refer to:
all primitive CLR types - those for which .IsPrimitive returns $true, namely [Boolean], [Byte], [SByte], [Int16], [UInt16], [Int32], [UInt32], [Int64], [UInt64], [IntPtr], [UIntPtr], [Char], [Double], [Single]
types [decimal], [bigint], and [securestring]
[string] (strings always print as themselves, in full)
any other property-less types.
If all objects in a pipeline are of the same type, the above by definition applies to all of them.
By contrast, if there is a mix of types in the pipeline, the following logic applies:
Any instances of primitive types always print and always print the same, namely as a representation of the single value that they are (not an as an object with properties), obtained via a call to their .ToString() method; e.g., 12 or 3.0 or hi; primitive types have no bearing on the formatting of subsequent objects in the pipeline.
The first non-primitive object in the pipeline:
is itself printed based on either its predefined formatting instructions or the default rules stated above (based on the number of properties).
locks in the format style - list vs. table - for all remaining non-primitive objects:
If the object itself implicitly uses Format-Table or Format-List, so will all remaining non-primitive objects.
If the object implicitly uses Format-Custom (e.g, in the case of Get-Date, via predefined formatting), it is Format-List that is locked in.
All subsequent non-primitive objects then use the locked-in format style.
Caveat: If Format-Table is locked in, the first non-primitive object alone determines the set of properties displayed as table columns:
If the first non-primitive object has no formatting data associated with it - which notably applies to [pscustomobject] - it
can cause subsequent non-primitive objects to seemingly disappear if they don't have these properties - such objects are still in the output stream, however, they're just not displayed - see this answer for a demonstration.
GitHub issue #7871 proposes at least issuing a warning when that happens.
If the first non-primitive object has formatting data associated with it (as reported by Get-FormatData), all subsequent non-primitive objects of a different type are formatted with Format-List. That is, you'll get a mix of tabular and list-style output.
On a side note: Since PSv5, implicit use of Format-Table results in asynchronous behavior that may be surprising; see this answer.
If it is Format-List that is locked in, no information is "lost", as each object's properties are then listed individually, on their own lines.
When the powershell console formatter sees objects of multiple types, it will default to outputting based on the first element output. For Date it output as a list, for the custom object output from Select-Object, it's a table. How the output is formatted depends on the type of the object itself (see help About Format.ps1xml). You can force the output of Select-Object to be a table using Format-Table:
get-date; Get-ADPrincipalGroupMembership username | Select-Object name | Format-Table

Why is the output format changed when running two PowerShell commands in one line?

I'm getting unexpected results when executing two PowerShell commands separated by a semicolon. The output of the second command changes. If I run them in reverse order, I don't see the second command output.
Here I'm simply trying to get a time stamp and a list of groups a user belongs to in AD, as a one-liner.
If I run this line, i get the following output:
Get-ADPrincipalGroupMembership username | Select-Object name
name
----
Domain Users
CL-Inventory-Group
...
However if I run the following, this behavior changes:
get-date; Get-ADPrincipalGroupMembership username | Select-Object name
Wednesday, April 3, 2019 2:31:35 PM
name : Domain Users
name : CL-Inventory-Group
...
Stranger yet, If i run the in reverse, meaning i say get-date after the first command, the date stamp never shows up after the groups are listed.
Am I improperly separating commands?
tl;dr:
Submitting multiple ;-separated commands at the prompt (interactively) still sends their output to a single pipeline (you can think of each command line submitted as an implicit script file).
In short: in your case, the first command output's automatic display formatting also determined the display formatting for the 2nd command, so which command comes first matters:
get-date; Get-ADPrincipalGroupMembership username | Select-Object name
locked in implicit use of Format-List for all output following Get-Date, which explains the each-property-on-its-own line output from the Get-ADPrincipalGroupMembership ... command.
If i run the reverse, meaning i say get-date after the first command, the date stamp never shows up after the groups are listed.
Select-Object output instances of type [pscustomobject], which, due to their having just 1 property in this case, locked in tabular display, i.e., implicit use of Format-Table, with the selected property as the only column, i.e., just Name here. Since the [datetime] type output by Get-Date doesn't have a Name property, Get-Date's output was effectively invisible.
Read on for background information and the complete rules.
PowerShell's default display formatting is optimized for objects of the same type, as that is the typical case.
If a pipeline contains a mix of types, the specific formatting that results by default depends on:
the order of objects in the pipeline
and their default formatting behavior
See the next section for details.
You can use explicit Format-* calls to control the formatting; in your case, you can use Format-Table on your 2nd command to force tabular output:
Get-Date; Get-ADPrincipalGroupMembership username | Select name | Format-Table
Caveat: The output from Format-* cmdlets are formatting instructions rather than the original data, which makes this output unsuitable for further programmatic processing.
How PowerShell formats objects of different types in the same pipeline for display:
In the absence of explicit formatting commands (Format-Table, Format-List, ...), PowerShell automatically chooses a suitable display format, based on a given object's type:
If present for a given type, PowerShell uses predefined formatting instructions (see Get-Help about_Format.ps1xml)
In their absence:
If the type is a primitive type (see below): the object's .ToString() representation is output.
Otherwise: the format style is chosen based on the following simple rules: 4 or fewer properties? -> Format-Table; 5 or more? -> Format-List.
Note: Primitive is used loosely here to refer to:
all primitive CLR types - those for which .IsPrimitive returns $true, namely [Boolean], [Byte], [SByte], [Int16], [UInt16], [Int32], [UInt32], [Int64], [UInt64], [IntPtr], [UIntPtr], [Char], [Double], [Single]
types [decimal], [bigint], and [securestring]
[string] (strings always print as themselves, in full)
any other property-less types.
If all objects in a pipeline are of the same type, the above by definition applies to all of them.
By contrast, if there is a mix of types in the pipeline, the following logic applies:
Any instances of primitive types always print and always print the same, namely as a representation of the single value that they are (not an as an object with properties), obtained via a call to their .ToString() method; e.g., 12 or 3.0 or hi; primitive types have no bearing on the formatting of subsequent objects in the pipeline.
The first non-primitive object in the pipeline:
is itself printed based on either its predefined formatting instructions or the default rules stated above (based on the number of properties).
locks in the format style - list vs. table - for all remaining non-primitive objects:
If the object itself implicitly uses Format-Table or Format-List, so will all remaining non-primitive objects.
If the object implicitly uses Format-Custom (e.g, in the case of Get-Date, via predefined formatting), it is Format-List that is locked in.
All subsequent non-primitive objects then use the locked-in format style.
Caveat: If Format-Table is locked in, the first non-primitive object alone determines the set of properties displayed as table columns:
If the first non-primitive object has no formatting data associated with it - which notably applies to [pscustomobject] - it
can cause subsequent non-primitive objects to seemingly disappear if they don't have these properties - such objects are still in the output stream, however, they're just not displayed - see this answer for a demonstration.
GitHub issue #7871 proposes at least issuing a warning when that happens.
If the first non-primitive object has formatting data associated with it (as reported by Get-FormatData), all subsequent non-primitive objects of a different type are formatted with Format-List. That is, you'll get a mix of tabular and list-style output.
On a side note: Since PSv5, implicit use of Format-Table results in asynchronous behavior that may be surprising; see this answer.
If it is Format-List that is locked in, no information is "lost", as each object's properties are then listed individually, on their own lines.
When the powershell console formatter sees objects of multiple types, it will default to outputting based on the first element output. For Date it output as a list, for the custom object output from Select-Object, it's a table. How the output is formatted depends on the type of the object itself (see help About Format.ps1xml). You can force the output of Select-Object to be a table using Format-Table:
get-date; Get-ADPrincipalGroupMembership username | Select-Object name | Format-Table

How to change default output Formatting of Powershell to use Format-Table -autosize?

How can I enforce powershell to use
Format-Table -auto
as a default formatting when writing a returned array of objects to the console?
Thanks
If you are OK calling the cmdlet every time and if you have at least PowerShell v3.0 then you can set a $PSDefaultParameterValues which you can read more about at about_Parameters_Default_Values.
The syntax that would satisfy your need would be:
$PSDefaultParameterValues=#{"<CmdletName>:<ParameterName>"="<DefaultValue>"}
So we add in the switch by setting it to $true.
$PSDefaultParameterValues = #{"Format-Table:Autosize"=$true}
To remove this you would have to do it much the same as you would a hashtable element
$PSDefaultParameterValues.Remove("Format-Table:Autosize")
From the aforementioned article here is some pertinent information as to how to deal with these.
$PSDefaultParameterValues is a preference variable, so it exists only in the session
in which it is set. It has no default value.
To set $PSDefaultParameterValues, type the variable name and one or more key-value pairs
at the command line.
If you type another $PSDefaultParameterValues command, its value replaces the original
value. The original is not retained.
To save $PSDefaultParameterValues for future sessions, add a $PSDefaultParameterValues
command to your Windows PowerShell profile. For more information, see about_Profiles.
Outside of that I am not sure as it would be difficult to change in a dynamic sense. You would want to be sure that data sent to the stream appears on screen in the same way that format-table -auto does but you would have to make sure that it does not affect data so that you could not capture it or send it down the pipe.
You are looking at creating custom output format files, like Frode F. talks about, then you would need to consider looking at about_Format.ps1xml but you would need to configure this for every object that you would want to display this way.
FileSystem.format.ps1xml, for example, would govern the output from Get-ChildItem. Format-Table is more dynamic and I don't think you can say just use Format-Table in that file.

powershell desc analogy - list output columns and their types

If there anything like SQL's describe so I don't have to look through a "blanket" of | select * output before actually selecting the few columns that I need?
E.g. Get-Process's possible output columns include Id, Name,VirtualMemorySize as well as about three dozen others. I want to get that list of column names, preferrably with their types.
If this for human viewable output then use Format-Table e.g.
Get-Process | Format-Table Name,Id,PM -Auto
Note: if you have lots of output do not use the -AutoSize parameter as that buffers up all its input to determine the optimal size of each column. If you don't specify that parameter, PowerShell will split up the screen space evenly based on number of properties selected but it will display each object as soon as it is received.
For the "column" names, that is bit trickier. You can easily get the list of "ALL" the property names e.g.:
Get-Process | Get-Member -MemberType Properties
If you want just the properties that would normally be display by Format-Table then you need to inspect the View Definition for the System.Diagnostics.Process type in C:\Windows\System32\WindowsPowerShell\v1.0\DotNetTypes.format.ps1xml.