Microsoft Azure (Automation): Runbook passing Hash as Parameter - powershell

I'm trying to pass a hash like {"server":"database","server2":"database_b"} as a parameter to a runbook on Microsoft Azure. But neither
[parameter(Mandatory=$true)] [hashtable]$ServersWithCorrespondingDatabase,
nor
[parameter(Mandatory=$true)] [object]$ServersWithCorrespondingDatabase,
seems to work?
In this example Runbook Gallery they go with the argument ChildRunbookInputParams as hashtable, like:
Start-ChildRunbook `
-ChildRunbookName "Update-VM" `
-ChildRunbookInputParams #{'VMName'='VM204';'Retries'=3} `
-AzureConnectionName "Visual Studio Ultimate with MSDN"
-AutomationAccountName "Contoso IT Automation Production" `
-WaitForJobCompletion $true `
-ReturnJobOutput $true `
-JobPollingIntervalInSeconds 20 `
-JobPollingTimeoutInSeconds 120
But somehow I can not pass the string #{"Server"="DB";"Server2"="DB3"} to my azure runbook as a parameter... Any idea?

In the runbook, you should define the parameter as [object] type, not [hashtable]. Are you starting the runbook through the Azure Automation portal, or inline via another runbook?
Assuming this is your runbook:
workflow a {
param(
[object] $obj
)
$obj
}
If via the portal, you need to specify the object parameter as JSON, ex:
{"server":"database","server2":"database_b"}
If via a runbook calling this runbook inline, specify it as a PowerShell object or hashtable:
a -Obj #{"server"="database";"server2"="database_b"}
For more info see http://azure.microsoft.com/blog/2014/08/12/azure-automation-runbook-input-output-and-nested-runbooks/
Edit: If you are trying to start this runbook specifically by calling the Start-ChildRunbook runbook within a runbook, it would look like this, since the Start-ChildRunbook runbook takes the parameters of the runbook to start as a hashtable, and in this case the value of one of those parameters is a hashtable/object itself:
$ValueForObjParam = #{"server"="database";"server2"="database_b"}
Start-ChildRunbook `
-ChildRunbookName "a" `
-ChildRunbookInputParams #{"obj"=$ValueForObjParam} `
-AzureConnectionName "Visual Studio Ultimate with MSDN" `
-AutomationAccountName "Contoso IT Automation Production" `
-WaitForJobCompletion $true `
-ReturnJobOutput $true `
-JobPollingIntervalInSeconds 20 `
-JobPollingTimeoutInSeconds 120

The script you refer to in the gallery uses a hashtable to specify all the params to the child runbook, not a single param of type hashtable. So, the child runbook probably has a param block like so:
workflow start-update-vm
{
param ($VMName, $retries)
#rest of code
}
You can, however, take a stringed json input and it will be converted into a hashtable/array as described here: http://blogs.technet.com/b/orchestrator/archive/2014/01/10/sma-capabilities-in-depth-runbook-input-output-and-nested-runbooks.aspx.

Related

Can we call a runbook from another runbook in Powershell?

I'm having two runbooks of two different Powershell versions (5.1, 7.1). How to call a runbook (7.1) from runbook (5.1)?
Modules used:
AZ-SecurityInsights - 5.1 version (runbook 5.1)
AzSentinel - 7.1 version (runbook 7.1)
Need to pass resourcevariable as an input parameter to second runbook from first runbook.
My code:
$AzureContext = Set-AzContext -SubscriptionName $AzureContext.Subscription -DefaultProfile $AzureContext
Start-AzAutomationRunbook -AutomationAccountName $automationAccountName -Name "ExportAlertRule" -ResourceGroupName $automationResourceGroupName
Error:
Object reference not set to an instance of an object.
What can I try next?
If the output stream of Start-AzAutomationAccount contains object, the command does not process the output stream correctly. For the same, you need to implement a polling logic, and use the Get-AzAutomationJobOutput cmdlet to retrieve the output.
For more information, refer below documents.
https://learn.microsoft.com/en-us/azure/automation/troubleshoot/runbooks#resolution-13
https://learn.microsoft.com/en-us/azure/automation/automation-child-runbooks#runbook-types

TFS/VSTS Custom variables that aren't string cannot be used

I have been using TFS to create some release variables from PowerShell. I can then use '$Env:Server' in subsequent tasks in TFS to reference this output, this seems great to start with! EG:
Task 1 returns a server name then creates the TFS Variable:
Write-Host "##vso[task.setvariable variable=Server]"MySevrer
Task 2 Uses this information:
Write-Output $env:Server
MyServer
Upon outputting something in another format like an array or a hash table this does not work. The variable that gets created is just string as the documentation states using "Write-Host".
Task1 returns:
##vso[task.setvariable variable=Server] System.Collections.DictionaryEntry
Task 2 can not use this:
Write-Output $env:Server
System.Collections.DictionaryEntry
Output that is created
I have tried outputting this as a string in the array format, EG:
[String]$Server = '#{MyServer=#("192.168.0.1")}'
Write-Host "##vso[task.setvariable variable=Server]"$Server
When i refer to this I try to convert this back to an array within PowerShell, however, I have had issues with doing this inside a script as it will see the string as being a single array object. (Not an array with a value)
Does anyone know if it posable to parse hashtables or arrays between Team Service's tasks/Task Task groups based on information output by a Powershell task?
I have currently got around this by writing a wrapper/orchestration function but this is not the ideal way for us. We are currently on Version 15.117.26714.0 but i cannot see anything in newer versions.
ConvertTo-Json will do the trick, as mentioned by Daniel Mann.
Example:
In Azure Devops release pipeline, there is an Azure PowerShell task with following code:
$apps = Get-AzureRmResource -ResourceGroupName "$(ResourceGroupName)" -ResourceType Microsoft.Web/sites
$objectIdArray = New-Object System.Collections.ArrayList
foreach ($app in $apps) {
if (!$app.Identity) {
Write-Host "Enabling identity for $($app.Name) app service..."
$app = Set-AzureRmWebApp -Name $($app.Name) -ResourceGroupName "$(ResourceGroupName)" -AssignIdentity $true
} else {
Write-Host "$($app.Name) app service has $($app.Identity.PrincipalId) as the identity."
}
$objectIdArray.Add($($app.Identity.principalId))
}
$objectIdArrayJson = ($objectIdArray | ConvertTo-Json -Compress)
Write-Host "##vso[task.setvariable variable=objectIdArray;]$objectIdArrayJson"
Write-Host $env:objectIdArray
The following task is an Azure Resource Group Deployment task that has an overridden parameter:
-objectIdArray "$(objectIdArray)"
The release variable "$(objectIdArray)" has a value like:
["0512706a-0344-418a-9f25-5708d95e44aa","6047cbe6-c109-4aa7-8cfb-b473c088b1b1","68ee0d25-351f-44c8-aecf-cfc259f3cd97","44a6f3d6-23a3-443d-824b-445e0141f09c","805c3e6d-ab31-41f4-9d6c-8c9fc13ce
460","aa13b9db-200d-4c38-abf8-562a915ed8cd","8d1d7ec1-faa6-4af6-b732-331e51e86a90","02222b28-6370-4995-a633-29a1cdd08fd0","a48c21b1-b6ef-4582-b9a0-050965cb3614","9111421b-8535-4326-bbe9-1e891
33a0b56","5b1f6fca-599c-4895-ae4b-fabc0d3a4dd3","b12a935a-b1c3-4dec-b764-7c0a5307a766","8af7d615-c042-43b5-8ac0-736c6cf4ec3f","f0dd4dd9-e540-4e13-a8be-69ce08a6221c","b131e123-a87e-4faf-afed-4
37d6dbae4ab","af7f679b-1ac8-4991-b467-93ba4a16ec22","1bbb649c-b5e6-4f5c-a050-3a0cee0af985","4a7b728e-e8c6-49c0-bde2-54811708d5ab","3b190d28-c390-43c7-9269-1177afaf7b00","49f3777f-8668-4c72-82
60-753f65b933aa","727db5c4-ad56-457e-ad87-47b17c71e29b","801efff8-a852-4e7b-bc81-3d81d3bcfeb5","0947556e-7ece-4a36-a687-3c50f59e32f6"]
Pass them as JSON and use ConvertTo-Json and ConvertFrom-Json to convert them back and forth between JSON representations and PowerShell objects. When using ConvertTo-Json, be sure to use the -Compress flag.

How to run multiple instance of PowerShell script

I wants to run a multiple instance of one powershell script for multiple service with different parameter. I have written below powershell script , but not sure what i am doing its not taking parameter.
[string[]] $ScriptstrArray = ‘-command Invoke-Expression ".\Smoke-Test.ps1 -Environment QA -servicename rpms"' ,
‘-command Invoke-Expression ".\Smoke-Test.ps1 -Environment QA - servicename rsms"' ,
‘-command Invoke-Expression ".\Smoke-Test.ps1 -Environment pvs - servicename spsms"'
workflow RunSmokeTests {
########################################################################
param([string[]]$sList)
ForEach -Parallel ($s in $sList) {
start-process powershell.exe -argument $s
}
}
RunSmokeTests -sList $ScriptstrArray
Can someone please me to identify the issue. Thanks in advance.
I have used the external helper Invoke-Parallel for such scenarios in the past. It has a -InputObject parameter that allows you to pass in an array with e.g. the servers/services and their corresponding details. See here or here for source and examples.

Error calling one Azure Automation Runbook from another

Background
I have one Azure Runbook (named RunStoredProcedure2) defined as such:
param(
[parameter(Mandatory=$True)]
[string] $SqlServer,
[parameter(Mandatory=$False)]
[int] $SqlServerPort = 1433,
[parameter(Mandatory=$True)]
[string] $Database,
[parameter(Mandatory=$True)]
[string] $StoredProcedureName,
[parameter(Mandatory=$True)]
[PSCredential] $SqlCredential
)
# Get the username and password from the SQL Credential
$SqlUsername = $SqlCredential.UserName
$SqlPass = $SqlCredential.GetNetworkCredential().Password
$Conn = New-Object System.Data.SqlClient.SqlConnection("Server=tcp:$SqlServer,$SqlServerPort;Database=$Database;User ID=$SqlUsername;Password=$SqlPass;Trusted_Connection=False;Encrypt=True;Connection Timeout=30;")
$Conn.Open()
$Cmd=new-object system.Data.SqlClient.SqlCommand("EXEC
$StoredProcedureName", $Conn)
$Cmd.CommandTimeout=120
$Cmd.ExecuteNonQuery()
# Close the SQL connection
$Conn.Close()
I'm now attempting to call this runbook from another Azure Runbook using this command:
& .\RunStoredProcedure2.ps1 -Database 'adventureworksnh.database.windows.net' -SqlServer 'AdventureWorksDW' -SqlServerPort 1433 -StoredProcedureName 'TestJob1' -sqlCredential 'awadmin'
Issue
When I attempt to run this, I get this error:
C:\Temp\uzahthmc.su1\RunStoredProcedure2.ps1 : Cannot process argument transformation on parameter 'SqlCredential'. A
command that prompts the user failed because the host program or the command type does not support user interaction.
The host was attempting to request confirmation with the following message: Enter your credentials.
I am able to run RunStoredProcedure with these parameters successfully
What I've Tried
Adding/removing the preceding ampersand
Using Invoke-Expression
Do you have a Credential asset named "awadmin" in your Automation account? When you start a runbook directly (using the Start button in the portal or the Start-AzureRmAutomationRunbook), Azure Automation allows you to pass a credential asset name as a parameter value, and it will retrieve the specified credential automatically. However, when you invoke a runbook from another runbook, you have to follow plain PowerShell rules and pass a PSCredential object, as declared:
$sqlCred = Get-AutomationPSCredential -Name 'awadmin'
& .\RunStoredProcedure2.ps1 ... -sqlCredential $sqlCred

Azure Powershell Runbook - Get-AzureRMWebAppSlot SiteConfig.ConnectionStrings[0] erroring cannot index into a null array

I'm trying to execute below command in a PowerShell Workflow Runbook. I'm getting the error "cannot index into a null array.", which is not true as the same script which ran perfectly on my local machine is not executing while in the Azure portal as a PowerShell Workflow Runbook.
Can anyone please look into this?
$webApp = Get-AzureRMWebAppSlot -ResourceGroupName $ResourceGroupName -Name $WebSiteName -Slot $WebSiteSlot
$webApp
"Printing Website ConncectionString"
$webApp.SiteConfig.ConnectionStrings.ConnectionString[0]
Some types do not serialize/deserialize correctly, and in PowerShell Workflow that is a problem because PowerShell Workflow relies on object serialization/deserialization (that's how PSWF is able to checkpoint, suspend, and resume -- it converts all objects to a string form when checkpointing/suspending, and restores back to full objects from those strings when resuming).
It would appear Get-AzureRMWebAppSlot's output object is one of those types that does not serialize/deserialize correctly. From your screenshot I can see that the SiteConfig property of $webApp is a string containing Microsoft.Azure.Management.WebSites.Model.SiteConfig rather than an object as you're expecting. Clearly, the object is not deserializing correctly back to its original form, where SiteConfig is a complex object.
The way to work around this is to only interact with the object in PowerShell script context, rather than workflow context. For example:
workflow foo {
$ResourceGroupName = "RG"
$WebSiteName = "WS"
$WebSiteSlot = "Slot"
$ConnectionString = InlineScript {
$webApp = Get-AzureRMWebAppSlot -ResourceGroupName $using:ResourceGroupName -Name $using:WebSiteName -Slot $using:WebSiteSlot
$webApp.SiteConfig.ConnectionStrings.ConnectionString[0]
}
"Printing Website ConnectionString"
$ConnectionString
}