首页 > 解决方案 > How to custom output of powershell function

问题描述

I am writing a small function to get the file sizes in several pathes. And I have a problem about the function output. Here is my script:

function Get-FileSize {
    param (
        [Parameter(Mandatory, 
                   ValueFromPipeline)]
        [string[]]$Path
    )
    PROCESS {
        foreach ($p in $Path) {
            Get-ChildItem -Path $p |
            ForEach-Object {
                $size = (Get-ChildItem -LiteralPath $PSItem -Recurse | Measure-Object -Sum Length).Sum + 0
                [PSCustomObject]@{
                    Name = $_.Name
                    Size = $size
                }
            }
        }
    }
}

This function will output several pscustomobjects. The size property is very hard to read, so I format the size property like this:

Size = "{0:N2} GB" -f $size

While this version is very easy to read, I can not be sort through the size property because the type of this property is string.

My problem is how can I custom the display style of pscustomobject's property? For example, the command Get-Volume has a nice output.

标签: powershell

解决方案


After reading related topic about Format.ps1xml mentioned by @Olaf, I have solved the problem. First, I create a customized Format.ps1xml:

<?xml version="1.0" encoding="utf-8"?>
<Configuration>
    <ViewDefinitions>
        <View>
            <Name>FileSizeView</Name>
            <ViewSelectedBy>
                <TypeName>MyType.FileSizeInfo</TypeName>
            </ViewSelectedBy>
            <GroupBy>
                <PropertyName>Path</PropertyName>
            </GroupBy>
            <TableControl>
                <TableHeaders>
                    <TableColumnHeader>
                        <Label>Name</Label>
                        <Width>50</Width>
                        <Alignment>left</Alignment>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>Size</Label>
                        <Width>15</Width>
                        <Alignment>right</Alignment>
                    </TableColumnHeader>
                </TableHeaders>
                <TableRowEntries>
                    <TableRowEntry>
                        <TableColumnItems>
                            <TableColumnItem>
                                <PropertyName>Name</PropertyName>
                            </TableColumnItem>
                            <TableColumnItem>
                                <ScriptBlock>
                                    if ($_.Size -lt 1KB) {
                                        $_.Size
                                    } elseif (($_.Size -ge 1KB) -and ($_.Size -lt 1MB)) {
                                        "{0:N2} KB" -f ($_.Size / 1KB)
                                    } elseif (($_.Size -ge 1MB) -and ($_.Size -lt 1GB)) {
                                        "{0:N2} MB" -f ($_.Size / 1MB)
                                    } else {
                                        "{0:N2} GB" -f ($_.Size / 1GB)
                                    }
                                </ScriptBlock>
                            </TableColumnItem>
                        </TableColumnItems>
                    </TableRowEntry>
                </TableRowEntries>
            </TableControl>
        </View>
    </ViewDefinitions>
</Configuration>

Second, add the new format file to the current session Update-FormatData \path\to\file\MyView.Format.ps1xml.

Third, before I return the pscustomobject in my function, I add the TypeName to it. The TypeName is defined in node <ViewSelectedBy>. Here is the function:

function Get-FileSize {
    param (
        [Parameter(Mandatory, 
                   ValueFromPipeline)]
        [string[]]$Path
    )
    PROCESS {
        foreach ($p in $Path) {
            Get-ChildItem -Path $p |
            ForEach-Object {
                $size = (Get-ChildItem -LiteralPath $PSItem -Recurse -File | Measure-Object -Sum Length).Sum + 0
                $object = [PSCustomObject]@{
                    Name = $_.Name
                    Size = $size
                    Path = $p
                }
                $object | Add-Member -TypeName 'MyType.FileSizeInfo'
                return $object
            }
        }
    }
}

推荐阅读