String.Trim() not removing characters in a string - powershell

I need to create a String from double the use String.Trim() to remove the full stop, but it doesn't remove it. I think there is also a way to do this numerically but I'd like to do it with the string. Is there a reason it won't remove it? The output from the code is 5.5
$MyDouble = 5.5
[String]$MyDouble2 = $MyDouble
$MyDouble2.Trim(".")
$MyDouble2

String.Trim() only trims from the beginning and end of strings, so it has no effect in your command, because the . only occurs inside your input string.
If you truly want to remove just the . and keep the post-decimal-point digits, use the -replace operator:
$MyDouble2 -replace '\.' # -> '55'
Note:
* -replace takes a regex (regular expression) as the search operand, hence the need to escape regex metacharacter . as \.
* The above is short for $MyDouble2 -replace '\.', ''. Since the replacement string is the empty string in this case, it can be omitted.
If you only want to extract the integer portion, use either 4c74356b41's .Split()-based answer, or adapt the regex passed to -replace to match everything from the . through the end of the string.
$MyDouble2 -replace '\..*' # -> '5'
#Matt mentions the following alternatives:
For removing the . only: Using String.Replace() to perform literal substring replacement (note how . therefore does not need \-escaping, as it did with -replace, and that specifying the replacement string is mandatory):
$MyDouble2.Replace('.', '') # -> '55'
For removing the fractional part of the number (extracting the integer part only), using a numerical operation directly on $MyDouble (as opposed to via the string representation stored in $MyDouble2), via Math.Floor():
[math]::Floor($MyDouble) # -> 5 (still a [double])

Looking at some documentation for .Trim([char[]]) you will see that
Removes all leading and trailing occurrences of a set of characters specified in an array from the current String object.
That does not cover the middle of strings, so using the .Replace() method would accomplish that.
I think there is also a way to do this numerically but I'd like to do it with the string.
Just wanted to mention that converting numbers to strings to then drop decimals via string manipulation is a poor approach. Assuming your example is what you are actually trying to do, I suggest using a static method from the [math] class instead.
$MyDouble = 5.5
[math]::Floor($MyDouble)

$MyDouble = 5.5
[String]$MyDouble2 = $MyDouble
$MyDouble2.Replace(".", "")

Well, why would it trim not the last (or first) character? It wouldn't, what you need (probably) is:
$MyDouble = 5.5
[String]$MyDouble2 = $MyDouble
$MyDouble2.Split(".")[0]

$MyDouble = 5.5
[String]$MyDouble2 = $MyDouble
$res=$MyDouble2 -split "\."
$res[0..($res.Count-1)] -join ""

Related

how to add quotes in this string

I have this string
[{listenport:443,connectaddress:10.1.10.20,connectport:443,firewallrulename:port443,direction:Inbound,action:Allow,protocol:TCP},{listenport:80,connectaddress:10.1.10.20,connectport:80,firewallrulename:port80,direction:Inbound,action:Allow,protocol:TCP}]
i'm wondering how can I write a function to convert it to
[{"listenport":"443","connectaddress":"10.1.10.20","connectport":"443","firewallrulename":"port443","direction":"Inbound","action":"Allow","protocol":"TCP"},{"listenport":"80","connectaddress":"10.1.10.20","connectport":"80","firewallrulename":"port80","direction":"Inbound","action":"Allow","protocol":"TCP"}]
I have tried to use insert and indexof , but couldn't figure out how to do for an entire string
If you really have to work with this format and cannot produce well-formed JSON to begin with, at least in your sample input both the property names and values are composed only of characters that are either . or fall into the \w regex category, so a single -replace operation is possible:
#'
[{listenport:443,connectaddress:10.1.10.20,connectport:443,firewallrulename:port443,direction:Inbound,action:Allow,protocol:TCP},{listenport:80,connectaddress:10.1.10.20,connectport:80,firewallrulename:port80,direction:Inbound,action:Allow,protocol:TCP}]
'# -replace '[\w.]+', '"$&"'
The result is well-formed JSON, which you can pipe to ConvertFrom-Json for OO processing in PowerShell.
If you can only assume that the property names are composed of only \w characters:
#'
[{listenport:443,connectaddress:10.1.10.20,connectport:443,firewallrulename:port443,direction:Inbound,action:Allow,protocol:TCP},{listenport:80,connectaddress:10.1.10.20,connectport:80,firewallrulename:port80,direction:Inbound,action:Allow,protocol:TCP}]
'# -replace '(\w+):', '"$1":"' -replace '\}|(?<!\}),', '"$&'
eventually hacked it by using replace
$proxyinfosjson = $proxyinfosjson.Replace(',', '","').Replace('{', '{"').Replace('}', '"}').replace(':', '":"').Replace('}"', '}').Replace('"{', '{')
so ugly.. not proud of it.. but works..

Pad IP addresses with leading 0's - powershell

I'm looking to pad IP addresses with 0's
example
1.2.3.4 -> 001.002.003.004
50.51.52.53 -> 050.051.052.053
Tried this:
[string]$paddedIP = $IPvariable
[string]$paddedIP.PadLeft(3, '0')
Also tried split as well, but I'm new to powershell...
You can use a combination of .Split() and -join.
('1.2.3.4'.Split('.') |
ForEach-Object {$_.PadLeft(3,'0')}) -join '.'
With this approach, you are working with strings the entire time. Split('.') creates an array element at every . character. .PadLeft(3,'0') ensures 3 characters with leading zeroes if necessary. -join '.' combines the array into a single string with each element separated by a ..
You can take a similar approach with the format operator -f.
"{0:d3}.{1:d3}.{2:d3}.{3:d3}" -f ('1.2.3.4'.Split('.') |
Foreach-Object { [int]$_ } )
The :dN format string enables N (number of digits) padding with leading zeroes.
This approach creates a string array like in the first solution. Then each element is pipelined and converted to an [int]. Lastly, the formatting is applied to each element.
To complement AdminOfThings' helpful answer with a more concise alternative using the -replace operator with a script block ({ ... }), which requires PowerShell Core (v6.1+):
PSCore> '1.2.3.50' -replace '\d+', { '{0:D3}' -f [int] $_.Value }
001.002.003.050
The script block is called for every match of regex \d+ (one or more digits), and $_ inside the script block refers to a System.Text.RegularExpressions.Match instance that represents the match at hand; its .Value property contains the matched text (string).

Zero being dropped from array

I have noticed is that if the 'version' ends in a zero, then that zero is being dropped.
So, for example, if the 'version' in the $statusContent is 1.9.7.680, then $version is 1.9.7.68. Is there a way to keep that zero?
$version = $statusContent.Content.Substring(145).TrimEnd('" counter="0" /></mibscalar>')
Sample string:
<mibscalar name="appRunningApp" type="readonly" link= "xxx.xxx.xxx.xxx/v1/mib/objs/appRunningApp?type=xml"; ><data index="1" value="ma xtime - 1.9.7.680" counter="0" /></mibscalar>
TrimEnd() is not the function you're looking for - it turns the string argument into a character array and eats away every occurrence of any of those characters from the end of the string until it can't find anymore.
Use Remove() instead to cut off the trailing part:
$string = $statusContent.Content.Substring(145)
$tail = '" counter="0" /></mibscalar>'
if($string.EndsWith($tail)){
# [string]::Remove() takes a start index as it's first argument
# Let's calculate the index at which we'll start removing characters
$string = $string.Remove($string.Length - $tail.Length)
}
Why not use regular expression?
> $txt
<mibscalar name="appRunningApp" type="readonly" link= "127.0.0.2/v1/mib/objs/appRunningApp?type=xml"; ><data index="1" value="ma xtime - 1.9.7.680" counter="0" /></mibscalar>
> if ($txt -match '\d+[.]\d+[.]\d+[.]\d+(?=\")') { $version = $matches[0] }
> $version
1.9.7.680
EDIT:
Now that I'm aware xxx.xxx.xxx.xxx bit was an IP address I had to change regular expression in above code to avoid matching it. IP addresses are too similar in their pattern to versions to tell them apart looking just at them.
I've added a lookahead (?=\") that matches only if " follows the pattern. It will work as long as quotes closes immediately after version number. You could as another option have a negative lookahead (?!\/) to make sure / is not following a pattern to make sure it's not and <IP>/<path> kind of string.

Powershell - Capture text in a var from a specific character

I want to grab the first char of a var string and the first char of the following caracter
Example:
$var1 = "Jean-Martin"
I want a way to grab the first letter "J" then I want to take the first char following the "-" (dash) which is "M".
Something like this?
$initial1 = $var1[0]
$initial2 = $var1.Split('-')[1][0]
Strings in Powershell use the System.String class from the .Net framework. As such, they are indexable to retrieve individual characters and have many methods available such as the Split method used above.
See the documentation here.
$var1 = "Jean-Martin"
To get the first character:
$var1[0]
To get the first character after the dash:
$characterToSeek = '-'
$var1[$var1.IndexOf($characterToSeek)+1]
Another option using regex:
PS> $var1 -replace '^(.)[^-]+-(.).+$','$1$2'
JM

Case-insensitive PowerShell replacement

I have the following PowerShell script:
$RegExplorer = Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters
$NullSessionPipes = "$($RegExplorer.NullSessionPipes)"
$NullSessionPipes
$NullSessionPipes = $NullSessionPipes.replace("browser", "")
$NullSessionPipes
The script works fine as long as the registry key examining exactly matches the case I've specified - "browser".
However if the case was different in the registry key say "BROWSER" or "Browser" it doesn't do the replacement.
I'm looking for some way to make string.replace case insensitive. I know I could convert the string using .tolower or .toupper first to make comparison easier, but I don't know if this particular registry key or applications which access it are case sensitive, so I don't want to change the case of existing key.
Is there an easy way to do this?
Call me pedantic but while nobody here was outright wrong, nobody provided the correct code for the final solution either.
You need to change this line:
$NullSessionPipes = $NullSessionPipes.replace("browser", "")
to this:
$NullSessionPipes = $NullSessionPipes -ireplace [regex]::Escape("browser"), ""
The strange [regex] text isn't strictly necessary as long as there are no regular expression characters (ex. *+[](), etc) in your string. But you're safer with it. This syntax works with variables too:
$NullSessionPipes = $NullSessionPipes -ireplace [regex]::Escape($stringToReplace), $stringToReplaceItWith
NullSessionPipes is a multi-string value and the replace method (in addition of being case-sensitive) may fail if there's more than one string in it. You can use the -replace operator. By default, all comparison operators are case-insensitive. Case-sensitive operators starts with 'c', like: -creplace,-ceq, etc.
Operators that starts with 'i' are case-insensitive, like -ireplace,-ieq, and they are the same as -replace, -ieq.
See the about_Comparison_Operators for more information.
Use a regular expression replacement instead:
$RegExplorer = Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters
$NullSessionPipes = "$($RegExplorer.NullSessionPipes)"
$NullSessionPipes
$NullSessionPipes = $NullSessionPipes -replace "browser", ""
$NullSessionPipes
The .Replace method doesn't have a case-insensitive option:
String.Replace method
...This method performs an ordinal (case-sensitive and culture-insensitive) search...
https://msdn.microsoft.com/en-us/library/fk49wtc1(v=vs.110).aspx
The other answers to this question suggest using -replace or -ireplace, which is fine if you want to use regex replacement. However, as #Bob mentions in his (her?) comments this isn't always appropriate. An example might be if you want to include a literal string such as $_ in the replacement text.
One trick borrowed from other case-sensitive places is to convert the "input" string and the "search" string to lower case:
[PS]> "TeXT".ToLower().Replace("text","NewString")
NewString
However... this causes the output to be in lower case for anything that doesn't match the search string, which may well be unacceptable.
[PS]> "DON'T CHANGE MY TeXT".ToLower().Replace("text","NewString")
don't change my NewString
The String.Replace method has two different overloads that allows a case-insensitive replacement:
Replace(String, String, StringComparison)
Replace(String, String, Boolean, CultureInfo)
For the first one, you need to pick a StringComparison that ignores case, e.g. OrdinalIgnoreCase.
For the second one, it's the Boolean that controls case sensitivity; a null for the CultureInfo uses the current culture.
Using these in PowerShell 7 would look like:
$s = 'All the HIP cats'
$s.Replace('hip','cool') # doesn't work: All the HIP cats
$s.Replace('hip','cool','OrdinalIgnoreCase') # works : All the cool cats
$s.Replace('hip','cool',$true,$null) # works : All the cool cats