Why does my VSTS custom task passes with exit code 1? - tfs

I've the following annoying problem. My custom VSTS build task won't fail.
It always passes, while the $LASTEXITCODE is other then zero.
The code does as expected. It generates an error in the log. Despite that, the step succeeds and the build / release continues.
Screenshot:
I've included a write-host with the exit code as well which shows exitcode 1 as well.
Code:
Try {
....
#Loop through the server list
Foreach ($Server in $machines)
{
# Use SSL or not
If($UseSSL -eq $true)
{
Write-Host "Connecting to $Server using a SSL connection (TCP/5986), Skip CA Check: $CheckCA ..."
$s = New-PSSession -ComputerName $Server -Credential $Cred -UseSSL -SessionOption $SessionOptions
}
Else
{
Write-Host "Connecting to $Server with an unsecure connection (TCP/5985) ..."
$s = New-PSSession -ComputerName $Server -Credential $Cred
}
# Run
$ExitCode = Invoke-Command -Session $s -ScriptBlock $script -ArgumentList $ApplicationPoolName,$Action,$Killswitch
# Cleanup the session
Write-Host "Closing connection to $Server."
Remove-PSSession -Session $s
}
} Catch {
Write-Host "##vso[task.logissue type=Error;]$Error"
$ExitCode = 1
} Finally {
#Leave TFS/VSTS trace
if (Get-Command -Name Trace-VstsEnteringInvocation -ErrorAction SilentlyContinue) {
Trace-VstsLeavingInvocation $MyInvocation
}
write-host "ExitCode: $ExitCode"
Exit $ExitCode
}
What am i missing here?

I solved it by removing the finally part.
Not working:
try {
.... do stuff ....
} catch {
write-error "some error"
exit 1
} Finally {
.. some final steps ...
}
Working:
try {
.... do stuff ....
} catch {
write-error "some error"
exit 1
}

For people arriving here, having the same problem with BAT/CMD files, my solution was to add this line:
exit /b %ERRORLEVEL%
to force transmitting the errorlevel to VSTS/TFS Command-Line Task

Related

Exception occurred: groovy.lang.MissingPropertyException: No such property: content for class: groovy.lang.Binding

am getting below error Cloudbees Jenkins job of console output.
error:
Exception occurred: groovy.lang.MissingPropertyException: No such property: content for class: groovy.lang.Binding
Jenkins file (particular stage):
stage('Solution check') {
when {
expression { params.SOLUTION_NAME_CHECK != 'None' }
}
steps {
script{
try{
SOLUTION_NAME = "${params.SOLUTION_NAME_CHECK}"
bat """
call pac solution check --path C:\ManagedSolution.zip --outputDirectory C:\\SolutionCheck --geo Asia >> solutioncheck.log
"""
powershell(returnStdout: true, script: """
$content = (Get-Content -Path '${WORKSPACE}\\${DATE_TIMESTAMPED_BN_DIR}\\${SOLUTION_NAME}\\solutioncheck.log.txt' -Tail 3).trim() | ConvertFrom-String -PropertyNames Critical,High,Medium,Low,Informational
$file = $content[1] -replace " ",""
$file | Foreach {
if(($_ -ilike "*critical=0*") -and ($_ -ilike "*High=0")){
echo "solution has no critical and High values"
}
else {
echo "Solution has critical and High values: $content[1]"
}
}
""")
}
catch (Exception err) {
echo 'Exception occurred: ' + err.toString()
}
}
}
}
Please assist on this issue.
thanks lot
Hemanth
Try adding an escape character(\) before $ for all the non-groovy variables.
\$content = (Get-Content -Path '${WORKSPACE}\\${DATE_TIMESTAMPED_BN_DIR}\\${SOLUTION_NAME}\\solutioncheck.log.txt' -Tail 3).trim() | ConvertFrom-String -PropertyNames Critical,High,Medium,Low,Informational
\$file = \$content[1] -replace " ",""
\$file | Foreach {
if((\$_ -ilike "*critical=0*") -and (\$_ -ilike "*High=0")){
echo "solution has no critical and High values"
}
else {
echo "Solution has critical and High values: \$content[1]"
}
}

Jenkinsfile - stop pipeline when catch error

I am having a problem with my pipelin in Jenkins.
I perform a path search for files with the specified extension. I then execute php -l with the previously found files.
Everything works ok but I would like if php -l finds an error then build and step go to UNSTABLE state and further execution of the pipeline is stopped.
I managed to do it this way but then build and step are in FAILED state
} catch (Exception e) {
error("${e}")
Part of code my pipeline.
def check(){
stage('Validate files') {
try {
sh "find . -type f -iregex '.*\\.\\(php\\)' | xargs -I % sh -c 'php -l \'%\''"
} catch (Exception e) {
error("${e}")
}
}
}
I hope someone smarter can direct me to a solution :)
Got an example to work but maybe not exactly what you wanted. I used unstable() to mark the stage / build and then checked for the exit code of the sh step to return or continue the pipeline.
There are 2 if's as you need to return outside of a stage to not just return from the stage.
#!/usr/bin/env groovy
try {
node {
def exitCode = 0
exitCode = check()
if (exitCode != 0){
return
}
somethingelse()
}
} catch (Throwable err) { // catch all exceptions
throw err
} finally {}
def check(){
stage('Validate files') {
exitCode = sh script:"exit 1", returnStatus:true
if (exitCode !=0){
unstable('message')
}
}
return exitCode
}
def somethingelse(){
stage('Something'){
echo "somethingelse"
}
}

What REST Api return AGENT.BUILDDIRECTORY value for the given pool in Azure DevOps Server on-prem?

So I fetched the build definition:
$bd = ...
It has the pool Id:
C:\> $bd.queue.pool.id
90
C:\>
Now I can get the pool data with the capabilities using the Url https://myserver.com/tfs/DefaultCollection/_apis/distributedtask/pools/90/agents?includeCapabilities=true
And I do get a lot of information, but Agent.BuildDirectory is not there:
C:\> $x = Invoke-RestMethod $Url -UseDefaultCredentials
C:\> $x.value.systemCapabilities[0].PSObject.Properties.Name |? { $_ -match '^Agent' }
Agent.Name
Agent.Version
Agent.ComputerName
Agent.HomeDirectory
Agent.OS
Agent.OSArchitecture
Agent.OSVersion
C:\>
Given a valid build definition how can I get Agent.BuildDirectory for every on-prem agent associated with it using the rest API?
If you access the capabilities of the agent from UI, you'll find there is no Agent.BuildDirectory capability, so you can not get it from REST API. Also, Agent.BuildDirectory is the local path on the agent where all folders for a given build pipeline are created, the format is like c:\agent_work\_work\1, so it's different between build pipelines.
You could get this variable from the build pipeline, or check the build log to get the path.
I ended up with the following function:
function Invoke-ForEachBuildAgent(
[Parameter(Mandatory)]$BuildDefinition,
[Parameter(Mandatory)][scriptblock]$Action,
[pscredential]$Credential
)
{
function MapShare($AgentComputerName, $RemoteDirectory, $PSDrive, [pscredential]$Credential)
{
if ($Credential)
{
$Share = "\\$AgentComputerName\$($RemoteDirectory[0])`$"
$Mapped = $null
try
{
$Mapped = Test-Path $Share
}
catch
{
}
if (!$Mapped)
{
New-PSDrive $PSDrive FileSystem $Share -Credential $Credential > $null
}
}
}
$RelSourceFolderPath = "SourceRootMapping\1a33a8ed-f8fd-4c08-9f44-440ea9f20315\$($BuildDefinition.Id)\SourceFolder.json"
$PSDrive = [guid]::NewGuid().ToString('N')
if (!$Credential -and ($env:USERNAME -ne INSERT_THE_DEFAULT_USER_NAME_HERE))
{
$Credential = Get-Credential -UserName INSERT_THE_DEFAULT_USER_NAME_WITH_DOMAIN_HERE -Message "Login to access the agents"
}
$Url = "$TfsInstanceUrl/_apis/distributedtask/pools/$($BuildDefinition.Queue.Pool.Id)/agents?includeCapabilities=true"
(Invoke-RestMethod $Url -UseDefaultCredentials).value.systemCapabilities | Where-Object {
$_
} | ForEach-Object {
try
{
$AgentComputerName = $_.'Agent.ComputerName'
$AgentHomeDirectory = $_.'Agent.HomeDirectory'
MapShare $AgentComputerName $AgentHomeDirectory $PSDrive $Credential
$Path = "\\$AgentComputerName\$AgentHomeDirectory\.agent".Replace(':', '$')
$AgentBuildDirectoryRoot = (Get-Content $Path | ConvertFrom-Json).workFolder
if ($AgentBuildDirectoryRoot[0] -ne $AgentHomeDirectory[0])
{
Remove-PSDrive $PSDrive -ErrorAction SilentlyContinue
MapShare $AgentComputerName $AgentBuildDirectoryRoot $PSDrive $Credential
}
$Path = "\\$AgentComputerName\$AgentBuildDirectoryRoot\$RelSourceFolderPath".Replace(':', '$')
if (!(Test-Path $Path))
{
return
}
$BuildFolderNumber = (Get-Content $Path | ConvertFrom-Json).agent_builddirectory
$AgentBuildDirectory = [io.path]::GetFullPath("$Path\..\..\..\..\$BuildFolderNumber")
& $Action -SystemCapabilities $_ `
-UncAgentBuildDirectory $AgentBuildDirectory `
-AgentBuildDirectory "$AgentBuildDirectoryRoot\$LastBuildFolderNumber" `
-Credential $Credential
}
catch
{
$_.Exception
}
finally
{
Remove-PSDrive $PSDrive -ErrorAction SilentlyContinue
}
}
}
I am pretty sure it only works for on-prem agents. I will update my answer. Those running agents hosted in Azure do not really need this functionality in the first place.

How to go to any specific line in PowerShell during execution

if ((Get-WmiObject -ComputerName . -Class Win32_ComputerSystem).Domain -eq "domain.local") {
# Check with User if she/he wants to continue or not
Write-Host "Hurray you are in domain.local domain"
$FirstCondition = Read-Host -Prompt "Do you want to continue? If yes please press [Y] else press[N] to discontinue"
if ($FirstCondition = "Y") {
# Check if server is pinging or not
if (Test-Connection -ComputerName . -Count 1 -ErrorAction SilentlyContinue) {
$NetworkAdapter = Get-WmiObject -ComputerName . -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=$true |
Select-Object -Property [a-z]* -ExcludeProperty IPX*,WINS*
Test-Connection $net.DNSServerSearchOrder[0] -Count 1 -ErrorAction Stop
}
} else {
Goto Line:1
}
}
In the else {Goto Line:1} part I'm facing an issue, as during execution I need this command to run the first line if ((Get-WmiObject -ComputerName . -Class Win32_ComputerSystem).Domain -eq "domain.local") and check if the server is in domain.local domain or not. Please help me find a substitute for Goto in PowerShell 2.0.

Powershell: search subfolders and run script on each subfolder that contains file1.txt and continue searching

I am looking for a bit of help on a script that :
Would search in sub folder and every time it would find a WIM file, it would update it with the latest updates from wsus. When that script is finished then it would continue with next subfolder.
Here you have the code i had so far:
$thismonth = (get-date).AddMonths(0).ToString("yyyMM")
$lastmonth = (get-date).AddMonths(-1).ToString("yyyMM")
$2ndlastmonth = (get-date).AddMonths(-2).ToString("yyyMM")
$date = get-date -f "yyyMM"
$LogName = "wim_update_$($thismonth).log"
$UpdatesPath = "d:\WSUS\WsusContent\*"
$MountPath = “d:\temp\mount”
$folder = Get-ChildItem -Path "D:\Distribution\Operating Systems"
########### DISM Mount path ########
Set-Location "d:\Distribution\Servicing\x86\"
forEach ($os in $folder)
{
###########Alias########
$WimFile = “d:\Distribution\Operating Systems\$os\sources\install.wim"
Write-Host $WimFile
if (-Not (Test-Path ($Wimfile))) { continue }
########### Backup WIM File########
Copy-Item "d:\Distribution\Operating Systems\$os\sources\install.wim" -Destination "d:\backup\install-$os-$thismonth.wim"
if (-Not $?)
{
Write-Host "Failed to copy WIM file"
continue
}
./DISM /Mount-Wim /WimFile:$WimFile /index:1 /Mountdir:$MountPath
if (-Not $?)
{
Write-Host "Failed to mount WIM file"
continue
}
############ Apply updates
$UpdateArray = Get-Item $UpdatesPath | where{$_.extension -eq ".cab"}
ForEach ($Updates in $UpdateArray)
{
./DISM /image:$MountPath /LogPath:d:\Temp\$LogName /LogLevel:3 /Format:List /Add-Package /Packagepath:$Updates
Start-Sleep –s 10
}
Write-Host "Updates Applied to WIM" -foregroundcolor red -backgroundcolor yellow
./DISM /Commit-Wim /Mountdir:$MountPath
########### DISM : Unmount WIM file ########
./DISM /Unmount-Wim /Mountdir:$MountPath /commit
./DISM /Cleanup-Wim
}
###########Remove N-2 ########
#Remove-Item "d:\backup\$os\install-$os-$2ndlastmonth.wim"

Resources