Azure Powershell Workflow : Failed to convert 'System.Activities.InArgument`1[System.String]' to type 'System.String' - azure-powershell

I have a couple of Azure Powershell Workflow runbooks that copy a production database and then run cleanup scripts against it and scale it down to generate dev and stage environemnts. I started getting the error "Failed to convert 'System.Activities.InArgument`1[System.String]' to type 'System.String'" from the parent workbook when I was editing it. I recreated the problem in a set of test runbooks: Test_Child and Test_Parent.
Test_Child is just an empty shell meant to receive a single input string.
workflow Test_Child
{
param(
[parameter(Mandatory=$True)]
[String] $Input
)
}
Test_Parent connects to Azure automation and executes the child workbook. If I run both processes in this order it fails. If I run either one separately or reverse the order of execution it succeeds.
workflow Test_Parent
{
$servicePrincipalConnection=Get-AutomationConnection -Name 'AzureRunAsConnection'
Write-Output "Logging into Azure AD ..."
Connect-AzAccount -Tenant $servicePrincipalConnection.TenantID `
-ApplicationID $servicePrincipalConnection.ApplicationID `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint `
-ServicePrincipal
try
{
Test_Child -Input "input"
}
catch
{
exit
}
}
If I execute the parent runbook I get an error.
Failed
Failed to convert 'System.Activities.InArgument`1[System.String]' to type 'System.String'.
If I remove the runbook call the process completes.
Test_Parent with runbook call removed:
workflow Test_Parent
{
$servicePrincipalConnection=Get-AutomationConnection -Name 'AzureRunAsConnection'
Write-Output "Logging into Azure AD ..."
Connect-AzAccount -Tenant $servicePrincipalConnection.TenantID `
-ApplicationID $servicePrincipalConnection.ApplicationID `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint `
-ServicePrincipal
}
Here is the output:
Logging into Azure AD ...
PSComputerName : localhost
PSSourceJobInstanceId : [My PSSourceJobInstanceId]
Environments : {AzureCloud, AzureUSGovernment, AzureChinaCloud, AzureGermanCloud}
Context : Microsoft.Azure.Commands.Profile.Models.Core.PSAzureContext
If I only call the workbook the process completes as well.
Here is the runbook Test_Parent with the Azure automation connection call removed:
workflow Test_Parent
{
try
{
Test_Child -Input "input"
}
catch
{
exit
}
}
The output
Completed
If I reverse the order of execution it completes.
workflow Test_Parent
{
try
{
Test_Child -Input "input"
}
catch
{
exit
}
$servicePrincipalConnection=Get-AutomationConnection -Name 'AzureRunAsConnection'
Write-Output "Logging into Azure AD ..."
Connect-AzAccount -Tenant $servicePrincipalConnection.TenantID `
-ApplicationID $servicePrincipalConnection.ApplicationID `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint `
-ServicePrincipal
}
Output
Completed
Logging into Azure AD ...
PSComputerName : localhost
PSSourceJobInstanceId : [My PSSourceJobInstanceId]
Environments : {AzureCloud, AzureUSGovernment, AzureChinaCloud, AzureGermanCloud}
Context : Microsoft.Azure.Commands.Profile.Models.Core.PSAzureContext
Any idea why making the automation connection and then executing the workbook creates a data type mismatch error?

I had the exact same problem. In our Test environment the runbooks ran without problem. In our UAT environment, which was set up at a later time, we had the same error as you.
After some investigation I noticed that both environments used a different version of the Az.Accounts module. (2.5.2 in Test, 2.6 in UAT).
After upgrading the Az.Accounts module to 2.7.2 the issue seems to have dissapeared, so i guess it was a bug in the 2.6 version.

Related

Azure Powershell New-AzSynapseManagedPrivateEndpoint Definition File format?

I'm trying to deploy a managed private endpoint to my synapse instance to connect it to a key Vault in the same resource Group. The documentation for the same deployment in Bicep is very incomplete so I thought to try my luck with PowerShell using the following command :
New-AzSynapseManagedPrivateEndpoint `
-WorkspaceName "synapse-test-joao" `
-Name "managedPrivateEndpointKeyVault" `
-DefinitionFile file.json
However, I cannot seem to find the format for the definition file anywhere on the internet, so was wondering if anyone had any information regarding the json format and what parameters need to go inside.
This would be immensely helpful,
Joao
The sample -DefinitionFile should be in below format:
{
# here i am using sample blob storage
"name": "testblob", #ManagePrivate Endpoint Name
"properties": {
"privateLinkResourceId": "/subscriptions/<subscription ID>/resourceGroups/<ResourceGroup name>/providers/Microsoft.Storage/storageAccounts/<Storage Account Name>",
"groupId": "blob"
}
}
To get the -DefinitionFile Sample file to follow the below ways:
Way 1:
Go to your Azure Synapse Workspace -> Managed Private Endpoints
Drag your cursor into your private endpoint you can see {} - (Code) from there you can get the sample -DefinitionFile.
Way 2:
This way you can get the PrivateLinkResourceId of ManagedPrivateEndpoint
$ds = Get-AzSynapseWorkspace -Name <Synapse workspaces Name>
$ws | Get-AzSynapseManagedPrivateEndpoint -Name <Your Created Managed Private Endpoint Name>
# Private Link Resource Id
/subscriptions/<subscription ID>/resourceGroups/<ResourceGroup name>/providers/Microsoft.Storage/storageAccounts/<Storage Account Name>
Refer here
The code to deploy the managed private endpoint for Synapse in a devOps pipeline can be as follows:
param(
$environment,
$synapseWorkspaceVar,
$subscriptionId,
$resourceGroupNameVar,
$keyVaultNameVar
)
$createPrivateEndpointJsonString = #"
{
"properties": {
"privateLinkResourceId": "/subscriptions/$subscriptionId/resourceGroups/$resourceGroupNameVar/providers/Microsoft.KeyVault/vaults/$keyVaultNameVar",
"groupId": "vault"
}
}
"#
write-output $createPrivateEndpointJsonString
$tempFolderPath = ".\temp"
if (!(Test-path -path $tempFolderPath)) {
echo "new file"
New-Item -ItemType directory -path $tempFolderPath
}
write-output "creating the PrivateEndpoint Definition Json file...."
$jsonpath = ".\$tempFolderPath\createprivateendpoint.json"
Set-Content -Path $jsonpath -value $createPrivateEndpointJsonString
echo "Creating new Managed Private Endpoint from Synapse to KeyVault..."
New-AzSynapseManagedPrivateEndpoint `
-WorkspaceName $synapseWorkspaceVar `
-Name "managedPrivateEndpointKeyVaultACEP" `
-DefinitionFile $jsonpath
Get-AzSynapseManagedPrivateEndpoint -WorkspaceName $synapseWorkspaceVar

Azure automation runbook Completed before running the code

I have a situation where in the Azure automation runbook results in 'Completed' state and does not run the 'actual' code. I have pasted the code below. It creates a Event Hub inside a Namespace. The code works perfectly executing in local machine but it does not execute in Runbook.
I have written a 'write-output "Declaring local variables for use in script"' --> to check if the printing is working. However, the code is not going beyond that. I am sure, I am missing some thing. Kindly help me.
Param(
[Parameter(Mandatory=$true)]
[string] $NameSpaceNameName,
[Parameter(Mandatory=$true)]
[string[]] $EventhubNames,
[Parameter(Mandatory=$true)]
[string] $ProjectId,
[Parameter(Mandatory=$true)]
[int] $PartitionCount,
[Parameter(Mandatory=$true)]
[string]$Requested_for,
[Parameter(Mandatory=$true)]
[string]$Comments
)
## Login to Azure using RunAsAccount
$servicePrincipalConnection = Get-AutomationConnection -Name 'AzureRunAsConnection'
Write-Output ("Logging in to Az Account...")
Login-AzAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
write-output "Declaring local variables for use in script"
## Declaring local variables for use in script
$Creation_date = [System.Collections.ArrayList]#()
$ResourceGroups = Get-AzResourceGroup
$provided_name_space_exists = $false
## Change context to Platform subscription
select-azsubscription -subscription "GC302_Sub-platform_Dev"
## Create Event Hub
foreach($Resourcegroup in $ResourceGroups){
Write-Host("Processing the Resource Group: {0} " -f $Resourcegroup.ResourceGroupName)
$EventhubNameSpaces = Get-AzEventHubNamespace -ResourceGroupName $ResourceGroup.ResourceGroupName
# Iterate over each Namespace. Fetch the Resource Group that contains the provided Namespace
foreach($EHNameSpace in $EventhubNameSpaces){
if($EHNameSpace.Name -eq $NameSpaceName){
$provided_name_space_exists = $true
Write-Host ("Found the provided Namespace in resource group: {0}" -f $Resourcegroup.ResourceGroupName)
Write-Output ("Found the provided Namespace in resource group: {0}" -f $Resourcegroup.ResourceGroupName)
$nameSpace_resource_group = $ResourceGroup.ResourceGroupName
# Fetch the existing Event Hubs in the Namespace
$existing_event_hubs_list = Get-AzEventHub -Namespace $EHNameSpace.Name -ResourceGroupName $nameSpace_resource_group
## Check provided EH for uniqueness
if($existing_event_hubs_list.Count -le 1000){
for($i = 0;$i -lt $EventhubNames.Count;$i++){
if($existing_event_hubs_list.name -notcontains $EventhubNames[$i]){
$EventHub = New-AzEventHub -ResourceGroupName $nameSpace_resource_group -Namespace $EHNameSpace.Name -Name $EventhubNames[$i] -PartitionCount $PartitionCount
$date = $EventHub.CreatedAt
$Creation_date+= $date.GetDateTimeFormats()[46]
}else{
Write-Host ("Event hub: '{0}' already exists in the NameSpace: {1}. skipping this Event hub creation" -f $EventhubNames[$i], $EHNameSpace.Name)
}
}
}else{
Write-Host ("The Namespace - {0} has Event Hubs count greater or equal to 1000." -f $EHNameSpace.Name)
Write-Host ("Please refer the Link for Eevent Hubs quota/limit: 'https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-quotas#event-hubs-dedicated---quotas-and-limits'")
exit
}
}
}
}
# Print a message that Namespace does not exist
if($provided_name_space_exists -eq $false){
Write-Host ("Provided NameSpace: {0} does not exist." -f $NameSpaceName)
exit
}
Screenshot:
You have $NameSpaceNameName in the parameters section of the runbook but later in the runbook at 50th line you have $NameSpaceName which is not the same as mentioned in parameters section. Correct it and then it should work as expected. One suggestion is to always have an else block wherever you have if block to overcome such issues in future.

Get All blob names from Storage account from Runbook

I have a very simple script which absolutely works fine when run from remote powershell ISE (not using the RUNAS credentials from the Automation Runbook), but when we try to run it from Automation Runbook it returns 0 . Following is the code:-
$connectionName = "AzureRunAsConnection"
$SubId = "XXXXXXXXXXXXXXXXXX"
try
{
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
Write-Verbose "Logging in to Azure..." -Verbose
Connect-AzAccount -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint -ApplicationId $servicePrincipalConnection.ApplicationId -Tenant $servicePrincipalConnection.TenantId -ServicePrincipal
Write-Verbose "Setting Subscription......" -Verbose
Set-AzContext -SubscriptionId $SubId | Write-Verbose
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
$storageAccount = Get-AzStorageAccount -ResourceGroupName $ResourceGroup -Name $StorageAccountName -ErrorAction SilentlyContinue
# Resource group name for the storage acccount
$ResourceGroup = "MYDEV01-RG"
# Storage account name
$StorageAccountName = "myDev01StrgName"
# Container name for analytics logs
$ContainerName = "`$logs"
$storageContext = $storageAccount.Context
$containers = New-Object System.Collections.ArrayList
$container = Get-AzStorageContainer -Context $storageContext -Name $ContainerName -ErrorAction SilentlyContinue |
ForEach-Object { $containers.Add($_) } | Out-Null
Write-Output("> Container count: {0}" -f $containers.Count)
Not sure if we are missing something like permissions or some other thing because of with the Automation Account (Runbook) is not working, any help?
Thank you,
After spending 24 hours on this one and staring and trying everything, it turned out that the ABOVE SCRIPT is correct and nothing is wrong in it but the STORAGE ACCOUNT's FIREWALL and NETWORK Setting were set to SELECTED NETWORK (You can either add the network IP addresses which you want to permit or select All Networks and that helped me resolve my issue). In NO WAYS I am suggesting SELECTING ALL NETWORKS but for testing we can and then add only the Selected networks and that should work.

Azure automation - credentials delivered by Get-PSAutomationCredential don't work with Add-AzureAccount?

I'm modifying a gallery runbook that copies a live database to a test database on a schedule. It's failing at the first hurdle; authenticating and selecting the relevatn azure subscription
The runbook looks like this:
$Cred = Get-AutomationPSCredential -Name 'automationCredential'
Write-Output "UN: $($Cred.Username)"
Add-AzureAccount -Credential $Cred
I've used the portal credentials blade to create a credential named "automationCredential". For the username and password I supplied the username/pw that I log into the azure portal with. Note: this is NOT a school/work microsoft account, but a personal one
I can tell the call to Get-PSAutomationCredential is working out, because the Write-Ouput call shows the correct value
Add-AzureAccount however, delivers the following error:
Add-AzureAccount : unknown_user_type: Unknown User Type At
Set-DailyDatabaseRestore:22 char:22 CategoryInfo :
CloseError: (:) [Add-AzureAccount], AadAuthenticationFailedException
FullyQualifiedErrorId :
Microsoft.WindowsAzure.Commands.Profile.AddAzureAccount
Any pointers how to get a working credential?
According to your description, it seems that your account is a Microsoft account(such as *#outlook.com, *#hotmail.com). Microsoft does not support non-interactive login. It is also unsafe for you to use your account to login your subscription directly. For a runbook, you could use the following codes to logon.
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
In above code, you need use connection AzureRunAsConnection, it is created by Azure default, you could use it directly, you could check this connection, it includes your subscription information.
Also, you could create a new connection, please refer to this link.
Have you tried using the resource manager version off the login cmdlet (Add-AzureRmAccount)?

How to run a SQL batch within an Azure runbook?

I need to execute a batch to perform some maintenance tasks in my database but all the examples on Azure Automation I see are dealing with a single SQL command.
How do I do it if creating an SP is not an option? I think I need to either somehow embed my script.sql file into a runbook script or reference it (like here, for example)?
You could store the .sql file in Azure Blob Storage, and within the runbook download the .sql file, read its contents, and pass that to the SqlCommand object.
Something like:
try {
# Connect to Azure using service principal auth
$ServicePrincipalConnection = Get-AutomationConnection -Name $AzureConnectionAssetName
Write-Output "Logging in to Azure..."
$Null = Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $ServicePrincipalConnection.TenantId `
-ApplicationId $ServicePrincipalConnection.ApplicationId `
-CertificateThumbprint $ServicePrincipalConnection.CertificateThumbprint
}
catch {
if(!$ServicePrincipalConnection) {
throw "Connection $AzureConnectionAssetName not found."
}
else {
throw $_.Exception
}
}
$Path = "C:\abc.sql"
Set-AzureRmCurrentStorageAccount -ResourceGroupName $ResourceGroupName -Name $StorageAccountName
Get-AzureStorageBlobContent -Container $Container -Blob $Blob -Destination $Path
$Content = Get-Content $Path
$Cmd = New-Object System.Data.SqlClient.SqlCommand($Content, $Conn)