RSS

Tag Archives: IT

#PowerShell – Getting started with #Pester unit tests to improve code quality

#PowerShell – Getting started with #Pester unit tests to improve code quality

On my list I have a couple of PowerShell related subjects I want/need to learn more about. These include, but are not limited to parallelization, GitHub, DSC, PowerShell Core, JEA, Plaster, DBAtools and DBAchecks.

I have been playing around a bit already with parallelization and Github and the next thing on my list was Pester.

Pester in general

For those that do not know it, the Pester Wiki describes Pester as follows:
“Pester provides a framework for running Unit Tests to execute and validate PowerShell commands”.

So basically you use it to run scripts/functions/code with a specific input and tell Pester what the expected output should be. Then the result of the test either passes or fails. This way you can verify if your code works as expected.

Instead of using it to test your code, you can also use it to test if a configuration is the way it should be/you want it to be. By example if you’ve created an Operating System deployment or configured DSC, you can check if the configuration has been applied (correctly) or not.

Another advantage of having Pester tests is that you can easily re-run tests without spending much time.

Reasons to re-run these tests could be if you run the code under other circumstances like by example with PowerShell Core instead of Windows PowerShell or on Windows Server 2019 instead of Windows Server 2012 R2.  A more common reason is when you change (parts of) your code that you can easily verify if your changes did not break anything. Keep in mind however that if you change your code, you might also need to change and/or add tests.

If you want to, you can use Pester as part of your Continuous Integration and Continuous Deployment (CI/CD) pipeline. But that’s beyond my knowledge and this post. If you want to know more about it, check Microsoft’s article ‘Building a Continuous Integration and Continuous Deployment pipeline with DSC’.

My plan for getting started with Pester

First, I started reading some articles about Pester, then I purchased ‘The Pester Book’ by Adam Bertram. I started reading the first couple of chapters, but didn’t finish it yet. It did provide me with the basics I needed to get started though. Instead of continuing to read the book, I decided to simply start using Pester with a simple real-life example and then build upon that.

The example I decided to start was a simple script I wrote in the past for a colleague to translate network addresses in the IP CIDR format to the IP subnet mask format. By example if the IP CIDR address was ‘192.168.1.1/24’ the output should be ‘192.168.1.1 255.255.255.0’. Basically it would take the input ‘192.168.1.1/24’ split it at the forward slash ( / ) and then use a switch statement to translate the CIDR notation (by example 24) to the subnet mask notation (by example 255.255.255.0).

To be honest I didn’t expect many advantages of using Pester for this specific script.

Actually getting started with Pester

Actually getting started with Pester consisted of the following steps that will be described in more detail:

  1. Installing Pester
  2. Creating a Pester tests file
  3. Coming up with tests
  4. Actually writing the PowerShell / Pester code for the tests you came up with
  5. Running the tests
  6. Analyzing the results, fixing code and re-running tests until all tests pass
  7. Checking code coverage, modifying code / tests, rerunning tests and checking code coverage

I have tried to include relevant parts of the code in my blog, but readability isn’t as good as I would like it to be. So it’s best if you simply download the files yourself from my GitHub.

1. Installing Pester

In my case I had already installed the latest version of Pester, but if you haven’t done that already you can do so by running PowerShell as administrator and running:

Install-Module -Name Pester -Force -SkipPublisherCheck

2. Creating a Pester tests file

My initial script full path was C:\Scripts\Convert-IPCIDRNotationtoIPSubnetMaskNotation.ps1 and the initial version of it can be found on my GitHub page.

Then I used

New-Fixture -path C:\Scripts -Name Convert-IPCIDRNotationtoIPSubnetMaskNotation

to create a C:\Scripts\Convert-IPCIDRNotationtoIPSubnetMaskNotation.tests.ps1 file that is linked to the initial script and that will contain the Pester tests for my script. The linking looks as follows:

$here = Split-Path -Parent $MyInvocation.MyCommand.Path

$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace ‘\.Tests\.’, ‘.’

. $here\$sut

Sidenote: When using Test Driven Development (TDD) to create your code you first define your tests and then write your code. So if you create a new solution this way, you would also use New-Fixture and it would create both your empty script file and a linked Pester tests file.

3. Coming up with tests

Think about all possible scenarios and how you can test them. In my case the tests should at least test all possible input CIDR values ranging from 0 to 32 and if the subnet mask output would be what I expected.

4. Actually writing the PowerShell / Pester code for the tests you came up with

Pester tests have their own terminology and syntax. The Pester Book’ by Adam Bertram does a great job covering them in detail.

In this example in its simplest form you have  a ‘Describe‘ block containing a single test or a logical group of tests contained in ‘It‘ statements where you define the code that should be run and what the output should be. By example you could have a logical group of tests for testing input validation and you could have a logical group of tests for testing if the output is as expected. In

This would then by example look like this:

$here = Split-Path -Parent $MyInvocation.MyCommand.Path

$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace ‘\.Tests\.’, ‘.’

. $here\$sut

Describe “Verify input validation working correctly” {

    It “Valid input (1.1.1.1/0) Should not throw” {

        {Convert-IPCIDRNotationtoIPSubnetMaskNotation -IPCIDR ‘1.1.1.1/0’ | Should Not Throw}

    }

    It “Invalid formatting (1.1.1.1-0 instead of 1.1.1.1/0) should throw” {

        {Convert-IPCIDRNotationtoIPSubnetMaskNotation -IPCIDR ‘1.1.1.1-0’ | Should Not Throw}

    }

    It “Invalid IP address (1.1.1.1.1) Should throw” {

        {Convert-IPCIDRNotationtoIPSubnetMaskNotation -IPCIDR ‘1.1.1.1.1/0’ | Should Not Throw}

    }

    It “Invalid IP address (1.1.1.256) Should throw” {

        {Convert-IPCIDRNotationtoIPSubnetMaskNotation -IPCIDR ‘1.1.1.1.1/0’ | Should Not Throw}

    }

    It “Invalid IP address (001.001.001.001) Should throw” {

        {Convert-IPCIDRNotationtoIPSubnetMaskNotation -IPCIDR ‘1.1.1.1.1/0’ | Should Not Throw}

    }

    It “Invalid CIDR (/33) Should Throw” {

        {Convert-IPCIDRNotationtoIPSubnetMaskNotation -IPCIDR ‘1.1.1.1/33’ | Should Throw}

    }

}

Describe “Verify if output from Convert-IPCIDRNotationtoIPSubnetMaskNotation is correct” {

    $TestCases = @(

        @{InputValue = ‘192.168.1.1/0’; ExpectedIPCIDR = ‘192.168.1.1/0’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘0.0.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 0.0.0.0’}

        @{InputValue = ‘192.168.1.1/1’; ExpectedIPCIDR = ‘192.168.1.1/1’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘128.0.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 128.0.0.0’}

        @{InputValue = ‘192.168.1.1/2’; ExpectedIPCIDR = ‘192.168.1.1/2’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘192.0.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 192.0.0.0’}

        @{InputValue = ‘192.168.1.1/3’; ExpectedIPCIDR = ‘192.168.1.1/3’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘224.0.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 224.0.0.0’}

        @{InputValue = ‘192.168.1.1/4’; ExpectedIPCIDR = ‘192.168.1.1/4’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘240.0.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 240.0.0.0’}

        @{InputValue = ‘192.168.1.1/5’; ExpectedIPCIDR = ‘192.168.1.1/5’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘248.0.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 248.0.0.0’}

        @{InputValue = ‘192.168.1.1/6’; ExpectedIPCIDR = ‘192.168.1.1/6’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘252.0.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 252.0.0.0’}

        @{InputValue = ‘192.168.1.1/7’; ExpectedIPCIDR = ‘192.168.1.1/7’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘254.0.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 254.0.0.0’}

        @{InputValue = ‘192.168.1.1/8’; ExpectedIPCIDR = ‘192.168.1.1/8’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.0.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.0.0.0’}

        @{InputValue = ‘192.168.1.1/9’; ExpectedIPCIDR = ‘192.168.1.1/9’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.128.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.128.0.0’}

        @{InputValue = ‘192.168.1.1/10’; ExpectedIPCIDR = ‘192.168.1.1/10’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.192.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.192.0.0’}

        @{InputValue = ‘192.168.1.1/11’; ExpectedIPCIDR = ‘192.168.1.1/11’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.224.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.224.0.0’}

        @{InputValue = ‘192.168.1.1/12’; ExpectedIPCIDR = ‘192.168.1.1/12’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.240.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.240.0.0’}

        @{InputValue = ‘192.168.1.1/13’; ExpectedIPCIDR = ‘192.168.1.1/13’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.248.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.248.0.0’}

        @{InputValue = ‘192.168.1.1/14’; ExpectedIPCIDR = ‘192.168.1.1/14’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.252.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.252.0.0’}

        @{InputValue = ‘192.168.1.1/15’; ExpectedIPCIDR = ‘192.168.1.1/15’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.254.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.254.0.0’}

        @{InputValue = ‘192.168.1.1/16’; ExpectedIPCIDR = ‘192.168.1.1/16’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.0.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.0.0’}

        @{InputValue = ‘192.168.1.1/17’; ExpectedIPCIDR = ‘192.168.1.1/17’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.128.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.128.0’}

        @{InputValue = ‘192.168.1.1/18’; ExpectedIPCIDR = ‘192.168.1.1/18’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.192.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.192.0’}

        @{InputValue = ‘192.168.1.1/19’; ExpectedIPCIDR = ‘192.168.1.1/19’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.224.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.224.0’}

        @{InputValue = ‘192.168.1.1/20’; ExpectedIPCIDR = ‘192.168.1.1/20’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.240.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.240.0’}

        @{InputValue = ‘192.168.1.1/21’; ExpectedIPCIDR = ‘192.168.1.1/21’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.248.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.248.0’}

        @{InputValue = ‘192.168.1.1/22’; ExpectedIPCIDR = ‘192.168.1.1/22’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.252.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.252.0’}

        @{InputValue = ‘192.168.1.1/23’; ExpectedIPCIDR = ‘192.168.1.1/23’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.254.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.254.0’}

        @{InputValue = ‘192.168.1.1/24’; ExpectedIPCIDR = ‘192.168.1.1/24’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.255.0’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.255.0’}

        @{InputValue = ‘192.168.1.1/25’; ExpectedIPCIDR = ‘192.168.1.1/25’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.255.128’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.255.128’}

        @{InputValue = ‘192.168.1.1/26’; ExpectedIPCIDR = ‘192.168.1.1/26’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.255.192’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.255.192’}

        @{InputValue = ‘192.168.1.1/27’; ExpectedIPCIDR = ‘192.168.1.1/27’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.255.224’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.255.224’}

        @{InputValue = ‘192.168.1.1/28’; ExpectedIPCIDR = ‘192.168.1.1/28’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.255.240’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.255.240’}

        @{InputValue = ‘192.168.1.1/29’; ExpectedIPCIDR = ‘192.168.1.1/29’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.255.248’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.255.248’}

        @{InputValue = ‘192.168.1.1/30’; ExpectedIPCIDR = ‘192.168.1.1/30’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.255.252’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.255.252’}

        @{InputValue = ‘192.168.1.1/31’; ExpectedIPCIDR = ‘192.168.1.1/31’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.255.254’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.255.254’}

        @{InputValue = ‘192.168.1.1/32’; ExpectedIPCIDR = ‘192.168.1.1/32’; ExpectedIpAddress = ‘192.168.1.1’; ExpectedSubnetMask = ‘255.255.255.255’; ExpectedIpAndSubnetMask = ‘192.168.1.1 255.255.255.255’}

        )

    It “IPCIDR result for input <inputvalue> should be <ExpectedIPCIDR>” -TestCases $TestCases {

        param($InputValue, $ExpectedIpCIDR, $ExpectedIpAddress, $ExpectedSubnetMask, $ExpectedIpAndSubnetMask)

        (Convert-IPCIDRNotationtoIPSubnetMaskNotation -IPCIDR $InputValue).IPCIDR | Should -Be $ExpectedIpCIDR

    }

    It “IPAddress result for input <inputvalue> should be <ExpectedIpAddress>” -TestCases $TestCases {

        param($InputValue, $ExpectedIpCIDR, $ExpectedIpAddress, $ExpectedSubnetMask, $ExpectedIpAndSubnetMask)

        (Convert-IPCIDRNotationtoIPSubnetMaskNotation -IPCIDR $InputValue).IpAddress | Should -Be $ExpectedIpAddress

    }

    It “SubNetMask result for input <inputvalue> should be <ExpectedSubnetMask>” -TestCases $TestCases {

        param($InputValue, $ExpectedIpCIDR, $ExpectedIpAddress, $ExpectedSubnetMask, $ExpectedIpAndSubnetMask)

        (Convert-IPCIDRNotationtoIPSubnetMaskNotation -IPCIDR $InputValue).SubnetMask | Should -Be $ExpectedSubnetMask

    }

    It “Ip and subnet mask result for input <inputvalue> should be <ExpectedIpAndSubnetMask>” -TestCases $TestCases {

        param($InputValue, $ExpectedIpCIDR, $ExpectedIpAddress, $ExpectedSubnetMask, $ExpectedIpAndSubnetMask)

        (Convert-IPCIDRNotationtoIPSubnetMaskNotation -IPCIDR $InputValue).IpAndSubnetMask | Should -Be $ExpectedIpAndSubnetMask

    }

}

Sidenote: In the example above I used testcases to define multiple inputs to test, but you could also use standard PowerShell code like getting input from a CSV and using a Foreach. This would look like this:

$Tests = Import-Csv -path $here\Convert-IPCidrNotationToIpSubnetMaskNotation.Tests.Csv” -Delimiter ‘;’

Foreach ($Test in $Tests) #Determine for your own situation if you should use a foreach or Pester test cases

{

    Describe “Convert-IPCIDRNotationtoIPSubnetMaskNotation for $($Test.Input) {

        $Result = Convert-IPCIDRNotationtoIPSubnetMaskNotation -IPCIDR $Test.Input

        It “IPCIDR result should be $($Test.ExpectedIpCIDR) {

            $Result.IPCIDR | Should -Be $($Test.ExpectedIpCIDR)

        }

        It “IPAddress result should be $($Test.ExpectedIPAddress) {

            $Result.IpAddress | Should -Be $($Test.ExpectedIPAddress)

        }

        It “SubNetMask result should be $($Test.ExpectedSubnetMask) {

            $Result.SubNetMask | Should -Be $($Test.ExpectedSubnetMask)

        }

        It “Ip and subnet mask result should be $($Test.ExpectedIpAndSubnetMask) {

            $Result.IpAndSubNetMask | Should -Be $($Test.ExpectedIpAndSubnetMask)

        }

    }

}

5. Running the tests

Even though you can simply run the C:\Scripts\Convert-IPCIDRNotationtoIPSubnetMaskNotation.tests.ps1 file directly and run the tests, you should use Invoke-Pester because it gives your more options. In this simple example however, the differences aren’t that big but with Invoke-Pester it will show you how long it took to run all tests and how many tests had the result passed, failed, skipped, pending and inconclusive. So in this case you would run:

Invoke-Pester -Script ‘C:\scripts\Convert-IPCIDRNotationtoIPSubnetMaskNotation.Tests.ps1’

6. Analyzing the results, fixing code and re-running tests until all tests pass

Before I mentioned that I didn’t expect many advantages of using Pester for this specific script, but boy was I wrong. Apparently I made typos in the switch statement and without Pester I would have probably never noticed them. It could have caused major issues If this had been used in production for by example creating firewall rules.

By fixing issues and re-running the tests I finally got rid of the errors in my code. If you are interested in what mistakes I made and what I corrected, take a look at GitHub.

7. Checking code coverage, modifying code / tests, rerunning tests and checking code coverage

The code coverage of your tests basically describes to what degree your tests cover all possible scenarios. So if I had only tested only half of the options in the switch statement, my code coverage could never be 100%. For more info, see the Pester Wiki about code coverage.

The cool thing about Pester is that if you specify the -CodeCoverage parameter with Invoke-Item, it will create a code coverage report for you. So you would run by example:

Invoke-Pester -Script ‘C:\scripts\Convert-IPCIDRNotationtoIPSubnetMaskNotation.Tests.ps1’ -CodeCoverage ‘C:\scripts\Convert-IPCIDRNotationtoIPSubnetMaskNotation.ps1’

Then it would tell you what percentage is covered by your tests and it even tells you what part(s) you not have tested. I have to admit that I don’t know exactly how it works and if it’s able to detect everything so you have to be critical yourself as well.

In my case I had defined the default keyword in the switch statement to return an error if the CIDR value was not between 0 and 32. I however forgot to write a test for it. Instead of writing a test for it, I decided in this case it would be better to modify the existing script to do input validation and then write tests to test if the input validation was working correctly. After this, the code coverage was 100%

Sidenote: You don’t always have to have 100% code coverage for a script from the start. Often you have limited time and it is not feasible to write tests for scenarios that are unlikely to ever happen. This is something you have to decide yourself. You can always add/improve tests later on and each test you have created is better than having none at all.

Closing thoughts

Pester is a great tool that helps to improve your code, even for simple code. We are all human and we all make mistakes. Pester helps me finding these issues and therefore improves my code quality. It also gives me a better feeling and more confidence about the scripts I’ve written.

What I also really like, is that making changes to an existing scripts takes less time and is less likely to create issues that will not be noticed. This is because you can easily re-run the tests that you have already created. You should still keep in mind that changes to your code might require changes to existing tests or might require you to add tests. But using the -codecoverage parameter of Invoke-Pester also helps you with that.

I purposely chose this simple example just to get started, but Pester can do much more. I plan to read more about it in ‘The Pester Book’ by Adam Bertram and when I get a good use case I will blog about it.

If you have any thoughts about this article, please leave a reply as this motivates me to create more blog posts.

Advertisements
 
Leave a comment

Posted by on June 15, 2018 in ICT, Microsoft, Powershell

 

Tags: , , , , , , , , , , , , , , , ,

ICT – Great article by Paul Simoneau about ICT challenges including suggestions to deal with them

As an ICT professional I believe working in ICT can be very challenging. Paul Simoneau wrote a great article about current and future challenges including suggestions to deal with them.

The challenges covered in the article are: new technology, cloud, big data analytics, virtualization, Bring Your Own Device/Apps (BYOD/BYOA), shadow IT, new generations of workers, energy  efficiency, user systems, creating value, interoperability and social networks.

I wanted to share this article because I feel it reflects reality very well.

 

Tags: , , , , , , , , , , , , , , , , , , , , , , , , , , ,

Cloud – ITpreneurs CCC Professional Cloud Solutions Architect course

At the beginning of September I had the opportunity to attend the first ever Cloud Credential Council (CCC) Professional Cloud Solutions Architect (PCSA) course from ITpreneurs. The trainer was Mark Skilton and I really loved the training. But before telling you more about my experience, I’ll first first explain both the certification and the course in a bit more detail.

What is the CCC Professional Cloud Solutions Architect (PCSA) certification and who is it for ?

The PCSA certification is a globally recognized certification for technology architects. Solution Architects need to understand the impact that cloud is having on business and information architecture, application design, data management and security architecture and be very familiar with the topology and ecosystems that are being created as a result of increasing adoption of cloud technologies and operating models The certification is designed for senior technology professionals who are architecting and designing the future generation of technology solutions. Being PCSA-certified showcases your cloud architecting experience, skills and knowledge, and demonstrates you are capable to manage the various stakeholders within the enterprise. For more information, please take a look at the website: http://www.cloudcredential.org/en/certifications/professional-level/cloud-solutions-architect

What is the ITpreneurs CCC Professional Cloud Solutions Architect (PCSA) course ?

The ITpreneurs CCC PCSA course is a 3-day instructor led course that provides attendees with the required knowledge and skills for the CCC Professional Cloud Solutions Architect (PCSA) certification. The course material was created by lead author Mark Skilton and peer reviewers Vladimir Baranek and RajaGopalan Varadan. For more information, contact ITpreneurs and/or take a look at the course description: http://www.itpreneurs.com/cloud/CCC-courses/cloud-solutions-architect-VCC1310-itpreneurs.pdf

My experiences with and opinion about the ITpreneurs CCC PCSA course

Like I said at the beginning, I really loved the CCC PCSA course because:

  • It covers an important current topic that I believe will become even more important in the future.
  • The course materials are very complete and of great quality.
  • There’s a good balance between theoretical and practical knowledge.
  • The cases are mini workshops that force you to apply your knowledge, which provides more insight. They are also consistent with cases from previous cloud courses from ITpreneurs.
  • There is a lot of interaction between the trainer and the students.
  • Mark Skilton presented the course with a lot of enthusiasm and modified the course content on the go to focus more on the interests of the audience. 

One of the difficult parts of cloud computing is that it’s a very broad definition. As such, different interpretations and explanations are used for the same word/technology by different people and companies. So during the course there were some discussions. I thought this was good, because this will happen in real-life as well. It also stresses the importance of clear definitions and verifying correct understanding of all involved parties.

The special version of the course I attended was only two days, while the regular course will be three days. Since there was so much information to take in and because there were many discussions, the two days unfortunately weren’t enough to cover everything. ITpreneurs and Mark Skilton modified the course on the fly to cover the most important things, but I would have loved to go into more detail during the course if there had been time. Unfortunately this wasn’t the case, but since the course materials are of great quality I’ll be reading them at home instead.

As always there’s room for improvement. Our class provided a lot of feedback that Mark Skilton and ITpreneurs took to heart. They seemed to be really committed to improving the course so I expect the course to become even better since the course materials are currently being reassessed and restructured.

I hope you enjoyed reading about my course experience. For those interested in it, I added some more information about ITpreneurs and the Cloud Credential Council at the end of this blog post.

Thanks

I’d like to thank Corjan Bast and ITpreneurs for providing me with the opportunity to attend this course free of charge. I also want to thank Mark Skilton and all other great people involved in this course for their participation, valuable input and hard work.

Read the rest of this entry »

 
 

Tags: , , , , , , , , , , , , , , , , ,

1st Dutch PowerShell User Group (DuPSUG) meeting on November 23rd

At November 23rd the 1st Dutch Powershell User Group (DuPSUG) meeting will be held in November at Master IT in Eindhoven for free.

Sessions:

  • Using Windows PowerShell 3.0 to manage the remote Windows 8 workstation
    Ed Wilson (Microsoft Scripting Guy)
  • PowerShell and WMI
    Richard Siddaway (PowerShell MVP)
  • What’s new in PowerShell 3.0
    Bert Wolters (Microsoft Certified Trainer with Master it Training)
  • Protect your PowerShell scripts with version control
    Stefan Stranger (Senior Premier Field Engineer at Microsoft Netherlands)
  • From command, to script, to function, to advanced function, to tool.
    Jeff Wouters (freelance Technology Specialist at Methos IT)

Read more about the meeting, the sessions and the speakers here: http://www.dupsug.com/

Also keep in mind that the available seats are very limited, so quickly sign up if your interested.

 

Tags: , , , , , , , , , , , , , , , , , , , , , ,

 
%d bloggers like this: