Suppose I have the following snippet:
$assoc = New-Object PSObject -Property @{
Id = 42
Name = "Slim Shady"
Owner = "Eminem"
}
Write-Host $assoc.Id + " - " + $assoc.Name + " - " + $assoc.Owner
I'd expect this snippet to show:
42 - Slim Shady - Eminem
But instead it shows:
42 + - + Slim Shady + - + Eminem
Which makes me think the +
operator isn't appropriate for concatenating strings and variables.
How should you approach this with PowerShell?
Write-host ($assoc.Id.ToString() + " - " + $assoc.Name + " - " + $assoc.Owner)
here $assoc.Id is an Int32
so we have to use its string representation. Otherwise PS tries to perform an arithmetic addition instead of concatenation.
Write-Host "$($assoc.Id) - $($assoc.Name) - $($assoc.Owner)"
See the Windows PowerShell Language Specification Version 3.0, p34, sub-expressions expansion.
There is a difference between single and double quotes. (I am using PowerShell 4).
You can do this (as Benjamin said):
$name = 'Slim Shady'
Write-Host 'My name is'$name
-> My name is Slim Shady
Or you can do this:
$name = 'Slim Shady'
Write-Host "My name is $name"
-> My name is Slim Shady
The single quotes are for literal, output the string exactly like this, please. The double quotes are for when you want some pre-processing done (such as variables, special characters, etc.)
So:
$name = "Marshall Bruce Mathers III"
Write-Host "$name"
-> Marshall Bruce Mathers III
Whereas:
$name = "Marshall Bruce Mathers III"
Write-Host '$name'
-> $name
(I find How-to: Escape characters, Delimiters and Quotes good for reference).
powershell
is neat and will put a space between the string and the content of the variable in Write-Host 'My name is'$name
You can also use -join
E.g.
$var = -join("Hello", " ", "world");
Would assign "Hello world" to $var.
So to output, in one line:
Write-Host (-join("Hello", " ", "world"))
$()
?
()
is necessary for my need. For example: -join("Timestamp: ", Get-Date)
gives an error, while -join("Timestamp: ", (Get-Date))
runs fine. However, this explains when $()
would be necessary.
Write-Host -join("Hello", " ", "world")
will not join as the whole join
argument needs brackets including the name of the arg = join.
One way is:
Write-Host "$($assoc.Id) - $($assoc.Name) - $($assoc.Owner)"
Another one is:
Write-Host ("{0} - {1} - {2}" -f $assoc.Id,$assoc.Name,$assoc.Owner )
Or just (but I don't like it ;) ):
Write-Host $assoc.Id " - " $assoc.Name " - " $assoc.Owner
$assoc.Id
and "
(et al). That is, option 1 gives you Id__-__Name__-__Owner
(two spaces on each side of each -
), but option 3 gives Id___-___Name___-___Owner
(three spaces).
$assoc.Id"###"$assoc.Name
will add spaces to either side of the ###, where "$($assoc.Id)###$($assoc.Name)"
won't.
Try wrapping whatever you want to print out in parentheses:
Write-Host ($assoc.Id + " - " + $assoc.Name + " - " + $assoc.Owner)
Your code is being interpreted as many parameters being passed to Write-Host
. Wrapping it up inside parentheses will concatenate the values and then pass the resulting value as a single parameter.
Write-Debug
or Write-Verbose
for including double quotes and variable values, such as Write-Debug ('Running "cmdlet" with parameter $MyVar = ' + $MyVar + " at time " + (Get-Date -DisplayHint Time))
Invoke-WebRequest -uri ('http://mysvr/guestauth/app/rest/...'+$param1+'_'+$param2+'_something,count:10')
Another option is:
$string = $assoc.ID
$string += " - "
$string += $assoc.Name
$string += " - "
$string += $assoc.Owner
Write-Host $string
The "best" method is probably the one C.B. suggested:
Write-Host "$($assoc.Id) - $($assoc.Name) - $($assoc.Owner)"
StringBuilder
option if you're going concat-crazy. ;^)
While expression:
"string1" + "string2" + "string3"
will concatenate the string, you need to put a $ in front of the parenthesis to make it evaluate as a single argument when passed to a PowerShell command. Example:
Write-Host $( "string1" + "string2" + "string3" )
As a bonus, if you want it to span multiple lines, then you need to use the awkward backtick syntax at the end of the line (without any spaces or characters to the right of the backtick).
Example:
Write-Host $(`
"The rain in " +`
"Spain falls mainly " +`
"in the plains" )`
-ForegroundColor Yellow
(Actually, I think PowerShell is currently implemented a little bit wrong by requiring unnecessary backticks between parentheses. If Microsoft would just follow Python or Tcl parenthesis rules of allowing you to put as many newlines as you want between the starting and ending parenthesis then they would solve most of the problems that people don't like about PowerShell related to line continuation, and concatenation of strings.
I've found that you can leave the backticks off sometimes on line continuations between parenthesis, but it's really flaky and unpredictable if it will work... It's better to just add the backticks.)
You need to place the expression in parentheses to stop them being treated as different parameters to the cmdlet:
Write-Host ($assoc.Id + " - " + $assoc.Name + " - " + $assoc.Owner)
(Current PowerShell version 5.1.17134.407)
This also works as of now:
$myVar = "Hello"
echo "${myVar} World"
Note: this only works with double quotes
Here is another way as an alternative:
Write-Host (" {0} - {1} - {2}" -f $assoc.Id, $assoc.Name, $assoc.Owner)
I just want to bring another way to do this using .NET String.Format:
$name = "Slim Shady"
Write-Host ([string]::Format("My name is {0}", $name))
String.Format
instead of old plain "{0}" -f $var
? I don't see the point in using .NET code where plain PowerShell can do the job...
I seem to struggle with this (and many other unintuitive things) every time I use PowerShell after time away from it, so I now opt for:
[string]::Concat("There are ", $count, " items in the list")
These answers all seem very complicated. If you are using this in a PowerShell script you can simply do this:
$name = 'Slim Shady'
Write-Host 'My name is'$name
It will output
My name is Slim Shady
Note how a space is put between the words for you
Concatenate strings just like in the DOS days. This is a big deal for logging so here you go:
$strDate = Get-Date
$strday = "$($strDate.Year)$($strDate.Month)$($strDate.Day)"
Write-Output "$($strDate.Year)$($strDate.Month)$($strDate.Day)"
Write-Output $strday
toString
option is easier: (Get-Date).toString('yyyyMMdd')
From What To Do / Not to Do in PowerShell: Part 1:
$id = $assoc.Id
$name = $assoc.Name
$owner = $assoc.owner
"$id - $name - $owner"
Write-Host can concatenate like this too:
Write-Host $assoc.Id" - "$assoc.Name" - "$assoc.Owner
This is the simplest way, IMHO.
If you're concatenating strings to build file paths, use the Join-Path command:
Join-Path C:\temp "MyNewFolder"
It'll automatically add the appropriate trailing / leading slashes for you, which makes things a lot easier.
$assoc = @{
Id = 34
FirstName = "John"
LastName = "Doe"
Owner = "Wife"
}
$assocId = $assoc.Id
$assocFN = $assoc.FirstName
$assocLN = $assoc.LastName
$assocName = $assocFN, $assocLN -Join " "
$assocOwner = $assoc.Owner
$assocJoin = $assocId, $assocName, $assocOwner -join " - "
$assocJoin
#Output = 34 - John Doe - Wife
Personally I prefer this style:
[string]::Join(' - ', 42, 'Slim Shady', 'Eminem')
or based on the above (unordered) object:
[string]::Join(' - ',$assoc.psObject.Properties.value)
You can also get access to C#/.NET methods, and the following also works:
$string1 = "Slim Shady, "
$string2 = "The real slim shady"
$concatString = [System.String]::Concat($string1, $string2)
Output:
Slim Shady, The real slim shady
Just for the fun. You can also access the values of the PSObject directly like below:
$assoc.psobject.Properties.value -join " - "
But if you do not specify that the object should be ordered, PowerShell will display the values in a random order. So you should add the flag [ordered]
:
$assoc = [pscustomobject] [ordered] @{
Id = 42
Name = "Slim Shady"
Owner = "Eminem"
}
As noted elsewhere, you can use join.
If you are using commands as inputs (as I was), use the following syntax:
-join($(Command1), "," , $(Command2))
This would result in the two outputs separated by a comma.
See https://stackoverflow.com/a/34720515/11012871 for related comment
Success story sharing
"... $name ..."
will work all the same, but in the original question for which this answer addresses, the question is how to access object properties. so if$name.id -eq 42
then"... $name.id ..."
would not work like you want because it would render like... @{id=42}.id ...
instead of the desired... 42 ...
For that, use the answer's method"... $($name.id) ..."
. I'm bookmarking question to edit later.( $string1, $string2, $string3 ) -join ""
or($string1 + $string2 + $string3)
. With these methods, you can have whitespace (spaces, tabs, and newlines) between the strings, but be sure that (1) each string has a comma/space after it on the same line, (2) you use the back-tick character ` at the end of any empty lines between your code, and (3) if you use-join
, the end bracket and the-join
operator must be on the same line