Powershell indent here-string - powershell

Does anybody know if it is possible to intend a here-string. Actually I've to write:
$someString = #"
First line
second line
"#
This becomes very ugly if you define a here-string on a deeper indentation level, because the ending "# must be the first character on the line. Additionally somebody might "fix" the missing indentation and break the script ...
Is it possible to define a here-string like:
$someString = #"
First line
second line
"#
Thx

The closing "# must be at the start of the line.
I agree with you that this can make the script file harder to read, but it is the rule, and there is no way around it as far as I know.
You can find a uservoice entry here, and you should vote for it if you feel this is important to you. It does not look like a priority at the moment, with only 3 votes, but the more votes, the higher the priority for the powershell team to look into it.

Late answer (technically "workaround"), I know, but this is currently one of the first search results for "PowerShell here-string indentation".
This becomes very ugly if you define a here-string on a deeper indentation level
I agree. For those of us concerned with the aesthetics of the resulting code, I found the following workaround on this TechNet question.
It's definitely not a here-string (especially since you must still escape embedded quotes), but at least for many multi-line use-cases, it will serve the same purpose, and allow you to keep indenting at the same level as the rest of the code-block:
$somestring = (
"First line",
"Second line"
) -join "`r`n"

To expand upon #NotTheDr01ds's answer, you can make it even more aesthetically pleasing by excluding commas after each item. So long as each item in the array is on its own line:
$HTML = #(
"<h1>OIDC Services are <font style='color:green'>Online</font></h1>"
"<br/><p>Your identity: <ul><li>Username: $($Context.User.Identity.Name)</li></ul></p>"
"<br/><p>Troubleshooting: <ul><li><a href='/restart-service'>Restart Service</a></li></ul></p>"
) -Join "`n"

Related

Regsubbing simple matches

I'm looking for a regsub example that does the following:
123tcl456TCL789 => 123!tcl!456!TCL!789
This is an Tcl example => This is an !Tcl! example
Yes, I could use string first to find a position and mash things but I saw in past a regsub command that does what I want but I can't recall. What would be the regsub command that allows that? I would guess regsub -all -nocase is a start.
I am bad at regsub and regexps. I wonder if there is a site or tool/script that we can supply a string, the final result and then we get the regsub form.
You're looking at the right tool, but there are various options, depending on exactly what the conditions are when faced with other text. Here's one that wraps each occurrence of "Tcl" (any capitalisation) with exclamation marks:
set inputString "123tcl456TCL789"
set replaced [regsub -all -nocase {tcl} $inputString {!&!}]
puts $replaced
That's using a very simple regular expression with the -nocase option, and the replacement means "put ! on either side of the substring matched".
Another (more generally applicable... perhaps) might be to put ! after any letter or number sequence that is followed by a number or letter.
set replaced [regsub -all {[A-Za-z]+(?=[0-9])|[0-9]+(?=[A-Za-z])} $inputString {&!}]
Note that doing things correctly typically requires understanding the real input data fairly well. For example, whether the numbers include floating point numbers in scientific notation, or whether the substrings to delimit are of fixed length.

Powershell confusion about Variable

I am confused regarding variables.
I have code, where I have the following line:
$search = $Name.SelectedItem.Split('-')[$($Name.SelectedItem.Split('-').Count-1)]+'*'
This line does nothing else, as split up a selected item (I am working with a Dropdownbox) and transfers it to $search.
The funny thing is, it does exactly that, what I want it to do.
When I type $search, the result can be for example:
Rue de Rivoli*
When I continue in the code and use $search through several arrays, for some reason, it does not function, because it does not find anything in a foreach loop. I have no error message and even the Rue de Rivoli* existing in one of the arrays, it does not find anything.
When I replace the above code and give directly the name to the variable $search, as seen below
$search = 'Rue de Rivoli*'
my search in the array works.
What am I missing here? I am doing something wrong, but I do not know what it is, can someone help me please to understand?
Thank you very much,
Mike
As requested, here more of the code. It is a lot to deal with, that is why I shorten it.
Clear-Host
$search = $CreateNewUserFormDropDownBoxLocation.SelectedItem.Split('-')[$($CreateNewUserFormDropDownBoxLocation.SelectedItem.Split('-').Count-1)]+'*'
#$search = 'Rue de Rivoli*'
$AllLocations = (get-variable -Include USPennsylvaniaAve, USSixthStreet, USRodeoDrive, USOneMicrosoftWay,`
USNorthTantauAvenue, USMarketStreet, USMainStreet, USEmilyDrive,`
USCalle8, USBroadway, US18thStreetNW, UKOxfordStreet, UKDowningStreet,`
UKBondStreet, FRRuedeRivoli, FRChampsElysees, CHBahnhofstrasse,`
CA17thAvenue) | ? {$_.value -is [array]}
Foreach ($Array in $AllLocations)
{
if ($array.value -like $search)
{break}
}
$result = "`$$($array.name)"
$result
This is about to become a function and does nothing else, as from the selecteditem, it takes it apart and add's the * behind it, so I can search
for a name with a wildcard.
I have several arrays and therefore I included only the necessary ones. Next step is to loop through the arrays and as soon as it found the item, it stops and gives the result to result.
This is my test code and it runs and does what I want, besides the line after Clear-Host. The code is correctly resolved and added to $search but does not work.
Below that code of line, I have my cheat line, where I add directly the correct result to the variable and it works fine.
As commented, this should solve the problem.
(I'm adding this as answer too, so the OP can accept it. Otherwise this question will remain seemingly unsolved)
When hardcoding the search string $search = 'Rue de Rivoli*' works, but using a Split() to get the search string does not, then usually the string you obtain using the split is surrounded by whitespace characters. If you leave these in, the string will appear to look just fine, but when using as comparison it won't work.
If for instance the complete $CreateNewUserFormDropDownBoxLocation.SelectedItem string is:
"François Exemple - Rue de Rivoli"
Then, using $CreateNewUserFormDropDownBoxLocation.SelectedItem.Split("-")[-1] will return:
" Rue de Rivoli"
Note the space in front.
By simply performing a Trim() you will get rid of that space.
The line therefore should be:
$search = ($CreateNewUserFormDropDownBoxLocation.SelectedItem.Split('-')[-1]).Trim() + '*'

What am I allowed to name a function in Powershell?

PS > function ]{1}
PS > ]
1
PS >
PS
Why does this work?
What else can I name a function? All I've found so far that works is * and ].
You can name it almost anything. You can even include newlines and emoji* in the name.
function Weird`nFunctionの名前😀 { Write-Host hey }
$c = gcm Weird*
$c.Name
& $c
Escaping helps with lots of things like that:
function `{ { Write-Host cool }
`{
function `0 { Write-Host null }
gci function:\?
I'll add that this is true for variables too, and there's a syntax that removes the need to do most escaping in the variable name: ${varname} (as opposed to $varname).
With that, you could easily do:
${My variable has a first name,
it's
V
A
something
R,
whatever I dunno
🤷} = Get-Process
You'll note that if you then start typing like $MyTAB it will tab complete in a usable way.
To (somewhat) answer why this should work, consider that the variable names themselves are just stored in .Net strings. With that in mind, why should there be a limit on the name?
There will be limits on how some of these names can be used in certain contexts, because the parser will not understand what to do with it if the names don't have certain characters escaped, but literal parsing of PowerShell scripts are not the only way to use functions or variables or other language constructs, as I've shown some examples of.
Being less limiting also means being able to support other languages and cultures by having wide support for character sets.
To this end, here's one more thing that might surprise you: there are many different characters to represent the same or similar things that we take for granted in code, like quotation marks for example.
Some (human) languages or cultures just don't use the same quote characters we do in English, don't even have them on the keyboard. How annoying would it be to type code if you have to keep switching your keyboard layout or use ALT codes to quote strings?
So what I'm getting at here is that PowerShell actually does support many quote characters, for instance, what do you think this might do:
'Hello’
Pretty obvious it's not the "right" set of quotes on the right side. But surprisingly, this works just fine, even though they aren't the same character.
This does have important implications if you're ever generating code from user input and want to avoid sneaky injection attacks.
Imaging you did something like this:
Invoke-Expression "echo '$($userMsg -replace "'","''")'"
Looks like you took care of business, but now imagine if $userMsg contained this:
Hi’; gci c: -recurse|ri -force -whatif;'
For what it's worth, the CodeGeneration class is aware of this stuff ;)
Invoke-Expression "echo '$([System.Management.Automation.Language.CodeGeneration]::EscapeSingleQuotedStringContent($userMsg))'"
* PowerShell Console doesn't have good support for Unicode, even though the language does. Use ISE to better see the characters.

String variable position being overwritten in write-host

If I run the below code, $SRN can be written as output or added to another variable, but trying to include either another variable or regular text causes it to be overwritten from the beginning of the line. I'm assuming it's something to do with how I'm assigning $autocode and $SRN initially but can't tell what it's trying to do.
# Load the property set to allow us to get to the email body.
$item.load($psPropertySet) # Load the data.
$bod = ($item.Body.Text -creplace '(?m)^\s*\r?\n','') -split "\n" # Get the body text, remove blank lines, split on line breaks to create an array (otherwise it is a single string).
$autocode = $bod[4].split('-')[2] # Get line 4 (should be Title), split on dash, look for 3rd element, this should contain our automation code.
$SRN = $bod[1] -replace 'ID: ','' # Get line 2 (should be ID), find and replace the preceding text.
# Skip processing if autocode does not match our list of handled ones.
if ($autocode -cin $autocodes)
{
write-host "$SRN $autocode"
write-host "$autocode $SRN"
write-host "$SRN test"
$var = "$SRN $autocode"
$var
}
The code results in this, you can see if $SRN isn't at the start of the line it is fine. Unsure where the extra spaces come from either:
KRNE8385
KRNE SR1788385
test8385
KRNE8385
I would expect to see this:
SR1788385 KRNE
KRNE SR1788385
SR1788385 test
SR1788385 KRNE
LotPings pointed me down the right path, both variables still had either "0D" or "\r" in them. My regex replace was only getting rid of them on blank lines, and I split the array on "\n" only. Changing line 3 in the original code to the below appears to have resolved the issue. First time seeing Format-Hex, but it appears to be excellent for troubleshooting such issues.
$bod = ($item.Body.Text -creplace '(?m)^\s*\r?\n','') -split "\r\n"

Using either Trim or Replace in PowerShell to clean up anything not contained in quotation marks

I'm trying to write a script that that will remove everything except text contained in quotation marks from a result-set generated by a SQL query. Not sure whether trim or -replace will do this.
Here is a sampling of the result-set:
a:5:{s:3:"Client Service";a:4:{s:15:"Client Training";b:0;s:11:"Payer
Error";
I would like it to end up looking like this:
Client Service
Client Training
Payer Error
I've tried everything I know to do in my limited PowerShell and RegEx familiarity and still haven't been able to figure out a good solution.
Any help would be greatly appreciated.
$s = 'a:5:{s:3:"Client Service";a:4:{s:15:"Client Training";b:0;s:11:"Payer Error";'
Replace the start of string up to the first quote, or the last quote up to the end of string. Then what you're left with is:
Client Service";a:4:{s:15:"Client Training";b:0;s:11:"Payer Error
Now the bits you don't want are "in quotation marks" and that's easy to match with ".*?" so replace that with a space.
Overall, two replaces:
$s -replace '^[^"]*"|"[^"]*$' -replace '".*?"', ' '
Client Service Client Training Payer Error
Here's a version that uses Regex to capture the strings including their quotes in to an array and then removes the quote marks with -replace:
$text = 'a:5:{s:3:"Client Service";a:4:{s:15:"Client Training";b:0;s:11:"Payer Error";'
([regex]::matches($Text, '(")(.*?)(")')).value -replace '"'
There's without a doubt a regex to get the strings without their quotes in the first place but i'm a bit of a regex novice.