How can I split a string into an array on every newline? - powershell

In my situation, I will have a string that looks like this.
$emailList = "example#mail.com
example2#mail.com
example3#mail.com"
How can I port this into an array with no white-space so it would look like
$emailList = #("example#mail.com","example2#mail.com","example3#mail.com"

Per the comments, if you do this:
($emailList -split '\r?\n').Trim()
It uses -split to separate the list in to an array based on the new line/return charaters and then .Trim() to remove any whitespace either side of each string.
Following this the result is now already an array. However if you explicitly want the output to be as a list of comma separated strings surrounded by double quotes you could then do this:
(($emailList -split '\r?\n').Trim() | ForEach-Object { '"'+$_+'"' }) -Join ','
Which uses ForEach-Object to add quote marks around each entry and then uses -Join to connect them with a ,.

$emailList = "example#mail.com
example2#mail.com
example3#mail.com"
$emailList.Split([Environment]::NewLine,[Stringsplitoptions]::RemoveEmptyEntries).trim()

-split on the left side splits on variable whitespace:
$emailList = -split 'example#mail.com
example2#mail.com
example3#mail.com'
$emailList
example#mail.com
example2#mail.com
example3#mail.com
You can also form an array list this. #() is almost never needed.
$emailList = 'example#mail.com','example2#mail.com','example3#mail.com'
Or as a shortcut (echo is an alias for write-output):
$emailList = echo example#mail.com example2#mail.com example3#mail.com

Related

PowerShell - how can I remove repeated backslashes in the string

$string = "my\\\name\\is\John\\\\Doe"
Desired output:
my\name\is\John\Doe
Thank you for your help in advance!
Lets talk about what we need to do.
Take the string and create an array by using -split '\\'.
Why \\ because -split allows for regex and \ is an escape string for regex.
Next we need to remove all blank array objects by using Where-Object making sure the length of the string is greater then 0.
Lastly we use that with the string method join(Joining Char, Array)
The join() method allows you to join an array creating a string using a char as the glue.
$string = "my\\\name\\is\John\\\\Doe"
[string]::join('\',($string -split "\\" | Where-Object{$_.length -gt 0}))
returning
my\name\is\John\Doe
Same principal, different methods
$string = "my\\\name\\is\John\\\\Doe"
$string.Split('\').where{$_} -join '\'
Output
my\name\is\John\Doe
Another way using regex
$string = "my\\\name\\is\John\\\\Doe"
while($string -match '\\\\'){$string = [regex]::Replace($string,'\\\\','\')}
Output
$string
my\name\is\John\Doe
Using -replace just seems simpler.
# replace all single or consecutive \ with a single \
$string -replace '\\+','\'
# replace each \ that had a preceding \
$string -replace '(?<=\\)\\'

Extract string between two special characters in powershell

I need to extract a list with strings that are between two special characters (= and ;).
Below is an example of the file with line types and the needed strings in bold.
File is a quite big one, type is xml.
<type="string">data source=**HOL4624**;integrated sec>
<type="string">data source=**HOL4625**;integrated sec>
I managed to find the lines matching “data source=”, but how to get the name after?
Used code is below.
Get-content regsrvr.txt | select-string -pattern "data source="
Thank you very much!
<RegisteredServers:ConnectionStringWithEncryptedPassword type="string">data source=HOL4624;integrated security=True;pooling=False;multipleactiveresultsets=False;connect timeout=30;encrypt=False;trustservercertificate=False;packet size=4096</RegisteredServers:ConnectionStringWithEncryptedPassword>
<RegisteredServers:ConnectionStringWithEncryptedPassword type="string">data source=HOL4625;integrated security=True;pooling=False;multipleactiveresultsets=False;connect timeout=30;encrypt=False;trustservercertificate=False;packet size=4096</RegisteredServers:ConnectionStringWithEncryptedPassword>
The XML is not valid, so it's not a clean parse, anyway you can use string split with regex match:
$html = #"
<RegisteredServers:ConnectionStringWithEncryptedPassword type="string">data source=HOL4624;integrated security=True;pooling=False;multipleactiveresultsets=False;connect timeout=30;encrypt=False;trustservercertificate=False;packet size=4096</RegisteredServers:ConnectionStringWithEncryptedPassword>
<RegisteredServers:ConnectionStringWithEncryptedPassword type="string">data source=HOL4625;integrated security=True;pooling=False;multipleactiveresultsets=False;connect timeout=30;encrypt=False;trustservercertificate=False;packet size=4096</RegisteredServers:ConnectionStringWithEncryptedPassword>
"#
$html -split '\n' | % {$null = $_ -match 'data source=.*?;';$Matches[0]} |
% {($_ -split '=')[1] -replace ';'}
HOL4624
HOL4625
Since the connectionstring is for SQL Server, let's use .Net's SqlConnectionStringBuilder to do all the work for us. Like so,
# Test data, XML extraction is left as an exercise
$str = 'data source=HOL4624;integrated security=True;pooling=False;multipleactiveresultsets=False;connect timeout=30;encrypt=False;trustservercertificate=False;packet size=4096'
$builder = new-object System.Data.SqlClient.SqlConnectionStringBuilder($str)
# Check some parameters
$builder.DataSource
HOL4624
$builder.IntegratedSecurity
True
You can expand your try at using Select-String with a better use of regex. Also, you don't need to use Get-Content first. Instead you can use the -Path parameter of Select-String.
The following Code will read the given file and return the value between the = and ;:
(Select-String -Path "regsrvr.txt" -pattern "(?:data source=)(.*?)(?:;)").Matches | % {$_.groups[1].Value}
Pattern Explanation (RegEx):
You can use -pattern to capture an String given a matching RegEx. The Regex can be describe as such:
(?: opens an non-capturing Group
data source= matches the charactes data source=
) closes the non-capturing Group
(.*?) matches any amount of characters and saves them in a Group. The ? is the lazy operator. This will stop the matching part at the first occurence of the following group (in this case the ;).
(?:;) is the final non-capturing Group for the closing ;
Structuring the Output
Select-String returns a Microsoft.PowerShell.Commands.MatchInfo-Object.
You can find the matched Strings (the whole String and all captured groups) in there. We can also loop through this Output and return the Value of the captured Groups: | % {$_.groups[1].Value}
% is just an Alias for For-Each.
For more Informations look at the Select-String-Documentation and try your luck with some RegEx.

Remove everything from string before given variable

I have a string some\string/with/**/special\chars\haha. In variable I hold chars string and I try to remove everything before and including chars so expected output would be \haha
I tried sth like:
$temp = "some\string/with/**/special\chars\haha"
$tmp="chars"
$temp -replace '(?s)^.*$tmp', ''
and
$temp -replace '(?s)^.*$([regex]::Escape($tmp))', ''
but the only thing that works is when I put the string directly into regex condition. Only this example gives expected output:
$temp -replace '(?s)^.*chars', ''
What am I doing wrong?
Edit.:
I need to use variable in regex, because I iterate through multiple strings like this one and not always the part I want to remove has the same string (example: some\string/with/**/special\chars\haha -> \haha; C:\st/h/*/1234\asdf\x -> \x). So in conclusion I have a problem using variable in regex, not with the regex itself as that works as intended when I replace variable with string (as shown above)
Try
$temp = "some\string/with/**/special\chars\haha"
$tmp="chars"
$regex = '(?s)^.*' + $tmp
$temp -replace $regex, ''
Looks like it's because you are using single quotes in your regex instead of double quotes. This means that the variable $tpm isn't being used.
Here is what your code should look like:
$temp = "some\string/with/**/special\chars\haha"
$tmp="chars"
$temp -replace "(?s)^.*$tmp", ''
Your code was using $tmp instead of the actual value inside the $tmp variable.

String coming with an extra new line

Below is the code where I am taking server names from a text file and concatenating with comma.
But when I am printing the value, it is coming with an extra new line after the values.
I tried doing $erversToReboot.Trim(), but didn't helped.
$ServerList = Get-Content "D:\ServerName.txt"
$Servers=""
foreach($Server in $ServerList)
{
$Servers += $Server + ","
}
[string]$ServersToReboot= $Servers.TrimEnd(",")
The output coming as
server1,server2
---one extra line here---
Please let me know what is going wrong here.
Best as I can tell, you're attempting to comma separate your servers. I'd skip the Foreach construct myself and simply use the join operator.
$ServerList = Get-Content -Path 'D:\ServerName.txt'
$ServerList -join ','
This can be done in a single statement, as well.
$ServerList = (Get-Content -Path 'D:\ServerName.txt') -join ','
Tommy
As others have noted, it's in general much simpler to use the -join operator to join the input lines with a specifiable separator.
As for the problem of an extra empty line: Gert Jan Kraaijeveld plausibly suggests that your input file has an extra empty line at the end, while noting that it is actually not what would happen with the code you've posted, which should work fine (despite its inefficiency).
Perhaps the extra line is an artifact of how you're printing the resulting value.
To answer the related question of how to ignore empty lines in the input file:
Assuming that it is OK to simply remove all empty lines from the input, the simplest PowerShell-idiomatic solution is:
#(Get-Content D:\ServerName.txt) -ne '' -join ','
#(Get-Content D:\ServerName.txt) returns the input lines as an array[1] of strings, from which -ne '' then removes empty lines, and the result of which -join joins with separator ,
[1] Get-Content D:\ServerName.txt would return a scalar (single string), if the input file happened to contain only 1 line, because PowerShell generally reports a single output object as itself rather than as a single-element array when pipeline output is collected.
Because of that, #(...), the array-subexpression operator - instead of just (...) - is needed in the above command: it ensures that the output from Get-Command is treated as an array, because the -ne operator acts differently with a scalar LHS and returns a Boolean rather than filtering the LHS's elements: compare 'foo' -ne '' to #('foo') -ne ''.
By contrast, the #(...) is not necessary if you pass the result (directly) to -join (which simply is a no-op with a scalar LHS):
(Get-Content D:\ServerName.txt) -join ','

How to Split DistinguishedName?

I have a list of folks and their DN from AD (I do not have direct access to that AD). Their DNs are in format:
$DNList = 'CN=Bob Dylan,OU=Users,OU=Dept,OU=Agency,OU=NorthState,DC=myworld,DC=com',
'CN=Ray Charles,OU=Contractors,OU=Dept,OU=Agency,OU=NorthState,DC=myworld,DC=com',
'CN=Martin Sheen,OU=Users,OU=Dept,OU=Agency,OU=WaySouth,DC=myworld,DC=com'
I'd like to make $DNList return the following:
OU=Users,OU=Dept,OU=Agency,OU=NorthState,DC=myworld,DC=com
OU=Contractors,OU=Dept,OU=Agency,OU=NorthState,DC=myworld,DC=com
OU=Users,OU=Dept,OU=Agency,OU=WaySouth,DC=myworld,DC=com
I decided to turn my comment into an answer:
$DNList | ForEach-Object {
$_ -replace '^.+?(?<!\\),',''
}
Debuggex Demo
This will correctly handle escaped commas that are part of the first component.
We do a non-greedy match for one or more characters at the beginning of the string, then look for a comma that is not preceded by a backslash (so that the dot will match the backslash and comma combination and keep going).
You can remove the first element with a replacement like this:
$DNList -replace '^.*?,(..=.*)$', '$1'
^.*?, is the shortest match from the beginning of the string to a comma.
(..=.*)$ matches the rest of the string (starting with two characters after the comma followed by a = character) and groups them, so that the match can be referenced in the replacement as $1.
You have 7 items per user, comma separated and you want rid of the first one.
So, split each item in the array using commas as the delimiter, return matches 1-6 (0 being the first item that you want to skip), then join with commas again e.g.
$DNList = $DNList|foreach{($_ -split ',')[1..6] -join ','}
If you then enter $DNList it returns
OU=Users,OU=Dept,OU=Agency,OU=NorthState,DC=myworld,DC=com
OU=Contractors,OU=Dept,OU=Agency,OU=NorthState,DC=myworld,DC=com
OU=Users,OU=Dept,OU=Agency,OU=WaySouth,DC=myworld,DC=com
Similar to Grahams answer but removed the hardcoded array values so it will just remove the CN portion without worrying how long the DN is.
$DNList | ForEach-Object{($_ -split "," | Select-Object -Skip 1) -join ","}
Ansgar most likely has a good reason but you can just use regex to remove every before the first comma
$DNList -replace "^.*?,"
Update based on briantist
To maintain a different answer but one that works this regex can still have issues but I doubt these characters will appear in a username
$DNList -replace "^.*?,(?=OU=)"
Regex uses a look ahead to be sure the , is followed by OU=
Similarly you could do this
($DNList | ForEach-Object{($_ -split "(,OU=)" | Select-Object -Skip 1) -join ""}) -replace "^,"