How to connect to azure devops from powershell in yaml pipelines? - powershell

We are trying to execute this az devops service-endpoint list in a powershell script added in a pipeline in yaml from Azure DevOps
$SubscriptionId = az devops service-endpoint list --organization "https://dev.azure.com/xxxxx" --project $ProjectName --query "[?data.subscriptionName==$SubscriptionName].data.subscriptionId" -o tsv
For executing the command above, The logs tell that we need to login using az devops login --organization https://dev.azure.com/xxxx/ , how do we do this in the pipeline?
Also we use the system access token variable for logging in like this:
$env:AZURE_DEVOPS_EXT_PAT = $env:SYSTEM_ACCESSTOKEN

Thank you Tejas Nagchandi. Posting your suggestion as an answer so that it will be helpful for other community members as well who is facing similar kind of issues.
Below is the sample code of Azure CLI task and try to use that by which you can pass a service connection as input and with the help of this task no need to use az-login as well.
- task: AzureCLI#2
displayName: Azure CLI
inputs:
azureSubscription: <Name of the Azure Resource Manager service connection>
scriptType: ps
scriptLocation: inlineScript
inlineScript: |
az --version
az account show
for further details check the Azure CLI task documentation.

Related

Azure DevOps 'az batch node list' with PowerShell ConvertFrom-Json not working [duplicate]

This question already has an answer here:
Call API inside powershell function
(1 answer)
Closed 3 months ago.
I am working in Azure DevOps, creating an automated build process.
Doing the PowerShell command:
$batchNodes = az batch node list --pool-id $poolId
...results in a json structure complete with all Nodes in my Pool, and all Node details. I am only looking for a list of node ids though, because I need to restart each Node in the Pool, which requires a Node id.
I expected this PowerShell command to work, but it doesn't. ($batchNodes is blank)
$batchNodes = az batch node list --pool-id $poolId | ConvertFrom-Json
Is there a fancier or simpler method I can use to get an array of Node id values from the 'az batch node list' command results?
I'm using PowerShell 7.2. If you know of some way to restart all of the Nodes in a Pool, please share this information.
Much thanks.
For using Azure Cli, you could use Azure Cli task in Azure DevOps services to run the Azure Cli.
This is my sample:
steps:
- task: AzureCLI#2
displayName: 'Azure CLI '
inputs:
azureSubscription: 'internalsub-wsupport'
scriptType: pscore
scriptLocation: inlineScript
inlineScript: |
$batchNodes = az batch node list --pool-id mypoolwutong --account-name vwutong196420 --account-endpoint vwutong196420.eastasia.batch.azure.com | ConvertFrom-Json
This is the output:
Hope that could do some help.
It turns out my code was working. I was trying to output the result incorrectly. This works:
$batchNodes = (az batch node list --pool-id $poolId) | ConvertFrom-Json
Write-Output "batchNodes:"
Write-Output "Index 0: $($batchNodes[0])"

How to install an Azure Key Vault certificate in an Azure DevOps pipeline?

Question says it all. I struggled with doing this so I'm going to answer my own question.
Maybe people have some suggestions/modifications but here's what we got working with some PowerShell commands.
Set up an Azure Resource Manager connection that has permission to access the Key Vault.
In the Azure portal, you can do this in "Access policies" in the Key Vault.
Give the application Get, List, and Backup permission.
In your CI YAML file:
- task: AzureCLI#2
displayName: "Install Certificate"
inputs:
azureSubscription: '<Your Azure Resource Manager connection name>'
scriptType: 'ps'
scriptLocation: 'inlineScript'
addSpnToEnvironment: true
inlineScript: |
Set-PSDebug -Trace 1
$vaultName="<Your Key Vault name>"
$certName="<Your certificate name in the Key Vault>"
az keyvault secret show --vault-name $vaultName --name $certName | ConvertFrom-Json | Select-Object -Expand value > certName.pfx
Import-PfxCertificate -FilePath certName.pfx Cert:\CurrentUser\My

Get secret value from azure key vault in variable in powershell script

I need to set secret value from azure key vault into a variable to be used in further task. I tried below script but it gives error: Could not find the modules: 'Az.Accounts' with Version: ''.
I understand that I can use variable directly but it needs to be set to a common variable since I am building generic pipeline
Script I tried:
- task: AzurePowerShell#4
inputs:
azureSubscription: 'SUB1'
ScriptType: 'InlineScript'
Inline: |
$secret = Get-AzKeyVaultSecret -VaultName '$(KeyVaultName)' -Name $(sqlServerAdminUsername)
$ssPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secret.SecretValue)
try {
$SqlServerUsername = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ssPtr)
} finally {
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ssPtr)
}
azurePowerShellVersion: 'LatestVersion'
pwsh: true
condition: and(succeeded(), eq(variables['EnvironmentType'], 'Dev'))
Check out this similar issue.
Fixes can be:
Try switching to version 3 and 5 of Powershell task and run.
Run the Powershell V4 task in Linux hosted Agents instead of Windows.
Run this powershell screipt from Azure CLI task.

Use Azure DevOps service principal details in Azure Powershell task

When writing an Azure CLI script in a Azure DevOps pipeline you can get access to the the serviceprincpal id, key and tenantid. Is there a way to get this info in a Azure Powershell task?
The addSpnToEnvironment input which adds service principal id and key of the Azure endpoint you chose to the script's context is one option available only in Azure ClI Task, but not Azure Powershell Task.
Is there a way to get this info in a Azure Powershell task?
As an alternative workaround, we can define job-scoped variables in Azure ClI Task, check this document.
Steps to test:
1.Using latest Azure CLI task 2.0-preview and choose Powershell type. Try inline script like this:
Write-Host "##vso[task.setvariable variable=SpId;]$env:servicePrincipalId"
Write-Host "##vso[task.setvariable variable=SpKey;]$env:servicePrincipalKey"
Write-Host "##vso[task.setvariable variable=TenantId;]$env:tenantId"
Write-Host "##vso[task.setvariable variable=TestVar;]JustForTest"
2.Then add one Azure Powershell task after Azure CLI Task to test:
Write-Host $env:SpId
Write-Host $env:SpKey
Write-Host $env:TenantId
Write-Host $env:TestVar
3.Output:
So if you define the job-scoped variables using Write-Host "##vso[task.setvariable variable=xxx]xxx"(Powershell) or echo "##vso[task.setvariable variable=xxx]xxx"(Batch), you can then use something like $env:VariableName to access the info. The *** in log is because these are secrets projected by Azure Devops, so they're masked.
You can invoke a powershell script via Azure CLI task and use the 'addSpnToEnvironment' flag as explained in accepted answer.
- task: AzureCLI#2
displayName: 'Custom ps script'
inputs:
azureSubscription: ${{ parameters.serviceConnection }}
addSpnToEnvironment: true # Adds DevOps SP details to context
scriptType: pscore
scriptPath: '$(System.DefaultWorkingDirectory)/somescript.ps1'

Use Azure CLI within Azure Powershell Task

I want to create a Powershell script which executes some AzureRm... commands and follows those up with some Az commands. Reason being that some commands are only available via Az.
When trying to execute these scripts in a release pipeline, the script always fails with the following error:
ERROR: Please run 'az login' to setup account.
Executing the Az commands in a Azure CLI task work as expected, because Az Login is executed by the task.
I don't want to pass the secret required to login to the script if at all possible. I would rather fall back to separating the scripts into two steps in the pipeline.
Is it possible to use the Azcommands within a Azure Powershell task without passing the secrets manually?
Minimal example:
Create a new release pipeline
Add a task Azure PowerShell
Use inline script
As script, execute az account show
The short term solution I already had in place was passing the ServicePrincipal information into the powershell script and executing az login manually (same as Bevan's answer below).
My long term solution was to replace all Azure CLI calls with "Az Powershell" commands.
Luckily, most commands are available by now.
A couple of commands don't have an equivalent commandlet. But if they are available via ARM, you can figure out an alternative command with Powershell.
Many of them involve using New-AzResource/New-AzureRmResource or Invoke-AzResourceAction/Invoke-AzureRmResourceAction
How to create a Linux AppService Plan with New-AzAppServicePlan?
Manage Azure Cosmos DB SQL API resources using PowerShell
# AzureCLI
az cosmosdb list-keys
# Powershell:
$keys = Invoke-AzResourceAction -Action listKeys `
-ResourceType "Microsoft.DocumentDb/databaseAccounts" -ApiVersion "2015-04-08" `
-ResourceGroupName $resourceGroupName -Name $accountName
When I have mixed commands I put this into my Azure Powershell task
az login --service-principal --username "$(ServicePrincipal)" --password "$(AzureDevOps-ServicePrincipal-Secret)" --tenant "$(Azure_Tenant)"
I have my SP and Tenant IDs as a variables and the Secret for the SP stored in Azure KeyVault linked to a Library Variable group. You can alternatively just stored the secret in a normal Variable/Variable Group and hit the padlock icon to secure it.
You may need to run az account set -s $(SubscriptionName) if the SP has access to multiple subscriptions in the same tenant.
I figured out this approach - store credentials in job scoped variables (currently only an Azure CLI task allows that) and then re-use in Azure PowerShell task:
- task: AzureCLI#2
displayName: 'Azure CLI - get credentials'
inputs:
azureSubscription: 'SUBSCRIPTIONNAME'
scriptType: 'pscore'
scriptLocation: 'inlineScript'
addSpnToEnvironment: true
inlineScript: |
Write-Host "##vso[task.setvariable variable=ARM_CLIENT_ID]$($env:servicePrincipalId)"
Write-Host "##vso[task.setvariable variable=ARM_CLIENT_SECRET]$($env:servicePrincipalKey)"
Write-Host "##vso[task.setvariable variable=ARM_TENANT_ID]$($env:tenantId)"
- task: AzurePowerShell#5
displayName: 'collector'
inputs:
azurePowerShellVersion: LatestVersion
azureSubscription: 'SUBSCRIPTIONNAME'
pwsh: true
scriptType: inlineScript
inline: |
az login --service-principal --username "$($env:ARM_CLIENT_ID)" --password "$($env:ARM_CLIENT_SECRET)" --tenant "$($env:ARM_TENANT_ID)"
./mixedscript.ps1
Anyway, it wont work like that, because you have to authenticate to az utility separately. az cli and powershell do not share connection information. you can try and use az step with some command before powershell step. that would force az to auth and after that you can use it inside powershell ste.