This question already has answers here:
How do I copy over all secrets from one Azure Keyvault to another using Powershell
(7 answers)
Closed 1 year ago.
All,
I have the below Azure DevOps pipeline setup that copy keyvault secrets from one KV to another. As you can see, I have two tasks: 1) one to read the secrets and 2) one to write the secrets. I am having difficulties figuring out how to pass the "$secrets" variable (thru "echo "##vso[task.setVariable variable=sourceSecrets]$json") from the first task to the second task.
stages:
- stage: "Test1"
displayName: "Test1 - Copy KV"
jobs:
- deployment : "Deploy"
timeoutInMinutes: 120
variables:
sourceSecrets: ""
strategy:
runOnce:
deploy:
steps:
- task: AzureCLI#2
inputs:
azureSubscription: $(ServiceConnection1)
scriptType: 'pscore'
scriptLocation: 'inlineScript'
inlineScript: |
if ("$(mysubscription1)"){
az account set --subscription "mysubscription1"
}
$secNames = az keyvault secret list --vault-name "kvName1" -o json --query "[].name" | ConvertFrom-Json
Write-Host 'Reading secrets...'
$secrets = $secNames | % {
$secret = az keyvault secret show --name $_ --vault-name "kvName1" -o json | ConvertFrom-Json
[PSCustomObject]#{
name = $_;
value = $secret.value;
}
}
$json = $($secrets | ConvertTo-Json)
echo "##vso[task.setVariable variable=sourceSecrets]$json"
- task: AzureCLI#2
inputs:
azureSubscription: $(ServiceConnection2)
scriptType: 'pscore'
scriptLocation: 'inlineScript'
inlineScript: |
if ("$(mysubscription2)"){
az account set --subscription $(mysubscription2)
}
$secrets = "$(sourceSecrets)" | ConvertFrom-Json
$secrets.foreach{
Write-Host 'Writing secrets:'
az keyvault secret set --vault-name $(kvName2) --name $_.name --value $_.value --output none
Write-Host '---->' $_.name
}
When the pipeline executes, tasks one executes fine. However, the 2nd task errored out with the following:
ConvertFrom-Json : Conversion from JSON failed with error: Error reading JArray from JsonReader. Path '', line 1, position 1.
At /home/vsts/work/_temp/azureclitaskscript1620360635888_inlinescript.ps1:4 char:18
+ $secrets = "[" | ConvertFrom-Json
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [ConvertFrom-Json], ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.ConvertFromJsonCommand
I did some checking, it appears the $(sourceSecrets) variable contain only "[" instead of the entire json content. This means the "echo "##vso[task.setVariable variable=sourceSecrets]$json" line from the first task is excluding everything after "[". I can't figure out why it is doing that. Ideas?
Thanks in advance.
Generally, the value of the pipeline variable only supports string type, and should be a single line string. If you pass a multi-line content to a pipeline variable, normally only the first line will be received as the value of the variable.
In your case, the value you pass to the variable is a JSON object that contains multi-line content.
To avoid the issue you are facing, you should convert the content of the JSON object to be a single line string before passing it to the pipeline variable.
To convert a multi-line string to be a single line string, you can try the command lines below:
. . .
# escape '%', '\n' and '\r'
json="${json//'%'/'%25'}"
json="${json//$'\n'/'%0A'}"
json="${json//$'\r'/'%0D'}"
echo "##vso[task.setVariable variable=sourceSecrets]$json"
Related
I am using the following script:
Run ADF Post-Deployment Powershell Script (Starts Triggers)
- task: AzurePowerShell#5
displayName: 'ADF Post-Deployment Script'
inputs:
azureSubscription: 'SC-Azure-Dev-Subscription' ## This input doesn't accept variables and has to be hard coded
ScriptType: 'FilePath'
ScriptPath: '$(Pipeline.Workspace)/ArmTemplates/PrePostDeploymentScript.ps1'
ScriptArguments: '-armTemplate "$(Pipeline.Workspace)/ArmTemplates/ARMTemplateForFactory.json" -ResourceGroupName $(resourceGroupName) -DataFactoryName $(dataFactoryName) -predeployment $false -deleteDeployment $true'
azurePowerShellVersion: LatestVersion
pwsh: true
This is giving me error at line 680: | ConvertFrom-Json -Depth 10
Error: ##[error] Conversion from JSON failed with error: Bad JSON escape sequence: \s. Path 'properties.pipelines[0].parameters.pVMSQLUserName', line 31, position 36. from Line: 680
##[error]Conversion from JSON failed with error: Bad JSON escape sequence: \s. Path 'properties.pipelines[0].parameters.pVMSQLUserName', line 31, position 36.
##[error]PowerShell exited with code '1'.
I even tried powershell core but still facing this issue
I want to create a Pipeline that is copying files from one Azure subscription to the next one in one Azure DevOps Pipeline.
For this I have setup my pipeline yaml and my two powershell scripts where the parameters are created via logging commands and passed to the second powershell task as arguments.
Pipeline.yaml
trigger:
- none
pool:
vmImage: ubuntu-latest
steps:
- task: AzurePowerShell#5
inputs:
ScriptType: filePath
ScriptPath: '$(System.DefaultWorkingDirectory)/Task.ps1'
azureSubscription: 'Sub1'
azurePowerShellVersion: latestVersion
displayName: 'Task 1'
- task: AzurePowerShell#5
inputs:
ScriptType: filePath
ScriptPath: '$(System.DefaultWorkingDirectory)/Task2.ps1'
azureSubscription: 'Sub2'
azurePowerShellVersion: latestVersion
ScriptArguments: >
-DestAcc "$(DestAcc)"
-DestKey "$(DestKey)"
-DestContext "$(DestContext)"
-DestStorageContainer "$(DestStorageContainer)"
displayName: 'Task 2'
Task1.ps1
$location="germanywestcentral"
$rg="rg1"
$StorageAccountName="storage1"
$StorageSku="Standard_ZRS"
$StorageKind="StorageV2"
$StorageContainer="blobcontainer"
$StorageAccount=Get-AzStorageAccount -ResourceGroupName $rg -Name $StorageAccountName
$storageAccountKey=(Get-AzStorageAccountKey -ResourceGroupName $rg -Name $StorageAccountName).Value[0]
$StorageAccountContext=$StorageAccount.Context
Write-Host "##vso[task.setvariable variable=DestStorageContainer;]$StorageContainer"
Write-Host "##vso[task.setvariable variable=DestKey;]$storageAccountKey"
Write-Host "##vso[task.setvariable variable=DestContext;]$StorageAccountContext"
Write-Host "##vso[task.setvariable variable=DestAcc;]$StorageAccountName"
Task2.ps1
param (
[string] $DestStorageContainer,
[string] $DestUrl,
[string] $DestKey,
[object] $DestContext,
[string] $DestAcc
)
$subscriptionId=(Get-AzSubscription).Id
$resourceGroupName ="rg2"
$diskName = "DD"
$DestFileName="Filename"
$DestAcc=$DestAcc
$DestContainer=$DestStorageContainer
$DestKey=$DestKey
$DestContext=$DestContext
$sasExpiryDuration="3600"
Start-AzStorageBlobCopy -AbsoluteUri $sas.AccessSAS -DestContainer $DestContainer -DestContext $DestContext -DestBlob $DestFileName
Now the problem is that the parameter $DestContext will be formatted to type string instead of being the type "Microsoft.WindowsAzure.Commands.Common.Storage.LazyAzureStorageContext". The whole error message in the pipeline is the following:
Cannot convert the "Microsoft.WindowsAzure.Commands.Common.Storage.LazyAzureStorageContext" value of type "System.String" to type "Microsoft.Azure.Commands.Common.Authentication.Abstractions.IStorageContext".
I then started to work on the problem and installed the "Az.Stroage" module to the runner while execution the powershell task. But this did not solve the issue as I am setting the type of the object inside the PARAM section and not after the import of "Az.Storage" module.
Does anybody know if this is possible? Is there a way that I can pass the Azure Storage context object to the next task via task variable? Or change the type from string to the Azure Storage context type?
Thank you!
Test with the same PowerShell and reproduce the same issue.
When you set the value in Pipeline variable, it will show as String type.
I'm afraid there is no method to keep the object form in a variable.
To meet your requirement, I suggest that you can add the command in Task2.ps1 to get the context in the same task.
New-AzStorageContext -StorageAccountName "ContosoGeneral" -StorageAccountKey "< Storage Key for ContosoGeneral ends with == >"
Here is an example:
param (
[string] $DestStorageContainer,
[string] $DestUrl,
[string] $DestKey,
[object] $DestContext,
[string] $DestAcc
)
$subscriptionId=(Get-AzSubscription).Id
$resourceGroupName ="rg2"
$diskName = "DD"
$DestFileName="Filename"
$DestAcc=$DestAcc
$DestContainer=$DestStorageContainer
$DestKey=$DestKey
$sasExpiryDuration="3600"
$Context = New-AzStorageContext -StorageAccountName "ContosoGeneral" -StorageAccountKey "< Storage Key for ContosoGeneral ends with == >"
Start-AzStorageBlobCopy -AbsoluteUri $sas.AccessSAS -DestContainer $DestContainer -DestContext $DestContext -DestBlob $Context
You can use the Storage Account key to access the storage account in different subscription.
Hi I have powershell script in azure devops. I used powershell task with file location. I used arguments to pass values. In that one variable name should be "stage-wb2018"
Powershell Script:
param (
[Parameter(Mandatory = $true)]
[string] $API_TOKEN,
[Parameter(Mandatory = $true)]
[string] $url,
[Parameter(Mandatory = $true)]
[string] $TAG_VALUE_ENVIRONMENT
)
Write-Host "TAGVALUE is :$TAG_VALUE_ENVIRONMENT"
#$startTime = Get-Date -UFormat %s
$startTime = [double](Get-Date -Date ((Get-Date).ToUniversalTime()) -UFormat %s) * 1000
$startTimeFormatted = Get-Date -UFormat "%x %R"
Write-Host "==============================================================="
Write-Host "Start Time: "$startTime
Write-Host "Start Time Formatted: "$startTimeFormatted
Write-Host "==============================================================="
#Write-Host ("##vso[task.setvariable variable=startTimeFormatted]$startTimeFormatted")
#Write-Host ("##vso[task.setvariable variable=startTime]$startTime")
#$test = stage_$(Environment.ResourceName)
Write-Host "$url"
# read Dynatrace values from the pipeline variables
$DYNATRACE_API_URL="$url" + "/api/v1/events"
# set the data for the API call
# adjust the number of tags in the JSON below and tag variables values
Write-Host "ENV Value: $TAG_VALUE_ENVIRONMENT"
Write-Host "Token Value: $API_TOKEN"
Write-Host "API URL: $DYNATRACE_API_URL"
powershell argument
-url $(URL) -API_TOKEN $(TOKEN) -TAG_VALUE_ENVIRONMENT '$(stage-$(Environment.ResourceName))'
- task: PowerShell#2
inputs:
filePath: '$(Build.SourcesDirectory)/dynatrace.ps1'
arguments: '-url $(URL) -API_TOKEN $(TOKEN) -TAG_VALUE_ENVIRONMENT ''$(stage-$(Environment.ResourceName))'''
Here we used Yaml pipeline with variables.
We have added variables and values like
stage-wb2018 = xxxxxxxxxxxx
stage-wb2019 = yyyyyyyyyyyy
we need to input xxxxxxxxxxx from pipeline to powershell script
wb2018, wb2019 are vm resource names. for that we are using (environment.resourcename).
This value dynamically have to take. But it is not taking. It only giving like $(stage-wb2018). Not replacing the variable value of stage-wb2018.
I am getting this output
ENV Value: $(stage-raja-win)
Token Value:123456789 API URL:
https://testapp.com/api/v1/events
But required output is
ENV Value: xxxxxxxxxxxx #(stage-wb2018 value)
Token Value: 123456789
API URL: https://testapp.com/api/v1/events
So please help us to solve this problem
I have the following yml. What I'm attempting to do is to create a version number based on several other variables (version.Major, version.Minor, versionDay, and BuildNumber). But the set variable powershell task isn't overwriting the initial values for versionday, so the output of versionNumber in my echo script below would be like: 1.0.set below.2021037.6 Any ideas? Syntax issues I'm not seeing?
trigger:
branches:
include:
- develop,
- sprint/*
- Sprint/*
pool:
name: 'MyCustomAgent'
variables:
solution: '**/*.sln'
buildPlatform: 'Any CPU'
version.Major: '1'
version.Minor: '0',
versionDay: 'set below'
versionNumber: 'set dynamically'
steps:
- script: |
echo: $(Build.SourceBranch)
- powershell: |
if ("$(Build.SourceBranch)".Contains('sprint')) {
Write-Host "##vso[task.setvariable variable=buildConfiguration;]Release"
[string] $currentMonthDay= (Get-Date -Format 'MMdd')
Write-Host "##vso[task.setvariable variable=versionDay]$currentMonthDay"
Write-Host "##vso[task.setvariable variable=versionNumber]$(version.Major).$(version.Minor).$(versionDay)"
} else {
Write-Host "##vso[task.setvariable variable=buildConfiguration;]Debug"
[string] $currentMonthDay= (Get-Date -Format 'MMdd')
Write-Host "##vso[task.setvariable variable=versionDay]$currentMonthDay"
Write-Host "##vso[task.setvariable variable=versionNumber]$(version.Major).$(version.Minor).$(versionDay).$(Build.BuildNumber)"
}
- script: |
echo building configuration $(buildConfiguration)
echo $(versionDay)
echo $(versionNumber)
You need to set the variables as output - note the change to your setvariable statements below:
pool:
name: 'MyCustomAgent'
variables:
solution: '**/*.sln'
buildPlatform: 'Any CPU'
version.Major: '1'
version.Minor: '0',
versionDay: 'set below'
versionNumber: 'set dynamically'
steps:
- script: |
echo: $(Build.SourceBranch)
- powershell: |
# note the use of ;isOutput=true in setvariable commands
if ("$(Build.SourceBranch)".Contains('sprint')) {
Write-Host "##vso[task.setvariable variable=buildConfiguration;]Release"
[string] $currentMonthDay= (Get-Date -Format 'MMdd')
Write-Host "##vso[task.setvariable variable=versionDay]$currentMonthDay"
# You can't use $(versionDay) here as setvariable is for subsequent steps/jobs/stages
# use its calculated value instead
Write-Host "##vso[task.setvariable variable=versionNumber]$(version.Major).$(version.Minor).$($currentMonthDay)"
} else {
Write-Host "##vso[task.setvariable variable=buildConfiguration;isOutput=true]Debug"
[string] $currentMonthDay= (Get-Date -Format 'MMdd')
Write-Host "##vso[task.setvariable variable=versionDay;isOutput=true]$currentMonthDay"
# You can't use $(versionDay) here as setvariable is for subsequent steps/jobs/stages
# use its calculated value instead
Write-Host "##vso[task.setvariable variable=versionNumber;isOutput=true]$(version.Major).$(version.Minor).$($currentMonthDay).$(Build.BuildNumber)"
}
- script: |
echo building configuration $(buildConfiguration)
echo $(versionDay)
echo $(versionNumber)
I have a first inline PowerShell script where I am filtering my test project directory and setting its value to a variable called testProjectPath.
- task: PowerShell#2
displayName: "Get tests path"
inputs:
targetType: "inline"
script: |
$testpath = Get-ChildItem -Filter *Tests.csproj -Recurse | Select-Object Directory -First 1
Write-Host "##vso[task.setvariable variable=testProjectPath]$testpath"
And then I have a second script which tries to Set-Location based on the path present in my testProjectPath variable.
- task: PowerShell#2
displayName: "Run mutations"
inputs:
targetType: "inline"
script: |
Set-Location $env:testProjectPath
But every time I try to run this pipeline I get the following error message:
#{Directory=D:\a\1\s\Wms.PickingCheck.Tests}
Set-Location : Cannot find drive. A drive with the name '#{Directory=D' does not exist.
At D:\a\_temp\752e8e31-b8ac-4f43-9ee0-248f6b12577c.ps1:4 char:1
+ Set-Location $env:testProjectPath
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (#{Directory=D:String) [Set-Location], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.SetLocationCommand
What am I doing wrong here?
In your original script, the value of $testpath is #{Directory=xxxxxx}. However, Set-Location doesn't recognize this format, Set-Location sets the current working location to a specified location, that's why you got error:
You could modify your script by adding -Expand as #AdminOfThings mentioned: $testpath = Get-ChildItem -Filter *Tests.csproj -Recurse | Select-Object -Expand DirectoryName -First 1