Category Archives: devops

Post navigation

Introduction

Last week saw the release of the Azure Automation Graphical SDK for creating graphical Runbooks programmatically. On its own, it is a library, represented by a single file, Orchestrator.GraphRunbook.Model.dll. It contains the .NET components required to allow creation of a graphical runbook object, serialize it, then save it to a.graphrunbook file, suitable for importing into Azure Automation.

The examples given in the documentation that accompanies the download from Microsoft’s web page for this are in C#. This series will show how these same graphical runbooks can be generated in PowerShell.

Overview

The next few articles walk through how we can make a runbook, using an existing graphical runbook generated in the Azure Portal, Get-DiceThrow, as a point of reference. It then shows how an identical one can be programmatically made using PowerShell and the SDK.

The Existing Runbook

In the screenshot below is the graphical runbook we mentioned, Get-DiceThrow.

Get-DiceThrow accepts as input two integer parameters, simulating the roll of two dice. It then identifies if one is greater than the other, or if they are both of the same value. Then, based on that, a message is displayed, describing the result.

When we’re looking at designing a graphical runbook via the SDK, it’s a good idea to first take a look at the structure of our existing one to get an insight of what it’s composed of. This helps later when development of the script starts.

To do this, the classes and properties that represent what we can see in Get-DiceThrow will be described.

Runbook Elements

Runbook

A runbook, or more specifically a graphical runbook, is repesented by an instance of the the GraphRunbook class. This describes the runbook in its entirety, and consists of the properties Activities, Links, and Parameters. This last one refers to the runbook’s input an output parmeters (see below).

Runbook Input and Output Parameters

Input and output parameters are defined by creating an one or more instances of a Parameter class and setting the Paramters property of the Runbook class.

Parameters

The attributes for the name of the parameter, the parameters type, and whether it is mandatory or not are represented in the Parameter class by the properties of Name, Type, and Optional.

Name, Type, and Optional

Workflows

Workflow script activities are represented by the WorkflowScriptActivity class. From the image below (anti-clockwise from Label) , the associated properties are Name, Description, CheckPointAfter, and Process.

Links

Links between activities use the aptly named class, Link. Links can either have conditions attached to them (restricting the use of the activity at the end of the link to situations where the condition’s expression evaluates to true), or be simple unconditional ones.

The settings in the image below (top to bottom) are referred to by the properties LinkType, Description,and Condition. Condition is another class, which contains the properties ConditionMode, to specify if a condition should be applied, and Expression for the conditional expression.

The next article will focus on the activities themselves, and the classes which inherit from them. This is probably the part that most of the development time will be spent on, since there is a substantial amount of configuration required.

Introduction

During the last article in this series on the use of PowerShell with GitLab, we noticed some displays on the build console, and some results from our build that was a bit unusual.

Today, I’m going to look a bit further into how the build engine works, which will also explain some of these results we are seeing.

How GitLab CI Runner Works

It would be logical to think that the PowerShell code is run in the same location or a subdirectory of the folder where the service file is, similar to Jenkins, but after a bit of investigation, I found out this is not the case.

To look further into what was happening, let’s add a line to the script section of the YAML file, and put a Start-Sleep command in.Make it ten minutes, to give enough time to remote onto the GitLab CI Runner, and do a search for our .ps1 file stored in a subdirectory of the repository.

Use the content below for our build file.

YAML

1

2

3

4

5

6

7

8

9

10

11

ps_helloworld:

script:

-functionHappyHelloWorld{

-$x="Hello world"

-Write-Output"I would just like to say $x"

}

-HappyHelloWorld|Out-File'c:\windows\temp\helloworld.txt'

-Start-Sleep-Seconds600

tags:

-windows

Save the changes

Add the updated file

Commit the changes

Push the changes

Navigate to the build section

Click on the commit

The job is running, and because of the Start-Sleep command, will continue to do so for the next ten minutes.

Discoveries

Remote onto your build server (if it is not already the same system you are accessing GitLab from.

Go to the C:\Windows\Temp

There will be a folder name of the format Build_xxxx

Double click on the folder

Within this folder is a script.ps1 file.

Open the file

The PowerShell code contained within the script: section of the YAML file is adjusted to make it suitable for returning the output we can see on the console window within a Gitlab job.

Looking at the code now, we can see that it has been changed significantly :

ErrorActionPreference has been set to ‘Stop‘.

Commands are in place to check to see if an error has occured, and if so to exit the script. This will also result in the job being flagged as having failed.

Probably the most interesting of the changes is the frequent use of Echo command which mimics the command that follows it.

This explains several things to us :

How the console output is seen on the job screen

Some lines output appeared strange because variables were undefined at the stage when the Echo command ran

Because PowerShell returns all output from a function, it explains why were receive an array when the HappyHelloWorld function is called. It consists of the intented output, but also the Echo commands.

The use of a function in our build code now becomes a challenge or possibly could be perceived as something to be avoided, since we cannot guarantee the element in the array that will contain our desired output. One way i’ve been able to get round this is to make the function return a PScustomobject, and make use of the -is operator outside of the function to obtain the value.

However, I’ve found a better approach is to minimize the actual PowerShell commands that you use in the script, and instead create a Build folder within your repository which contains files with the actual commands that you wish to use for the build. These can be dotsourced to make them available from within the script, without the need for adding custom code to handle this.

There are many other aspects and configuration settings possible within GitLab, which lets you have powerful control over your build steps. Examples of this are defining the order of execution, ignoring errors, and setting the steps to be taken after each one.

It’s also worthwhile noting that these articles do not include the use of testing, which should be part of your chain of operations. If you are not already familiar with the use of Pester, I’d recommend taking a look at the documentation and examples on GitLab. Amongst others, Jakub Jareš has also written an excellent series of articles on its use, which you can find on PowerShellMagazine.com

That’s it for this series of articles on the use of PowerShell and GitLab. Thanks for reading, and feel free to provide feedback.

Part 3 of this series on using PowerShell and GitLab CI gave us an initial insight into how to setup and run PowerShell code as part of a build script. During it, we were introduced to the YAML build file, .gitlab-ci.yml.

This article, and the following one will cover some of the gotchas I’ve encountered whilst getting to grips with this file, and how to get these working as you’d expect. Hopefully these will help save you some time setting these up.It will also touch on some oddities you might experience creating build scripts.

Overview

At this point, I’m going to continue to use the same project with the same job name, even though it will deviate from the original script we created earlier. This is to allow us to go through the situations I’ll mention slightly faster, and I’ll indicate for each example what the subject is about. Let’s begin!

Succeeds

Don’t use the TAB character

Unless you are using an editor which automatically translate the use of the TAB key into spaces, your scripts will fail. Use normal spaces.

Fails

The script below, whilst appearing indentical to the one that succeeds, uses table characters for indentation.

YAML

1

2

3

4

5

ps_helloworld:

script:

-.\HelloWorld.ps1|Out-File'c:\windows\temp\helloworld.txt'

tags:

-windows

Succeeds

YAML

1

2

3

4

5

ps_helloworld:

script:

-.\HelloWorld.ps1|Out-File'c:\windows\temp\helloworld.txt'

tags:

-windows

Watch Out For ScriptBlocks

The formatting for the use of a scriptblock can sometimes be a bit confusing. The final brace that closes the scriptblock should not have a ‘-‘ prefixing it. Additionally, if there is only one line of code within the scriptblock, it is not neccessary to use this prefix (but see below)

Fails

YAML

1

2

3

4

5

6

7

ps_helloworld:

script:

-For($i=1;$i-le5;$i++){

-.\HelloWorld.ps1|Out-File'c:\windows\temp\helloworld.txt'-Append

-}

tags:

-windows

Succeeds

YAML

1

2

3

4

5

6

7

ps_helloworld:

script:

-For($i=1;$i-le5;$i++){

.\HelloWorld.ps1|Out-File'c:\windows\temp\helloworld.txt'-Append

}

tags:

-windows

And if we actually look a the build output, we will see the details.
You might be quite correctly thinking that something looks a bit unusual with the output. This will be covered shortly……..

And a look at helloworld.txt to make sure it has worked correctly.

You Must Use ‘-‘ For Any Code Within Braces If It Consists of More Than One Line

If you have any code that surrounds itself in braces, such as a scripblock, function, or reiteration action, it will execute successfully without using the ‘-‘ character if there is only one line. However, two or more lines of code will fail.

Fails

YAML

1

2

3

4

5

6

7

8

ps_helloworld:

script:

-For($i=1;$i-le5;$i++){

.\HelloWorld.ps1|Out-File'c:\windows\temp\helloworld.txt'-Append

.\HelloWorld.ps1|Out-File'c:\windows\temp\helloworld.txt'-Append

}

tags:

-windows

Succeeds

It is probably best to start using ‘-‘ even with one single line within braces.

YAML

1

2

3

4

5

6

7

8

ps_helloworld:

script:

-For($i=1;$i-le5;$i++){

-.\HelloWorld.ps1|Out-File'c:\windows\temp\helloworld.txt'-Append

-.\HelloWorld.ps1|Out-File'c:\windows\temp\helloworld.txt'-Append

}

tags:

-windows

The script works, but the output on the screen is even stranger!

But the results are good….

Watch for error handling

Watch your syntax if you are wanting to use a Try..Catch block
Also, code within

Fails

YAML

1

2

3

4

5

6

7

8

9

10

11

ps_helloworld:

script:

-$ErrorActionPreference='Stop'

-Try{

-1/0

}

-Catch{

-Write-Output"Theres been a division by zero action"|Out-File'c:\windows\temp\helloworld.txt'

}

tags:

-windows

Succeeds

YAML

1

2

3

4

5

6

7

8

9

10

11

ps_helloworld:

script:

-$ErrorActionPreference='Stop'

-Try{

-1/0

}

Catch{

-Write-Output"Theres been a division by zero action"|Out-File'c:\windows\temp\helloworld.txt'

}

tags:

-windows

So the script has successfully executed. Again, the output on the screen is a bit strange, but let’s check the helloworld.txt file out.

However, the file itself has not been created, despite the fact that we know this should raise a division by zero error, which should mean the catch scriptblock is executed.

Functions Behave Differently Than You Would Expect

This final part is the greatest challenge i’ve come across so far, and deserves a bit extra detail. It will also be covered further in the next article in this series.

Here, we’ve modified our build script by adding a function which returns a string, and then output it to the same text file we’ve been using previously. If you want, you can verify the PowerShell code in the ISE, and also that the helloworld.txt file has been successfully created.

This would be put into our build script like this :

YAML

1

2

3

4

5

6

7

8

9

10

ps_helloworld:

script:

-functionHappyHelloWorld{

-$x="Hello world"

-Write-Output"I would just like to say $x"

}

-HappyHelloWorld|Out-File'c:\windows\temp\helloworld.txt'

tags:

-windows

And it builds successfully

So let’s take a look at helloworld.txt

This is strange!!! There is other items there that shouldn’t be. In fact, only the last line of the file should be there.

Let’s do a bit of detective work and see if we can get more information about what’s being returned. A good starting place would be to see if we are getting a multiline string or an array returned.

YAML

1

2

3

4

5

6

7

8

9

10

11

ps_helloworld:

script:

-functionHappyHelloWorld{

-$x="Hello world"

-Write-Output"I would just like to say $x"

}

-$result=HappyHelloWorld

-$result.GetType()|Out-File'c:\windows\temp\helloworld.txt'

tags:

-windows

So let’s take a look at helloworld.txt

This is real strange, an array is being returned. But we know that only a string is returned from the function. In the next article, we’ll dig deeper into what’s actually happening during the build process, which will shed some light on some of the strange things we’ve been noticing. Then we’ll also take a look at Lint, and how we can use it carry out checking of our YAML files.