Error trying to merge 2 variables into one - powershell

I have a problem when I try to merge 2 variables into one.
Example:
$MyA = #{
foo = 1..10
bar = 2,4,6,8,10,12,14,16,18,20
}
$MyB = #{
foo = 1..30
bar = ""
}
Foreach ($_ in $MyA) {Where $MyB.foo -eq $_.foo; $MyB.bar = $_.bar}
What I want to do is: Insert $MyA.bar into $MyB.bar where the property foo matches....
But it ends up with this error message:
Where-Object : A positional parameter cannot be found that accepts argument 'System.Object[]'.
What I want to end up with is something like this:
$MyB
foo bar
--------
1 2
2 4
etc. until foo is grater than 10 then bar should be empty
Please help!

Related

Cannot convert the "System.Reflection.Missing" value of type "System.Reflection.Missing" to type "System.Int32". - PowerShell PPT Printing

I'm trying to put in default/null/missing values for .printout in PowerPoint but I can't get it to work. The value's that are giving me troubles are defined as integers in this page.
Usually I have been able to use [System.Type]::Missing or '' but neither of those work and I get the following:
Cannot convert the "System.Reflection.Missing" value of type "System.Reflection.Missing" to type "System.Int32".
How can I put in null values for those two params of .printout for PowerPoint?
Here is what I have for code so far:
###PPT
IF ($FILETYPE -eq "PPT") {
ECHO "PPT_FOUND"
$msoFalse = [Microsoft.Office.Core.MsoTriState]::msoFalse
$msoTrue = [Microsoft.Office.Core.MsoTriState]::msoTrue
$ObjPPT = New-Object -comobject PowerPoint.Application
$ObjPPT.Visible = $msoTrue
#$ObjPPT.DisplayAlerts = $msoFalse
#Exception setting "DisplayAlerts": "Cannot convert value "msoFalse" to type "Microsoft.Office.Interop.PowerPoint.PpAlertLevel" due to enumeration values that are not valid. Specify one of the following
#enumeration values and try again. The possible enumeration values are "ppAlertsNone,ppAlertsAll"."
#.Open
$FILENAME = $FILEPATH
IF (!$ReadOnly){$ReadOnly = $msoTrue}
IF (!$Untitled){$Untitled = $missing}
IF ((!$WithWindow) -and ($OPENUI -eq "FALSE")){$WithWindow = $msoFalse} ELSE {$WithWindow = $msoTrue}
$ObjPresentation=$ObjPPT.Presentations.open($FILENAME,$ReadOnly,$Untitled,$WithWindow)
#.Print
#.PrintOut (From[Integer], To[Integer], PrintToFile[String], Copies [Integer], Collate[Bool]{msoTrue/False})
IF (!$From){[int]$From = $missing}
IF (!$To){[int]$To = $missing}
IF (!$PrintToFile){[string]$PrintToFile = $missing}
#Copies Defined Earlier
IF (!$Collate){$Collate = $msoTrue}
#$ObjPresentation.printout($From,$To,$PrintToFile,$COPIES,$Collate)
$ObjPresentation.printout($From,$To)# , ,$COPIES,$Collate)
#All Done
Sleep 2
$ObjPresentation.Close()
$ObjPPT.Quit()
Do-CloseIfRunning -Process $PROCESS
}
[gc]::collect()
[gc]::WaitForPendingFinalizers()
#Get-Variable
#PAUSE
Turns out using 0 caused an error, but using -1 for From/To values worked as expected (null values).

Declare a here-string containing variables outside of a loop

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

Powershell hashtable with multiple values and one key

Im looking for a data structure/cmdlet that will allow me to add multiple values to a single key in Powershell.
My data would ideally look like this:
KEY-------------------------- VALUES
HOSTNAME1-------------DATABASE1,DATABASE2,DATABASE3
HOSTNAME2-------------DATABASE1,DATABASE2
etc...
I thought a hashtable would do the trick, but I'm unable to do the following:
$servObjects = #{}
$servObjects.Add("server1", #())
$servObjects.get_item("server1") += "database1"
This yields an empty array when I try:
$servObjects.get_item("server1")
I have also tried to do the following, hoping that powershell would understand what I want:
$servObjects2 = #{}
$servObjects2.add($servername, $databasename)
This will unfortunately yield a duplicate key exception
Thanks for any and all input
You basically want a hash table with values that are arrays. You don't have to use $hashtable.get_item or .add
$myHashTable = #{} # creates hash table
$myHashTable.Entry1 = #() #adds an array
$myHashTable.Entry1 += "element1"
$myHashTable.Entry1 += "element2"
This results in the following output:
$myHashTable
Name Value
---- -----
Entry1 {element1, element2}
$myHashTable.Entry1
element1
element2
If you have your data in an array you can group the array and convert to a hash table:
$ary = #()
$ary = $ary + [PSCustomObject]#{RowNumber = 1; EmployeeId = 1; Value = 1 }
$ary = $ary + [PSCustomObject]#{RowNumber = 2; EmployeeId = 1; Value = 2 }
$ary = $ary + [PSCustomObject]#{RowNumber = 3; EmployeeId = 2; Value = 3 }
$ary = $ary + [PSCustomObject]#{RowNumber = 4; EmployeeId = 2; Value = 4 }
$ary = $ary + [PSCustomObject]#{RowNumber = 5; EmployeeId = 3; Value = 5 }
$ht = $ary | Group-Object -Property EmployeeId -AsHashTable
$ht is then:
Name Value
---- -----
3 {#{RowNumber=5; EmployeeId=3; Value=5}}
2 {#{RowNumber=3; EmployeeId=2; Value=3}, #{RowNumber=4; EmployeeId=2; Value=4}}
1 {#{RowNumber=1; EmployeeId=1; Value=1}, #{RowNumber=2; EmployeeId=1; Value=2}}
In your original example, instead of writing
$servObjects.get_item("server1") += "database1"
you had written
$servObjects.server1 += "database1"
it would have worked.
I'm very new to PowerShell, but I prefer to use
$servObjects.Add("key",#())
over
$servObjects.key = #())
because the .Add will throw a duplicate exception if the key is already present in the hashtable, whereas the assignment will replace an existing entry with a new one. For my purposes, I have found that the implicit replacement is (more often than not) an error, either in my logic, or an anomaly in the input data that needs to be handled.
If you know the value at creation time, it would be clearer this way :
[hashtable]$hash = #{
HOSTNAME1 = #(DATABASE1, DATABASE2, DATABASE3);
HOSTNAME2 = #(DATABASE1, DATABASE2);
}
Which will get you the following :
Name Value
---- -----
HOSTNAME2 {DATABASE1, DATABASE2}
HOSTNAME1 {DATABASE1, DATABASE2, DATABASE3}

PowerShell HashTable - self referencing during initialization

I have a theoretical problem - how to reference a hash table during its initialization, for example, to compute a member based other already stated members.
Remove-Variable myHashTable -ErrorAction Ignore
$myHashTable =
#{
One = 1
Two= 2
Three = ??? # following expressions do not work
# $This.One + $This.Two or
# $_.One + $_.Two
# $myHashTable.One + $myHashTable.Two
# ????
}
$myHashTable.Three -eq 3 # make this $true
Any ideas how to do it? Is it actually possible?
Edit:
This was my solution:
$myHashTable =
#{
One = 1
Two= 2
}
$myHashTable.Three = $myHashTable.One + $myHashTable.Two
This won't be possible using the object initializer syntax I'm afraid. While it is possible to use variables, you'll have to compute the values before creating the object.
I cannot recommend this, but you can iterate the initializer twice or more:
(0..1) | %{
$a = #{
One = 1
Two = $a.One + 1
}
}
(0..2) | %{
$b = #{
One = 1
Two = $b.One + 1
Three = $b.Two + 1
}
}
Make sure all calculations are idempotent, i.e. do not depend on a number of iterations.
You can also recur to this...
sometimes when the hashtable is very long
and can be defined only in 2 or three recurrences...
works fine:
$AAA = #{
DAT = "C:\MyFolderOfDats"
EXE = "C:\MyFolderOfExes"
}
$AAA += #{
Data = $AAA.DAT + "\#Links"
Scripts = $AAA.EXE + "\#Scripts"
ScriptsX = $AAA.EXE + "\#ScriptsX"
}
Note in the second part we are just adding ( += ) more items to the first part... but now... we can refer the items in first part
of the hashtable

Issue in using Powershell return in a statement

function a()
{
return 10
}
$b = 10
write-Host "b = $b"
[int]$b += a
write-Host "b = $b"
[int]$b = a + 10
write-Host "b = $b"
Output for the above script is:
b = 10
b = 20
b = 10
I have programming background in C and recently started programming in PS. I tried to write simple program which uses return value from a function in a statement. I am confused about the results. Following statements works differently.
[int]$b += a
[int]$b = a + 10
Can someone please explain me the reason?
Regards
Jugari
Yes strange for a C programmer.
[int]$b = a + 10 means that you call a function with two parameters try [int]$b = (a) + 10
retry using this function
function a()
{
write-host $args.count
return 10
}
You have also to be very careful to the values returned by a function.
I suspect the interpreter is trying to pass '+ 10' as parameters to your function; because there are no parameters specified in your function they are set as null. Putting parentheses around your function call will prevent this and I suspect work as you intend.
[int]$b = (a) + 10
write-Host "b = $b"