Menu Close

Create an Azure DevOps service connection to Azure with PowerShell

One of the benefits of the Azure DevOps pipeline is it’s direct connection to Azure. This helps with quick deployment and management of an Azure subscription through the Azure DevOps pipeline. If your Azure subscription is in the same tenant as your Azure DevOps account, you can create an Azure DevOps Service connection to Azure in no time, as long as your account has the correct permissions. You just sign in at the service connection page and you’re done. But another option you have is to create a connection manually. This gives more flexibility. In this post, I will show a script that can help you create a Azure DevOps service connection to Azure with PowerShell.

I have written a post about this previously. It shows the step-by-step process to set up the manually connection. If you are new to that process, I recommend to look into that post first, as it helps to learn the process. But I found myself getting lazy and constantly using the same (test) projects as I couldn’t be bothered to create a new connection. So I decided to automate the whole thing.

But why?

There are a few use cases for manually creating a service connection:

  • You want to manage the permissions for the service connection.
    This is something you should consider, as the service connection is available for everyone in the project with permissions to run pipelines, without extra verification. This means that if you have a service connection that has contributor rights to the subscription (the default setting), you give users in the project the same access!
  • You want to deploy resources to a different Azure tenant.
    Azure DevOps is connected to an Azure AD Tenant. You will be able to create a connection to every subscription you can access based on your account in that tenant. If you want to access a subscription outside of that scope, you will need to create the connection manually.

What does the script do?

The process of creating a manual connection will be completely automated by using the script. It takes care of the Service principal in Azure. After that a service connection will be created in an Azure DevOps project. You are then able to use the connection to connect to Azure from a pipeline, for example to deploy ARM templates or for Azure PowerShell. I have written about some pipeline options in this post.

To know a little bit more about the Azure DevOps REST API that is used, you could read this post.

Prerequisites

To use this script, there are a few things you need to take care of:

  • A PAT token in Azure DevOps. You can find how you can create one here. Take note of the permissions you need, because the PAT token doesn’t need full access. You want to select Service Connections: Read, query and manage.

    You can find that option by clicking show all scopes at the bottom.
  • A connection with Azure. The script makes use of the Az PowerShell module. You need to sign in to Azure with an account that has owner permissions to the specified subscription. The reason for that is that the owner for the scoped Azure resource group or subscription. It also needs permissions to create a service principal.

Get the script

There are two ways for you to get the script.

Install from the PowerShell Gallery

I have added the script as a module to the PowerShell gallery for easy access. To download it, use the following commands

Install-Module -Name NewAzDoServiceConnection
Import-Module -Name NewAzDoServiceConnection

Download from GitHub

If you can’t or don’t want to install a module, you can collect the script from the GitHub repository.
To do this, you can clone it, fork it or download it as a zip.

You can find the repo here

Use the script

To use the script, you need to define quite some parameters. I will quickly walk through them:

AzServicePrincipalName

The name the Service Principal in Azure. The script creates this principal. This name has to be unique in your tenant.

AzSubscriptionName

The name of the subscription that the service connection will connect to.
If no Azresourcegroupscope is added, the service principal will get permissions to this subscription.

AzResourceGroupScope

You can optionally define a resource group that the service principal will get permissions for. This way the connection will not get permissions to the complete subscription.

AzRole

The AzRoleDefinition that the Service principal will use, like contributor or owner. If not defined, this will default to Contributor.

AzDoOrganizationName

The organization name in Azure DevOps, so the part that comes directly after https://dev.azure.com/

AzDoProjectName

The project name in Azure DevOps

AzDoConnectionName

The name you choose for your Azure DevOps Connection. This will be how you call the connection in a pipeline.
If left empty, it defaults to the name of the subscription without spaces.

AzDoUserName

The username to use to connect to Azure DevOps

AzDoToken

The PAT token to use to connect to Azure DevOps

Run the cmdlet

So with that information, the complete cmdlet would look like something like this:

Note: This cmdlet can take some time to run, depending on your connections and if you have already imported the AZ module. If you want to be kept up to date on the progress, use the -verbose parameter.

Azure DevOps service connection to Azure with PowerShell: example of PowerShell window

This will create the following:

  • In Azure: a service principal called example with owner permissions to the resourcegroup RG01
  • In Azure DevOps: a connection in the Azure DevOps organization AzDoCompany for project AzureDeployment.

Azure DevOps service connection to Azure with PowerShell: finished service connection

Conclusion

So this is how you can setup a Azure DevOps service connection to Azure with PowerShell. I hope this works well for you. If you have any issues, let me know in the comments or in the GitHub issues.

11 Comments

  1. Darren

    Hi. Can the above function be used to create a Service Connection based on a different domain account, for example, I want to create a Service Connection to an Azure Container Registry, but it mustn’t be linked back to any regular user domain account in any way, but rather to a service account?

    I think, based on the requirement to have an ADO PAT token created, that it would have to be under my own user account, but hoping you might be able to offer that functionality…

    Thanks
    Darren

    • Barbara

      Hi Darren,
      Basically what you can use here is two separate account.
      One of the accounts is the service principal in Azure. This is an app registration in Azure AD. You give that principal the right permission in Azure, so for your case that account would get permission to the Container registry.

      The other account you need is an account with permissions in Azure DevOps to create a service connection. These do not have to be the same account at all. In Azure DevOps, you can actually create the PAT key from your own account, use it to create the connection and then delete the PAT key. That way there is no compromise of your credentials.

      Hope this helps you,

      Barbara

  2. Jamie Hebbs

    Hi, this looks like a great script and will save me heaps of time. However, after creating the SPN, I get the following error:-

    ConvertFrom-SecureString : A parameter cannot be found that matches parameter name ‘AsPlainText’.
    At C:\Users\JamieHebbs\Documents\WindowsPowerShell\Modules\NewAzDoServiceConnection\0.0.3\NewAzDoServiceConnection.psm1:178 char:92
    + … = ($ServicePrincipal.Secret | ConvertFrom-SecureString -AsPlainText)
    + ~~~~~~~~~~~~
    + CategoryInfo : InvalidArgument: (:) [ConvertFrom-SecureString], ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.ConvertFromSecureStringCommand

    ConvertFrom-Json : Invalid JSON primitive: The.
    At C:\Users\JamieHebbs\Documents\WindowsPowerShell\Modules\NewAzDoServiceConnection\0.0.3\NewAzDoServiceConnection.psm1:208 char:30
    + $ErrorMessage = $_ | ConvertFrom-Json
    + ~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [ConvertFrom-Json], ArgumentException
    + FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.ConvertFromJsonCommand

    Any ideas ?

    • Barbara

      Hi Jamie,
      Good catch!
      Are you by any chance using Windows PowerShell version 5.1? I have only tested the cmdlet in PowerShell version 6+ and just found this error shows up in Windows PowerShell.

      I have made an issue in the GitHub repository to fix this, so it can be kept track off: https://github.com/Ba4bes/New-AzDoServiceConnection/issues/1.
      In the mean time, you could use PowerShell version 6+ as a workaround

  3. Boudewijn Plomp

    I like this PowerShell Module. Unfortunately I can’t use it, because we need to create a manual Service Connections to a Management Group. Is there a way to build this?

  4. Graham Hardie

    Good afternoon Barbara,
    Thank you for a great module. Does exactly what it says on the tin. Intrigue to know how you retrieved the Security Key of the SPN. Did you define this up front when you created it?
    Thanks, G

  5. Mike Fleming

    Hi,

    I get

    ConvertFrom-Json: Conversion from JSON failed with error: Unexpected character encountered while parsing value: R. Path ”, line 0, position 0.

    $Parameters

    Name Value
    —- —–
    AzResourceGroupScope rg-redacted-dev-westeur-001
    AzDoToken redacted
    AzRole contributor
    AzSubscriptionName Enterprise Dev/Test
    AzDoProjectName Lab
    AzDoUserName redacted@redacted.com
    AzServicePrincipalName BicepTestPipeline-Dev
    AzDoOrganizationName redacted

    New-AzDoServiceConnection @Parameters -Verbose
    VERBOSE: Starting Function New-AzDoServiceConnection
    VERBOSE: Changing Context to redacted
    VERBOSE: Resourcegroup exists
    VERBOSE: Scope set: /subscriptions/redacted75-ae2c7e3c7909/resourceGroups/redacted
    VERBOSE: Created ServicePrincipal BicepTestPipeline-Dev
    VERBOSE: HTTP/1.1 GET with 0-byte payload
    VERBOSE: received 0-byte response of content type
    ConvertFrom-Json: Conversion from JSON failed with error: Unexpected character encountered while parsing value: R. Path ”, line 0, position 0.
    VERBOSE: Collected ID:
    VERBOSE: Populating RepositorySourceLocation property for module Az.Resources.
    VERBOSE: Populating RepositorySourceLocation property for module Az.Resources.
    VERBOSE: Creating Connection
    VERBOSE: HTTP/1.1 POST with 883-byte payload
    VERBOSE: received 0-byte response of content type
    ConvertFrom-Json: Conversion from JSON failed with error: Unexpected character encountered while parsing value: R. Path ”, line 0, position 0.
    VERBOSE: Connection Created

    $PSVersionTable

    Name Value
    —- —–
    PSVersion 7.3.3
    PSEdition Core
    GitCommitId 7.3.3
    OS Microsoft Windows 10.0.22621
    Platform Win32NT
    PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
    PSRemotingProtocolVersion 2.3
    SerializationVersion 1.1.0.1
    WSManStackVersion 3.0

Leave a Reply

Your email address will not be published. Required fields are marked *