Formatting a Powershell string containing hashtable values - powershell

The answer to this is likely to be trivial, but I have spent half an hour and still can't work it out.
Assume I have a the following hashtable:
$hash = #{face='Off';}
What I have tried to do, is output the value of "face" along side some other string elements.
This works:
Write-Host Face $hash['face']
=> Face Off
However, this doesn't:
Write-Host Face/$hash['face']
=> Face/System.Collections.Hashtable[face]
Somehow the lack of a space has affected the operator precedence - it is now evaluating $hash as a string, the concatenating [face] afterwards.
Trying to solve this precedence problem, I tried:
Write-Host Face/($hash['face'])
=> Face/ Off
I now have an extra space I don't want.
This works, but I don't want the extra line just to reassign:
$hashvalue = $hash['face']
write-host Face/$hashvalue
=> Face/Off
Any idea how to get this working as a one-liner?

Sure, use a subexpression:
Write-Host Face/$($hash['face'])
Generally, I'd just use a string, if I need precise control over whitespace with Write-Host:
Write-Host "Face/$($hash['face'])"
Yes, in this case you need a subexpression again, but more because you simply can't include an expression like $foo['bar'] in a string otherwise ;-)
By the way, $hash.face works just as well with much less visual clutter.

In such cases, and more so if there are more variables involved, I prefer using the string formatting. While in this case you can live with the $(..), be aware that string formatting will remove lot of doubt, cruft and improves readability:
write-host ("Face/{0}" -f $hash['face'])

In addition to using sub expressions as Joey showed you can:
Use string formatting:
Write-Host ('Face/{0}' -f $hash.face)
This will stick the value of face key in the place of {0}
Use string concatenation:
Write-Host ('Face/' + $hash.face)
Both of those require an expression to be evaluated which outputs a string which is used as Write-Host's Object parameter.

Another option is to insert your slash with the -Separator option of Write-Host:
$hash = #{Face="off"}
Write-Host ("Face",$hash.Face) -Separator '/'

Related

I want to remove certain parts of a certain string in Powershell 7.2.4, how do I do it?

I have the string "url": "https://maven.fabricmc.net/net/fabricmc/fabric-installer/0.11.0/fabric-installer-0.11.0.jar". I want to remove everything from the string except https://maven.fabricmc.net/net/fabricmc/fabric-installer/0.11.0/fabric-installer-0.11.0.jar (I want to remove the quotes as well).
How do I go about it?
$str = """url"": ""https://maven.fabricmc.net/net/fabricmc/fabric-installer/0.11.0/fabric-installer-0.11.0.jar"""
$str.Split(""": """)[1].Replace("""","")
The shortest I could think of
Might have the incorrect indexnumber, just test switching '3'
( $str -split """ )[3]
You could use the -replace operator and extract the section you want.
'"url": "https://maven.fabricmc.net/net/fabricmc/fabric-installer/0.11.0/fabric-installer-0.11.0.jar"' -replace '"url": "(.+)"','$1'
However since this appears to be in JSON format you may be better off using ConvertFrom-Json on the entire thing and then accessing the property through dot notation.
It's slightly easier than trying to regex or string match sections of JSON.
$converted = Get-Content file.json | ConvertFrom-Json
$converted.url

Powershell indexing for creating user logon name

I'm trying to make a user creation script for my company to make things more automated.
I want the script to take the Firstname + Lastname[0] to make the users logon name, but i can't get the syntax right,
I have tried writing {} and () but no luck there.
that's the original peace from my script
New-ADuser...........-UserPrincipalName $fname+$lname[0]
any tips?
Gabriel Luci's helpful answer provides an effective solution and helpful pointers, but it's worth digging deeper:
Your problem is that you're trying to pass expression $fname+$lname[0] as an argument, which requires enclosing (...):
New-ADuser ... -UserPrincipalName ($fname+$lname[0])
PowerShell has two distinct parsing modes, and when a command (such as New-ADUser) is called, PowerShell operates in argument mode, as opposed to expression mode.
Enclosing an argument in (...) forces a new parsing context, which in the case of $fname+$lname[0] causes it to be parsed in expression mode, which performs the desired string concatenation.
In argument mode, unquoted arguments are implicitly treated as if they were enclosed in "...", i.e., as expandable strings under the following circumstances:
If they don't start with (, #, $( or #(.
If they either do not start with a variable reference (e.g., $var) or do start with one, but are followed by other characters that are considered part of the same argument (e.g., $var+$otherVar).
Therefore, $fname+$lname[0] is evaluated as if "$fname+$lname[0]" had been passed:
The + become part of the resulting string.
Additionally, given that inside "..." you can only use variable references by themselves (e.g., $fname), not expressions (e.g., $lname[0]), $lname[0] won't work as intended either, because the [0] part is simply treated as a literal.
Embedding an expression (or a command or even multiple expressions or commands) in "..." requires enclosing it in $(...), the subexpression operator, as in Gabriel's answer.
For an overview of PowerShell's string expansion rules, see this answer.
The following examples use the Write-Output cmdlet to illustrate the different behaviors:
$fname = 'Jane'
$lname = 'Doe', 'Smith'
# WRONG: Same as: "$fname+$lname[0]", which
# * retains the "+"
# * expands array $lname to a space-separated list
# * treats "[0]" as a literal
PS> Write-Output -InputObject $fname+$lname[0]
Jane+Doe Smith[0]
# OK: Use an expression via (...)
PS> Write-Output -InputObject ($fname+$lname[0])
JaneDoe
# OK: Use an (implicit or explicit) expandable string.
PS> Write-Output -InputObject $fname$($lname[0]) # or: "$fname$($lname[0])"
JaneDoe
# OK: Use an intermediate variable:
PS> $userName = $fname + $lname[0]; Write-Output -InputObject $userName
Use a string for the UserPrincipalName, with the variables in the string:
New-ADuser -UserPrincipalName "$fname$($lname[0])"
PowerShell can usually figure out when you put a variable inside a string. When it can't, like in the case of $lname[0], you enclose it in $().
This is called "variable expansion" (other languages, like C#, call it "string interpolation"). Here's a good article that describes it in more detail: https://powershellexplained.com/2017-01-13-powershell-variable-substitution-in-strings/
i just saw the answers and a minute before i realized that i should actually set it up as another variable, $logon = $fname+lname[0]
and pass it as -userPrincipalName $logon.
Thanks for the help, you guy are the best!

Combining String and Variable causes leading extra Space [duplicate]

When I use Write-Host within a Foreach-Object, I get an unnecessary space in the output.
write-host "http://contoso.com/personal/"$_.ADUserName
Output:
http://contoso.com/personal/ john.doe
How can I remove the space before john? Trim does not work because there is no space in $_.ADUserName
This is happening because Write-Host is considering your constant string and your object to be two separate parameters -- you aren't actually joining the strings together the way you're calling it. Instead of calling it this way, actually concatenate the strings:
write-host "http://contoso.com/personal/$($_.ADUserName)"
or
write-host ("http://contoso.com/personal/" + $_.ADUserName)
or
write-host ("http://contoso.com/personal/{0}" -f $_.ADUserName)
Just do it without write-host:
"http://contoso.com/personal/{0}" -f $_.ADUserName

Unnecessary space in output when using Write-Host

When I use Write-Host within a Foreach-Object, I get an unnecessary space in the output.
write-host "http://contoso.com/personal/"$_.ADUserName
Output:
http://contoso.com/personal/ john.doe
How can I remove the space before john? Trim does not work because there is no space in $_.ADUserName
This is happening because Write-Host is considering your constant string and your object to be two separate parameters -- you aren't actually joining the strings together the way you're calling it. Instead of calling it this way, actually concatenate the strings:
write-host "http://contoso.com/personal/$($_.ADUserName)"
or
write-host ("http://contoso.com/personal/" + $_.ADUserName)
or
write-host ("http://contoso.com/personal/{0}" -f $_.ADUserName)
Just do it without write-host:
"http://contoso.com/personal/{0}" -f $_.ADUserName

Passing string variable to Sharepoint command without desired outcome

I have a number of fields that I am using to build a string for an extraction of values from a SharePoint 2013 list.
I use this to build the string.
foreach($Column in $StringColumns){
$Fields=$Fields+"`""+$Column+"`""
if($Loop -ne $ColumnCount){
$Fields=$Fields+","
$Loop++}
}
I take the built $Fields [string] variable and pass it to this command.
$SPList.getitems($queryfromsource)[$ItemNumber][$Fields]
The result is that I receive no output from the command. What makes it odd is that I can confirm that $Fields has the appropriate string in it for that command. I have done so by calling it in the console and then copying the output into the SharePoint command directly. When I do that, I receive the output I am looking for.
This seems like it should be incredibly simple but it is driving me insane.
would something like this work?
foreach ($Column in $StringColumns)
{
$Fields+= "`"$($Column)`""
if ($Loop -ne $ColumnCount)
{
$Fields+= ","
$Loop++
# Only use Write-Host for debugging
Write-Host "Column $Loop of $ColumnCount"
}
}
Do you initialize $Loop somewhere, might try having it print the loop number you're on?
You probably should learn a bit about string building techniques in PowerShell. That convoluted construct you have there is not just too much work to create, it's also difficult to debug, as your example proves perfectly. You need to initialize $Loop to 1, not 0 (I assume that's what you are doing, please always post the complete code), or put the $Loop++ at the beginning of the loop, otherwise the string has a comma at the end. You also need to initialize the $Fields variable to an empty string.
Have you checked the string output of your script by printing the actual variable? If you check it in the console, you might have already initialized some variable which you forgot to do in the script.
A much easier way to build the string:
$columns = 'Title', 'Created', 'Description'
$string = "`"$($columns -join '","')`""