Skip to content

Instantly share code, notes, and snippets.

@ninmonkey
Last active November 10, 2023 20:13
Show Gist options
  • Save ninmonkey/47787656a7ead241f9bed9092b09dfd6 to your computer and use it in GitHub Desktop.
Save ninmonkey/47787656a7ead241f9bed9092b09dfd6 to your computer and use it in GitHub Desktop.
Using Join-String verses the -format operator in Powershell

The first wins on points of assumed knowledge, and runs on WinPS But if you weren't limited to that, are other possibilities interesting?

Basic direct comparison

$Config = @{ Delimiter = ' ' }
# [1]
"--delimiter='{0}'" -f @( $Config.Delimiter )

# [2]
Join-string -In $Config.Delimiter -f "--delimiter='{0}'"

# [3]
$Config.Delimiter
    | Join-String -f "--delimiter='{0}'"

# [4] same as 3
$Config.Delimiter | Join-String -f "--delimiter='{0}'"

true $Nulls can coerce to empty strings instead of partial formats

  • If you're piping true null values, then the last 3 return empty strings instead of a 14 length strings
  • if you're piping empty string it returns the 14 length string for Join-string too
$Config.Delimiter = $Null
("--delimiter='{0}'" -f @( $Config.Delimiter ) ).Length             # 14
( Join-string -Inp $Config.Delimiter -f "--delimiter='{0}'").Length # 0 
( $Config.Delimiter | Join-String -f "--delimiter='{0}'" ).Length   # 0

$Config.Delimiter = $Null
("--delimiter='{0}'" -f @( $Config.Delimiter ) ).Length             # 14
( Join-string -Inp $Config.Delimiter -f "--delimiter='{0}'").Length # 14 
( $Config.Delimiter | Join-String -f "--delimiter='{0}'" ).Length   # 14

Important Properties

The most import parameters:

  • -FormatString is applied on each iteration. it works like -f when passing 1 value
  • -Separator -Sep is like the -join [string] operator
  • -OutputPrefix -op and -OutputSuffix -os are applied once when there's an array
  • If you pass objects rather than strings,-Property lets you drill into objects
  • -SingleQuote -Single or -DoubleQuote -Double will surround every item with quotes

Compared to using -Join, you're able to modify the output quite a lot with minimal changes. For example:

Function Join.Csv { 
   $Input | Sort-Object -Unique | Join-String -sep ', ' -Single
} 
Function Join.UL { 
   $Input | Sort-Object -Unique | Join-String -f "`n - {0}"
} 

You get the same result using these

... | Join-String -DoubleQuote
... | Join-String -f '"{0}"'
Get-Process | Sort-Object -Unique 
    | Join-String Name -sep ', '

# Color /w pansies
@( 
  Import-Module Pansies -PassThru
  Import-Module ImportExcel -PassThru 
) 
  | Join-String -op 'Loading Modules: ' -p { $_.Name, $_.Version }  -sep ', '  
  | Write-host -bg 'gray25' # using pansies

# color /w pwsh
@( 
    Import-Module Pansies -PassThru
    Import-Module ImportExcel -PassThru 
) 
  | Join-String -op 'Loading Modules: ' -p { $_.Name, $_.Version }  -sep ', ' 
  | Join-String -op $PSStyle.Foreground.FromRgb('#0e9931') -os $PSStyle.Reset
function RenderEmp { 
  @( Join-String -i $Emp.id -f 'id={0}'
     Join-String -i $Emp.State -f 'state={0}'
  ) | ?{ $_ } # drop blanks
    | Join-String -sep ', ' -op ' [ ' -os ' ] '
}

$Emp = @{ Id = 123 ; State = 'active' } 
RenderEmp
$Emp = @{ State = 'disabled' } 
RenderEmp

Clipboard cleanup

# sort and remove duplicate lines
Get-Clipboard | Sort-Object -Unique | Set-Clipboard

# indent all lines by 4 spaces
(Get-Clipboard) -split '\r?\n' 
    | Join-String -f "    {0}" -sep "`n" | Set-Clipboard -PassThru

-P -Property can be a calculated property

"   `tline1`n`t    line3`nline4" -split '\r?\n' 
    | Join-String -sep "`n" -P { $_.Trim() }

"   `tline1`n`t    line3`nline4" -split '\r?\n' 
    | Join-String -sep "`n" -P { $_ -replace '\s+', '' }

Generate values as pasteable literals

gci . *.ps1
   | %{ Join-String -in $_ -sep FullName -DoubleQuote } 
   | Join-String -sep ', ' 
   | Join-String -op '$files = @( ' -os ' )'

# outputs the string:
# $files = @( "c:\foo\bar.ps1", "c:\foo\cat.ps1" )
"   `tline1`n`t    line3`nline4" | Set-Clipboard
# Sometimes you want to cleanup tokens to be pastable as a language literal
(Get-Clipboard) -split '\r?\n' | %{ 
    Join-String -In $_ { $_.Trim() } -SingleQuote 
} | Join-String -sep ', ' 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment