Access YAML variable in inline PowerShell script - powershell

If I have a YAML Pipeline;
variables:
- name : myVariable
value : 'abcd'
and if I want to run some inline powershell - how can i access that value (abcd) in the powershell script;
I expected this to work - but it didnt;
- task: PowerShell#2
displayName: "Do the thing"
inputs:
targetType: 'inline'
script:
write-host $(myVariable)

we could refer to this doc to specify variables at the pipeline, stage, or job level.
YAML build definition:
pool:
vmImage: 'vs2017-win2016'
variables:
- name : myVariable
value : 'abcd'
steps:
- task: PowerShell#2
displayName: "Do the thing"
inputs:
targetType: 'inline'
script:
write-host $(myVariable)
Result:

Not sure if this works in Azure DevOps, but in GitLab it's:
$VAR_NAME
or
$env:VAR_NAME
I'm using these two line in existing yaml and they work fine:
- $PKG_VERSION = (Get-ChildItem -Path . -Filter *.version).basename
- Write-Host $PKG_VERSION

Related

Azure devOps deployment release setup

If the connection string is setup as a secret variable in the release pipeline.
Is there any way or any one to view the secret variable? If yes, how could we do it?
I write a powershell demo in the YAML file for you(Based on Daniel's idea.), please notice on the pipeline you will be unable to output the value because all of the same value will be captured by the pipeline and all of them will be covered by "***".
trigger:
- none
pool:
vmImage: ubuntu-latest
steps:
- task: PowerShell#2
inputs:
targetType: 'inline'
script: |
Write-Host $(not_secure)
Write-Host $(secure)
#convert string to based64 string:
$secret = "$(secure)"
$secret = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($secret))
Write-Host $secret
Write-Host "value2" #Whenever the pipeline capture the same value of the secured secret, the pipeline will output '***'. So doing any tricks inside the pipeline can't make the pipeline output this value
Whenever the pipeline capture the same value of the secured secret,
the pipeline will output '***'. So doing any tricks inside the
pipeline can't make the pipeline output this value.
My pipeline output:
My variables:
get_secret_of_pipeline.ps1(run this on your machine.)
$secret = "dmFsdWUy"
$secret = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($secret))
Write-Host $secret
Successfully get the value of secret:

How can I check that an artifact is built in ADO

I'm building an ADO pipeline and want to check that an artifact has been created before continuing with the build stage. I'm trying to create a variable to tell me if the file exists but when I run the pipeline I get an error saying the file path is invalid.
This is the relevant ymal code:
- task: PublishBuildArtifacts#1
inputs:
PathtoPublish: $(Build.ArtifactStagingDirectory) # dist or build files
ArtifactName: 'www' # output artifact named www
- task: PowerShell#2
inputs:
script: |
$fileExists = Test-Path -Path "$(Build.ArtifactStagingDirectory)/www/dist/apps/poc/index.html"
Write-Output "##vso[task.setvariable variable=FileExists]$fileExists"
- stage: deploy
condition: and(succeeded(), eq(variables['FileExists'], True))
This is the error that I get when I run the pipeline:
##[error]Invalid file path '/home/vsts/work/1/s'. A path to a .ps1 file is required.
##[error]Invalid file path '/home/vsts/work/1/s'. A path to a .ps1 file is required.
From your YAML sample, the Powershell task definition format is not correct if you are using inline script type.
You need to define the targetType field.
For example: targetType: 'inline'
- task: PowerShell#2
inputs:
targetType: 'inline'
script: |
$fileExists = Test-Path -Path "$(Build.ArtifactStagingDirectory)/www/dist/apps/poc/index.html"
Write-Output "##vso[task.setvariable variable=FileExists]$fileExists"

Download and publish artifact only if exist in azure pipeline

Using task of azure pipeline is it possible to download and publish artifact only if exists?
-> My first task is a build - but that build is a bit special, it will check if there is something that have changed since the last commit. If nothing has changed, nothing will be build.
-> The second task is the download artifact, but in the case nothing was build, there will be nothing to download.
Because no folder has been created by the build, my CI failed.
Is there a way to "tell" the download task: "download only if exist".
Or continue to task 3 only if folder created otherwise finish.
Thank you
You can use for this purpose variables and set them dynamically based on the fact if you are going to create your artifact or not
steps:
- bash: |
echo "Test here if you have folder which will you use to create an artifact and then set Yes or No"
echo "##vso[task.setvariable variable=doThing]Yes" #set variable doThing to Yes
name: DetermineResult
- script: echo "Job Foo ran and doThing is Yes."
condition: eq(variables['doThing'], 'Yes')
- script: echo "Skip this one"
condition: ne(variables['doThing'], 'Yes')
Based on your requirement, you can add a task before downloading artifacts task to determine whether there is a folder, and then decide whether to run the download artifacts task.
Here are the examples:
Check if the folder exists:
steps:
- powershell: |
$Folder = '$(Build.ArtifactStagingDirectory)'
"Test to see if folder [$Folder] exists"
if (Test-Path -Path $Folder) {
echo "##vso[task.setvariable variable=test]Yes"
} else {
echo "##vso[task.setvariable variable=test]No"
}
displayName: 'PowerShell Script'
- task: DownloadBuildArtifacts#1
displayName: 'Download Build Artifacts'
inputs:
downloadType: specific
condition: ne(variables['test'], 'Yes')
Check if the folder is empty:
steps:
- powershell: |
$directoryInfo = Get-ChildItem $(Build.ArtifactStagingDirectory) | Measure-Object
$directoryInfo.count
echo $directoryInfo.count
if ( $directoryInfo.count -eq 0 )
{
echo "##vso[task.setvariable variable=test]Yes"
}
else
{
echo "##vso[task.setvariable variable=test]No"
}
displayName: 'PowerShell Script'
- task: DownloadBuildArtifacts#1
displayName: 'Download Build Artifacts'
inputs:
downloadType: specific
condition: ne(variables['test'], 'Yes')

##[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'

How to add a manual intervention step in Azure Pipelines yaml

How do you add a manual intervention step into a multi-stage Azure Devops YAML pipeline?
In jenkins you can do some thing like:
stage ('approve-prod') {
steps {
input "Approve deployment to production?"
}
}
I am looking for the equivalent in Azure Devops YAML.
Note: this is for the newly released multi-stage Azure Devops pipelines, not the old style release pipelines. Related announcement here https://devblogs.microsoft.com/devops/whats-new-with-azure-pipelines/
Microsoft have now made available a brand new official Manual Validation task that allows for manual intervention to be added into a YAML pipeline.
Quick example of how to use this task is as follows:
jobs:
- job: waitForValidation
displayName: Wait for external validation
pool: server
timeoutInMinutes: 4320 # job times out in 3 days
steps:
- task: ManualValidation#0
timeoutInMinutes: 1440 # task times out in 1 day
inputs:
notifyUsers: |
test#test.com
example#example.com
instructions: 'Please validate the build configuration and resume'
onTimeout: 'resume'
Some key constraints to be aware of:
This task is only supported in YAML pipelines
Can be used only in an agentless job of a YAML pipeline.
Azure DevOps/Pipelines now has a feature called Environments which supports approvals.
https://learn.microsoft.com/en-us/azure/devops/pipelines/process/environments?view=azure-devops#approvals
We are using them as a workaround. Basically we have specified two environments ApprovalNotRequired and ApprovalRequired in Azure DevOps. On the latter we have specified who can approve deployments. Then in the pipeline we reference the environment like this.
- stage: 'Approval not required'
jobs:
- deployment: 'MyDeployment'
displayName: MyDeployment
environment: 'ApprovalNotRequired'
strategy:
runOnce:
deploy:
# whatever
- stage: 'Approval required'
jobs:
- deployment: 'MyDeployment2'
displayName: MyDeployment2
environment: 'ApprovalRequired'
strategy:
runOnce:
deploy:
# whatever
The first stage will run without interference and the second will pause until it's approved.
This doesn't appear to be available yet, but there is a GitHub Issue tracking this:
https://github.com/MicrosoftDocs/vsts-docs/issues/4241
From the issue:
So what I heard from the product team is that this "approval per stage" policy isn't available yet but is on their backlog.
There is also a Roadmap work item tracking it:
https://dev.azure.com/mseng/AzureDevOpsRoadmap/_workitems/edit/1510336/
Because there's a long time since Microsoft is ignoring this, and because this is a critical missing functionality , I will add an workaround here (for the moment, it's working only to ignore the entire step for all machines in case of a multi stage YAML but I think this can be solved also, but I am not looking into it for the moment).
Unfortunately, there is a task that needs to be added before each task. This can be solved also by iterative insertion (https://learn.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops).
Shortly, in order to be able to ignore a specific task:
T1 is checking the build run for "IgnoreStep"tag. If found, it will set IgnoreStep variable to true and remove the tag
T2 is running only if previous IgnoreStep is on false
When something is failing and I want to ignore the step, I will add "IgnoreStep" tag for the run and retry.
For adding tags, I am using the API because there is no task to do it yet. For request details, F21 in Chrome and check what it sent to server after you will add a tag, and export the request to power shell.
Below you have the YAML:
trigger: none
jobs:
- deployment: Dev
environment:
name: Dev
resourceType: virtualMachine
tags: online
strategy:
runOnce:
deploy:
steps:
- task: PowerShell#2
displayName: CheckIfWeShouldIgnoreStep
name: CheckIfWeShouldIgnoreStep
inputs:
targetType: 'inline'
script: |
$user = "user"
$pass= "pass"
$secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($user, $secpasswd)
$response = Invoke-RestMethod -Uri "https://server/tfs/collection/projectId/_apis/build/builds/$(Build.BuildId)/tags" `
-Method "GET" `
-Headers #{
"accept"="application/json;api-version=6.0;excludeUrls=true;enumsAsNumbers=true;msDateFormat=true;noArrayWrap=true"
} `
-ContentType "application/json" `
-Credential $credential -UseBasicParsing
Write-Host "##vso[task.setvariable variable=IgnoreStep]false"
Write-Host "Tags: $response"
foreach($tag in $response)
{
if($tag -eq "IgnoreStep")
{
Write-Host "##vso[task.setvariable variable=IgnoreStep]true"
Invoke-RestMethod -Uri "https://server/tfs/collection/projectId/_apis/build/builds/$(Build.BuildId)/tags/IgnoreStep" `
-Method "DELETE" `
-Headers #{
"accept"="application/json;api-version=6.0;excludeUrls=true;enumsAsNumbers=true;msDateFormat=true;noArrayWrap=true"
}`
-Credential $credential -UseBasicParsing
}
}
- task: PowerShell#2
displayName: Throw Error
condition: eq (variables.IgnoreStep, false)
inputs:
targetType: 'inline'
script: |
throw "Error"