I would like to declare a here-string outside of a loop use that string in the loop where the variables get resolved.
My ideal scenario would look like below. This doesn't work as Powershell evaluates the string one time before entering the loop instead of each time inside the loop kind of obvious but bitten by it nevertheless.
$number = "Number $($_)"
1..2 | % { $number }
I know I can use one of these solutions
1..2 | % { "Number $($_)" }
$number = "Number {0}"
1..2 | % { $number -f $_ }
$number = "Number <replace>"
1..2 | % { $number -replace "<replace>", "$_" }
but they have drawbacks I'd like to avoid
Due to the size of the string, declaring it inside the loop obfuscates the logic of the loop making the code less readable.
The formatting solution is too easy to get wrong when many variables are involved.
In the replace solution it's easier to match what get's replaced by what variable but I would have to chain many replace commands.
Edit
Rereading my own question makes it obvious that the actual use case is missing from the question.
Note that ultimately I ended up choosing the formatting option
Following would declare the template with some variables that need replacing in a loop
$sqltemplate = #"
SELECT aud.dpt_mov_hex||aud.dpt_ref||aud.can_typ||TO_CHAR(aud.dte_aud-1,'YYYYMMDD')||'000001' transaction_id,
acc.dos_nbr contract_id, acc.pay_acc_nbr account_id,
CASE WHEN NULL IS NULL THEN unt.nam_unt ELSE unt.nam_unt||'<'||NULL ||'>' END product_id,
aud.dpt_ref, aud.dpt_mov_hex, aud.dpt_mov_dte uitwerkingsdatum,
CASE WHEN can_typ = 0 THEN 'VZ'||aud.dpt_mov_ven_typ ELSE 'VZ'||aud.dpt_mov_ven_typ||'-CR' END transactietype,
aud.dpt_mov_amt_eur bedrag_in_eur, aud.dte_cnv, aud.dpt_mov_fix_eur, aud.dpt_mov_con_inc, aud.dpt_mov_amt_sgn bedrag_teken,
aud.dpt_mov_amt_unt bedrag_in_units, aud.dpt_mov_amt_rte, aud.dpt_mov_amt_val_pre, aud.dpt_mov_amt_val_aft,
aud.dpt_mov_amt_ioc, aud.dte_exe verwerkingsdatum, aud.exe_mng, aud.cmt, aud.trn_nbr, aud.dte_aud datum_aanlevering, aud.can_typ
FROM lfe_dpt_mov_aud aud, vnv_isr_pay_acc acc, vnv_bel_unt unt
WHERE aud.dte_aud >= TO_DATE('$((Get-Date).ToString('dd.MM.yyyy'))', 'DD.MM.YYYY')
AND aud.dpt_ref = '{0}'
AND acc.pay_acc_nbr = '{1}'
AND unt.inv_unt = '{2}'
UNION
SELECT aud.dpt_mov_hex||aud.dpt_ref||aud.can_typ||TO_CHAR(aud.dte_aud-1,'YYYYMMDD')||'000001' transaction_id,
acc.dos_nbr contract_id, acc.pay_acc_nbr account_id,
CASE WHEN itr_rte IS NULL THEN unt.nam_unt ELSE unt.nam_unt||'<'||itr_rte ||'>' END product_id,
aud.dpt_ref, aud.dpt_mov_hex, aud.dpt_mov_dte uitwerkingsdatum,
CASE WHEN can_typ = 0 THEN 'VZ'||aud.dpt_mov_ven_typ ELSE 'VZ'||aud.dpt_mov_ven_typ||'-CR' END transactietype,
aud.dpt_mov_amt_eur bedrag_in_eur, aud.dte_cnv, aud.dpt_mov_fix_eur, aud.dpt_mov_con_inc, aud.dpt_mov_amt_sgn bedrag_teken,
aud.dpt_mov_amt_unt bedrag_in_units, aud.dpt_mov_amt_rte, aud.dpt_mov_amt_val_pre, aud.dpt_mov_amt_val_aft,
aud.dpt_mov_amt_ioc, aud.dte_exe verwerkingsdatum, aud.exe_mng, aud.cmt, aud.trn_nbr, aud.dte_aud datum_aanlevering, aud.can_typ
FROM lfe_dpt_mov_aud aud, vnv_dpt dpt, vnv_isr_pay_acc acc, vnv_bel_unt unt
WHERE aud.dpt_ref = dpt.dpt_ref
AND dpt.pay_acc = acc.pay_acc_nbr
AND dpt.inv_unt = unt.inv_unt
AND aud.dte_aud >= TO_DATE('$((Get-Date).ToString('dd.MM.yyyy'))', 'DD.MM.YYYY')
AND acc.pay_acc_nbr = '{1}'
AND unt.inv_unt = '{2}'
UNION
"#
and this template would get used in a statement such as this
$rolledbackMatchs is an array of custom object containing the three properties: dtp_ref, pay_acc_nbr and inv_unt.
$rolledbackMatches | ForEach-Object { $sqltemplate -f $_.dpt_ref, $_.pay_acc_nbr, $_.inv_unt }
Couple of approaches come to mind:
dot source here-string assignment from a separate file:
# loop.variables.ps1
$myVar = #"
Stuff going on with $_ in here
"#
and then in the loop itself:
1..2 | % { . .\loop.variables.ps1; <# do stuff with $myVar here #> }
Manually invoke string expansion:
$hereString = #'
Stuff (not yet) going on with $_ in here
'#
1..2 | % { $myVar = $ExecutionContext.InvokeCommand.ExpandString($hereString) }
Wrap it in a scriptblock
(as suggested by PetSerAl)
$stringBlock = {
#"
Stuff going on with $_ in here
"#
}
1..2 | % { $myVar = &$stringBlock}
I'm struggling to understand what you're trying to achieve here.
For a start you never define a here-string you just define $number as a string
A here-string would look like this
$number = #"
Number 4
"#
if all you're trying to do is push a number into a string try this
foreach ($number in (1..3)){
"Number $number"
}
which is close to your desired option and less ambiguous
This is my first question here, so sorry if I make any mistakes posting this.
I'm trying to split an array based on its values. Basically I want to create two arrays whose values are as close to the average as possible. I managed to do this with this code:
function Sum($v) {
[Linq.Enumerable]::Sum([int64[]]$v)
}
$arr = 0..9 | % {get-random -min 1 -max 10}
"ARRAY:" + $arr
"SUM: " + (sum $arr)
"AVG: " + (sum $arr)/2
# start of the code that matters
$wavg = (sum $arr)/2
foreach ($i in (0..($arr.Count-1))) {
$wavg -= $arr[$i]
if ($wavg -le 0) {
$i-=(-$wavg -gt $arr[$i]/2);break
}
}
"SPLIT INDEX: " + $i
"ARR1: " + $arr[0..$i] + " (" + $(sum $arr[0..$i]) + ")"
"ARR2: " + $arr[($i+1)..$arr.Count] + " (" + $(sum $arr[($i+1)..$arr.Count]) + ")"
The reason my foreach is structured this way is because in my actual code the values are in an index hash and are accessed as $index[$arr[$i]].
This means that the resulting two arrays could be of unequal size (it would be easy if I could just split the array in half). Sample output of my code to demonstrate this:
ARRAY: 5 3 6 3 2 3 6 3 1 3
SUM: 35
AVG: 17.5
SPLIT INDEX: 3
ARR1: 5 3 6 3 (17)
ARR2: 2 3 6 3 1 3 (18)
The code works as is, but I feel it could be done in a more elegant and speedier way. Because I need to execute this code a few thousand times in my script I want it to be as fast as possible.
Hello Below is my momentary Code..
It takes seven random „meals“ out of an list and then orders them into a weekly list ordert in days.
# Food selector for the week!
#random Stuff mixed for every day.
Enum Food
{#Add Food here:
Tacos
Pizza
Quesedias
Lasagne
Älplermakkaronen
Apfelwähe
Apprikosenwähe
Rabarberwähe
Käsekuchen
Pasta
Ravioli
Empanadas
Hamburger
}
function Food {
$foodsOfWeek = [Enum]::GetValues([Food]) | Get-Random -Count 7
foreach ($day in [Enum]::GetValues([DayOfWeek])) {
([string]$day).Substring(0, 3) + ': ' + $foodsOfWeek[[DayOfWeek]::$day]
}
}
I am trying to make it so it can be combined with more arrays like this:
Enum Food
{#Add Food here:
Tacos
Pizza
Quesedias
Lasagne
Älplermakkaronen
Apfelwähe
Apprikosenwähe
Rabarberwähe
Käsekuchen
Pasta
Ravioli
Empanadas
Hamburger
}
Enum Food2
{#Add Fish Stuff here:
Whatever Fish I want^^ :)
}
#and an array for meat(like steak)
.....
#an array for som healthy food!
.....
function Food {
$foodsOfWeek = [Enum]::GetValues([Food]) | Get-Random -Count 7
foreach ($day in [Enum]::GetValues([DayOfWeek])) {
([string]$day).Substring(0, 3) + ': ' + $foodsOfWeek[[DayOfWeek]::$day]
}
}
So it does combine them and takes RANDOM out of them all but I can set criterias like it must have one at least from every "List".
Perfect would be:
Every week at least once —> Meat, Fish, Vegetables and then the rest is random from the first list...
I hope you guys can help me :)
Kind regards Alex
Albeit this may not be exactly what you are looking for, you could try the following:
{
# Food selector for the week!
#random Stuff mixed for every day.
Enum FastFood
{#Add Food here:
Tacos
Pizza
Quesedias
Lasagne
Älplermakkaronen
Apfelwähe
Apprikosenwähe
Rabarberwähe
Käsekuchen
Pasta
Ravioli
Empanadas
Hamburger
}
Enum Meat
{#Add Food here:
Steak
Chop
Beaf
Lamb
Pork
Chicken
}
function Food {
#either
$Foods = [Enum]::GetValues([FastFood]) + [Enum]::GetValues([Meat])
#or
$Foods = [Enum]::GetValues([FastFood])
$Foods += [Enum]::GetValues([Meat])
$foodsOfWeek = $Foods | Get-Random -Count 7
foreach ($day in [Enum]::GetValues([DayOfWeek])) {
([string]$day).Substring(0, 3) + ': ' + $foodsOfWeek[[DayOfWeek]::$day]
}
The $Foods variable of course is not an Enum type but an object collection, however you can then generate your random 'meal' of the day & have the option to extend the list as additional categories are added. To access a specific entry you can index as follows: $Foods[10]
The current variable contains 19 elements ($Foods.count)
Hope it helps,
I am trying to create a script that would calculate the difference between samples in a list.
If we take this example:
- result1 = 33
- result2 = 45
- result3 = 66
- result4 = 47
- result"n" = 50
The calculus should start at the second result from the list and descend until the last result, and then sum up those results:
result2 - result1 = 12,
result3 - result2 = 21,
result4 - result3 = 19,
result"n" - result4= 3
sum = 12 + 21 + 19 + 3 = 55
I am new at scripting, and so far i only came up with this solution:
$numbers
$1=[math]::abs($numbers[0]-$numbers[1])
$2=[math]::abs($numbers[1]-$numbers[2])
$3=[math]::abs($numbers[2]-$numbers[3])
$4=[math]::abs($numbers[3]-$numbers[4])
write-host "the results = $1, $2, $3, $4"
$sum = $1 + $2 + $3 + $4
The problem is that the list is dynamic and changes in length, one time there are 10 results and one time 20 for example.
I found a similar question here, but i don't know how to implement the solution to my case, as that is too complicated for me.
What you need is a For loop. It is structured as such:
For(<initial declaration, usually a start point like $i = 0>; <Condition to stop when false>;<Action to perform on each iteration to progress loop>){
Code to perform on each loop
}
For you we would do something like:
For($i=1;$i -le $numbers.count;$i++)
That starts 1, and since arrays start at 0 this will get you going with the second record. Then in the scriptblock we do something like:
{
[array]$Results += [math]::abs($numbers[$i] - $numbers[($i-1)])
}
That will get the differences for you, then to display them you can do something like:
"the results = " + ($Results -join ", ")
$sum = $Results|Measure -sum|select -expand Sum
So you put that all together and get
For($i=1;$i -le $numbers.count;$i++){
[array]$Results += [math]::abs($numbers[$i] - $numbers[($i-1)])
}
"the results = " + ($Results -join ", ")
$sum = $Results|Measure -sum|select -expand Sum
Use a for loop, use the length of your $numbers array to know when to stop.
$numbers = #(33,45,66,47,50)
$sum = 0
for($cur=1;$cur -lt $numbers.Length; $cur += 1){
$sum += [math]::abs($numbers[$cur]-$numbers[$cur-1]);
}
$sum
Have a question on powershell and hopeful will get some hint to get me going in the right direction.
I have a variable which has data stored in it for example $A will output
Year Cost
---- ----
1997 12
1998 42
1999 6
2000 12
2001 14
I want to add another column here, lets say Trend and compute the difference between the years for example
Year Cost Trend
1997 12 0
1998 42 30 (42-12)
1999 6 -36 (6-42)
Any hints will be really helpful
You could loop through each row comparing it to the previous and then create a new object from the results like so:
$result = 0..($a.count - 1) | % {
if($_ -eq 0) {$t = $a[$_].Cost} else {$t = $a[$_].Cost - $a[$_ - 1].Cost}
New-Object PSObject -property #{
Year = $a[$_].Year
Cost = $a[$_].Cost
Trend = $t
}
}
$result