Skip main navigation

New offer! Get 30% off your first 2 months of Unlimited Monthly. Start your subscription for just £29.99 £19.99. New subscribers only. T&Cs apply

Find out more

CI/CD Pipelines for Deploying and Configuring Environments

Hello, and welcome back to this video on version control, build, and test PowerShell script. You’re probably getting at the ninja level with PowerShell already. Over the last two modules, we’ve talked a lot about PowerShell, and, as a sysadmin, you’re probably using PowerShell already. Now, in the scheme of converging tools using the same best practises of CICD, why not test your PowerShell scripts? Why not run code analyzers on your PowerShell scripts to identify whether they’re coded up in the best possible way or whether there is scope for improvement? And what better than using the same development tools that your development team is using to run these activities?
In this video, what we’ll do is we’ll drop right into Visual Studio, go into the– sorry– Visual Studio Team Services, go into the team project that we created earlier. We will clone that project into Visual Studio. And, as an operations engineer or as an infrastructure engineer, you may or may not have used Visual Studio a lot, but the integration is so nice that you’re not going to see the friction. And then, from that point onwards, coding up your PowerShell functions in there, and creating some unit tests for that.
And then we’ll go back into VSTS, set up a CI pipeline that not only compiles the code that you have for PowerShell but also runs your tests, and then giving you a way of analysing the test results as well. So let’s flip right into the demo here. So I’m in Team Services now. And, as you can see, this is the project that we created in one of the previous videos. We’ll go into the Code hub, select the Git repository. And then, at this point, I can simply select the Git repository and click Clone, and decide to clone the Git repository in Visual Studio. And it’s just asking for a confirmation.
It identifies the version of Visual Studio that’s installed behind the scenes. It, in the context of cloning, specifies the endpoint. I’m already authenticated, so it’s not going to prompt for credentials. It’s just loading up Visual Studio now. Now, at this point, it’s confirming whether I want to clone the repository locally on my machine, and I can confirm to do so. It will take a few minutes to complete.
As you can see, this activity is completed now. And what’s great is, although the repository is empty at the minute and only has a readme file, it’s giving– it’s loading it up in the Solution Explorer window. So I don’t need to create artificial solution files to put in my PowerShell scripts in there. I could just come in, right-click the repository folder, and decide to add a new folder. Let’s call the folder code. And, within this folder, I’m going to create a new file of type– let’s call it calculator.ps1.
So this is a PowerShell file. And as it detects the extension, it figures out that this is a PowerShell script, so the right editor syntax IntelliSense will kick in automatically. So, in this case, I’m just going to create a function.
And I’m creating this PowerShell function to do something. So let’s call it Add two numbers. And I’m going to cheat a little bit, because I’ve already created that function.
Very simple function that simply does addition on two numbers. So this function will accept number 1 which is of type integer, number 2 which is of type integer. And then it’s basically going to sum them up and return the results.
What I can do now is– traditionally, I would have just committed this code and I’d be done with it. But, as a good practise, I want to unit test this code, and I want to make sure that this function actually does what it’s supposed to do. The other advantage of unit testing this is, tomorrow, if I come back and I want to extend this library to do something more than just add two numbers, then I’ve got some unit tests that back this function. And as I refactor the code, I will have confidence, because I can simply run my test and see whether any of the other functionality has been impacted or not.
So, right in here, I’m going to right-click on the code folder, click Add, choose a New File, and call this calculator.Test.ps1.
Again, I’m going to cheat a little bit because I’ve created the test here. But I’ll just copy one of the tests and walk you through as to what it’s really doing. When you look at the syntax, this is a very BDD-style syntax, where you’re calling the function that you are testing, but you’re saying what it is supposed to do, passing the parameters. And then you’re specifying what the expected behaviour of the result is. So, in this case, I’m saying describe the tag Demo. This is a Sum test which adds two– which adds positive numbers. And I’m calling the function and I’m passing the input parameters, and this should result in number 5 being returned.
So if I now go into the PowerShell interactive window– and if you don’t see it, you can type it in the quick navigation search window at the top and, it will load this window up for you. I’m simply going to change directly to where this repository has been cloned to copy this path and do a cd, paste. Now if I go in this directory, I can see I’ve got the code folder, so and so forth. So let me just change directory into code. Let’s do a directory. Now I’m in the same directory as where my code is and my tests are. At this point, I’m going to start using Pester now.
We talked about or we mentioned Pester before, but you can search for it online. Pester is a unit testing framework for PowerShell. Very, very supported in the community. You’ll find a lot of examples on it. So let me just invoke Pester here. And you can see the support for that is available right within Visual Studio. When I run Invoke-Pester– and it doesn’t work. The reason it doesn’t work is because the default behaviour is that it expects the test file to have the keyword Tests, Tests, not just Test. If I make that amendment now and run this test again, there you go. It finds the test, which is describing Sum. Plus adds positive numbers.
And it’s even giving you the telemetry on how much time it’s been executing that line of code. Completes the test in 38 seconds. The test has passed, and great. So fairly easy, right? I mean, I was able to create a test here. The kind of scenarios I would want to test here is, instead of an integer, if I’m passing a decimal. Or what if I’m passing negative numbers, or boundary testing? This is a very basic function, but when you’re writing PowerShell runbooks to do stuff that needs to be mocked up because they are complex objects, then this framework supports all of that. And integration with VS– Visual Studio just makes the testing exercise a lot more easier.
I’m just going to copy a bunch of more tests that I have here.
And then just save it, and then invoke the command again, this Invoke-Pester. There you go. It’s run all the tests. All the four tests have passed. Nothing’s failed, nothing’s skipped. So, at this point, what I want to do is I just want to commit these changes. And let me go into the Git Changes. Adding a function and adding tests for that function. I’m going to commit this. And then I just need to sync this up to the Git repository. So I’ll push this. And that operation is completed. So if I go back into the Git repository here now– whoops– this one here, and click Refresh, you see I’ve got the code folder.
My calculator function is available, and the test that I’ve created are available here as well. Now, what I really want to do is set up a build process so I can not only validate this now but have it run every time I make changes to this repository. So I’ll choose to click a build definition here. And let’s select an empty process. Let’s get the sources. Let’s select the right repository, selected the right branch. And it’s able to do that because I triggered the set build process creation task right from the context of my Git repository. So it’s already able to preempt the right configuration details of that Git repository. Coming back here, let’s add the task for PowerShell.
And let’s add the task for Pester. Now, you’d find that Pester might not be available within your VSTS solution. That’s because Pester isn’t available as a task that’s provided by Microsoft. It’s a task that’s available from the open source community. Again, if, in your product, you create the right APIs and you create an ecosystem, then people will come and contribute to it, and this is a classic example of that. If I browse to the VSTS marketplace– let’s just try that again.
From here, Browse Marketplace, and look for Pester, you see I’ve got a couple of options here. And both are open source. You come in here, you can see it’s gone through a certain evolution. It was quite basic. It was just able to run the test before, only supported a version of PowerShell, and it’s since been upgraded and updated and provides a lot more features now. So going back in here, I’m going to just add the Pester task which we’ve added from the marketplace. In my PowerShell Script, I’m going to select the script that I just want to exercise. In this case, it’s the calculator function.
And in the Pester Test Runner, I’m not going to make any changes because the default values are good enough. It’s going to look at the build output– build location, identify anything that has– that is a test file, and then simply pick it up. So let’s just save this, call it, click Save. And now queue this build.
It should be pretty quick. It’s just waiting for the hosted agent to be available so that it can schedule this build on the hosted agent.
The build has been picked up by the hosted agent. It’s just taking the code, downloading it. It’s run my PowerShell function. And now it’s executing the Pester test. As you can see here, it’s completed the test execution, and the build is completed. Now, while all your tests have executed, what would have happened if a test would have failed? It would have been a little difficult to start diagnosing why it failed, because you would have had to go in the logs, look at the exact test that was failing, figure out in the log what the inputs and the outputs were.
But, in this case, you don’t really have to do it, because the VSTS testing framework is magically able to pick up the test result file generated by Pester and parse it into a VSTS, and then gives you a way of analysing the test execution results in a graphical interactive way. Let me show you that. So let’s go into the Tests section. And, at the moment, it says that the Visual Studio Test task needs to be added because it’s unable to find any test results.
So in order to make VSTS discover the test results that Pester has generated, I’m going to have to edit the build definition and just add one more task in here, which is called Visual Studio– which is called Publish Test Results.
Publish Test Results, click Add. Now, I don’t have to make any changes apart from changing the format to NUnit. What it’s going to do is it’s going to look at the output directory of the build compile folder and then see if it can find any test results that match the following format. And as long as the framework in question can generate the format which is supported by JUnit, NUnit, VSTest, or XUnit, VSTS will be able to parse that result set and display it in a graphical format. So let’s just save this definition and queue another build.
And, hopefully, this time, when the test executes and it discovers the XML file, when we go back into the Tests section, we should be able to analyse them in a graphical way.
So it’s acquired the agent. It’s just downloading the code. Next up, executing my function. Next up, running the test. And almost done there with the test execution. Now it’s looking to find the XML file. It’s found it. It’s finished the build. Now if we go to the Tests section– whoa, look at that. You get not only test results but incremental test results, which means it’s tracking the trends of the test execution. What you see here is that no tests have failed. If you change the outcome to Passed, then you can see all the individual tests that were executed. It’s got code– it’s code-aware as well.
So if you right-click this and say open a new tab, it will take you to the test analysis results for this specific test, where you can see how much time it spent. And then you can Update analysis here. If a test was failing, you could launch a bug creation report from here. And, again, that brings in all the artefacts with it, for example what build did this test fail in, the specifics of the test execution, when was it run. So all this information, if this tool wasn’t integrated, if the code wasn’t living in the same tool, then you would have had to put in yourself. But the power of integration, boy, this is amazing.
So if we go back into the test results here, what it also allows you to do is look at the test execution duration over the last few builds. And if you wanted to monitor this on a dashboard, then you could simply pin this to the dashboard. If I go back from here into the dashboard for this project, you would see here that a new tile has been added. So if test execution for your PowerShell code or important runbooks is something that the team wants to track, then a widget is available that can simply be put on the dashboard for purposes of tracking. So, really, information radiators integration, all built into this classic devops platform.
So that’s all I really wanted to show you with PowerShell source control, integration with Visual Studio, test execution, CI, and test results analysis. In this module, we’ve covered quite a journey. We started off by looking at ARM templates. We started using PowerShell ISE to deploy them. We quickly promoted ourselves to doing it through Visual Studio. We looked at DevTest Labs manually again, and then we looked at the automation capabilities within DevTest Labs. We looked at creating templates within DevTest Labs, and taking them the whole mile into production. And then we looked at the specifics of PowerShell and how we can use the same tools as the developers use to build a CI test process around your PowerShell scripts.
That’s the end of module 2, but– module 3, but we’ll be back with more exciting stuff in module 4.

Throughout this course, we’ve talked a lot about PowerShell. In this step, we will demonstrate how to set up a CI pipeline in Visual Studio and we’ll test your PowerShell Scripts.

The goal of Infrastructure as Code (IaC) is to generate a build process that creates consistent infrastructure and deploys the application. Changes are committed, and the build process spins up a new server and deploys the application. This means that testing is always performed on a clean machine with a known configuration.

It’s possible with source control to create several builds such as development, test, and production, and to choose which one to target.

Automated testing is critical to any DevOps build process. A set of tests should be run each time your build process is changed. If you’re using Windows PowerShell for your code, you can use the Pester module (Windows 10 and Windows Server 2016, or download it from the PowerShell gallery).

Pester is a test framework for PowerShell. It provides a language that allows you to define test cases, and the Invoke-Pester cmdlet to execute these tests and report the results.

With Export-ODataEndpointProxy, New-WebServiceProxy, Invoke-WebRequest and Invoke-RestMethod, you can interact with web APIs. Because Pester tests are simply PowerShell code, this means that you can use Pester to test all of these things even if they’re not actually written in PowerShell.

The following is a simple example of creating tests with Pester:

A function for dividing two numbers, returns the result of the operation.

function division {

param (




return $a / $b


Add # and say unit tests for the method division below…

Describe -Tags ‘BasicTests’ ‘divisiontest’{

It ‘divides positive numbers’{

divisiontest 6 3 | Should Be 2


It ‘divides negative numbers’ {

divisiontest -6 -3 | Should Be 2


It ‘throws error for divide by zero’ {

{divisiontest 6 0} | Should Throw



The function divides the first parameter by the second. The tests are wrapped in the Describe block and, in this case, test for the correct division of positive and negative numbers. The third test is to determine if the function correctly throws an error when attempting to divide by zero. The results look like this:

Describing divisiontest

[+] divides positive numbers 70ms

[+] divides negative numbers 25ms

[+] throws error for divide by zero 45ms

When you test IaC routines, check the installed Windows features and roles, the network configuration (IP addresses and subnet masks), or the existence of particular folders (use Test-Path).

Be sure to use the same code to create the infrastructure for development, test, and production environments to ensure that you have consistency across the environments.

This prevents any assumptions made in development or testing that might cause problems in production. You now have a reliable and tested configuration to ensure smooth rollout to production.

Join the discussion

Continuous integration and continuous delivery (CI/CD) are often cited as pillars of successful DevOps. Do you agree with this statement and why? Can you think of any other key elements of successful DevOps? Share your thoughts with the group.

Use the Discussion section below and let us know your thoughts. Try to respond to at least one other post and once you’re happy with your contribution, click the Mark as complete button to move on to the next step.

This article is from the free online

Microsoft Future Ready: DevOps Development, Implementation and Azure Automation

Created by
FutureLearn - Learning For Life

Reach your personal and professional goals

Unlock access to hundreds of expert online courses and degrees from top universities and educators to gain accredited qualifications and professional CV-building certificates.

Join over 18 million learners to launch, switch or build upon your career, all at your own pace, across a wide range of topic areas.

Start Learning now