foreach pipe in multipleline string - powershell

Here is my code:
$collection1 = "1","2","3","4"
"
collection1:
$($collection1 | % {$_})
"
The output is:
collection1:
1 2 3 4
However, I'm expecting:
collection1:
1
2
3
4
So I changed my code to:
"
$($collection1 | % {$_ + "`n"})
"
Now, it shows:
collection1:
1
2
3
4
Why there is always an extra space in the front of each line?
Any way to remove them?
I tried to use Trim(), [String]::Format(), and few other ways, none is working as expected.

I think I found the answer... For anyone's interest...
$collection1 = "1","2","3","4"
$body = [System.Text.StringBuilder]::new()
foreach($item in $collection1)
{
[void]$body.Append($item+"`n")
}
"
collection1:
$body
"

$collection1 | % {$_} takes the array $collection1 and outputs each of its elements, which gives you the exact same thing you strated with: an array of the elements of $collection1. Using a subexpression to put that array into a string auto-converts the array to a string, so that it can be inserted into the outer string. In PowerShell this array-to-string conversion is done by joining the array elements with the $OFS character (Output Field Separator, by default a single space), which for your example produces the string "1 2 3 4".
The simplest way of getting the result you expect is to convert the array to a formatted string yourself:
"
collection1:
$($collection1 | Out-String)
"
The Out-String cmdlet converts array input to a single string by joining all input strings with newlines. Alternatively join the array yourself:
"
collection1:
$($collection1 -join "`n")
"
You could also (temporarily) modify $OFS and use the variable directly:
$OFS_bak = $OFS
$OFS = "`n"
"
collection1:
$collection1
"
$OFS = $OFS_bak
although I wouldn't normally recommend that.
As a side note: when working with a format/template string it's usually a good idea to use here-strings (so that don't need to escpae quotes inside the strings) and the format operator (-f):
#"
collection1:
{0}
"# -f ($collection1 | Out-String)

Related

How to get 2 variables from a file PowerShell

I'm trying to make an script that take numbers from a file and then do some maths with them, but I don't know how to take from a single line 2 variables.
The file it must be something like this:
3 5
What I need is that one variable is for example $a be 3 and other $b be 5
$a=3
$b=5
The problem is that I found this
$Contents = Get-Content ".\file.txt"
$a = $Contents[0] -split(" ")[1]
$b = $Contents[1] -split(" ")[1]
but it doesen´t work with the second number, how can I do this?
To refer to the first line in the file, you want $Contents[0] ($Contents[1] would refer to the second line).
$a,$b = -split $Contents[0] -as [int[]]
Using -split in unary mode will make PowerShell split on any sequence of consecutive whitespace characters, and throw away any empty parts (this way it works when the iput has leading or trailing whitespace, like " 3 5 ").
The -as [int[]] operation will force PowerShell to attempt to convert the resulting string values to [int] values, so now you can meaningfully do integer arithmetic with them:
PS ~> $a + $b
8

powershell - mystery whitespace from output of loops

I am getting whitespace added to my output from the following section of code. I need to format this a certain way so for sake of finding out where this whitespace is coming from I am just outputting the variables. I even added .trim() to make sure it wasn't coming from the variables themselves. Where in the heck is this whitespace coming from?
#sort by Name and sort Values of each
$output += foreach($icon in $table.GetEnumerator() | sort -Property Name) {
$icon.Name.trim()
foreach($type in $icon.Value | sort) {
$fa_types[$type].trim()
}
}
#Output to file
"version: " + $fa_version + "`r`nicons:`r`n" + $output | Out-File $output_file
example output file :
version: 5.13.0
icons:
arrow-circle-right solid regular calendar-week regular users solid usb-drive solid file-alt regular key solid user-graduate solid comment-dots regular plus solid calendar-check regular spinner regular stopwatch regular file-search solid user-chart solid map-marker-alt regular calculator regular apple brands
Running powershell version 5 on Windows 10.
That's a strange way to create a string... I recommend a safer way, where no output functions of PowerShell are involved:
#sort by Name and sort Values of each
$output = ""
foreach($icon in $table.GetEnumerator() | sort -Property Name) {
$output += $icon.Name
foreach($type in $icon.Value | sort) {
$output += $fa_types[$type]
}
}
#Output to file
"version: " + $fa_version + "`r`nicons:`r`n" + $output | Out-File $output_file
Reason this is happening is because you are printing an array within a string. When you loop over your items and print just the $fa_types[$type], it writes it as item of an array to the $output.
If you print only $output, you will see multiple items separated new line but if you put that inside of a string, its represented by a space delimiter.
Examples:
$outp = foreach($var in (0..5)) { $var }
$outp
# shows the following output
# 0
# 1
# 2
# 3
# 4
# 5
Write-Output "string $outp end"
# prints it in a single line
# string 0 1 2 3 4 5 end
You can concatenate your array via a join so no spaces are printed in your output.
"version: " + $fa_version + "`r`nicons:`r`n" + $output -join "" | Out-File $output_file
#or
"version: " + $fa_version + "`r`nicons:`r`n" + -join $output | Out-File $output_file

Remove particular characters from lines and concatenate them

I have a problem where I need to cut specific characters from a line and then concatenate the line with the next lines, separated by commas.
Consider there is a text file abc.txt and I need the last 3 lines from the file. The last 3 lines are in the this format:
11/7/2000 17:22:54 - Hello world.
19/7/2002 8:23:54 - Welcome to the new technology.
24/7/2000 9:00:13 - Eco earth
I need to remove the starting time stamp from each line and then concatenate the lines as
Hello world.,Welcome to the new technology,Eco earth.
The time stamp is not static and I want to make use of a regex
I tried the following:
$Words = (Get-Content -Path .\abc.txt|Select-Object -last 3|Out-String)
$Words = $Words -split('-')
$regex = "[0-9]{1,2}/[0-9]{1,2}/[0-9]{1,4} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}):[0-9]{1,3}"
The output I used to get is like
11/7/2000 17:22:54
Hello world
19/7/2002 8:23:54
Welcome to the new technology.
24/7/2000 9:00:13
Eco earth
There is no need to create a Regex that tries to figure out the timestamp part, because you want to skip that anyway.
This should work:
# read the file and get the last three lines as string array
$txt = Get-Content -Path 'D:\abc.txt' -Tail 3
# loop through the array and change the lines as you go
for ($i = 0; $i -lt $txt.Count; $i++) {
$txt[$i] = ($txt[$i] -split '-', 2)[-1].Trim()
}
# finally, join the array with commas
$txt -join ','
Output:
Hello world.,Welcome to the new technology.,Eco earth
try this:
Get-Content "C:\temp\example.txt" | %{
$array=$_ -split "-", 2
$array[1].Trim()
}
When you have for example : "DATE - blablabla"
If you do .Split("-") on it you get :
Date
blablabla
What you can do is $string.Split("-")[Which_Line] -> so
$string="12/15/18 08:05:10 - Hello World."
$string=$string.Split("-")[1]
Returns : Hello world. (with spaces before)
Now on string you can apply Trim() function - it removes spaces before and after your string
$string=$string.Trim()
Gives you Hello world.
For your answer, if it's static usage (always 3) :
$Words = (Get-Content -Path .\abc.txt|Select-Object -last 3|Out-String).Split("-")
$end=$Words[2].Trim() + "," + $Words[4].Trim() + "," + $Words[6].Trim()

How to enumerate a hash in powerhshell where the values are arrays of strings

I have a hashtable defined in powershell as below:
$jobs = #{
"Test1"=[Array](
[Array]("\\server1\file1.txt", "\\server2\file1.txt")
);
"Test2"=[Array](
[Array]("\\sever1\file2.txt", "\\server2\file2.txt"),
[Array]("\\server1\file3.txt", "\\server2\file3.txt")
);
}
I am trying to enumerate over this collection and call a function on each pair. Test1 has 1 file comparison and Test2 has two file comparisons.
$jobs.GetEnumerator() | Sort-Object Key | foreach {
LogWrite($_.Key + ": comparing files")
$_.value | foreach {
LogWrite("Comparing files '" + $_[0] + "' and '" + $_[1] + "'")
#$r = CompareFiles($_[0], $_[1])
#LogWrite("Result : " + $r)
}
LogWrite($_.Key + ": comparison successful")
LogWrite("")
}
The output I am getting is:
Test1: comparing files
Comparing files '\' and '\'
Comparing files '\' and '\'
Test1: comparison successful
Test2: comparing files
Comparing files '\\server1\file2.txt' and '\\server2\file2.txt'
Comparing files '\\server1\file3.txt' and '\\server2\file3.txt'
Test2: comparison successful
Powershell (something) seems to be creating equal sized arrays. Can anyone suggest a better data structure or solution?
Referencing Avoiding Agnostic Jagged Array Flattening in Powershell, it would appear if you add a comma in the single-element array, it will stop it from being flattened:
$jobs = #{
"Test1"=[Array](,
[Array]("\\server1\file1.txt", "\\server2\file1.txt")
);
"Test2"=[Array](
[Array]("\\sever1\file2.txt", "\\server2\file2.txt"),
[Array]("\\server1\file3.txt", "\\server2\file3.txt")
);
}
There must be something odd about the way arrays are handled in Powershell.

Powershell Using Backtick for new lines - weirdness

What exaxctly is happening in example 1? How is this parsed?
# doesnt split on ,
[String]::Join(",",("aaaaa,aaaaa,aaaaa,aaaaa,aaaaa,aaaaa," + `
"aaaaa,aaaaa,aaaaa,aaaaa,aaaaa,aaaaa,aaaaa,aaaaa,aaaaa,aaaaa".Split(',') `
| foreach { ('"' + $_ + '"') }))
# adding ( ) does work
[String]::Join(",",(("aaaaa,aaaaa,aaaaa,aaaaa,aaaaa,aaaaa," + `
"aaaaa,aaaaa,aaaaa,aaaaa,aaaaa,aaaaa,aaaaa,aaaaa,aaaaa,aaaaa").Split(',') `
| foreach { ('"' + $_ + '"') }))
In you first example you may remove the backtick, because Powershell knows that the string will continue (there is a + sign).
What posh does
takes string "aaaa,aaaa..." (1) from first
evaluates the expression with split - it returns array of strings (from "aaaa,...aaaa".Split(','))
converts the array of strings to string, which returns again string "aaaa,...aaaa"
adds results from 1. and 3.
Note: when posh converts array to string, it uses $ofs variable. You will see it better in action when you will try this code:
$ofs = "|"
[String]::Join(",", ("aaaaa,aaaaa" + "bbbb,bbbb,bbbb".Split(',') | foreach { ('"' + $_ + '"') }))
Your first example only has the Split method applied to the second string of a's. The parentheses are necessary for order of operations. The Split method is performed before the concatenation in your first example.