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

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.

Related

How to use key vault secret on Powershell that run on DevOps pipeline

everyone,
There are 2 tasks in my DevOps pipeline, the first is for getting the secret value from Azure Key Vault,
trigger: none
jobs:
- job: PBICDSolution
pool:
vmImage: windows-latest
steps:
- checkout: self
- task: AzureKeyVault#2
inputs:
azureSubscription: '<my subscription>'
KeyVaultName: 'PA01'
SecretsFilter: '<my secret name>'
RunAsPreJob: false
Next I want to use this secret value inside my powershell script for login a service principal account. Here is my powershell code,
$azureAplicationId = "<my service principal client id>"
$azureTenantId= "<my tanant id>"
Write-Output "Generate Credential"
$azurePassword = ConvertTo-SecureString <here should be the variable of AKV secret value> -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($azureAplicationId , $azurePassword)
Write-Output "Login SP"
Connect-PowerBIServiceAccount -Tenant $azureTenantId -ServicePrincipal -Credential $psCred
Here is the pipeline yml code for above task,
- task: AzurePowerShell#5
inputs:
azureSubscription: '<my subscripton name>'
ScriptType: 'FilePath'
ScriptPath: '$(Build.SourcesDirectory)\<my ps file name>.ps1'
ScriptArguments: '<how can i set the variable here?>'
azurePowerShellVersion: 'LatestVersion'
So the question is here, how can I get the output value from task1, then pass this value into task2 (PowerShell script)?
I have refer to this docs but it's not helpful since I don't need to download the secret to a txt file.
Any solution would be grateful!
how can I get the output value from task1, then pass this value into task2 (PowerShell script)?
The key vault you downloaded in the azure key vault task can be used as a Pipeline variable.
Refer to the following steps to use the Key vault.
In Azure Powershell Task, you can define the arguement: -azurePassword $(azurePassword)
For example:
- task: AzurePowerShell#5
displayName: 'Azure PowerShell script: FilePath'
inputs:
azureSubscription: xx
ScriptPath: test.ps1
ScriptArguments: '-azurePassword $(azurePassword)'
preferredAzurePowerShellVersion: 3.1.0
In Powershell file, you can define the param.
For example:
param (
[string]$azurePassword
)

##[error]Required: 'ConnectedServiceNameARM' input --- Azure DevOps

##[error]Required: 'ConnectedServiceNameARM' input
This is in Azure DevOps using YAML inline script.
Need help with what to enter to fix this error? I am really new at YAML. This is a inline YAML and what tried seems to break the YAML script. The ConnectedServiceNameARM is just the Azure Subscription name? My service connection in azure devops has a working azure subscription name so I am wondering what is wrong?
Also need this YAML code to run so that the output file is placed in agent/_work/_tasks folder and not the artifacts folder. How would I move the file from the _tasks/Powershell folder to something that can be copied to share?
trigger:
- main
pool:
name: 'CloudUiPath001'
demands:
- agent.name -equals UiPathAgent01
steps:
- task: AzurePowerShell#3
displayName: 'Azure PowerShell script: InlineScript'
inputs:
ScriptType: InlineScript
Inline: |
$filePath='C:\Program Files (x86)\UiPath\Studio'
$dir=(New-Object -com scripting.filesystemobject).getFolder($filePath).ShortPath
$ProjectFilePath= "$(System.DefaultWorkingDirectory)/_TESTREPO7/project.json"
$ExecutableFilePath=$dir+"\UiPath.Studio.CommandLine.exe"
$OutputFilePath=".\$(Get-Date -Format 'yyyy-MM-dd-HH-mm-ss')-Workflow-Analysis.json"
#This was an attempt to write the filename to a pipeline variable: Feel free to continue on this path if possible
Write-Host "##vso[task.setvariable variable=jsonFilePath]$OutputFilePath"
Write-Output "$(Get-Date -Format 'HH:mm:ss') - STARTED - Workflow Analyzer CLI Script"
$Command = "$ExecutableFilePath analyze -p $ProjectFilePath"
Invoke-Expression $Command | Out-File -FilePath $OutputFilePath
Write-Output "$(Get-Date -Format 'HH:mm:ss') - COMPLETED - Workflow Analyzer CLI Script"
azurePowerShellVersion: LatestVersion
How do I fix his error within a INLINE YAML script. I am new to YAML and when I tried to enter a input I got errors.
##[error]Required: 'ConnectedServiceNameARM' input
According to your AzurePowerShell task definition, you don’t seem to specify the azureSubscription field.
steps:
- task: AzurePowerShell#5
displayName: 'Azure PowerShell script: InlineScript'
inputs:
azureSubscription: 'xxx'
ScriptType: InlineScript
Inline: xxx
azurePowerShellVersion: 'LatestVersion'
You can click the Settings shown in the figure below to specify the subscription.
About Azure PowerShell task, please refer to this document for details.
to go around this error change from task: AzurePowerShell#5 to pwsh:
- pwsh: |
InlineScript
displayName: 'Azure PowerShell script: InlineScript'

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'

Pass build variables to powershell inline script in Azure DevOps pipeline

I have set a build variable which I would like to consume in my inline powershell script.
I tried $($myvariable) but this comes out blank.
Pass build variables to powerhshell inline script in Azure DevOps
To get the build variables with inline power shell script, you can try to use following syntax $env:variable:
$env:myvariable
The build variable:
The build result:
Note:At this moment, the value of nested variables (like $(myvariable$(Build.SourceBranchName))) on build variables table are not yet supported in the build pipelines.
Hope this helps.
here's what's working for me:
$(variableName)
for example built-in variable called Build.BuildNumber can be accessed like so:
$(Build.BuildNumber)
full example with format function:
- task: AzurePowerShell#3
displayName: UpdatePrereq
inputs:
azureSubscription: ${{ parameters.azureSubscription }}
ScriptType: InlineScript
Inline: |
${{ format('. $(Build.Repository.LocalPath)\scripts\_helpers.ps1
Update-DeploymentPrereq -resourceGroup {1} -location {3}
Update-Prereq -pathSuffix {0} -pathBase $(Build.Repository.LocalPath) -resourceGroup {1} -buildId $(Build.BuildNumber) -paramFile {2}
Update-DeploymentConcurrency -resourceGroup {1} -buildId $(Build.BuildNumber)',
parameters.buildDir, parameters.resourceGroupName, parameters.paramFile, parameters.location ) }}
azurePowerShellVersion: LatestVersion
If you need to use nested variables you can use something like this:
$name = "CONNECTIONSTRING_$(Agent.MachineName)"
$val = [System.Environment]::GetEnvironmentVariable($name)
And then you get the value of the variable ConnectionString.MACHINENAME

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.