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.
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.
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.
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
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
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 ?
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
Can we specify multiple resource groups?
Thanks
Hi Spardin,
At this time, that is not possible. Would you mind creating an issue for that at the GitHub repository? https://github.com/Ba4bes/New-AzDoServiceConnection/issues
Then I can look into adding that feature.
Thank you
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?
Hi Boudewijn,
Thank you for your comment. I can look into that if I can find time. Could you create an issue for that on the GitHub repository? https://github.com/Ba4bes/New-AzDoServiceConnection/issues
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
Hi Graham,
you could look at this post: https://4bes.nl/2019/07/11/step-by-step-manually-create-an-azure-devops-service-connection-to-azure/
There I describe how to create a secret. When you create a SPN through PowerShell, it is created automatically and that is the one I use here.
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