Referencing Powershell array index produces unexpected results when referenced with string - powershell

I am trying to find out why the following occurs if you have
$arr = #("Filename1", "Filename2")
for($i =0; $i -le $arr.Length -1; $i++) {
write-host ".\"$arr[$i]
write-host ".\$arr[$i]"
write-host $arr[$i]
}
So taking just one loop through it produces:
".\ Filename1"
".\ Filename1 Filename2[0]"
"Filename1"
Just referencing the array[index] will produce the correct value, but if I concatenated with a string it places a space between the string and value. When placed within the string I assume it is dumping the entire contents because it is evaluating $array then evaluating $i ending up with
".\ filename1 filename2[index number]"
But if I assign the individual value to a separate variable and concatenate it with a string there is no space? Why is that:
Example:
$name = $arr[$i]
write-host ".\$name"
output = ".\filename1"
which is correct.

You have to do:
write-host ".\$($arr[$i])"
so that it is evaluated as array indexing.
It would be the case with something like accessing properties of an object or key of hash etc within the string:
PS > $a = #{test="A";test2="B"}
PS > write-host "$a.test"
System.Collections.Hashtable.test
PS > write-host "$($a.test)"
A
Another alternative is to use string formatting, especially useful when you have lots of variables / objects in the string:
write-host (".\{0}" -f $arr[$i])

Your code should look like this:
$arr = #("Filename1", "Filename2")
#for($i =0; $i -le $arr.Length-1; $i++) {
for($i =0; $i -le $arr.Length; $i++) {
write-host ".\"$arr[$i]
#write-host ".\$arr[$i]"
write-host ".\$($arr[$i])"
write-host $arr[$i]
}

Related

Powershell - output a foreach loop to one line

I am trying to take the output of my foreach loop and apply the array to a string that reads on one line. Here is my code so far:
$upper = 65..90
$lower = 97..122
foreach ($i in $upper)
{
[char]$i
}
foreach ($i in $lower)
{
[char]$i
}
I'm guessing I need to convert the output of the scriptblock to a variable and use the -join option, but everywhere I look I'm struggling to find how to structure that. Any guidance would be appreciated.
For this particular case, ForEach(type convertToType) is very useful, here is a cool way to get your lower and upper case dictionary string:
$lowerDict = [string]::new(([int][char]'a'..[int][char]'z').ForEach([char]))
$upperDict = $lowerDict.ToUpper()
If you have access to PowerShell Core, it can be reduced to:
$lowerDict = [string]::new('a'..'z')
$upperDict = $lowerDict.ToUpper()
As for what you are struggling on, how to do it with what you currently have (a foreach loop). You can capture all the output from the loop first:
$upper = foreach ($i in 65..90) { [char]$i }
Now, $upper is an array of chars, then to convert it to string, you can either use -join (guessed right) or [string]::new(...) as I did on my previous example:
$upperDict = -join $upper
# OR
$upperDict = [string]::new($upper)

Padding the iterator in a for loop

I'm trying to pad the iterator in a for loop using PowerShell, but I get an error message.
Normal padding works fine:
$mytext = "Test"
Write-Host $mytext.PadLeft(5, "0")
# Output: 0Test
But using the iterator doesn't work:
for ($i=1; $i -lt 20; $i++) {
Write-Host $i.PadLeft(2, "0")
}
Method invocation failed because [System.Int32] does not contain a method named 'PadLeft'.
Not even if I copy the iterator into a variable before padding:
for ($i=1; $i -lt 20; $i++) {
$Iterator = $i
Write-Host $Iterator.PadLeft(2, "0")
}
Method invocation failed because [System.Int32] does not contain a method named 'PadLeft'.
Is it impossible to use PadLeft() in a for loop at all?
Its because $i is an integer and as the error message tells you, it doesn't contain a PadLeft method. Anyway, you could cast the integer to a string:
for ($i=1; $i -lt 20; $i++) {
$Iterator = [string]$i
Write-Host $Iterator.PadLeft(2, "0")
}

Find variables within a string in PowerShell

I've a sample code like this:
[string] $Text = "This is a string text with some $($variable.Option) and $otherOption and that's it".
Now what I would like to know is it possible to split that $Text into standard strings and variables separately? So that when I pass this $Text variable to a method it's able to extract $($variable.Option) separately?
I know it's a long shot but maybe it's not being processed right away at assignment time?
The ultimate goal is to create a better version of method I wrote for making colorful powershell:
function Write-Color([String[]]$Text, [ConsoleColor[]]$Color = "White", [int]$StartTab = 0, [int] $LinesBefore = 0,[int] $LinesAfter = 0) {
$DefaultColor = $Color[0]
if ($LinesBefore -ne 0) { for ($i = 0; $i -lt $LinesBefore; $i++) { Write-Host "`n" -NoNewline } } # Add empty line before
if ($StartTab -ne 0) { for ($i = 0; $i -lt $StartTab; $i++) { Write-Host "`t" -NoNewLine } } # Add TABS before text
if ($Color.Count -ge $Text.Count) {
for ($i = 0; $i -lt $Text.Length; $i++) { Write-Host $Text[$i] -ForegroundColor $Color[$i] -NoNewLine }
} else {
for ($i = 0; $i -lt $Color.Length ; $i++) { Write-Host $Text[$i] -ForegroundColor $Color[$i] -NoNewLine }
for ($i = $Color.Length; $i -lt $Text.Length; $i++) { Write-Host $Text[$i] -ForegroundColor $DefaultColor -NoNewLine }
}
Write-Host
if ($LinesAfter -ne 0) { for ($i = 0; $i -lt $LinesAfter; $i++) { Write-Host "`n" } } # Add empty line after
}
Usually I can assign colors by doing something like
write-color -Text "[View][$($singleView.Title)]",
"[Row Limit: $($singleView.RowLimit)]",
"[Paged: $($singleView.Paged)]",
"[Default View: $($singleView.DefaultView)]",
"[Style ID: $($singleView.StyleID)]" -Color Yellow, Green, Red, Gray, Green
But this means I get colors for the whole "line". If i would like to get normal text colors in one color and variables being in second color I would have to do something like this:
write-color -Text "[View: ", "$($singleView.Title)", "]",
"[Row Limit: ", "$($singleView.RowLimit)", "]" `
-Color Yellow, Green, Yellow, Yellow, Green, Yellow
It's not bad.. but I just thought if this can be accomplished in a better way where simple text is one color and variables are the 2nd. If I would want to go even further and have $true being in Green and False being in Red that would also require some parsing.
Variables will expand inside double quotes. Once that is done there is no history to speak of.
You have one of two options here. You can use the format operator to send in string with placeholders for your variables.
Use the format operator
ss64 on Using the format operator
# Create a formatted string with variable placeholders
$Text = "This is a string text with some {0} and {1} and that's it"
# Pass that string into a function and put in the variables
$stringParameterinFunction -f $variable.Option, $otherOption
String Expansion
If you really wanted what I think you are asking for then you can delay the string expansion by use single quotes on the original string. Note the single quote inside the string was escaped.
$Text = 'This is a string text with some $($variable.Option) and $otherOption and that''s it.'
# Pass that string into a function and put in the variables
$ExecutionContext.InvokeCommand.ExpandString($stringParameterinFunction)

How to declare and get array value

I am new to Powershell, first time using it.
I have declared an array and use array value but using below code, I am not able to retrieve the array value...Any idea what I am missing here?
Just FYI.. I am executing script in ADOBE ILLUSTRATOR and for testing I am using 3 here in condition (for loop)... will use $array later
$array = "a.jpg","b.jpg","c.jpg";
for ($i=1; $i-le=3; $i++)
{
$.writeln("This is line number " + $array[$i]);
var targetFileName = $array[$i]+'.png';
$.writeln(targetFileName);
}
I tried $array[$i].toString() as well but still not getting values... I am getting 0
Any help is appreciated and thanks in advance to all for your help
for ($i=1; $i-le=3; $i++)
The condition in the above line doesn't have a valid comparison operator. Change that to
for ($i=1; $i -le 3; $i++)
if you want the loop to terminate after 3 cycles.
$.writeln("This is line number " + $array[$i]);
var targetFileName = $array[$i]+'.png';
$.writeln(targetFileName);
This is not valid PowerShell. Looks more like JavaScript to me. In PowerShell it should probably look like this:
Write-Output "This is line number $i"
$targetFileName = $array[$i] + '.png'
Write-Output $targetFileName
or shorter
"This is line number $i"
$array[$i] + '.png'
Note that PowerShell arrays are zero-based, so the last iteration ($array[3]) will return $null instead of an element from the array. If you want to iterate over the elements of the array you should change your loop to this:
for ($i=0; $i -lt $array.Length; $i++) {
"This is line number $($i+1)"
$array[$i] + '.png'
}
or (better) pipe your array into a foreach loop:
$i = 0
$array | % {
"This is line number " + ++$i
$_ + '.png'
}

Powershell - concatenating an array reference with another variable

I'm trying to concatenate a variable with a value from an array, and having problems.
The output I get is the variable value, plus the ENTIRE array, not just the desired value (index of $i).
$Database = "Checklist.dbo."
$ExtractTables = #("Page"
, "HotelOwner"
, "Hotel"
)
for ($i=0; $i -le $ExtractTables.Length – 1; $i++) {
write-host $Database$ExtractTables[$i] # <<<<<<< takes ENTIRE array
}
My ultimate goal is to call an executable (bcp) something like this:
# & bcp $Database$ExtractTables[$i] out $OutputDirectory$ExtractTables[$i].txt -c -T -SCHELDEV02
Any pointers for a newbie?
Thanks!
$Database = "Checklist.dbo."
$ExtractTables = #("Page"
, "HotelOwner"
, "Hotel"
)
for ($i=0; $i -le $ExtractTables.Length – 1; $i++) {
write-host "$Database$($ExtractTables[$i])"
}
To evaluate a sub-expression before the rest of the expression put it inside $()
$Database = "Checklist.dbo."
$ExtractTables = #("Page"
, "HotelOwner"
, "Hotel"
)
$ExtractTables | ForEach {
write-host "$Database$_"
}