14

Simple (probably stupid) question. I'm a Powershell novice and am mainly using it to instantiate managed libraries so I don't have to write little apps when I need to use members from them. Some of these libraries are old and have methods with long, painful signatures. Using get-member after instantiating with new-object, I've often run into frustrating results like this:

PS> $object | get-member MethodWithLongSignature

TypeName: SomeLib.SomeObject

Name                      MemberType Definition
----                      ---------- ----------
MethodWithLongSignature   Method     System.Void MethodWithLongSignature(string param1, int param2, string param3, string param4, stri....

Is there any way to wrap the results of get-member? Alternatively, is there a switch for get-member that will produce the results in a manner that won't wrap?

AJ.
  • 16,368
  • 20
  • 95
  • 150

8 Answers8

24

Output in table structures are auto-formatted to fit the width of the screen, truncating long values in the process if necessary.

Pipe the results into the format-list command to get verbose, vertical formatting of the results.

PS> $object | get-member MethodWithLongSignature | format-list
HipCzeck
  • 486
  • 3
  • 8
  • 1
    why doesn't this work `$object | get-childitem env:path | format-list` ? – whytheq Feb 07 '16 at 22:52
  • whytheq, try Get-ChildItem Env:Path | format-list. Frustratingly difficult to figure this out. All I want to know is, where should i put my practice script. For everyone's convenience, the ms how-to article (How to Write and Run Scripts...) doesn't mention this. – captain puget Feb 10 '20 at 04:37
6

Format-Table has a -Wrap switch to wrap the last column. Since the last column of the output of Get-Member is pretty big already, this will produce readable results.

Another option is Format-Wide (but it doesn't wrap, so you are limited to console width):

Get-Process | Get-Member | Format-Wide Definition -Column 1
JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
6

You can also try Format-Table -wrap. For example:

(get-process -id 3104).startinfo.EnvironmentVariables | Format-Table -wrap
rstml
  • 310
  • 2
  • 6
FPardo
  • 61
  • 1
  • 1
5

I couldn't find something built in that allowed to to word-wrap to an arbitrary width, so I wrote one - a bit verbose but here it is:

function wrapText( $text, $width=80 )
{
    $words = $text -split "\s+"
    $col = 0
    foreach ( $word in $words )
    {
        $col += $word.Length + 1
        if ( $col -gt $width )
        {
            Write-Host ""
            $col = $word.Length + 1
        }
        Write-Host -NoNewline "$word "
    }
}
Leo
  • 51
  • 1
  • 1
4

Building on Leo's answer, I decided to make a word-wrap cmdlet.

<#
.SYNOPSIS
wraps a string or an array of strings at the console width without breaking within a word
.PARAMETER chunk
a string or an array of strings
.EXAMPLE
word-wrap -chunk $string
.EXAMPLE
$string | word-wrap
#>
function word-wrap {
    [CmdletBinding()]
    Param(
        [parameter(Mandatory=1,ValueFromPipeline=1,ValueFromPipelineByPropertyName=1)]
        [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
    }
}

It works both by passing a string or array of strings as a function argument, or on the pipeline. Examples:

$str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " * 5

word-wrap $str
$str | word-wrap
get-content txtfile.txt | ?{ $_ } | sort | word-wrap

The metadata comment block at the top of the function allows get-help word-wrap to show some useful information. See this page for more info on defining pipeline cmdlets.

rojo
  • 24,000
  • 5
  • 55
  • 101
0

As an alternative you can use "PowerShell Tools for Visual Studio 2015" extension to run your powershell scripts in VS 2015.

https://marketplace.visualstudio.com/items?itemName=AdamRDriscoll.PowerShellToolsforVisualStudio2015&showReviewDialog=true

This gives you all VS Editor features, word-wrapping, debugging, intellisense etc.

Teoman shipahi
  • 47,454
  • 15
  • 134
  • 158
0

I like the intention behind @Leo & @rojo's answers but splitting lines is inappropriate for massive amounts of text, and a state machine (or better yet, an easily programmable one..like regex) will be way more efficient.

On top of writing my own complex solution, I made its complexity warranted as it maintains newlines in the original string and even permits you to force a line break on certain characters

Wrap -Length 30 -Force '.' "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."

Here I try to break around 30 characters, finding the nearest whitespace, but also forcing a break on full stops, ignoring periods within words, and making sure not to break lines that would have already broken due to a period.

Lorem Ipsum is simply dummy
text of the printing and
typesetting industry.
Lorem Ipsum has been the
industry's standard dummy text
ever since the 1500s, when an
unknown printer took a galley
of type and scrambled it to
make a type specimen book.
It has survived not only five
centuries, but also the leap
into electronic typesetting,
remaining essentially
unchanged.
It was popularised in the
1960s with the release of
Letraset sheets containing
Lorem Ipsum passages, and more
recently with desktop
publishing software like Aldus
PageMaker including versions
of Lorem Ipsum.

Here's the function itself, but note you'll need the stuff at the bottom of this answer to generate the regexes (I put this up higher so you can read the parameters)

Function Wrap {
    Param (
        [int]$Length=80,
        [int]$Step=5,
        [char[]]$Force,
        [parameter(Position=0)][string]$Text
    )
    $key="$Length $Step $Force"
    $wrap=$_WRAP[$key]
    if (!$wrap) {
        $wrap=$_WRAP[$key]=_Wrap `
            -Length $Length `
            -Step $Step `
            -Force ($Force -join '') `
        | Concat -Join '|' -Wrap '(',')(?:[^\n\r\S])+'
    }
    return $Text -replace $wrap,$_WRAP['']
}

Here's something a little more meaningful to show its versitility.
Dont worry about the rest of the script, it's colours/backgrounds, emailing, or GridView.
It's basically doing a bunch of pings, tcp checks, and http requests and putting the error messages into an info property:

        $_.info=(
            $style.bf.yellow, `
            (Wrap -Length 55 -Force ':.' $_.info), `
            $colour `
        | Concat)

enter image description here

You will need these following utility functions defined above Wrap

Function Concat {
    Param ([switch]$Newlines, $Wrap, $Begin='', $End='', $Join='')
    Begin {
        if ($Newlines) {
            $Join=[System.Environment]::NewLine
        }
        $output=[System.Text.StringBuilder]::new()
        $deliniate=$False

        if (!$Wrap) {
            $output.Append($Begin) | Out-Null
        }
        elseif ($Wrap -is [string]) {
            $output.Append(($End=$Wrap)) | Out-Null
        }
        else {
            $output.Append($Wrap[0]) | Out-Null
            $End=$Wrap[1]
        }
    }
    Process {
        if (!($_=[string]$_).length) {
        }
        elseif ($deliniate) {
            $output.Append($deliniate) | Out-Null
            $output.Append($_) | Out-Null
        }
        else {
            $deliniate=$Join
            $output.Append($_) | Out-Null
        }
    }
    End {
        $output.Append($End).ToString()
    }
}

$_WRAP=@{''="`$1$([System.Environment]::NewLine)"}
Function _Wrap {
    Param ($Length, $Step, $Force)

    $wrap=$Force -join '' -replace '\\|]|-','\$0'
    $chars="^\n\r$wrap"
    $preExtra="[$chars\S]*"
    $postExtra="[^\s$wrap]"

    $chars="[$chars]"
    $postChars="$preExtra$postExtra"
    if ($wrap) {
        $wrap="[$wrap]"
        $wrap
        $wrap="$wrap(?=\S)"
        $chars="$chars|$wrap"
        $postChars="$postChars|$preExtra$wrap"
    }

    for (
        ($extra=0),($next=$NULL),($prev=$NULL);
        ($next=$Length - $Step) -gt 0 -and ($prev=$extra + $Step);
        ($Length=$next),($extra=$prev)
    ) {
        "(?:$chars){$next,$Length}(?=(?:$postChars){$extra,$prev})"
    }
}
Hashbrown
  • 12,091
  • 8
  • 72
  • 95
0
PS> $object | get-member MethodWithLongSignature | select -ExpandProperty Definition

For example:

PS>gci | gm EnumerateFiles
TypeName: System.IO.DirectoryInfo

Name           MemberType Definition
----           ---------- ----------
EnumerateFiles Method     System.Collections.Generic.IEnumerable[System.IO.FileInfo] EnumerateFiles(), System.Collections.Generic.IEnumerable[System.IO.FileInfo] EnumerateFiles(string searchPattern), System.Collections.Generic.IEnume...

Compared to:

PS>gci | gm EnumerateFiles | select -ExpandProperty definition

    System.Collections.Generic.IEnumerable[System.IO.FileInfo] EnumerateFiles(), System.Collections.Generic.IEnumerable[System.IO.FileInfo] EnumerateFiles(string searchPattern), System.Collections.Generic.IEnumerable[System.IO.FileInfo] EnumerateFiles(string searchPattern, System.IO.SearchOption searchOption)

Well ironically, my PS line wraps the output, but the code formatting on SO doesn't seem to. However, you can clearly see the ... truncation in the first example.

Here's a picture of the wrapped output in my shell:

enter image description here

ExpandProperty is useful whenever you want to output a specific attribute.

Blaisem
  • 557
  • 8
  • 17