PowerShell

More, HTML Reporting in PowerShell – Part 5

HTMLReport.jpg

More?  Okay, Part 5.I just created some new functions for creating two columns in a sections and added functionality for optional alternating row colors for tables. If you have worked through the other 4 parts you will be up to speed. If this is all new to you, I'd suggest to start here @ Part 1, otherwise, let's jump straight in.

Pre-requisites We are going to use the same code to create the Azure VMs recordset and other session variables we built up in the other parts. If you have previously installed this module, you will need to update it to 1.0.0.12 from the PowerShell Gallery. You can run update-module -name ReportHTML or if this is new to you you can use install-module -name ReportHTML.  Additionally you can contribute via github ReportHTML which also has all the Examples scripts for download Example 15 without comments and Example 15 with comments.

Section with Columns (Example 15) First we will create a section with two columns and split the array into each column.

[powershell] ####### Example 15 ######## $rpt = @() $rpt += Get-HtmlOpen -TitleText ($ReportName + "Example 15") $rpt += Get-HtmlContentOpen -BackgroundShade 2 -HeaderText "VM States"

# We will start the first column with a get-htmlColumn1of2 $rpt += get-HtmlColumn1of2

# Now add the content you want in the first column $rpt += Get-HtmlContentOpen -BackgroundShade 1 -HeaderText Deallocated $rpt += Get-HtmlContentTable ($RMVMArray | where {$_.PowerState -eq "Deallocated"} | select ResourceGroup, Name, Size, DataDiskCount, ImageSKU) $rpt += Get-HtmlContentClose

# Next we need to close this first section $rpt += get-htmlColumnClose

# Then we can start the second column with a get-htmlColumn2of2 $rpt += get-htmlColumn2of2 $rpt += Get-HtmlContentOpen -BackgroundShade 1 -HeaderText Running $rpt += Get-HtmlContentTable ($RMVMArray | where {$_.PowerState -eq "Running"} | select ResourceGroup, Name, Size, DataDiskCount, ImageSKU ) $rpt += Get-HtmlContentClose

# Now we need to close this second section $rpt += get-htmlColumnClose $rpt += Get-HtmlContentClose [/powershell]

Alternating Row Color (Example 15) This next code section show the Set-TableRowColor with the -Alternating switch. Using this switch is an either or with the expression colouring.

[powershell] $rpt += Get-HtmlContentOpen -HeaderText 'Alternating Row Color'

# For Alternating row color you can use the -Alternating switch which will add the row color definition for Odd and Even and also adds a header color. $rpt += Get-HtmlContentTable (Set-TableRowColor ($RMVMArray | select ResourceGroup, Name, Location, Size, ImageSKU ) -Alternating) $rpt += Get-HtmlContentclose [/powershell]

ReportExample15

Report Suggestions? Next, I plan to turn my attention to creating some practical reports for use. Even possibly recreating some existing reports for distribution like this computer report.  If you have a report you can share or perhaps one you would like to see created, with special attention given to Azure content please share links, requests or ideas in the comments below.

Addendum Here is a Sample Systems Report and the script that is a recreation of the computer report linked above it could use some more work but shows you what is possible. SystemReportScreenShot It looks like I have a few system errors I need to go look at :)

Part 1 | Part 2 | Part 3 | Part 4 | Part 5

Automation Frameworks & Threshold for Creation

gears-930x620cut.jpg

IntroductionYears ago I was walking through an office and saw an administrator logging onto a system, checking the C drive, updating a spreadsheet, logged off and then repeated this task. In pure disbelief, I stood and watched for a minute then asked, "What are you doing?", as I feared the response was "One of the monthly maintenance tasks, checking C drive space".  I calmly asked him to please stop and went back to my desk to write a script.

As administrators and consultants we constantly have to evaluate when do you automate and when do you just do the task.  There are many variables, time to automate, level of production access or change required (and security's opinion about this), how long it takes now, who's paying, how long will you have to keep doing it and what else you have to do.

Automation Frameworks While there are tasks we can automate and this programmer takes it to a new level of task automation including scripts for emailing his wife and making coffee (if I may quote Wayne and Garth, "we're not worthy, we're not worthy"), there is another side, automation frameworks for multiple scenarios and reuse.   The PowerShell Deployment Toolkit was an amazing framework for deploying System Center.  It took the task of deployment from days and weeks of installations and months of fixing deployments to a few minutes, hours and days and still flex to a variety of deployment patterns.

However, there was a learning curve, a list of prerequisites (some documented and some not), a few tricks and digging around custom code you sometimes had to reverse engineer.   This PowerShell framework could have deployed anything, you just had to write your own XML manifest for what you wanted to deploy but that would take a lot of time learning the XML syntax that the deployment framework understood, testing the deployment, working through 'undocumented features' and so on. I actually extended the existing scripts for our own needs, but now a total of one person knows what those extra XML properties mean.

New Thresholds Cloud technologies like Azure are changing at a pace unseen in the enterprise space. VMs or IaaS compute has shifted through Classic, ARM deployments, versions V1 and V2, not to mention API versions.  Extensions keep being added and DSC brings another layer to the table.  These layers are all shifting with and without each other.  Recently I had the property of the VM.OSProfile change on me from virtualharddisks to VHDs which broke a script.

When we consider developing frameworks like PDT in the cloud space with tools like PowerShell and RGTs we have to consider this threshold to develop with a new set of values.  Is a script with 30 parameters at the top and some blocks of code you have to run manually enough? As opposed to building script with if, then, else, switch and validation logic around this original code.  The logic flow is more than the code for actual deployment. The next level being script to generate the RGTs JSON code or PowerShell syntax dynamically. If this complex code had been using the property VM.OSProfile.virtualharddisks how would the script have responded and would the time to develop (and in the future maintain) this framework, around what is already a fairly streamlined deployment, be worth trading for the time to deploy manually?

Azure Resource Group Templates are a great example, the language is JSON and fairly straight forward at a glance, there are Inputs, Variables, Resources and Outputs. With Azure's rate of changes writing code around this could take weeks and months as opposed to managing several RGTs as the deployments are needed. Devops methodologies are starting to introduce this level of automation into code development and Infrastructure as code is rapidly changing what and how quickly we can rip down an environment and redeploy it.

Investing Time If you do want to invest time, it could be spent working on scripts and policy to reduce cloud costs like turning off VMs over the weekends or machines not tagged properly that were possibly deployed for testing and never deleted which could save more dollars than your time to execute a complex deployment script every month. Perhaps writing PowerShell modules to help with things like reporting or authentication.  Maybe it's worth just reading about what's new instead, I found out about Azure Resource Manager policies months after they were released, keeping up is almost becoming a full time job.

Summary This article doesn't have the answers, it's meant to add new perspective and raise questions about what you automate and how far you push the modularization and reuse of code.

Generating HTML Reports in PowerShell – Part 4

HTMLReport.jpg

Almost doneI'm sure you would like to have something other than "Your Logo Here" at the top of these reports, well you can.  I have modified the module to accept two methods for rendering logos.  The Module will now to accept a file path to a logo or alternatively you can code your base64 string into the module which is the default if no files are specified.

Pre-requisites Again, we are going to use the code to create the Azure VMs recordset and other session variables we built up in Part 1. The module is available through the PowerShell Gallery or can be installed from PowerShell using install-module -name ReportHTML.  Additionally you can contribute via github ReportHTML which also has and all the Examples scripts for download. You can get the example code for part 4 from these Github links with comments and without comment.

Using images for Logos (Example 12) This example will utilize two jpg files, clientlogo and mainlogo and will encode these into base64 strings in the Get-HTMLClose function.

[powershell] ####### Example 12 ######## # The two logo files are stored in the report path $MainLogoFile = join-path $ReportOutputPath "ACELogo.jpg" $ClientLogoFile = join-path $ReportOutputPath "YourLogo.jpg"

$rpt = @() $rpt += Get-HtmlOpen -TitleText ($ReportName + " Example 12") $rpt += Get-HtmlContentOpen -HeaderText "Size Summary" $rpt += Get-HtmlContentTable ($RMVMArray | group Size | select name, count | sort count -Descending) $rpt += Get-HtmlContentClose

# In this case we are going to swap the logos around using ClientLogoFile and MainLogoFile parameters and switching the files used $rpt += Get-HtmlClose -ClientLogoFile $MainLogoFile -MainLogoFile $ClientLogoFile Test-Report -TestName Example12 [/powershell]

ReportExample12

Change logos in the module (Example 13) This example show how the default option works. There are 5 client logo base64 strings encoded into the module. Simply calling the module with -ClientLogoType ClientLogo1 to ClientLogo5 with use a switch statement to select which logo to use. You can use Powershell or a website to create the encoding string. This string can then be put into the module. This obviously breaks receiving updates so I would recommend not using this but it's there at the moment.  Below shows the code where the ClientLogo and MainLogo strings are located.

LogosInModule

[powershell] ####### Example 13 ######## $rpt = @() $rpt += Get-HtmlOpen -TitleText ($ReportName + " Example 13") $rpt += Get-HtmlContentOpen -HeaderText "Size Summary" $rpt += Get-HtmlContentTable ($RMVMArray | group Size | select name, count | sort count -Descending) $rpt += Get-HtmlContentClose

# We have been using Get-HTMLClose up until now which has a default of ClientLogo1 # In this case we can specify ClientLogo5 $rpt += Get-HtmlClose -ClientLogoType ClientLogo5

Test-Report -TestName Example13 [/powershell]

Using images for Logos (Example 14) This example we can pass in the base 64 string directly making moving a report around without an image file easier. This uses the ClientLogoBase64 and MainLogoBase64 parameters.

Edit Please note I uploaded some bad code relating to get-htmlclose and logos please update to 1.0.0.12.  Apologies for any inconvenience. 

[powershell] ####### Example 14 ######## # for this we need to get the file and create the string. You could do this once and code the base64 string into the script $MainLogoFilePath = join-path $ReportOutputPath "ACELogo.jpg" $ClientLogoFilePath = join-path $ReportOutputPath "YourLogo.jpg" $MainBase64 = [Convert]::ToBase64String((Get-Content $ClientLogoFilePath -Encoding Byte)) $clientBase64 = [Convert]::ToBase64String((Get-Content $MainLogoFilePath -Encoding Byte))

# if you run the $clientBase64 and copy the content into a here string you can create the logo image without access to the file.

$rpt = @() $rpt += Get-HtmlOpen -TitleText ($ReportName + " Example 14") $rpt += Get-HtmlContentOpen -HeaderText "Size Summary" $rpt += Get-HtmlContentTable ($RMVMArray | group Size | select name, count | sort count -Descending) $rpt += Get-HtmlContentClose $rpt += Get-HtmlClose -ClientLogoBase64 $MainBase64 -MainLogoBase64 $MainBase64

Test-Report -TestName Example14 [/powershell]

ReportExample14

Conclusion I really hope you find this useful and hope it can help you generate HTML reports on the fly to make someone's job easier.  There is another function ConvertTo-AdvHTML here that requires some HTML knowledge. However this output could be intertwined into ReportHTML module for advanced usage.  There is also a module here which has column sort which could be merged. There is a lot of potential here for expansion on what is there and a lot of room to improve as well.  Please feel free to post suggestions, contact me or contribute via Github.

Good luck.

Part 1 | Part 2 | Part 3 | Part 4 | More

Generating HTML Reports in PowerShell – Part 3

HTMLReport.jpg

Welcome BackYou're still here, hopefully you got the content working from Part 1 and Part 2 in this series about generating HTML reports in Powershell. Now let's have a look at creating a Pie Chart in the script.  The module is available through the PowerShell Gallery or can be installed from PowerShell using install-module -name ReportHTML.  Additionally you can contribute via github ReportHTML which also has and all the Examples scripts for download.

Pre-requisites Again, we are going to use the code to create the Azure VMs recordset and other session variables we built up in Part 1.  You can get the code for part 3 from these Github links with comments and without comment

Module Changes I have added two functions to the module to help create Pie charts.  The first function creates an object that contains the properties for creating the chart.  There is lot of room for expansion and options to create different chart styles I will discuss at the end of this post. Create-HTMLPieChartObject will create a custom object with default chart properties that we pass to the Create-HTMLPieChart function along with a grouped recordset.  Simply using the Powershell group command on an array will create an array with name and count properties that get used as the data points on the chart.  You can alternatively create your own array with Name and Count headings or use and expression to change the existing headings to name and count, meaning you dont have to use group by function.  Please make sure to update your local module files from Github

Creating a Pie Chart (Example 9) First we will create a very basic chart showing a summary of virtual machine power state.

[powershell] ####### Example 9 ######## # First we create a PieChart Object and load it into a variable $PieChartObject = Create-HTMLPieChartObject

# Have a look at what is in this object. $PieChartObject

# Let's set one property $PieChartObject.Title = "VMs Power State"

$rpt = @() $rpt += Get-HtmlOpen -TitleText ($ReportName + " Example 9") $rpt += Get-HtmlContentOpen -HeaderText "Chart Series" $rpt += Create-HTMLPieChart -PieChartObject $PieChartObject -PieChartData ($RMVMArray | group powerstate) $rpt += Get-HtmlContentClose $rpt += Get-HtmlClose

Test-Report -TestName Example9 [/powershell]

ReportExample9

Pie Chart & additional Properties (Example 10) Let's have a look at some of the properties we can set

[powershell] ####### Example 10 ######## $PieChartObject = Create-HTMLPieChartObject $PieChartObject.Title = "VMs Sizes Deployed"

# There is a lot of data so let's make the pie chart a little bigger and explode the largest value $PieChartObject.Size.Height = 600 $PieChartObject.Size.Width = 600 $PieChartObject.ChartStyle.ExplodeMaxValue = $true

$rpt = @() $rpt += Get-HtmlOpen -TitleText ($ReportName + " Example 10") $rpt += Get-HtmlContentOpen -HeaderText "Chart Series"

# To summarize the data I have simply changed the group by property to size $rpt += Create-HTMLPieChart -PieChartObject $PieChartObject -PieChartData ($RMVMArray | group size) $rpt += Get-HtmlContentClose $rpt += Get-HtmlClose Test-Report -TestName Example10 [/powershell]

ReportExample10

Pie Chart & Results Table (Example 11) Here is a quick example with a pie chart and results table

[powershell] ####### Example 11 ######## $PieChartObject1 = Create-HTMLPieChartObject $PieChartObject.Title = "VMs Powerstate" $PieChartObject2 = Create-HTMLPieChartObject $PieChartObject.Title = "VMs Sizes" $PieChartObject.Size.Height = 800 $PieChartObject.Size.Width = 800 $PieChartObject.ChartStyle.ExplodeMaxValue = $true

$rpt = @() $rpt += Get-HtmlOpen -TitleText ($ReportName + " Example 10") $rpt += Get-HtmlContentOpen -HeaderText "Power Summary" $rpt += Create-HTMLPieChart -PieChartObject $PieChartObject1 -PieChartData ($RMVMArray | group powerstate) $rpt += Get-HtmlContentTable ($RMVMArray | group powerstate | select name, count) $rpt += Get-HtmlContentClose $rpt += Get-HtmlContentOpen -HeaderText "VM Size Summary" $rpt += Create-HTMLPieChart -PieChartObject $PieChartObject2 -PieChartData ($RMVMArray | group size) $rpt += Get-HtmlContentTable ($RMVMArray | group Size | select name, count | sort count -Descending) $rpt += Get-HtmlContentClose $rpt += Get-HtmlClose

Test-Report -TestName Example11 [/powershell]

ReportExample11

More Charting Properties There are a lot of properties that can be added to this object. I even thought about creating a couple of defaults sets of properties, for instance defaults for 'Exploded', 'SLA' or 'DisplayValues'. If you want to help expand this chart object, please contribute and edit the github project. The options for charting can be found at microsoft in the Class Reference

Additionally I would like to create some chart functions for line and bar charts, however I haven't had the time to create those functions recently.  If you want to explore this please contribute to github or you can reach out and we can discuss how to go about this.

Summary We have one component left to cover which is changing the logos at the top left and top right that are displayed on the report. Currently these base64 strings are hard coded in the module.  I will be working to create some more dynamics options before posting about this in Part 4.

Part 1 | Part 2 | Part 3 | Part 4 | More

Generating HTML Reports in PowerShell – Part 2

HTMLReport.jpg

Welcome BackHopefully you found Part 1 in this series about generating HTML reports useful. That was an introduction to the basic functions and how to construct a report using ReportHTML module, available through the PowerShell Gallery or can be installed from PowerShell using install-module -name ReportHTML.  Additionally you can contribute via github ReportHTML. Now we are going to build upon those functions and show what else we can do with this module.

Pre-requisites To continue with these examples you will need the code to create the Azure VMs recordset and other session variables from Part 1.  Here is a link for the code for part 2 with comments Report-AzureVMsExamples_Part2WithComments and code without comments Report-AzureVMsExamples_Part2

Adding HyperLinks (Example 6) In this example we are going to create a Hyperlink as a string of values. To do this we need to wrap the hyperlink and the link name in three strings URL01, URL02 and URL03. The construction of a link will look like this. ("URL01 "+ HyperLink + "URL02" + LinkName + "URL03"). We will do this in the below example and create the structure of a hyperlink to the Azure Virtual Machine for each row in the recordset.

[powershell] ####### Example 6 ######## # We need to set some variables for building the URLs to the Azure Resource $Base = "https://portal.azure.com/#resource/subscriptions/" $SubID = $AzureRMAccount.Context.Subscription.SubscriptionId $RG = "/resourceGroups/" $vm = "/providers/Microsoft.Compute/virtualMachines/"

$rpt = @() $rpt += Get-HtmlOpen -TitleText ($ReportName + " Example 6") $rpt += Get-HtmlContentOpen -HeaderText "Virtual Machines"

# Using the expression we can create an expression for each record. # We string the base URL with the subscription ID add the resource group and VM name, # This link is used between URL01 and URL02 we reuse the VM name for the link name and add URL03 $rpt += Get-HtmlContentTable ($RMVMArray | select ResourceGroup, ` @{Name="Azure VM";Expression={"URL01" + $Base + $SubID + $RG + $_."ResourceGroup" + $vm + $_."Name" + "URL02" + $_."Name" + "URL03" }}, ` location, Size,PowerState, DataDiskCount, ImageSKU ) -GroupBy ResourceGroup

$rpt += Get-HtmlContentClose $rpt += Get-HtmlClose

Test-Report -TestName Example6 [/powershell]

ReportExample6

Adding dynamic row colors (Example 7 & 8) In this example we are going to use an to add a colour name to a recordset, which when passed passed to the table content function will render in HTML with colour. There are three colors you can set, green, yellow and red. The first step is to create an expressions that can be evaluated. For this example we are going to color row based on the number of hard disks attached to the VM. You must use a single quote for this expression, that is '. In the expression the work $this is used to represent the current record. In this case we create three expressions, one for each color.

[powershell] ####### Example 7 ######## $VMs = ($RMVMArray | select ResourceGroup, Name, Location, Size,PowerState, DataDiskCount, ImageSKU )

# You must use single quotes here for the expression $Red = '$this.DataDiskCount -ge 2' $Yellow = '$this.DataDiskCount -eq 1' $Green = '$this.DataDiskCount -lt 1'

# call the function and pass the array and color expressions $VMsColoured = Set-TableRowColor $VMs -Red $Red -Yellow $Yellow -Green $Green

# let's just see what the function did $VMsColoured | select ResourceGroup ,name, datadiskcount , RowColor -first 30

$rpt = @() $rpt += Get-HtmlOpen -TitleText ($ReportName + "Example 7") $rpt += Get-HtmlContentOpen -HeaderText "Virtual Machines" $rpt += Get-HtmlContentTable $VMsColoured $rpt += Get-HtmlContentClose $rpt += Get-HtmlClose

Test-Report -TestName Example7 [/powershell]

ReportExample7

[powershell] ####### Example 8 ######## $rpt = @() $rpt += Get-HtmlOpen -TitleText ($ReportName + "Example 8") $rpt += Get-HtmlContentOpen -HeaderText "Virtual Machines"

# here we can sort the rows so the colours are grouped together $rpt += Get-HtmlContentTable ( $VMsColoured | sort DataDiskCount) $rpt += Get-HtmlContentClose $rpt += Get-HtmlClose

[/powershell]

ReportExample8

Summary I hope this has been a useful and you can see potential for using this module in your own scripting. There is still a few more examples to work through. Stay tuned for Part 3. Additionally I will be loading the project into Github.

Part 1 | Part 2 | Part 3 | Part 4 | More