Use deployment scripts in templates (Preview)

Learn how to use deployment scripts in Azure Resource templates. With a new resource type called Microsoft.Resources/deploymentScripts, users can execute deployment scripts in template deployments and review execution results. These scripts can be used for performing custom steps such as:

  • add users to a directory
  • perform data plane operations, for example, copy blobs or seed database
  • look up and validate a license key
  • create a self-signed certificate
  • create an object in Azure AD
  • look up IP Address blocks from custom system

The benefits of deployment script:

  • Easy to code, use, and debug. You can develop deployment scripts in your favorite development environments. The scripts can be embedded in templates or in external script files.
  • You can specify the script language and platform. Currently, Azure PowerShell and Azure CLI deployment scripts on the Linux environment are supported.
  • Allow specifying the identities that are used to execute the scripts. Currently, only Azure user-assigned managed identity is supported.
  • Allow passing command-line arguments to the script.
  • Can specify script outputs and pass them back to the deployment.

The deployment script resource is only available in the regions where Azure Container Instance is available. See Resource availability for Azure Container Instances in Azure regions.

Important

A storage account and a container instance are needed for script execution and troubleshooting. You have the options to specify an existing storage account, otherwise the storage account along with the container instance are automatically created by the script service. The two automatically created resources are usually deleted by the script service when the deployment script execution gets in a terminal state. You are billed for the resources until the resources are deleted. To learn more, see Clean-up deployment script resources.

Prerequisites

  • A user-assigned managed identity with the contributor's role to the target resource-group. This identity is used to execute deployment scripts. To perform operations outside of the resource group, you need to grant additional permissions. For example, assign the identity to the subscription level if you want to create a new resource group.

    Note

    The script service creates a storage account (unless you specify an existing storage account) and a container instance in the background . A user-assigned managed identity with the contributor's role at the subscription level is required if the subscription has not registered the Azure storage account (Microsoft.Storage) and Azure container instance (Microsoft.ContainerInstance) resource providers.

    To create an identity, see Create a user-assigned managed identity by using the Azure portal, or by using Azure CLI, or by using Azure PowerShell. You need the identity ID when you deploy the template. The format of the identity is:

    /subscriptions/<SubscriptionID>/resourcegroups/<ResourceGroupName>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<IdentityID>
    

    Use the following CLI or PowerShell script to get the ID by providing the resource group name and the identity name.

    echo "Enter the Resource Group name:" &&
    read resourceGroupName &&
    echo "Enter the managed identity name:" &&
    read idName &&
    az identity show -g $resourceGroupName -n $idName --query id
    

Sample templates

The following json is an example. The latest template schema can be found here.

{
  "type": "Microsoft.Resources/deploymentScripts",
  "apiVersion": "2019-10-01-preview",
  "name": "runPowerShellInline",
  "location": "[resourceGroup().location]",
  "kind": "AzurePowerShell", // or "AzureCLI"
  "identity": {
    "type": "userAssigned",
    "userAssignedIdentities": {
      "/subscriptions/01234567-89AB-CDEF-0123-456789ABCDEF/resourceGroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myID": {}
    }
  },
  "properties": {
    "forceUpdateTag": 1,
    "containerSettings": {
      "containerGroupName": "mycustomaci"
    },
    "storageAccountSettings": {
      "storageAccountName": "myStorageAccount",
      "storageAccountKey": "myKey"
    },
    "azPowerShellVersion": "3.0",  // or "azCliVersion": "2.0.80",
    "arguments": "-name \\\"John Dole\\\"",
    "environmentVariables": [
      {
        "name": "someSecret",
        "secureValue": "if this is really a secret, don't put it here... in plain text..."
      }
    ],
    "scriptContent": "
      param([string] $name)
      $output = 'Hello {0}' -f $name
      Write-Output $output
      $DeploymentScriptOutputs = @{}
      $DeploymentScriptOutputs['text'] = $output
    ", // or "primaryScriptUri": "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/deployment-script/deploymentscript-helloworld.ps1",
    "supportingScriptUris":[],
    "timeout": "PT30M",
    "cleanupPreference": "OnSuccess",
    "retentionInterval": "P1D"
  }
}

Note

The example is for demonstration purpose. scriptContent and primaryScriptUri can't coexist in a template.

Property value details:

  • Identity: The deployment script service uses a user-assigned managed identity to execute the scripts. Currently, only user-assigned managed identity is supported.

  • kind: Specify the type of script. Currently, Azure PowerShell and Azure CLI scripts are supported. The values are AzurePowerShell and AzureCLI.

  • forceUpdateTag: Changing this value between template deployments forces the deployment script to re-execute. If you use the newGuid() or the utcNow() function, both functions can only be used in the default value for a parameter. To learn more, see Run script more than once.

  • containerSettings: Specify the settings to customize Azure Container Instance. containerGroupName is for specifying the container group name. If not specified, the group name is automatically generated.

  • storageAccountSettings: Specify the settings to use an existing storage account. If not specified, a storage account is automatically created. See Use an existing storage account.

  • azPowerShellVersion/azCliVersion: Specify the module version to be used. For a list of supported PowerShell and CLI versions, see Prerequisites.

  • arguments: Specify the parameter values. The values are separated by spaces.

    Deployment Scripts splits the arguments into an array of strings by invoking the CommandLineToArgvW system call. This is necessary because the arguments are passed as a command property to Azure Container Instance, and the command property is an array of string.

    If the arguments contain escaped characters, use JsonEscaper to double escaped the characters. Paste your original escaped string into the tool, and then select Escape. The tool outputs a double escaped string. For example, in the previous sample template, The argument is -name \"John Dole\". The escaped string is -name \\\"John dole\\\".

    To pass an ARM template parameter of type object as an argument, convert the object to a string by using the string() function, and then use the replace() function to replace any \" into \\\". For example:

    replace(string(parameters('tables')), '\"', '\\\"')
    

    To see a sample template, select here.

  • environmentVariables: Specify the environment variables to pass over to the script. For more information, see Develop deployment scripts.

  • scriptContent: Specify the script content. To run an external script, use primaryScriptUri instead. For examples, see Use inline script and Use external script.

  • primaryScriptUri: Specify a publicly accessible Url to the primary deployment script with supported file extensions.

  • supportingScriptUris: Specify an array of publicly accessible Urls to supporting files that are called in either ScriptContent or PrimaryScriptUri.

  • timeout: Specify the maximum allowed script execution time specified in the ISO 8601 format. Default value is P1D.

  • cleanupPreference. Specify the preference of cleaning up deployment resources when the script execution gets in a terminal state. Default setting is Always, which means deleting the resources despite the terminal state (Succeeded, Failed, Canceled). To learn more, see Clean up deployment script resources.

  • retentionInterval: Specify the interval for which the service retains the deployment script resources after the deployment script execution reaches a terminal state. The deployment script resources will be deleted when this duration expires. Duration is based on the ISO 8601 pattern. The retention interval is between 1 and 26 hours (PT26H). This property is used when cleanupPreference is set to OnExpiration. The OnExpiration property is not enabled currently. To learn more, see Clean up deployment script resources.

Additional samples

  • Sample 1: create a key vault and use deployment script to assign a certificate to the key vault.
  • Sample 2: create a resource group at the subscription level, create a key vault in the resource group, and then use deployment script to assign a certificate to the key vault.
  • Sample 3: create a user-assigned managed identity, assign the contributor role to the identity at the resource group level, create a key vault, and then use deployment script to assign a certificate to the key vault.

Note

It is recommended to create a user-assigned identity and grant permissions in advance. You might get sign-in and permission related errors if you create the identity and grant permissions in the same template where you run deployment scripts. It takes some time before the permissions to become effective.

Use inline scripts

The following template has one resource defined with the Microsoft.Resources/deploymentScripts type. The highlighted part is the inline script.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "identity": {
      "type": "string"
    },
    "name":{
      "type": "string",
      "defaultValue": "\\\"John Dole\\\""
    },
    "utcValue": {
      "type": "string",
      "defaultValue": "[utcNow()]"
    }
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deploymentScripts",
      "apiVersion": "2019-10-01-preview",
      "name": "runPowerShellInlineWithOutput",
      "location": "[resourceGroup().location]",
      "kind": "AzurePowerShell",
      "identity": {
        "type": "userAssigned",
        "userAssignedIdentities": {
          "[parameters('identity')]": {
          }
        }
      },
      "properties": {
        "forceUpdateTag": "[parameters('utcValue')]",
        "azPowerShellVersion": "3.0",
        "scriptContent": "
          param([string] $name)
          $output = \"Hello {0}\" -f $name
          Write-Output $output
          $DeploymentScriptOutputs = @{}
          $DeploymentScriptOutputs['text'] = $output
        ",
        "arguments": "[concat('-name', ' ', parameters('name'))]",
        "timeout": "PT1H",
        "cleanupPreference": "OnSuccess",
        "retentionInterval": "P1D"
      }
    }
  ],
  "outputs": {
    "result": {
      "value": "[reference('runPowerShellInlineWithOutput').outputs.text]",
      "type": "string"
    }
  }
}

Note

Because the inline deployment scripts are enclosed in double quotes, the strings inside the deployment scripts need to be escaped by using a \ or enclosed in single quotes. You can also consider using string substitution as it is shown in the previous JSON sample.

The script takes one parameter, and output the parameter value. DeploymentScriptOutputs is used for storing outputs. In the outputs section, the value line shows how to access the stored values. Write-Output is used for debugging purpose. To learn how to access the output file, see Monitor and troubleshoot deployment scripts. For the property descriptions, see Sample templates.

To run the script, select Try it to open the Cloud Shell, and then paste the following code into the shell pane.

$resourceGroupName = Read-Host -Prompt "Enter the name of the resource group to be created"
$location = Read-Host -Prompt "Enter the location (i.e. centralus)"
$id = Read-Host -Prompt "Enter the user-assigned managed identity ID"

New-AzResourceGroup -Name $resourceGroupName -Location $location

New-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateUri "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/deployment-script/deploymentscript-helloworld.json" -identity $id

Write-Host "Press [ENTER] to continue ..."

The output looks like:

Resource Manager template deployment script hello world output

Use external scripts

In addition to inline scripts, you can also use external script files. Only primary PowerShell scripts with the ps1 file extension are supported. For CLI scripts, the primary scripts can have any extensions (or without an extension), as long as the scripts are valid bash scripts. To use external script files, replace scriptContent with primaryScriptUri. For example:

"primaryScriptURI": "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/deployment-script/deploymentscript-helloworld.ps1",

To see an example, select here.

The external script files must be accessible. To secure your script files that are stored in Azure storage accounts, see Deploy private ARM template with SAS token.

You are responsible for ensuring the integrity of the scripts that are referenced by deployment script, either PrimaryScriptUri or SupportingScriptUris. Reference only scripts that you trust.

Use supporting scripts

You can separate complicated logics into one or more supporting script files. The supportingScriptUris property allows you to provide an array of URIs to the supporting script files if needed:

"scriptContent": "
    ...
    ./Create-Cert.ps1
    ...
"

"supportingScriptUris": [
  "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/deployment-script/create-cert.ps1"
],

Supporting script files can be called from both inline scripts and primary script files. Supporting script files have no restrictions on the file extension.

The supporting files are copied to azscripts/azscriptinput at the runtime. Use relative path to reference the supporting files from inline scripts and primary script files.

Work with outputs from PowerShell script

The following template shows how to pass values between two deploymentScripts resources:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "identity": {
      "type": "string"
    },
    "name":{
      "type":"string"
    },
    "utcValue": {
      "type": "string",
      "defaultValue": "[utcNow()]"
    }
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deploymentScripts",
      "apiVersion": "2019-10-01-preview",
      "name": "scriptInTemplate1",
      "location": "[resourceGroup().location]",
      "kind": "AzurePowerShell",
      "identity": {
        "type": "userAssigned",
        "userAssignedIdentities": {
          "[parameters('identity')]": {
          }
        }
      },
      "properties": {
        "forceUpdateTag": "[parameters('utcValue')]",
        "azPowerShellVersion": "3.0",
        "timeout": "PT1H",
        "arguments": "[concat('-name', ' ', parameters('name'))]",
        "scriptContent": "
          param([string] $name)
          $output = 'Hello {0}' -f $name
          Write-Output $output
          $DeploymentScriptOutputs = @{}
          $DeploymentScriptOutputs['text'] = $output
        ",
        "cleanupPreference": "Always",
        "retentionInterval": "P1D"
      }
    },
    {
      "type": "Microsoft.Resources/deploymentScripts",
      "apiVersion": "2019-10-01-preview",
      "name": "scriptInTemplate2",
      "location": "[resourceGroup().location]",
      "kind": "AzurePowerShell",
      "identity": {
        "type": "userAssigned",
        "userAssignedIdentities": {
          "[parameters('identity')]": {
          }
        }
      },
      "dependsOn": [
        "scriptInTemplate1"
      ],
      "properties": {
        "forceUpdateTag": "[parameters('utcValue')]",
        "azPowerShellVersion": "3.0",
        "timeout": "PT1H",
        "arguments": "[concat('-textToEcho', ' ', reference('scriptInTemplate1').outputs.text)]",
        "scriptContent": "
          param([string] $textToEcho)
          Write-Output $textToEcho
          $DeploymentScriptOutputs = @{}
          $DeploymentScriptOutputs['text'] = $textToEcho
        ",
        "cleanupPreference": "Always",
        "retentionInterval": "P1D"
      }
    }
  ],
  "outputs": {
    "result": {
      "value": "[reference('scriptInTemplate2').outputs.text]",
      "type": "string"
    }
  }
}

In the first resource, you define a variable called $DeploymentScriptOutputs, and use it to store the output values. To access the output value from another resource within the template, use:

reference('<ResourceName>').output.text

Work with outputs from CLI script

Different from the PowerShell deployment script, CLI/bash support does not expose a common variable to store script outputs, instead, there is an environment variable called AZ_SCRIPTS_OUTPUT_PATH that stores the location where the script outputs file resides. If a deployment script is run from a Resource Manager template, this environment variable is set automatically for you by the Bash shell.

Deployment script outputs must be saved in the AZ_SCRIPTS_OUTPUT_PATH location, and the outputs must be a valid JSON string object. The contents of the file must be saved as a key-value pair. For example, an array of strings is stored as { "MyResult": [ "foo", "bar"] }. Storing just the array results, for example [ "foo", "bar" ], is invalid.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "identity": {
      "type": "string"
    },
    "utcValue": {
      "type": "string",
      "defaultValue": "[utcNow()]"
    }
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deploymentScripts",
      "apiVersion": "2019-10-01-preview",
      "name": "runBashWithOutputs",
      "location": "[resourceGroup().location]",
      "kind": "AzureCLI",
      "identity": {
        "type": "UserAssigned",
        "userAssignedIdentities": {
          "[parameters('identity')]": {
          }
        }
      },
      "properties": {
        "forceUpdateTag": "[parameters('utcValue')]",
        "AzCliVersion": "2.0.80",
        "timeout": "PT30M",
        "arguments": "'foo','bar'",
        "scriptContent": "result=$(az keyvault list); echo \"arg1 is: $1\"; echo \"arg2 is: $2\"; echo $result | jq -c '{Result: map({id: .id})}' > $AZ_SCRIPTS_OUTPUT_PATH",
        "cleanupPreference": "OnSuccess",
        "retentionInterval": "P1D"
      }
    }
  ],
  "outputs": {
    "result": {
      "value": "[reference('runBashWithOutputs').outputs]",
      "type": "object"
    }
  }
}

jq is used in the previous sample. It comes with the container images. See Configure development environment.

Use existing storage account

A storage account and a container instance are needed for script execution and troubleshooting. You have the options to specify an existing storage account, otherwise the storage account along with the container instance are automatically created by the script service. The requirements for using an existing storage account:

  • Supported storage account kinds are:

    SKU Supported Kind
    Premium_LRS FileStorage
    Premium_ZRS FileStorage
    Standard_GRS Storage, StorageV2
    Standard_GZRS StorageV2
    Standard_LRS Storage, StorageV2
    Standard_RAGRS Storage, StorageV2
    Standard_RAGZRS StorageV2
    Standard_ZRS StorageV2

    These combinations support file share. For more information, see Create an Azure file share and Types of storage accounts.

  • Storage account firewall rules are not supported yet. For more information, see Configure Azure Storage firewalls and virtual networks.

  • Deployment script's user-assigned managed identity must have permissions to manage the storage account, which includes read, create, delete file shares.

To specify an existing storage account, add the following json to the property element of Microsoft.Resources/deploymentScripts:

"storageAccountSettings": {
  "storageAccountName": "myStorageAccount",
  "storageAccountKey": "myKey"
},
  • storageAccountName: specify the name of the storage account.

  • storageAccountKey": specify one of the storage account keys. You can use the listKeys() function to retrieve the key. For example:

    "storageAccountSettings": {
        "storageAccountName": "[variables('storageAccountName')]",
        "storageAccountKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2019-06-01').keys[0].value]"
    }
    

See Sample templates for a complete Microsoft.Resources/deploymentScripts definition sample.

When an existing storage account is used, the script service creates a file share with a unique name. See Clean up deployment script resources for how the script service cleans up the file share.

Develop deployment scripts

Handle non-terminating errors

You can control how PowerShell responds to non-terminating errors by using the $ErrorActionPreference variable in your deployment script. If the variable is not set in your deployment script, the script service uses the default value Continue.

The script service sets the resource provisioning state to Failed when the script encounters an error despite the setting of $ErrorActionPreference.

Pass secured strings to deployment script

Setting environment variables (EnvironmentVariable) in your container instances allows you to provide dynamic configuration of the application or script run by the container. Deployment script handles non-secured and secured environment variables in the same way as Azure Container Instance. For more information, see Set environment variables in container instances.

The max allowed size for environment variables is 64KB.

Monitor and troubleshoot deployment scripts

The script service creates a storage account (unless you specify an existing storage account) and a container instance for script execution. If these resources are automatically created by the script service, both resources have the azscripts suffix in the resource names.

Resource Manager template deployment script resource names

The user script, the execution results, and the stdout file are stored in the files shares of the storage account. There is a folder called azscripts. In the folder, there are two more folders for the input and the output files: azscriptinput and azscriptoutput.

The output folder contains a executionresult.json and the script output file. You can see the script execution error message in executionresult.json. The output file is created only when the script is executed successfully. The input folder contains a system PowerShell script file and the user deployment script files. You can replace the user deployment script file with a revised one, and rerun the deployment script from the Azure container instance.

Use the Azure portal

After you deploy a deployment script resource, the resource is listed under the resource group in the Azure portal. The following screenshot shows the Overview page of a deployment script resource:

Resource Manager template deployment script portal overview

The overview page displays some important information of the resource, such as Provisioning state, Storage account, Container instance, and Logs.

From the left menu, you can view the deployment script content, the arguments passed to the script, and the output. You can also export a template for the deployment script including the deployment script.

Use PowerShell

Using Azure PowerShell, you can manage deployment scripts at subscription or resource group scope:

The Get-AzDeploymentScript output is similar to:

Name                : runPowerShellInlineWithOutput
Id                  : /subscriptions/01234567-89AB-CDEF-0123-456789ABCDEF/resourceGroups/myds0618rg/providers/Microsoft.Resources/deploymentScripts/runPowerShellInlineWithOutput
ResourceGroupName   : myds0618rg
Location            : centralus
SubscriptionId      : 01234567-89AB-CDEF-0123-456789ABCDEF
ProvisioningState   : Succeeded
Identity            : /subscriptions/01234567-89AB-CDEF-0123-456789ABCDEF/resourceGroups/mydentity1008rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myuami
ScriptKind          : AzurePowerShell
AzPowerShellVersion : 3.0
StartTime           : 6/18/2020 7:46:45 PM
EndTime             : 6/18/2020 7:49:45 PM
ExpirationDate      : 6/19/2020 7:49:45 PM
CleanupPreference   : OnSuccess
StorageAccountId    : /subscriptions/01234567-89AB-CDEF-0123-456789ABCDEF/resourceGroups/myds0618rg/providers/Microsoft.Storage/storageAccounts/ftnlvo6rlrvo2azscripts
ContainerInstanceId : /subscriptions/01234567-89AB-CDEF-0123-456789ABCDEF/resourceGroups/myds0618rg/providers/Microsoft.ContainerInstance/containerGroups/ftnlvo6rlrvo2azscripts
Outputs             :
                      Key                 Value
                      ==================  ==================
                      text                Hello John Dole

RetentionInterval   : P1D
Timeout             : PT1H

Use Azure CLI

Using Azure CLI, you can manage deployment scripts at subscription or resource group scope:

The list command output is similar to:

[
  {
    "arguments": "-name \\\"John Dole\\\"",
    "azPowerShellVersion": "3.0",
    "cleanupPreference": "OnSuccess",
    "containerSettings": {
      "containerGroupName": null
    },
    "environmentVariables": null,
    "forceUpdateTag": "20200625T025902Z",
    "id": "/subscriptions/01234567-89AB-CDEF-0123-456789ABCDEF/resourceGroups/myds0624rg/providers/Microsoft.Resources/deploymentScripts/runPowerShellInlineWithOutput",
    "identity": {
      "tenantId": "01234567-89AB-CDEF-0123-456789ABCDEF",
      "type": "userAssigned",
      "userAssignedIdentities": {
        "/subscriptions/01234567-89AB-CDEF-0123-456789ABCDEF/resourceGroups/myidentity1008rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myuami": {
          "clientId": "01234567-89AB-CDEF-0123-456789ABCDEF",
          "principalId": "01234567-89AB-CDEF-0123-456789ABCDEF"
        }
      }
    },
    "kind": "AzurePowerShell",
    "location": "centralus",
    "name": "runPowerShellInlineWithOutput",
    "outputs": {
      "text": "Hello John Dole"
    },
    "primaryScriptUri": null,
    "provisioningState": "Succeeded",
    "resourceGroup": "myds0624rg",
    "retentionInterval": "1 day, 0:00:00",
    "scriptContent": "\r\n          param([string] $name)\r\n          $output = \"Hello {0}\" -f $name\r\n          Write-Output $output\r\n          $DeploymentScriptOutputs = @{}\r\n          $DeploymentScriptOutputs['text'] = $output\r\n        ",
    "status": {
      "containerInstanceId": "/subscriptions/01234567-89AB-CDEF-0123-456789ABCDEF/resourceGroups/myds0624rg/providers/Microsoft.ContainerInstance/containerGroups/64lxews2qfa5uazscripts",
      "endTime": "2020-06-25T03:00:16.796923+00:00",
      "error": null,
      "expirationTime": "2020-06-26T03:00:16.796923+00:00",
      "startTime": "2020-06-25T02:59:07.595140+00:00",
      "storageAccountId": "/subscriptions/01234567-89AB-CDEF-0123-456789ABCDEF/resourceGroups/myds0624rg/providers/Microsoft.Storage/storageAccounts/64lxews2qfa5uazscripts"
    },
    "storageAccountSettings": null,
    "supportingScriptUris": null,
    "systemData": {
      "createdAt": "2020-06-25T02:59:04.750195+00:00",
      "createdBy": "someone@contoso.com",
      "createdByType": "User",
      "lastModifiedAt": "2020-06-25T02:59:04.750195+00:00",
      "lastModifiedBy": "someone@contoso.com",
      "lastModifiedByType": "User"
    },
    "tags": null,
    "timeout": "1:00:00",
    "type": "Microsoft.Resources/deploymentScripts"
  }
]

Use Rest API

You can get the deployment script resource deployment information at the resource group level and the subscription level by using REST API:

/subscriptions/<SubscriptionID>/resourcegroups/<ResourceGroupName>/providers/microsoft.resources/deploymentScripts/<DeploymentScriptResourceName>?api-version=2019-10-01-preview
/subscriptions/<SubscriptionID>/providers/microsoft.resources/deploymentScripts?api-version=2019-10-01-preview

The following example uses ARMClient:

armclient login
armclient get /subscriptions/01234567-89AB-CDEF-0123-456789ABCDEF/resourcegroups/myrg/providers/microsoft.resources/deploymentScripts/myDeployementScript?api-version=2019-10-01-preview

The output is similar to:

{
  "kind": "AzurePowerShell",
  "identity": {
    "type": "userAssigned",
    "tenantId": "01234567-89AB-CDEF-0123-456789ABCDEF",
    "userAssignedIdentities": {
      "/subscriptions/01234567-89AB-CDEF-0123-456789ABCDEF/resourceGroups/myidentity1008rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myuami": {
        "principalId": "01234567-89AB-CDEF-0123-456789ABCDEF",
        "clientId": "01234567-89AB-CDEF-0123-456789ABCDEF"
      }
    }
  },
  "location": "centralus",
  "systemData": {
    "createdBy": "someone@contoso.com",
    "createdByType": "User",
    "createdAt": "2020-06-25T02:59:04.7501955Z",
    "lastModifiedBy": "someone@contoso.com",
    "lastModifiedByType": "User",
    "lastModifiedAt": "2020-06-25T02:59:04.7501955Z"
  },
  "properties": {
    "provisioningState": "Succeeded",
    "forceUpdateTag": "20200625T025902Z",
    "azPowerShellVersion": "3.0",
    "scriptContent": "\r\n          param([string] $name)\r\n          $output = \"Hello {0}\" -f $name\r\n          Write-Output $output\r\n          $DeploymentScriptOutputs = @{}\r\n          $DeploymentScriptOutputs['text'] = $output\r\n        ",
    "arguments": "-name \\\"John Dole\\\"",
    "retentionInterval": "P1D",
    "timeout": "PT1H",
    "containerSettings": {},
    "status": {
      "containerInstanceId": "/subscriptions/01234567-89AB-CDEF-0123-456789ABCDEF/resourceGroups/myds0624rg/providers/Microsoft.ContainerInstance/containerGroups/64lxews2qfa5uazscripts",
      "storageAccountId": "/subscriptions/01234567-89AB-CDEF-0123-456789ABCDEF/resourceGroups/myds0624rg/providers/Microsoft.Storage/storageAccounts/64lxews2qfa5uazscripts",
      "startTime": "2020-06-25T02:59:07.5951401Z",
      "endTime": "2020-06-25T03:00:16.7969234Z",
      "expirationTime": "2020-06-26T03:00:16.7969234Z"
    },
    "outputs": {
      "text": "Hello John Dole"
    },
    "cleanupPreference": "OnSuccess"
  },
  "id": "/subscriptions/01234567-89AB-CDEF-0123-456789ABCDEF/resourceGroups/myds0624rg/providers/Microsoft.Resources/deploymentScripts/runPowerShellInlineWithOutput",
  "type": "Microsoft.Resources/deploymentScripts",
  "name": "runPowerShellInlineWithOutput"
}

The following REST API returns the log:

/subscriptions/<SubscriptionID>/resourcegroups/<ResourceGroupName>/providers/microsoft.resources/deploymentScripts/<DeploymentScriptResourceName>/logs?api-version=2019-10-01-preview

It only works before the deployment script resources are deleted.

To see the deploymentScripts resource in the portal, select Show hidden types:

Resource Manager template deployment script, show hidden types, portal

Clean up deployment script resources

A storage account and a container instance are needed for script execution and troubleshooting. You have the options to specify an existing storage account, otherwise a storage account along with a container instance are automatically created by the script service. The two automatically created resources are deleted by the script service when the deployment script execution gets in a terminal state. You are billed for the resources until the resources are deleted. For the price information, see Container Instances pricing and Azure Storage pricing.

The life cycle of these resources is controlled by the following properties in the template:

  • cleanupPreference: Clean up preference when the script execution gets in a terminal state. The supported values are:

    • Always: Delete the automatically created resources once script execution gets in a terminal state. If an existing storage account is used, the script service deletes the file share created in the storage account. Because the deploymentScripts resource may still be present after the resources are cleaned up, the script service persists the script execution results, for example, stdout, outputs, return value, etc. before the resources are deleted.
    • OnSuccess: Delete the automatically created resources only when the script execution is successful. If an existing storage account is used, the script service removes the file share only when the script execution is successful. You can still access the resources to find the debug information.
    • OnExpiration: Delete the automatically created resources only when the retentionInterval setting is expired. If an existing storage account is used, the script service removes the file share, but retain the storage account.
  • retentionInterval: Specify the time interval that a script resource will be retained and after which will be expired and deleted.

Note

It is not recommended to use the storage account and the container instance that are generated by the script service for other purposes. The two resources might be removed depending on the script life cycle.

Run script more than once

Deployment script execution is an idempotent operation. If none of the deploymentScripts resource properties (including the inline script) is changed, the script will not be executed when you redeploy the template. The deployment script service compares the resource names in the template with the existing resources in the same resource group. There are two options if you want to execute the same deployment script multiple times:

  • Change the name of your deploymentScripts resource. For example, use the utcNow template function as the resource name or as a part of the resource name. Changing the resource name creates a new deploymentScripts resource. It is good for keeping a history of script execution.

    Note

    The utcNow function can only be used in the default value for a parameter.

  • Specify a different value in the forceUpdateTag template property. For example, use utcNow as the value.

Note

Write the deployment scripts that are idempotent. This ensures that if they run again accidentally, it will not cause system changes. For example, if the deployment script is used to create an Azure resource, verify the resource doesn't exist before creating it, so the script will succeed or you don't create the resource again.

Configure development environment

You can use a pre-configured container image as your deployment script development environment. For more information, see Configure development environment for deployment scripts in templates.

After the script is tested successfully, you can use it as a deployment script in your templates.

Deployment script error codes

Error code Description
DeploymentScriptInvalidOperation The deployment script resource definition in the template contains invalid property names.
DeploymentScriptResourceConflict Cannot delete a deployment script resource that is in non-terminal state and the execution hasn't exceeded 1 hour. Or cannot re-run the same deployment script with the same resource identifier (same subscription, resource group name, and resource name) but different script body content at the same time.
DeploymentScriptOperationFailed The deployment script operation failed internally. Please contact Microsoft support.
DeploymentScriptStorageAccountAccessKeyNotSpecified The access key hasn't been specified for the existing storage account.
DeploymentScriptContainerGroupContainsInvalidContainers A container group created by the deployment script service got externally modified, and invalid containers got added.
DeploymentScriptContainerGroupInNonterminalState Two or more deployment script resources use the same Azure container instance name in the same resource group, and one of them has not finished its execution yet.
DeploymentScriptStorageAccountInvalidKind The existing storage account of the BlobBlobStorage or BlobStorage type doesn't support file shares, and can't be used.
DeploymentScriptStorageAccountInvalidKindAndSku The existing storage account does not support file shares. For a list of supported storage account kinds, see Use existing storage account.
DeploymentScriptStorageAccountNotFound The storage account doesn't exist or has been deleted by an external process or tool.
DeploymentScriptStorageAccountWithServiceEndpointEnabled The storage account specified has a service endpoint. A storage account with a service endpoint is not supported.
DeploymentScriptStorageAccountInvalidAccessKey Invalid access key specified for the existing storage account.
DeploymentScriptStorageAccountInvalidAccessKeyFormat Invalid storage account key format. See Manage storage account access keys.
DeploymentScriptExceededMaxAllowedTime Deployment script execution time exceeded the timeout value specified in the deployment script resource definition.
DeploymentScriptInvalidOutputs The deployment script output is not a valid JSON object.
DeploymentScriptContainerInstancesServiceLoginFailure The user-assigned managed identity was not able to login after 10 attempts with 1-minute interval.
DeploymentScriptContainerGroupNotFound A Container group created by deployment script service got deleted by an external tool or process.
DeploymentScriptDownloadFailure Failed to download a supporting script. See Use supporting script.
DeploymentScriptError The user script threw an error.
DeploymentScriptBootstrapScriptExecutionFailed The bootstrap script threw an error. Bootstrap script is the system script that orchestrates the deployment script execution.
DeploymentScriptExecutionFailed Unknown error during the deployment script execution.
DeploymentScriptContainerInstancesServiceUnavailable When creating the Azure container instance (ACI), ACI threw a service unavailable error.
DeploymentScriptContainerGroupInNonterminalState When creating the Azure container instance (ACI), another deployment script is using the same ACI name in the same scope (same subscription, resource group name, and resource name).
DeploymentScriptContainerGroupNameInvalid The Azure container instance name (ACI) specified doesn't meet the ACI requirements. See Troubleshoot common issues in Azure Container Instances.

Next steps

In this article, you learned how to use deployment scripts. To walk through a deployment script tutorial: