Creating reports in PowerShell

the article Considers questions of text output, report generation, mail sending. Gives advice on how to write reports so many times you can use the code snippets to add the missing pieces, and assemble into a report of greater length.
Definitely need everyone who makes information gathering using PowerShell or want to learn its effective use.

the

the Secrets of creating reports Chapter 33


This section contains

    HTML fragments

    Create stylish HTML reports

    Sending reports via email



In this Chapter we will look at techniques for working with PowerShell when creating reports. PowerShell does not possess if you want to work with strings, try to use objects for this. The more you will use when creating reports the object, the better you will be able to do the treatment.

33.1 What not to do.
Let's start the head with the fact that we believe an example of poor technology reporting. We constantly encounter this style. A big part of IT professionals don't think about it and perpetuate in the code style from other languages, such as VBScript.
The following code is written in a style that we hope you will not apply, and you will see in the code are less well-informed system administrators.

Listing 33.1 Poorly designed script inventory
the
param ($computername)
Write-Host '------- COMPUTER INFORMATION -------'
Write-Host "Computer Name: $computername"

$os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computername
Write-Host " OS Version: $($os.version)"
Write-Host " OS Build: $($os.buildnumber)"
Write-Host " Service Pack: $($os.servicepackmajorversion)"

$cs = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $computername
Write-Host " RAM: $($cs.for totalphysicalmemory)"
Write-Host " Manufacturer: $($cs.manufacturer)"
Write-Host " Model: $($cd.model)"
Write-Host " Processors: $($cs.numberofprocessors)"

$bios = Get-WmiObject -Class Win32_BIOS -ComputerName $computername
Write-Host "BIOS Serial: $($bios.serialnumber)"
Write-Host "
Write-Host '------- DISK INFORMATION -------'
Get-WmiObject -Class Win32_LogicalDisk -Comp $computername –Filt 'drivetype is applied=3' |
Select-Object @{n='Drive';e={$_.DeviceID}},
@{n='Size(GB)';e={$_.Size / 1GB -as [int]}},
@{n='FreeSpace(GB)';e={$_.freespace / 1GB -as [int]}} | Format-Table –AutoSize

The code in listing 33.1 will produce output like this
image
Figure 33.1 the conclusion based on the rows.

As you can see this script working, don Jones (one of authors) seeing the output from a script with clean lines angrily pronounces the saying involving deities and puppies (probably a dirty word in the original Don has a saying involving angry deities and puppies that he utters whenever he sees a script that outputs pure text like this). First of all, this script can output only to the screen, because the output is via Write-Host. In most cases, when you use Write-Host, you're doing it wrong. It would be nice if there would be an opportunity to bring this information in a file or in HTML? You can achieve this by changing all the Write-Host to Write-Output, but it's still going the wrong way.

There are more effective ways of formation of the report, and it's the reason we have written this Chapter. First, we would suggest for each block or function where the generation of information to create a single object containing all the necessary information. The more you break the blocks of code, the more you'll be able to reuse these blocks. In our bad example, the first section of "computer information", should be a function that we will write. It can be used in all reports of this kind. In the tab "disc info" data is indicated as one object, to combine information from different sources is not necessary, but all the cmdlets on the Write needs to go. (note of the translator. How to do it, see the example section 33.2.1 Getting the source information)

Exceptions to every rule
There are exceptions to every rule. Richard Siddaway spends a lot of time conducting audits of foreign systems. He does this in a standard set of scripts. Scenarios are designed to produce output, which then goes either directly into a Word document, either generated files which are then inserted into the document. Thus the initial data can be very quickly obtained and reviewed, so that their analysis and discussion is not delayed.
Rules to break in these scenarios, the following
    the
  1. Output is a mixture of text and objects
  2. the
  3. Output from formatted

It is a conscious decision, because we know how to apply scripts and how to look the report. The moral of the story to deduce objects, and to be ready to go beyond the paradigm if there are reasons for that.

33.2 Working with HTML fragments and files:
The trick of our method is that ConvertTo-HTML can be used in two different ways. The first way is to produce a full HTML page, the second to produce the HTML fragment. This fragment is just an HTML table with the data that was passed to the cmdlet, we will produce each section of the report in the form of fragments, and then assemble the fragments into a complete HTML page.

33.2.1 Getting source information
We will begin with that will collect data in objects, one object for each section of the report. In our case, two object – computer information and disk information. We agree that humility and clarity, we skip the error handling and other niceties. In real terms we would have added them. Get-WMIObject by itself produces an object containing information on the disks. Then I have to create a function object with outstanding information on the computer.

the
function Get-CSInfo {
param($computername)
$os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computername
$cs = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $computername
$bios = Get-WmiObject -Class Win32_BIOS -ComputerName $computername

#property names with spaces need to be enclosed in quotes
$props = @{ComputerName = $computername
'OS Version' = $os.version
'OS Build' = $os.buildnumber
'Service Pack' = $os.sevicepackmajorversion
RAM = $cs.for totalphysicalmemory
Processors = $cs.numberofprocessors
'BIOS Serial' = $bios.serialnumber}

$obj = New-Object -TypeName PSObject -Property $props

Write-Output $obj
}

The function extracts the information from three different WMI classes. Create an object using the hash table, gathered from three objects because I want to be able to transfer the output of the function through the pipeline. Usually we prefer to give the properties names without spaces, now deviate from this rule because they are going to use the names in the final report.

33.2.2 the Production of fragments of HTML reports.

We can now use the written function to get the report in HTML

the
$frag1 = Get-CSInfo –computername SERVER2 | ConvertTo-Html -As LIST-Fragment –PreContent '<h2>Computer Info</h2>' | Out-String

We've been moving towards this trick, so it need to parse:
1. You save the output as a HTML fragment into a variable named $frag1, later we will be able to insert it in the right place withdrawal either alone save it to a file.
2. run Get-CSInfo, it is passed the name of the computer from which we want to get the data, now we write the name of the computer harsh, in the future we will replace it with a variable.
3. The resulting output is served on the ConvertTo-HTML, this command generates the output HTML fragment in a vertical list instead of horizontally. The list will mimic the old report is fail-technology-display-information.
4. We use the option –PreContent to add a label before the label of the report. We have added tags to get a bold header.
5. All that happened is the trick – given in the Out-String. You will see that ConvertTo-HTML put a bunch of stuff in the pipeline. You can see that in the pipeline are written line, the collection of rows, all different other objects. All this will lead in the end to problems when you try to pack it all in the final HTML page, instead we just filed Out String and get a good old row.

You can go ahead and produce the second fragment. It's easier because no need to write a function to generate the HTML will look just as well. The only difference is that we collect data this section in a table rather than a list:

the
$frag2 = Get-WmiObject -Class Win32_LogicalDisk -Filter 'drivetype is applied=3' -ComputerName SERVER2 |
Select-Object @{name='Drive';expression={$_.DeviceID}},
@{name='Size(GB)';expression={$_.Size / 1GB -as [int]}},
@{name='FreeSpace(GB)';expression={
$_.freespace / 1GB -as [int]}} | ConvertTo-Html-Fragment-PreContent '<h2>Disk Info</h2>' | Out-String

We have both fragments, you can proceed to the formation of the final report.

33.2.3 Assembling the final HTML file
Assembly includes adding your two snippets, and style sheets. The use of CSS and language is beyond the scope of this book. The stylesheet allows you to control the formatting of HTML pages so that it looked much better. If you want a good tutorial and links to additional materials on CSS, check http://www.w3schools.com/css/

the
$head = @'
<style>
body { background-color:#dddddd;
font-family:Tahoma;
font-size:12pt; }
td, th { border:1px solid black;
border-collapse:collapse; }
th { color:white;
background-color:black; }
table, tr, td, th { padding: 2px; margin: 0px }
table { margin-left:50px; }
</style>
'@

ConvertTo-HTML -head $head-PostContent $frag1, $frag2 -PreContent "<h1>Hardware Inventory for SERVER2</h1>"

Creates a stylesheet $head in a variable of type string describes the desired style. Then this variable is passed in head, and your fragments are separated with comma in the parameter PostContent. Also add a report title in the PreContent. Save the entire script as C: \ Good.ps1 and run it as follows:
./good > Report.htm
It will redirect output to file Report.htm that will be beautiful, as in figure 33.2

image
Figure 33.2 the report of several fragments

It may not be a work of art, but it is a report that looks better than the report on the screen which was the beginning of this Chapter. Listing 33.2 shows the completed script, where you can specify the computer name, default is localhost. In the title spelled out [CmdletBinding()], that allows you to use –verbose. In the body of the script inserted Write-Verbose, you can see what makes each step.

Listing 33.2 the HTML script inventory
the
<#
.DESCRIPTION
Retrieves inventory information and produces HTML
.EXAMPLE
./Good > Report.htm
.PARAMETER
The name of a computer to query. The default is the local computer.
#>
[CmdletBinding()]
param([string]$computername=$env:computername)
# function to get computer system info
function Get-CSInfo {
param($computername)

$os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computername
$cs = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $computername
$bios = Get-WmiObject -Class Win32_BIOS -ComputerName $computername
$props = @{'ComputerName'=$computername
'OS Version'=$os.version
'OS Build'=$os.buildnumber
'Service Pack'=$os.servicepackmajorversion
'RAM'=$cs.for totalphysicalmemory
'Processors'=$cs.numberofprocessors
'BIOS Serial'=$bios.serialnumber}
$obj = New-Object -TypeName PSObject -Property $props
Write-Output $obj
}
Write-Verbose 'Producing computer system info fragment'
$frag1 = Get-CSInfo -computername $computername | ConvertTo-Html -As LIST-Fragment-PreContent '<h2>Computer Info</h2>' | Out-String
Write-Verbose 'Producing disk info fragment'
$frag2 = Get-WmiObject -Class Win32_LogicalDisk -Filter 'drivetype is applied=3' -ComputerName $computername |
Select-Object @{name='Drive';expression={$_.DeviceID}},
@{name='Size(GB)';expression={$_.Size / 1GB -as [int]}},
@{name='FreeSpace(GB)';expression={$_.freespace / 1GB -as [int]}} |
ConvertTo-Html-Fragment-PreContent '<h2>Disk Info</h2>' | Out-String

Write-Verbose 'Defining CSS'
$head = @'
<style>
body { background-color:#dddddd;
font-family:Tahoma;
font-size:12pt; }
td, th { border:1px solid black;
border-collapse:collapse; }
th { color:white;
background-color:black; }
table, tr, td, th { padding: 2px; margin: 0px }
table { margin-left:50px; }
</style>
'@
Write-Verbose 'Producing final HTML'
Write-Verbose 'Pipe this output to a file to save it'
ConvertTo-HTML -head $head-PostContent $frag1,$frag2 -PreContent "<h1>Hardware Inventory for $ComputerName</h1>"


Using a script
the
PS C:\> $computer = SERVER01
PS C:\> C:\Scripts\good.ps1 -computername $computer |
>> Out-File "$computer.html"
>>
PS C:\> Invoke-Item "$computer.html"

The script generates a HTML file that you can use in the future, and displays the report. Keep in mind that the function Get-CSInfo can be reused. Since it outputs an object and not text, you can use it in many different places where you need to display the same information.
If you need to add more information to the report, to add the new section you will need:
the
    the
  • to Write a function or command generating facility information new sections to the report.
  • the
  • to Create this object an HTML snippet and save it in a variable.
  • the
  • to Add the variable in the variable list of the team build a final report. Thus you will add to the report.
  • the
  • All

Yes, this report is a text. Ultimately, each report will be text because text is what we read. The essence of this method is that everything stays with the object until the last moment. You let PowerShell format for you. Work items this script can be copied and used elsewhere, which is not possible with the original text in the beginning of the Chapter.
33.3 sending email
What could be better than the HTML report? The report, which will automatically come on email!

Fortunately, PowerShell contains a cmdlet Send-MailMessage. A little fix our script:
the
Write-Verbose 'Producing final HTML'
Write-Verbose 'Pipe this output to a file to save it'
ConvertTo-HTML -head $head-PostContent $frag1,$frag2 -PreContent "<h1>Hardware Inventory for $ComputerName</h1>" | Out-File report.htm

Write-Verbose "Sending e-mail"
$params = @{'To'='whomitmayconcern@company.com'
'From'='admin@company.com'
'Subject'='That report you wanted'
'Body'='Please see the attachment.'
'Attachments'='report.htm'
'SMTPServer'='mail.company.com'}

Send-MailMessage @params

we changed the end of the pipeline to redirect the output to a file. Then used the Send-MailMessage as an attachment. You can send HTML as the message body. You don't need to create a file on disk, you can take the output from the conveyor directly. Here is an alternative example
the
Write-Verbose 'Producing final HTML'
$body = ConvertTo-HTML -head $head-PostContent $frag1,$frag2 -PreContent "<h1>Hardware Inventory for $ComputerName</h1>" | Out-String

Write-Verbose "Sending e-mail"
$params = @{'To'='whomitmayconcern@company.com'
'From'='admin@company.com'
'Subject'='That report you wanted'
'Body'=$Body
'BodyAsHTML'=$True
'SMTPServer'='mail.company.com'}

Send-MailMessage @params

Here we built the Send-MailMessage in the hash table and store them in a variable $Param. This allows you to use splat equipment and feed all the parameters of the team immediately. No matter what you will type them as parameters, or will indicate via a hash table will work in any case, but it is better to read.

33.4 Summary
Reporting is definitely a great need for administrators, we wanted to show that PowerShell is well suited for this task. The trick is to create reports so that information retrieval be separated from formatting, and generate output. In fact, PowerShell is able to provide great opportunities for formatting and output when a small amount of work on your part.

PS. from translator
for correct display of the Russian text you need to use
the
$encoding = [System.Text.Encoding]::UTF8
Send-MailMessage @params -Encoding $encoding
Article based on information from habrahabr.ru

Комментарии

Популярные сообщения из этого блога

Monitoring PostgreSQL + php-fpm + nginx + disk using Zabbix

Templates ESKD and GOST 7.32 for Lyx 1.6.x

Customize your Google