How to read the logs from TFS Build/Release and change the task status accordingly? - powershell

I am using TFS(on premises 2015)automated build and release for one of my project. In release definition, I have an ALM task and I can see the TFS release log returning "completed successfully: Y (or N) " in the log based on the task completion status in ALM and the ALM task always shows a success. Is there any way that I can read the this "completed successfully: N" from the logs and fail the ALM release task itself as an indication of failure?
Thanks in advance for any help!

Well you're not giving much help here. With or having a better idea of what your script does... But you could do something like
(At the end of your command)
Command -errorvariable fail
If ($fail -ne $null){
$success = $fail
} Else {
$success = $true
}
You could also pipe the error variable into the file at the next line if it's a txt log.
Command -ev fail
$fail | out-file log.txt -append
Or
Command -ev fail
If ($fail -ne $null) {
Write-output "the command failed at $variable" | out-file log.txt -append
}
$variable would be the variable used for your loop or whatever to identify the current task.

Related

Powershell - get string information to a console for user from one script to another

I have 2 scripts, one serves as a Worker - uses variables to complete commands, second serves as a function Library. Worker via variable loads Library and uses functions from there.
As a user, when I run the script I would like to see the output in the console which I defined as the outcome for Library script.
Example Worker script:
Param(
[string]$server_01,
[string]$releaseDefinitionName,
[string]$pathRelease,
[string]$buildNumber,
[string]$command_01,
[string]$scheduledTask_01
)
$pathScriptLibrary = $pathRelease + "\" + $buildNumber + "\" + "_scripts"
. $pathScriptLibrary\_library.ps1
$user = xxx
$password = xxx
$cred = xxx
Invoke-Command -ComputerName $server_01 -Credential $cred -ErrorAction Stop -ScriptBlock {powershell $command_01}
Example Library script:
function Stop-ScheduledTasks{
Write-Output [INFO]: Stopping scheduled tasks... -ForegroundColor White
Get-ScheduledTask -TaskName "$scheduledTask_01" | ForEach {
if ($_.State -eq "Ready") {
Write-Output [WARNING]: Scheduled task $scheduledTask_01 was already stopped. -ForegroundColor Yellow
}
else {
Stop-ScheduledTask -TaskName "$scheduledTask_01"
Write-Output [OK]: Running task $scheduledTask_01 stopped. -ForegroundColor Green
}
}
}
function Start-ScheduledTasks{
Write-Output [INFO]: Starting scheduled tasks... -ForegroundColor White
Get-ScheduledTask -TaskName "$scheduledTask_01" | ForEach {
if ($_.State -eq "Running") {
Write-Output [WARNING]: Scheduled task $scheduledTask_01 already started. -ForegroundColor Yellow
}
else {
Start-ScheduledTask -TaskName "$scheduledTask_01"
Write-Output [OK]: Stopped scheduled task $scheduledTask_01 started. -ForegroundColor Green
}
}
}
Use case:
User starts the deployment by clicning the deploy button in Azure DevOps UI
The task using the Worker script takes function from Library script (in this case stops Scheduled Task) and performs it
User checks log on the Azure DevOps side and sees the custom output lines from Library script. (2 of them now - 1. starting with [INFO], 2. either starting with [WARNING] or [OK]).
Could you please advice a solution how to achieve that? Thank you.
NOTE: Those examples are run in Azure DevOps (on premise) release pipelines and desired outcomes are ment for users running those pipelines.
If you're trying to write to the azure devops pipeline log, then you should avoid using Write-Output. That does something subtly different; it adds to the function's return value.
So for example the Write-Output in the function Stop-ScheduledTask; that is roughly equivalent to you putting at the end of the function:
return "[WARNING]: Scheduled task $scheduledTask_01 was already stopped."
That might end up being printed to the pipeline log, or it might not; and importantly, it might completely mess up a function which is genuinely trying to return a simple value.
Instead of using Write-Output, I recommend using Write-Host. What that does is immediately write a line to the pipeline log, without affecting what a library function will return.
Write-Output "[WARNING]: Scheduled task $scheduledTask_01 was already stopped."
You can also use Write-Warning and Write-Error.

Gitlab CI/CD validate powershell script

I am distributing several powershell scripts to various machines and want to make sure it is executable and does not contain any errors before uploading the new version to our distribution system.
How can I solve this with Gitlab .gitlab-ci.yml?
I have found a solution for my issue. This step in the build process checks the Powershell script and aborts the build if there are any errors.
gitlab-ci.yml
stages:
- validate
validate_script:
stage: validate
image:
name: "mcr.microsoft.com/powershell:ubuntu-20.04"
script:
- pwsh -File validate.ps1
tags:
- docker
validate.ps1
Write-Host "Install PSScriptAnalyzer"
Install-Module PSScriptAnalyzer -Scope CurrentUser -Confirm:$False -Force
Write-Host "Check mypowershell.ps1"
$result = Invoke-ScriptAnalyzer -Path 'src/mypowershell.ps1'
if ($result.Length -gt 0) {
Write-Host "Script Error"
Write-Host ($result | Format-Table | Out-String)
exit 1;
}
Not sure if this is what you are looking for or if it applies at all to .yml files as I'm not familiar with them, but for powershell script files you can use the creation of [scriptblock] to check for syntax and other compile errors. You can create a function with this code and pass in powershell script files to it which can take the code, try to compile it, and return any exceptions encountered.
# $code = Get-Content -Raw $file
$code = #"
while {
write-host "no condition set on while "
}
do {
Write-Host "no condition set on unitl "
} until ()
"#
try {
[ScriptBlock]::Create($code)
}
catch {
$_.Exception.innerexception.errors
}
Output
Extent ErrorId Message IncompleteInput
------ ------- ------- ---------------
MissingOpenParenthesisAfterKeyword Missing opening '(' after keyword 'while'. False
MissingExpressionAfterKeyword Missing expression after 'until' in loop. False
I also recommend looking into Pester for testing scripts. If you are unfamiliar it is a testing and mocking framework for Powershell code

Azure Runbook query running jobs

Azure Powershell runbook, scheduled to run every 1h.
The script runs "Invoke-AzVMRunCommand" to call a Powershell script on remote VM locally.
The problem -
sometimes it runs longer than 1h and overlaps with next in the schedule, and the second run fails with an error related to "Invoke-AzVMRunCommand" :
"Run command extension execution is in progress. Please wait for completion before invoking a run command."
The question - how to query if the runbook job is currently running.
We can not change schedule.
thank you!
This one does the check:
$jobs = Get-AzAutomationJob -ResourceGroupName $rgName -AutomationAccountName $aaName -RunbookName $runbook
$runningCount = ($jobs | Where-Object { $_.Status -eq "Running" }).count
if (($jobs.status -contains "Running" -And $runningCount -gt 1 ) -Or ($jobs.Status -eq "New"))
{
Write-Output "`n This runbook [$runbook] execution is stopped - there is another job currently running. Execution will start as per schedule next hour."
Exit 1
}
else
{
Write-Output "`n Let's proceed with runbook [$runbook] execution - there are no interfering jobs currently running." | Out-File -Filepath StarStop.txt -Append
} #end of check runbook status
You may use Az PowerShell cmdlet Get-AzAutomationJob to check the status of the job. Also, based on that status you may decide to remove or set existing schedule using schedule related cmdlets from here.

Prorgess bar for `New-MailboxExportRequest`

I'm trying to create a script that can export a user's mailbox to a PST, remotely (Exchange Server 2010 console is installed on the server we're running this from, and the module is loaded correctly). It's being done using a script so our L2 admins do not have to manually perform the task. Here's the MWE.
$UserID = Read-Host "Enter username"
$PstDestination = "\\ExServer\Share\$UserID.pst"
$Date = Get-Date -Format "yyyyMMddhhmmss"
$ExportName = "$UserID" + "$Date"
try {
New-MailboxExportRequest -Mailbox $UserID -FilePath $PstDestination -Name $ExportName -ErrorAction Stop -WarningAction SilentlyContinue | Out-Null
# Loop through the process to track its status and write progress
do {
$Percentage = (Get-MailboxExportRequest -Name $ExportName | Get-MailboxExportRequestStatistics).PercentComplete
Write-Progress "Mailbox export is in progress." -Status "Export $Percentage% complete" -PercentComplete "$Percentage"
}
while ($Percentage -ne 100)
Write-Output "$UserID`'s mailbox has been successfully exported. The archive can be found at $PstDestination."
}
catch {
Write-Output "There was an error exporting the mailbox. The process was aborted."
}
The problem is, as soon as we initiate the export, the task gets Queued. Sometimes, the export remains queued for a very long time, and the script is currently unable to figure out when the task begins, and when it does, is unable to display the progress correctly. The export happens in the background, but the script remains stuck there. So anything after the export, does not get executed, and the whole thing then has to be done manually.
Please suggest a way to handle this?
I tried adding a wait timer and then a check to see if the export has begun. It didn't quite work as expected.
Two things. First one is more about performance/hammering Exchange with unnesacary requests in do/while loop. Start-Sleep -Seconds 1 (or any other delay that makes sense depending on the mailbox size(s)) inside the loop is a must.
Second: rather than wait for job to start, just resume it yourself:
if ($request.Status -eq 'Queued') {
$request | Resume-MailboxExportRequest
}

How do you get powershell script output in the deployment log for a vNext Release Template?

This blog post is the only thing I have found that comes close to the problem but it doesn't explain how to configure the Deploy Using PS/DSC to run with the verbose option:
http://nakedalm.com/create-log-entries-release-management/
I can get this Agent-based Release Template to run the script:
Write-Debug "debug"
Write-Output "output"
Write-Verbose "verbose"
Write-Warning "warning"
The drilling down into deployment log for this release provides a log with the lines:
output
WARNING: warning
If I add -verbose to the Arguments field I also get a "VERBOSE: verbose" line in the log.
This is great, but I need the access to the System Variables ($Stage, $BuildNumber, etc). When I create a vNext template to run the same script (instructions are here: http://www.visualstudio.com/en-us/get-started/deploy-no-agents-vs.aspx), the log reports:
Copying recursively from \\vsalm\Drops2\TestBuild\TestBuild_20130710.3 to c:\Windows\DtlDownloads\my vnext component succeeded.
It is nice that this copying operation succeeded and all, but I'd like my script's output to be in this log as well. Does anyone have any idea about configuring a "Deploy Using PS/DSC" action so that the powershell script output is captured by Release Management?
For a vNext Release Template, try Write-Verbose with a -verbose switch if you want to see the powershell script output in the logs.
Eg. Write-Verbose "Some text" -verbose
Allow me to shamelessly plug my own blog article about this subject, because I found that it's not easy to get a script that does everything right.
The following script skeleton ensures that stdout output is logged without empty lines, and that processing is halted on the first error, in which case both the error details and the stdout output upto that point are visible in MSRM:
function Deploy()
{
$ErrorActionPreference = "Stop"
try
{
#
# Deployment actions go here.
#
}
catch
{
# Powershell tracks all Exceptions that occured so far in $Error
Write-Output "$Error"
# Signal failure to MSRM:
$ErrorActionPreference = "Continue"
Write-Error "Error: $Error"
}
}
pushd $Global:ApplicationPath
Deploy | Out-String | Write-Verbose -Verbose
popd
This is just the final result, the explanation behind it can be found here.