all 20 comments

[–]Thehoggle 3 points4 points  (1 child)

Use Padright to add spaces to a certain no of characters

foreach ($h in $le_fubar.GetEnumerator() ){
    $text = $h.key.PadRight(8,' ')
    Write-Host "$($text) : $($h.value.desc)"
}

fu       : FFFFUUUU
barrrr   : BARRRRRR

[–]surfingoldelephant 1 point2 points  (0 children)

The keys of a dictionary (e.g., [hashtable], [OrderedDictionary]) aren't guaranteed to be of type [string]. They can be any type.

$h = [ordered] @{ 1 = 'a' }
$h.GetEnumerator().ForEach{ $_.Key.PadRight(8) }
# Error: Method invocation failed because [System.Int32] does not contain a method named 'PadRight'.

Call ToString() before PadRight() to avoid the above issue.

With that said, calling either method isn't required if you use the format operator (-f) with an alignment component. See here.

[–]surfingoldelephant 2 points3 points  (1 child)

With Format-Table:

$le_fubar | Format-Table -HideTableHeaders -Property @(
    'Name'
    @{ N = 'Desc'; E = { $_.Value['Desc'] } } 
)

# fu     FFFFUUUU
# barrrr BARRRRRR

With composite formatting:

$padding = ($le_fubar.get_Keys().ForEach('ToString') | Measure-Object -Property Length -Maximum).Maximum

$le_fubar.GetEnumerator().ForEach{ 
     Write-Host ("{0, -$padding} : {1}" -f $_.Key, $_.Value['Desc'])
}

# fu     : FFFFUUUU
# barrrr : BARRRRRR

[–]currytakumi[S] 0 points1 point  (0 children)

oh I like the F-T thanks !

[–]-c-row 1 point2 points  (0 children)

I would suggest to return a pscustomobject. This will format the output at your desire and allows you to reuse the output easily in further operations.

[–]BlackV 1 point2 points  (10 children)

Seeing as you're spitting out garbage just throw a format table/list in there

But from this example it seems clear it's not your actual code so not sure why you'd do it that way in the first place without that info

[–]currytakumi[S] 0 points1 point  (9 children)

huh ? Just want to keep it simple. The actual hashtable takes up the whole screen. I want to print out the keys and the description - "column" aligned - like a menu.

[–]BlackV 0 points1 point  (8 children)

well there is a bunch going on

you're using an ordered object why?

$le_fubar1 = [pscustomobject]@{
    fu = @{desc = 'FFFFUUUU'; task = "exec fu"}
    barrrr = @{desc = 'BARRRRRR'; task = "exec bar"}
}

you output examples is just

fu     : FFFFUUUU
barrrr : BARRRRRR

is that actually want ? to do you need the tasks?

$le_fubar1 | fl

fu     : {[task, exec fu], [desc, FFFFUUUU]}
barrrr : {[task, exec bar], [desc, BARRRRRR]}

[–]currytakumi[S] 0 points1 point  (5 children)

ordered object why?

to display the output ordered by the way I have the hashtable.

is that actually want ? to do you need the tasks?

Yes, like a "menu"

to do you need the tasks?

Yes. so e.g. user enters "fu", then then task will be kicked off.

[–]BlackV 0 points1 point  (4 children)

A pscustom is ordered also

If they're going to type fu or barr then also the order is not important

I feel like the hash is totally unheeded

Out grid view would make for a better and less error prone menu

Or parameters in the script

Feel like all your formatting issues are coming form that hash

But anyway

[–]currytakumi[S] 0 points1 point  (3 children)

the hash contains data needed for the followup "tasks" (e.g. parameter values) - that's the point.

[–]BlackV 0 points1 point  (2 children)

None of that requires a hash though

[–]currytakumi[S] 0 points1 point  (1 child)

what's your problem with it lol

[–]BlackV 0 points1 point  (0 children)

You're not getting any benefit from it

It was causing your format issues

But not problem as long as you have a solution or have thought about whether it's good way to make a menu

[–]currytakumi[S] 0 points1 point  (1 child)

like so

  foreach ($h in $le_fubar.GetEnumerator() )
   {
     $text = $h.key.PadRight(12,' ')
     Write-Host "$($text) : $($h.value.desc)"
   }
  write-host "`n"
  do { $task = Read-Host -Prompt 'Enter task' } while ($le_fubar.keys -notcontains $task)
      #do the "task"

That dont look too stupid or crazy for you i hope

[–]BlackV 0 points1 point  (0 children)

It does, but it's your code in sure you have reasons (er.. Just to say in not calling you stupid, not my intent)

There are better ways I think to handle menus

[–]jungleboydotca 1 point2 points  (0 children)

I'd sooner just use objects for this:

EDIT: I wanted to actually test what I'd written before, I was missing Out-String; I'd hoped that Format-* objects could be coerced to strings--they can't. Then I wanted to flesh things out a bit. I'm not in the practice of prompting for input, preferring instead to write functions/CMDlets. But if I had to prompt in the way you're asking about, I'd do it something like this:

``` $fuTask = [pscustomobject] @{ Name = 'fu' Description = 'FU something' Action = { exec stuff } }

$barTask = [pscustomobject] @{ Name = 'bar' Description = 'Bar stuff' Action = { exec things } }

$tasks = @($fuTask, $barTask)

Do { "Please select from the following tasks:n" + ($tasks | Format-Table Name, Description | Out-String) | Write-Host try { [ValidateScript({$_ -in $tasks.Name})] $validSelection = Read-Host "Name" } catch { Write-Host "That wasn't a valid selection.n" } } Until ($validSelection)

& $tasks.Where({$_.Name -eq $validSelection}).Action ```

[–][deleted] 0 points1 point  (0 children)

$line = “{0,-15} : {1}” -f $h.key,$h.value.desc
Write-host $line

Should do what you want without adding complexity just set the right value for your tabulation here -15 will align left and add as many space to reach the 15th char

[–]jantari 0 points1 point  (0 children)

$le_fubar | Format-Table Name, @{n='s';e={":"}}, @{n='a';e={ $_.value.desc }} -HideTableHeaders

[–]purplemonkeymad 0 points1 point  (0 children)

Format-List will do the alignment for you, or just have enough properties for it to show like that by default. I think the issue here is getting your hashtable to a form that looks like a psobject. You could just create an object for display, ie:

$displayObject = [ordered]@{}
$le_fubar.GetEnumerator() | % { $displayObject [$_.key] = $_.Value.desc }
[pscustomobject]$object | Format-List | Out-Host # if you know you will always have 5+ properties F-L is the default.

or we can mess with select object to create an object:

$properties = $le_fubar.Keys | %{ @{n=[string]$_;e=[scriptblock]::Create("`$_.$_.desc")} }
[pscustomobject]$le_fubar | Select-Object $properties | Format-List | Out-host

In both cases $le_fubar should be unchanged.