I'm fairly new to powershell scripting after years of unix/linux scripting and I'm still trying to get the handle of object output. I am trying to run the Get-Alias command to return just the column "Name." When I try to select just the column "name" I either get the whole get-alias output, or errors.
The script/ command line I am trying to use is: get-alias | format-table
When I add select-object
logic, it either cuts off the name of the alias and leaves off the command name or the select-object
logic is just ignored. I'm sure the solution is simple. Thanks
tl;dr:
PS> Get-Alias | Select-Object -ExpandProperty DisplayName
? -> Where-Object
cd -> Set-Location
...
That is, the true property name underlying the Name
display column is DisplayName
.
PowerShell's default output formatting sometimes uses column names that differ from or the underlying objects' property names (which is the case here) and/or use values that are calculated.
What shows as column Name
by default is actually the underlying objects' .DisplayName
property, whereas the true .Name
property contains just the alias' own name.
You can inspect the members (properties and methods) of an object's type via Get-Member
or, to see both the property (but not method) names and their concrete values for a given object, pipe to Format-List *
:
PS> Get-Alias | Select-Object -First 1 | Format-List *
HelpUri : https://go.microsoft.com/fwlink/?LinkID=113423
ResolvedCommandName : Where-Object
DisplayName : ? -> Where-Object
ReferencedCommand : Where-Object
ResolvedCommand : Where-Object
Definition : Where-Object
Options : ReadOnly, AllScope
Description :
OutputType : {}
Name : ?
CommandType : Alias
Source :
Version :
Visibility : Public
ModuleName :
Module :
RemotingCapability : None
Parameters : {[InputObject, System.Management.Automation.ParameterMetadata], [FilterScript, System.Management.Automation.ParameterMetadata], [Property,
System.Management.Automation.ParameterMetadata], [Value, System.Management.Automation.ParameterMetadata]...}
ParameterSets :
Optional reading: How to inspect a given type's formatting data:
For background information, see Get-Help about_Format.ps1xml
.
Get-Alias
outputs [System.Management.Automation.AliasInfo]
instances (as Get-Member
will tell you).
Using the Get-FormatData
cmdlet you can inspect a type's formatting data:
Caveat: Not all formatting data in effect is by default reported by Get-FormatData
for backward-compatibility reasons - see this GitHub issue; notable omissions are [System.IO.FileInfo]
and [System.IO.DirectoryInfo]
, as returned by Get-ChildItem
/ Get-Item
; in short, to see all formatting data in effect for the PowerShell version at hand, use:
Get-FormatData -PowerShellVersion $PSVersionTable.PSVersion [...]
Somewhat ironically, there is no custom formatting data defined for the System.Management.Automation.ExtendedTypeDefinition
instances that Get-Format
outputs, and the default formatting isn't helpful.
Currently, the simplest way to inspect formatting data is to pipe to the Format-Custom
cmdlet, which provides an informal, human-readable representation of the internal structure of objects:
# Best to send this to a file and open that file in a text editor for perusal.
$prev, $FormatEnumerationLimit = $FormatEnumerationLimit, [int]::MaxValue
Get-FormatData System.Management.Automation.AliasInfo | Format-Custom -Depth 10
$FormatEnumerationLimit = $prev
Note:
$FormatEnumerationLimit
is temporarily set to the highest possible value to ensure that all column / property definitions are shown in the output (by default, only up to 4 would be shown, and omitted ones would be indicated with ...
(Windows PowerShell, 3 chars.) / …
(PowerShell Core, 1 char.).
-Depth 10
ensures that the internal structure of the output objects is fully represented; by default, only up to 5 levels would be.
The output will look vaguely like JSON, and is suited to visual inspection only, not programmatic processing.
You'll see one or more of the following blocks:
class ExtendedTypeDefinition
{
TypeNames =
[
<typeName>
]
FormatViewDefinition =
[
class FormatViewDefinition
{
Name = <formatName>
Control =
class <viewType>Control
...
}
class FormatViewDefinition
{
Name = <formatName>
Control =
class <viewType>Control
...
}
}
<typeName>
is the full type name to which the format applies (e.g., System.Management.Automation.AliasInfo
)
<formatName>
is an internally used, non-standardized name for the format-definition at hand
<viewType>Control
is one of the following classes, defining the views for use with the corresponding Format-Table,
Format-List, Format-Wide
, and Format-Custom
cmdlets: TableControl
, ListControl
, WideControl
, CustomControl
, all derived from the System.Management.Automation.PSControl
base class.
Note that the output may contain duplicate information, as it does in the case of System.Management.Automation.AliasInfo
(because the formatting information is repeated for all other command types that share the same formatting), but it is sufficient to examine the first class <viewType>Control
instance of interest.
Specifically, here's an excerpt from the first class TableControl
block:
class TableControl # Defines the format for Format-Table
{
Headers = # The table headers (column names and column properties)
...
class TableControlColumnHeader # The "Name" column *header*
{
Label = Name
Alignment = Undefined
Width = 50
}
...
]
Rows = # The table rows (underlying or calculated property values)
[
class TableControlRow
{
Columns =
[
...
class TableControlColumn # The "Name" column *value*
{
Alignment = Undefined
DisplayEntry =
class DisplayEntry
{
ValueType = ScriptBlock # A *calculated* property
Value =
if ($_.CommandType -eq "Alias")
{
$_.DisplayName
}
else
{
$_.Name
}
}
FormatString =
}
...
]
...
Note that the header and column-value definitions are matched positionally; e.g., the 2nd TableControlColumn
instance defines the value for the 2nd TableControlColumnHeader
instance.
The above explains why, even though the column is entitled "Name", it is an alias' .DisplayName
property that is displayed, whereas all the other command types are represented by their .Name
property, by way of the embedded script block (the piece of PowerShell code in which $_
represents the input object at hand).
Presumably, the decision to show the .DisplayName
for aliases was made to provide more helpful information by default, but the discrepancy between the column name and underlying property name can certainly lead to confusion.
Note that there is also a dedicated table view for type [System.Management.Automation.AliasInfo]
that (a) defines only 2 columns, and (b) calls the .DisplayProperty
column values by their true name.
However, as of the PowerShell versions listed above, this view is preempted by the multi-type definition discussed above and effectively ignored.