Passing parameters between runbooks in Azure Automation - powershell

I'm calling another runbook using the following code:
$parameters = #{"Table" = 'myTable'}
Start-AutomationRunbook `
-Name "ChildRunBook" `
-Parameters $parameters
the reason I'm using `Start-AutomationRunBook' is that this is in a loop and they need to run in parallel, I don't care about the result.
The Parameters parameter takes in an IDictonary which I have declared first, with one value.
My child runbook has a string parameter called Table defined as:
param(
[parameter(Mandatory=$True)]
[string] $Table
)
and the value that is being passed in is:
{"CliXml":"<Objs Version=\"1.1.0.1\" xmlns=\"http://schemas.microsoft.com/powershell/2004/04\">\r\n <S>myTable</S>\r\n</Objs>"}
How do I either:
parse this string to get the value or;
get the runbook parse the parameter and assign it for me?
Thanks

Related

passing $MyInvocation.UnBoundArguments to a nested function in Powershell

I want a function to pass all of it arguments to another function. Is there a better way of doing this? My version doesn't seem to work right however.
function remote {
$fargs = $MyInvocation.UnboundArguments
remote_version1 #fargs
}
function remote_version1 {
param(
[alias("m", "computer")]
[Parameter(Mandatory=$false)] [string]$Machine = "",
[Parameter(Mandatory=$false)] [string]$loc_file = "",
[Parameter(Mandatory=$false)] [string]$rem_file = "",
[Parameter(Mandatory=$false)] [switch]$tmp,
[Parameter(Mandatory=$false)] [switch]$banner,
[Parameter(Mandatory=$false)] [int]$profile = $script:remote_profile,
[Parameter(Mandatory=$false)] [int]$Hop = $script:remote_hop # Second Hop Mode
)
#write-host $MyInvocation.BoundParameters
write-host "loc_file: $loc_file"
write-host "rem_file: ($rem_file)"
}
$common_flags = #{}
$common_flags["Banner"] = $true
$common_flags["Machine"] = "mymachine"
$common_flags["Hop"] = $true
$common_flags["Profile"] = $true
remote #common_flag -loc_file .\file.txt -tmp
Result:
loc_file: .\file.txt
rem_file: True ##<==== Why True? SHould be "" since
## it isn't set when called??
(I can't seem to reproduce the output by snipping the code out of script.. makes me think powershell has some type of pointer bug?
But this is the problem i'm having... $rem_file is set
to a boolean for some reason, when its a string...)
Maybe i'm passing the wrong type into the "splat operator" #, and the orderingof items is random in the hash? but powershell doesn't seem to complain its the wrong object type?
Is there a way to convert a string into a company and execute it instead of using splat?
The automatic $args variable has built-in magic when used for splatting (#args), allowing it to pass named arguments through properly - note that this does not work with any other arrays, whether self-created array or returned from $MyInvocation.UnboundArguments.
Therefore, the following should meet your needs:
function remote {
# #args passes both named and positional (unnamed) arguments through.
remote_version1 #args
}
Note:
If the relaying function (remote) itself had declared parameters (with a param(...) block), you could also relay them with #PSBoundParameters, via automatic $PSBoundParameters variable.
If a relaying function with declared parameters is non-advanced, you may use #PSBoundParameters in addition to passing unbound arguments through with #args, whereas advanced functions by definition prevent passing unbound arguments (in other words: they do not support $args).
UnboundArguments is an Array instead of a Hash. I simply print the Array to convert it to a string and feed it to invoke-expression.
$fargs = $MyInvocation.UnboundArguments
$fargs = $fargs -replace "True", "`$true"
$fargs = $fargs -replace "False", "`$false"
invoke-expression "remote_version1 $fargs"

How to check Number of arguments in powershell?

param (
[string]$Name = $args[0],#First argument will be the adapter name
[IPAddress]$IP = $args[1],#Second argument will be the IP address
[string]$InterfaceId = $args[3],#Second argument will be the IP address
[string]$VlanId = $args[4], #Fourth argument will be vlanid
[string]$SubnetIP = $args[5],#subnet mask
[string]$IPType = "IPv4",
[string]$Type = "Static"
)
Write-Host $Args.Count
I want to check if command line arguments are supplied to the powershell script or not and if its not supplied then i want to show the usage by write. I am running the script in admin mode. I found one method after searching that using $Args.Count we can get the arguments count while running the script but its always zero for me. what am i doing wrong?
enter image description here
Get rid of the $args[x] assignments and add [cmdletbinding()] on top.
[CmdLetbinding()]
param (
[string]$Name, #First argument will be the adapter name
[IPAddress]$IP, # etc...
[string]$InterfaceId,
[string]$VlanId,
[string]$SubnetIP,
[string]$IPType = "IPv4",
[string]$Type = "Static"
)
Then you can use $PSBoundParameters.Count to get the argument count.
$args is a special variable that is used when named parameter are not present.
Therefore, since you have named parameter, it will always give you a count of zero (except maybe if you add more arguments than there is named parameters)
If you use a param block, then you don't need to assign $args[0] and others. In fact, this is totally useless as they will be $null.
The other approach, although I recommend you to keep the param block, is to not use any named parameters at all. In that case, $args will work as you expect it to.
[string]$Name = $args[0]
[IPAddress]$IP = $args[1]
[string]$InterfaceId = $args[3]
[string]$VlanId = $args[4]
[string]$SubnetIP = $args[5]
[string]$IPType = "IPv4"
[string]$Type = "Static"
The main difference is that if you have a param block, you can call your script in the following ways:
.\MyScript.ps1 -Name "Hello" -Ip 127.0.0.1
.\MyScript.ps1 "Hello" 127.0.0.1
Without the param block, you have only option #2 available to call the script.

Powershell Call-Operator(&) with Parameters from Variable

G'day everyone,
I'm trying to execute a function in PowerShell with the Parameters coming from a Variable I'm not sure if it's possible in the way I want it to but maybe someone has any idea how I would go about doing that.
$scriptPath = "C:\temp\Create-File.ps1"
$parameters = "-Path C:\temp\testfile.txt -DoSomethingSpecial"
& $scriptPath $parameters
Something along those lines, I don't know in which order the Parameters get entered so I can't use $args[n..m] or binding by position for that. Maybe there is some other Cmdlet I don't know about that is capable of doing that?
Passing an Object as #James C. suggested in his answer allows only to pass parameters in Powershell syntax (e.g. -param1 value1 -param2 value2)
When you need more control over the parameters you pass such as:
double dash syntax for unix style --param1 value1
Slash syntax for Windows style /param1 value1
Equals sign required (or colon) -param1=value1 or -param1:value1
No value for parameter -boolean_param1
additional verbs (values without a param name) value1 value2
you can use an array instead of an object
take ipconfig command for example to renew all connections with "con" in their name:
$cmd = "ipconfig"
$params = #('/renew', '*Con*');
& $cmd $params
or the specific question given example:
$params = #('-Path', 'C:\temp\testfile.txt', '-DoSomethingSpecial')
.\Create-File.ps1 #params
You can use a hastable and Splatting to do this.
Simply set each param name and value in the variable as you would a normal hastable, then pass this in using #params syntax.
The switch param however, needs a $true value for it to function correctly.
$params = #{
Path = 'C:\temp\testfile.txt'
DoSomethingSpecial = $true
}
.\Create-File.ps1 #params
You can run it by Start-Process
Start-Process powershell -ArgumentList "$scriptPath $parameters"

Send variable number of key value pairs from CLI

I'm needing to execute a PowerShell script as part of my TFS build pipeline. The PowerShell script is generic and executes a given AWS Cloud Formation template given to it. I need the developer to supply the template with a list of key/value pairs that represent the templates parameters. Since they can use this to execute any Cloud Formation template, the input parameters will vary.
How can I create an input parameter that is key/value based that I can pass as a parameter to another PowerShell object that accepts a Hashmap of parameters?
The following pseudo code is what I'm trying to achieve
param(
[Parameter(Mandatory=$true)][string]$environment,
[KeyValuePair[]]$templateParameters
)
New-CFNStack -StackName $stackName -TemplateURL $fullTemplateUrlPath -Parameters #( $templateParameters)
I can explicitly create the parameters and pass them in like this:
$bucketNameParameter = new-object Amazon.CloudFormation.Model.Parameter
$bucketNameParameter.ParameterKey = "bucketname"
$bucketNameParameter.ParameterValue = "FooBar"
$isVersionedParameter = new-object Amazon.CloudFormation.Model.Parameter
$isVersionedParameter.ParameterKey = "bucketname"
$isVersionedParameter.ParameterValue = "FooBar"
New-CFNStack -StackName $stackName -TemplateURL $fullTemplateUrlPath -Parameters #( $environmentParameter, #isVersionedParameter )
Since each template has completely different parameters they can take, I would like to make this script flexible to facilitate re-use. What is the most PowerShell way of approaching that?
You can accept a [hashtable] instance and create your [Amazon.CloudFormation.Model.Parameter] instances based on its entries:
param(
[Parameter(Mandatory=$true)] [string] $environment,
[hashtable] $templateParameters
)
# Convert the hashtable's entries to an array of
# [Amazon.CloudFormation.Model.Parameter] instances.
$params = $templateParameters.GetEnumerator() | ForEach-Object {
$param = New-Object Amazon.CloudFormation.Model.Parameter
$param.ParameterKey = $_.Key
$param.ParameterValue = $_.Value
$param # output
}
New-CFNStack -StackName $stackName -TemplateURL $fullTemplateUrlPath -Parameters $params
Note the use of .GetEnumerator(), which is necessary in order to enumerate the hashtable's entries and send them through the pipeline; by default, PowerShell sends hashtables as a whole through the pipeline.
Using your (modified-to-be-unique) example values, you'd invoke your script as:
./script.ps1 -environment foo `
-templateParameters #{ bucketName1 = 'FooBar1'; bucketName2 = 'FooBar2' }

How to pass a switch parameter to another PowerShell script?

I have two PowerShell scripts, which have switch parameters:
compile-tool1.ps1:
[CmdletBinding()]
param(
[switch]$VHDL2008
)
Write-Host "VHDL-2008 is enabled: $VHDL2008"
compile.ps1:
[CmdletBinding()]
param(
[switch]$VHDL2008
)
if (-not $VHDL2008)
{ compile-tool1.ps1 }
else
{ compile-tool1.ps1 -VHDL2008 }
How can I pass a switch parameter to another PowerShell script, without writing big if..then..else or case statements?
I don't want to convert the parameter $VHDL2008 of compile-tool1.ps1 to type bool, because, both scripts are front-end scripts (used by users). The latter one is a high-level wrapper for multiple compile-tool*.ps1 scripts.
You can specify $true or $false on a switch using the colon-syntax:
compile-tool1.ps1 -VHDL2008:$true
compile-tool1.ps1 -VHDL2008:$false
So just pass the actual value:
compile-tool1.ps1 -VHDL2008:$VHDL2008
Try
compile-tool1.ps1 -VHDL2008:$VHDL2008.IsPresent
Assuming you were iterating on development, it is highly likely that at some point you are going to add other switches and parameters to your main script that are going to be passed down to the next called script. Using the previous responses, you would have to go find each call and rewrite the line each time you add a parameter. In such case, you can avoid the overhead by doing the following,
.\compile-tool1.ps1 $($PSBoundParameters.GetEnumerator() | ForEach-Object {"-$($_.Key) $($_.Value)"})
The automatic variable $PSBoundParameters is a hashtable containing the parameters explicitly passed to the script.
Please note that script.ps1 -SomeSwitch is equivalent to script.ps1 -SomeSwitch $true and script.ps1 is equivalent to script.ps1 -SomeSwitch $false. Hence, including the switch set to false is equivalent to not including it.
According to a power shell team's blog (link below,) since V2 there is a technique called splatting. Basically, you use the automatic variable #PsBoundParameters to forward all the parameters. Details about splatting and the difference between # and $ are explained in the Microsoft Docs article (link below.)
Example:
parent.ps1
#Begin of parent.ps1
param(
[Switch] $MySwitch
)
Import-Module .\child.psm1
Call-Child #psBoundParameters
#End of parent.ps1
child.psm1
# Begin of child.psm1
function Call-Child {
param(
[switch] $MySwitch
)
if ($MySwitch){
Write-Output "`$MySwitch was specified"
} else {
Write-Output "`$MySwitch is missing"
}
}
#End of child.psm1
Now we can call the parent script with or without the switch
PS V:\sof\splatting> .\parent.ps1
$MySwitch is missing
PS V:\sof\splatting> .\parent.ps1 -MySwitch
$MySwitch was specified
PS V:\sof\splatting>
Update
In my original answer, I sourced the children instead of importing it as a module. It appears sourcing another script into the original just makes the parent's variables visible to all children so this will also work:
# Begin of child.ps1
function Call-Child {
if ($MySwitch){
Write-Output "`$MySwitch was specified"
} else {
Write-Output "`$MySwitch is missing"
}
}
#End of child.ps1
with
#Begin of parent.ps1
param(
[Switch] $MySwitch
)
. .\child.ps1
Call-Child # Not even specifying #psBoundParameters
#End of parent.ps1
Maybe, this is not the best way to make a program, nevertheless, this is the way it works.
About Splatting(Microsoft Docs)
How and Why to Use Splatting (passing [switch] parameters)
Another solution. If you declare your parameter with a default value of $false:
[switch] $VHDL2008 = $false
Then the following (the -VHDL2008 option with no value) will set $VHDL2008 to $true:
compile-tool1.ps1 -VHDL2008
If instead you omit the -VHDL2008 option, then this forces $VHDL2008 to use the default $false value:
compile-tool1.ps1
These examples are useful when calling a Powershell script from a bat script, as it is tricky to pass a $true/$false bool from bat to Powershell, because the bat will try to convert the bool to a string, resulting in the error:
Cannot process argument transformation on parameter 'VHDL2008'.
Cannot convert value "System.String" to type "System.Management.Automation.SwitchParameter".
Boolean parameters accept only Boolean values and numbers, such as $True, $False, 1 or 0.