Powershell : Cannot compare array.Length with int32 - powershell

I am creating a ps script that will handle different user commands.
Since every function the user can call has a different number of parameters I just wanted to pass the rest of the usrInput[] array starting from index 1 as a parameter of the function for usrInput[0].
This is what I did:
$function
while($function -ne "backup" -or $function -ne "restore") { #Wait for user to make a valid input
$usrInput = Read-Host "Enter -backup args[] or -restore args[] to backup or restore vms" -split " "
$args
for ($i = 1, $i -le $usrInput.Length, $i++) {
$args[$i -1] = $usrInput[$i]
}
if ($usrInput[0] -eq "-backup") {
backup($args)
}
elseif ($usrInput[0] -eq "-restore") {
restore($args)
}
}
Now what I get is the following (English equivalent to the german shell output):
Enter -backup args[] or -restore args[] to back
"last comment in my code"
"1" couln't be compared to "96 62".
couldn't be converted to "System.Int32"
in line :5 letter:6
+ for ($i = 1, $i -le $inputLength, $i++) {
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation:
+ FullyQualifiedErrorId : ComparisonFailure
Enter -backup args[] or -restore args[] to back
Why is that?
I thought array.Lengths type was int!?
(Note: I also tried putting and [int] before it, but it didn't work)
Thank you very much in advance for your help.

The problem is the for statement you should write it like this:
for ($i = 1; $i -le $input.Length; $i++)
with ";" and not ",".
I didn't check the rest of the code as your question was about $input.length and int32.

Related

One powershell script calling another but makes the script being called break

Currently, I am struggling to run a powershell script within another powershell GUI. I am trying to program it so that once a button is pressed, another powershell script would begin to run. The issue is that the second powershell script being ran does not run correctly when called. (It runs perfectly fine on its own.)
Code for the button:
$handler_runBTN_Click =
{
if($compliance){#runs Compliance training scripts
.\"Follow-up Email Generator.ps1"
}
}
$runBTN.Text = "Run"
$System_Drawing_Point.X = 140
$System_Drawing_Point.Y = 170
$runBTN.Location = $System_Drawing_Point
$runBTN.add_Click($handler_runBTN_Click)
$runBTN.FlatStyle = "Standard"
$emailForm.Controls.Add($runBTN)
Code not running properly when being called by button (It is called by other code but that runs correctly):
function csvCheck($intervalDate, $reminderDate) { #gathers all courses due on a specific date for a user through a csv file
for ($j = 0; $j -lt $row_count.Count; $j++) {#goes through every row of CSV file
if ($global:skip -eq $j ) {continue} #if the emails under $j are in the array $skip, the loop will skip it and continue
$requiredDate = $file[$j].'Required Date'
if (($requiredDate -eq $reminderDate)) { #courses that are coming due
$global:skip += $j #skips the iteration so it does not occur again
$bodyText = "<li>" + $file[$j].'Curriculum #' + "- <strong>Due: " + $file[$j].'Required Date' + " </strong></li>"
for ($k = $j + 1; $k -lt $row_count.Count; $k++) { #checks every other date for roccurances
if ($file[$j].'Employee ID' -eq $file[$k].'Employee ID' -and $file[$j].'Required Date' -eq $file[$k].'Required Date') {
#checks for any other courses for the same user due on the same id
$file[$k].'Last Sent' = $today
$bodyText += "<li>" + $file[$k].'Curriculum #' + "- <strong>Due: " + $file[$k].'Required Date' + " </strong></li>" #Adds onto the default bullet form text
$global:skip += $k
}
}
email $bodyText "due in $intervalDate day(s):" "comingDue"
}
}
}
I was wondering if it was my code that was causing this to happen or if it had something to do with the nature of the button.
Thanks,
Turns out that I was calling my second script incorrectly.
This line of code ran the second script under the same context as the first causing $global: variables to not work correctly.
.\"Follow-up Email Generator.ps1"
To solve this, I changed the code that runs the second script to:
Powershell -File ".\Follow-up Email Generator.ps1"
This ran the second script in its separate context allowing the $global: variables to work

IndexOutOfRange

I'm getting this error:
Array assignment failed because index '3' was out of range.
At Z:\CSP\deploys\aplicacional\teste.ps1:71 char:12
+ $UNAME[ <<<< $i]= $line
+ CategoryInfo : InvalidOperation: (3:Int32) [], RuntimeException
+ FullyQualifiedErrorId : IndexOutOfRange
I really can't find why the index end there.
$CSNAME = #(KPScript -c:GetEntryString $PASSHOME\$PASSFILE -pw:$PASS -Field:csname $SEARCH)
$UNAME = #()
$i = 0
Write-Host "Length="$CSNAME.Length
while($i -le $CSNAME.Length)
{
Write-Host "Start "$i
#$CSNAME[$i].GetType()
if ($CSNAME[0].StartsWith("OK:")) {
Write-Host "ACES $ACES does not exist" -Foreground "red"
}
if ($CSNAME[$i].StartsWith("OK:")) {
break
}
Write-Host "CSNAME="$CSNAME[$i]
$UNAME = $UNAME + $i
$UNAME = KPScript -c:GetEntryString $PASSHOME\$PASSFILE -pw:$PASS -Field:UserName -ref-csname:$CSNAME[$i]
foreach ($line in $UNAME) {
if (! ($line.StartsWith("OK:"))) {
Write-Host $i
$UNAME = $UNAME + $i
Write-Host "uname var"$i
$UNAME[$i] = $line
} else {
Write-Host "break"
break
}
}
#$UNAME[$i].GetType()
#if ($UNAME[$i].StartWith("OK:*")){
# break
#}
Write-Host "UNAME="$UNAME[$i]
#$UNAME[$i]
Write-Host "End "$i
$i += 1
Write-Host "switch"
}
Since the second while is based in the first array length and it has values, why is the it getting out of range?
PowerShell arrays are zero-based, so an array of length 3 has index values from 0 through 2. Your code, however, would iterate from 0 to 3, because the loop condition checks if the variable is less or equal the length (-le):
while($i -le $CSNAME.Length)
{
...
}
You need to check if the variable is less than the length (or less or equal the length minus one):
while($i -lt $CSNAME.Length)
{
...
}
Also, you'd normally use a for loop for iterating over an array, so you can handle the index variable in one place:
for ($i=0; $i -lt $CSNAME.Length; $i++) {
...
}
Edit: You initialize $UNAME as an array, but inside the loop you assign $UNAME = KPScript ..., which replaces the array with whatever the script returns (another array, a string, $null, ...). Don't use the same variable for different things in a loop. Assign the script output to a different variable. Also, your way of appending to the array is rather convoluted. Instead of $UNAME = $UNAME + $i; $UNAME[$i] = $line simply do $UNAME += $line.
$res = KPScript -c:GetEntryString $PASSHOME\$PASSFILE -pw:$PASS -Field:UserName -ref-csname:$CSNAME[$i]
foreach ($line in $res) {
if (! ($line.StartsWith("OK:"))) {
$UNAME += $line
} else {
break
}
}

PowerShell: Running executable in variable without misinterpetting argument as part of path

I need to benchmark two different programs on two diferent corpuses, and in order to get more accurate readings, I want to run the benchmark in a loop and take the mean execution time for each benchmark. In order to simplify for myself, I wrote the following PowerShell function:
Function Benchmark {
Param($progPath, $benchmarkPath, $iters=27)
$time = (Measure-Command { & "$progPath" "$benchmarkPath" }).TotalSeconds
$sum = $lowest = $highest = $time
for($i = 1; $i -lt $iters; $i++) {
$time = (Measure-Command { & "$progPath" "$benchmarkPath" }).TotalSeconds
$sum += $time
if($time -lt $lowest) { $lowest = $time }
elseif($time -gt $highest) {$highest = $time }
}
$sum -= ($lowest + $highest)
$sum / ($iters - 2)
}
In theory, this should execute the program supplied as a command in $progPath with the benchmarking script in $benchmarkPath as its argument, but when I run it like this, I get the following result:
PS > $nonPrivateBenchmark = Benchmark(".\Python\PCbuild\amd64\python", ".\Benchmarks\non_private_access.py")
& : The term '.\Python\PCbuild\amd64\python .\Benchmarks\non_private_access.py' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:3 char:30
+ $time = (Measure-Command { & "$progPath" "$benchmarkPath" }).TotalSeconds
+ ~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (.\Python\PCbuil...ivate_access.py:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
(Plus 26 repetitions of the same error but on line 6.)
However, if assign the three parameter arguments and copy the remaining function body directly into PowerShell, it works and sets $nonPrivateAccess to a reasonable value:
$progPath = ".\Python\PCbuild\amd64\python"
$benchmarkPath = ".\Benchmarks\non_private_access.py"
$iters = 27
$time = (Measure-Command { & "$progPath" "$benchmarkPath" }).TotalSeconds
$sum = $lowest = $highest = $time
for($i = 1; $i -lt $iters; $i++) {
$time = (Measure-Command { & "$progPath" "$benchmarkPath" }).TotalSeconds
$sum += $time
if($time -lt $lowest) { $lowest = $time }
elseif($time -gt $highest) {$highest = $time }
}
$sum -= ($lowest + $highest)
$nonPrivateBenchmark = $sum / ($iters - 2)
I have through experimentation concluded that the problem is that "$progPath" "$benchmarkPath" is concatenated into the single string '.\Python\PCbuild\amd64\python .\Benchmarks\non_private_access.py' before executed with the & operator, and the space separating them is interpretted as a part of the command name, making PowerShell try to execute the entire string as a single command (which can't be executed). I have tried putting escaped quotes both around and inside the argument parameter, but to no avail. Does anyone else have a solution to this problem?
PS:
Quite extensive searching has only given me a lot of hits with people having the opposite problem. Could it be that I have some non-default PowerShell settings activated making it parse the spaces overly aggressively?
Benchmark(".\Python\PCbuild\amd64\python", ".\Benchmarks\non_private_access.py")
This syntax is passing an array to the first parameter of your Benchmark function, which then gets converted to a single string when it's used as a command. This is effectively the same as:
Benchmark ".\Python\PCbuild\amd64\python", ".\Benchmarks\non_private_access.py"
The normal syntax for passing multiple parameters to a PowerShell function is to place a space between the parameters:
Benchmark ".\Python\PCbuild\amd64\python" ".\Benchmarks\non_private_access.py"
You can also use the parameter names:
Benchmark -progPath ".\Python\PCbuild\amd64\python" -benchmarkPath ".\Benchmarks\non_private_access.py"

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'
}

How do I loop through a dataset in PowerShell?

I am trying to output values of each rows from a DataSet:
for ($i=0;$i -le $ds.Tables[1].Rows.Count;$i++)
{
Write-Host 'value is : ' + $i + ' ' + $ds.Tables[1].Rows[$i][0]
}
gives the output ...
value is : +0+ +System.Data.DataSet.Tables[1].Rows[0][0]
value is : +1+ +System.Data.DataSet.Tables[1].Rows[1][0]
value is : +2+ +System.Data.DataSet.Tables[1].Rows[2][0]
value is : +3+ +System.Data.DataSet.Tables[1].Rows[3][0]
value is : +4+ +System.Data.DataSet.Tables[1].Rows[4][0]
value is : +5+ +System.Data.DataSet.Tables[1].Rows[5][0]
value is : +6+ +System.Data.DataSet.Tables[1].Rows[6][0]
How do I get the actual value from the column?
The PowerShell string evaluation is calling ToString() on the DataSet. In order to evaluate any properties (or method calls), you have to force evaluation by enclosing the expression in $()
for($i=0;$i -lt $ds.Tables[1].Rows.Count;$i++)
{
write-host "value is : $i $($ds.Tables[1].Rows[$i][0])"
}
Additionally foreach allows you to iterate through a collection or array without needing to figure out the length.
Rewritten (and edited for compile) -
foreach ($Row in $ds.Tables[1].Rows)
{
write-host "value is : $($Row[0])"
}
Here's a practical example (build a dataset from your current location):
$ds = new-object System.Data.DataSet
$ds.Tables.Add("tblTest")
[void]$ds.Tables["tblTest"].Columns.Add("Name",[string])
[void]$ds.Tables["tblTest"].Columns.Add("Path",[string])
dir | foreach {
$dr = $ds.Tables["tblTest"].NewRow()
$dr["Name"] = $_.name
$dr["Path"] = $_.fullname
$ds.Tables["tblTest"].Rows.Add($dr)
}
$ds.Tables["tblTest"]
$ds.Tables["tblTest"] is an object that you can manipulate just like any other Powershell object:
$ds.Tables["tblTest"] | foreach {
write-host 'Name value is : $_.name
write-host 'Path value is : $_.path
}
The parser is having trouble concatenating your string. Try this:
write-host 'value is : '$i' '$($ds.Tables[1].Rows[$i][0])
Edit: Using double quotes might also be clearer since you can include the expressions within the quoted string:
write-host "value is : $i $($ds.Tables[1].Rows[$i][0])"