PowerShell HTML report output format

I need some help on the report output for a PowerShell script I'm putting together. The script get's information from a computer on the following items.

Last Rebooted by Uptime Pending Reboot Patching Information

The problem I'm having is with the "Patching Information" output. The information I want returned under this heading is "Hotfixid","description","installedby","installedon"

If I specify one value such as "Updates.hotfixid" I get the results but If I try adding the others I get returned System.Object[] System.Object[].

Also the output under this heading wraps but i'd like it to list.

Below is the script

    $comps = Get-Content 'c:\temp\comp.txt'

    $total = $null

    $html = @'
    <html>
    <head>
    <meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>
    <title> Server Maintenance Report</title>
    <STYLE TYPE="text/css">
    <!--
    td {
    font-family: Tahoma;
    font-size: 13px;
    border-top: 1px solid #999999;
    border-right: 1px solid #999999;
    border-bottom: 1px solid #999999;
    border-left: 1px solid #999999;
    padding-top: 0px;
    padding-right: 0px;
    padding-bottom: 0px;
    padding-left: 0px;
    }
    body {
    margin-left: 5px;
    margin-top: 5px;
    margin-right: 0px;
    margin-bottom: 10px;

    table {
    border: thin solid #000000;
    }
    -->
    </style>
    </head>
    <body>
    <table width='100%'>
    <tr bgcolor='#CCCCCC'>
    <td colspan='7' height='25' align='center'><strong><font color="#003399" size="4" face="tahoma"> Report </font></strong></td>
    </tr>
    </table>
    <table width='100%'><tbody>
          <tr bgcolor=#CCCCCC>
          <td width='14%' height='15' align='center'> <strong> <font color="#003399" size="2" face="tahoma" >Server Name</font></strong></td>
          <td width='14%' height='15' align='center'> <strong> <font color="#003399" size="2" face="tahoma" >Last Rebooted By</font></strong></td>
          <td width='16%' height='15' align='center'> <strong> <font color="#003399" size="2" face="tahoma" >Uptime</font></strong></td>
          <td width='8%' height='15' align='center'> <strong> <font color="#003399" size="2" face="tahoma" >Pending Reboot</font></strong></td>
          <td width='50%' height='15' align='center'> <strong> <font color="#003399" size="2" face="tahoma" >Patching Information</font></strong></td>
          </tr>" 
    </table>
    <table width='100%'><tbody>
    '@

    Function Uptime($comp){
            function WMIDateStringToDate($Bootup) {
             [System.Management.ManagementDateTimeconverter]::ToDateTime($Bootup)
            }
            $NameSpace = "Root\CIMV2"
            $wmi = [WMISearcher]""
            #$wmi.options.timeout = '0:0:30' #set timeout to 30 seconds
            $query = 'Select * from Win32_OperatingSystem'
            $wmi.scope.path = "\\$comp\$NameSpace"

            $wmi.query = $query
            Try{
                $wmiresult = $wmi.Get()
                foreach ($wmioutput in $wmiresult){
                   $Bootup = $wmioutput.LastBootUpTime
                   $LastBootUpTime = WMIDateStringToDate($Bootup)
                   $now = Get-Date
                   $Reporttime = $now - $lastBootUpTime
                   $d = $Reporttime.Days
                   $h = $Reporttime.Hours
                   $m = $Reporttime.Minutes
                   $time = "Up for: {0} days, {1} hours, {2:N0} minutes" -f $d,$h,$m
                   return $time 
                }
            }
            Catch [Exception] {
                $uperr = '<font color="#FF0000"> RPC Issue : </font>'+ $_
                return $uperr 
            }
        }

    Function RebootedBy($comp){
            try {
            gwmi win32_ntlogevent -filter "LogFile='System' and EventCode='1074' and Message like '%restart%'" -ComputerName $comp | 
            Where {$_.ConvertToDateTime($_.TimeGenerated) -gt $lastBootUpTime}  | 
            select User,@{n="Time";e={$_.ConvertToDateTime($_.TimeGenerated)}} -First 1
            }
            Catch [Exception] {
                $uperr = '<font color="#FF0000"> RPC Issue : </font>'+ $_
                return $uperr 
            }
        }


    Function Updates ($comp){
            try {
            $date = Get-Date '26/09/2013'
            (Get-HotFix -ComputerName $comp| where-object {$_.hotfixid -ne "file 1"} | where "InstalledOn" -gt $date | Select hotfixid,description,installedby,@{l="InstalledOn";e={[DateTime]::Parse($_.psbase.properties["installedon"].value,$([System.Globalization.CultureInfo]::GetCultureInfo("en-US")))}} )
            }
            Catch [Exception] {
                $uperr = '<font color="#FF0000"> RPC Issue : </font>'+ $_
                return $uperr 
            }
         }


    function PendingReboot ($comp){
        process {
            try {
                $WMI_OS = ""
                $RegCon  = ""
                $WMI_OS = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $comp -ErrorAction Stop
                if ($?){
                try{ 
                    $RegCon = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]"LocalMachine",$comp) 
                    If ($WMI_OS.BuildNumber -ge 6001){ 
                        $RegValueSetupex = ""
                        $RegValuePFRO2k8 = ""
                        $RegSubKeySM = $RegCon.OpenSubKey("SYSTEM\CurrentControlSet\Control\Session Manager\") 
                        $RegValueSetupex = $RegSubKeySM.GetValue("SetupExecute",$null) 
                        if ($RegValueSetupex){
                            $RegValueSetupex = $true
                        }

                        $RegSubKeySM = $RegCon.OpenSubKey("SYSTEM\CurrentControlSet\Control\Session Manager\") 
                        $RegValuePFRO2k8 = $RegSubKeySM.GetValue("PendingFileRenameOperations",$null) 
                        if ($RegValuePFRO2k8 ){
                            $RegValuePFRO2k8  = $true
                        }

                        $RegCon.Close()

                        if ( $RegValueSetupex -eq $true -or $RegValuePFRO2k8 -eq $true){
                            return '<font color="#FF0000">'+$true
                        }
                        else {
                            return $false                           
                        }
                    }
                    else{   
                        $RegValuePFRO2k3 = $false;
                        $RegCon = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]"LocalMachine","$comp") 
                        $RegSubKeySM = $RegCon.OpenSubKey("SYSTEM\CurrentControlSet\Control\Session Manager\") 
                        $RegValuePFRO2k3 = $RegSubKeySM.GetValue("PendingFileRenameOperations",$null) 
                        $RegCon.Close()
                        If ($RegValuePFRO2k3) { 
                            return  '<font color="#FFFF00">'+$true; 
                        }
                        else {
                            return $false; 
                        } 
                    }

                }
                catch {
                    return '<font color="#7CFC00">'+"Remote Registry Service OK"
                }
                }
                else {
                    throw $error[0].Exception
                }
            }   
            catch {
                    return '<font color="#FF0000">'+"RPC Issue"         
            }
        }
    }


    $i=0 # for Progress bar

    foreach($comp in $comps){
        $i++
        $ErrorActionPreference = "SilentlyContinue" 
        Write-Progress   -Activity "Report v1.0" -Status ("Checking : {0}" -f $comp) -PercentComplete ($i/$comps.count*100) -Id 0 
        $ErrorActionPreference = "Continue"
        #region Var_Nulling :p  
        $Reporttimestatus  = $null

        #endregion
        $Reporttimestatus = uptime -comp $comp
        $RebootedBy = RebootedBy $comp
        $Pending = PendingReboot -comp $comp
        $Updates = Updates -comp $comp

        $newobj = $null
        $newobj = new-object psobject
        $newobj | add-member -membertype noteproperty -name "Server" -value $comp 
        $newobj | add-member -membertype noteproperty -name "Uptime" -value $Reporttimestatus
        $newobj | add-member -membertype noteproperty -name "RebootedBy" -value $RebootedBy.User , $RebootedBy.Time
        $newobj | add-member -membertype noteproperty -name "PendingReboot" -value $Pending
        $newobj | add-member -membertype noteproperty -name "Updates" -value $Updates.hotfixid
        #, $Updates.description , $Updates.installedby , $Updates.InstalledOn

        $htmlserver = $newobj.Server
        $htmluptime = $newobj.Uptime
        $htmlrebootedby = $newobj.RebootedBy
        $htmlpendingreboot =  $newobj.PendingReboot
        $htmlupdates = $newobj.Updates

    $current = "
            <tr bgcolor=#CCCCCC>
            <td width='14%' align='center'>$htmlserver</td>
            <td width='14%' align='center'>$htmlrebootedby</td>
            <td width='16%' align='center'>$htmluptime</td>
            <td width='8%' align='center'>$htmlpendingreboot</td>
            <td width='50%' align='left'>$htmlupdates</td>
            </tr> "

        $total += $current

    }

    $HTMLEnd = @"
    </div>
    </body>
    </html>
    "@

    $MainHtml= $html + $total + $HTMLEnd
    $MainHtml  | Out-File "c:\temp\Report.html" -Append

Answers


You're trying to assign Updates an array of arrays value because in Powershell V3 $arrayOfObject.propertyName outputs the property value for every element in that array. The feature is called member enumeration. That is why the formatting you're getting isn't ideal.

Why don't you assign the "Updates" field the value $updates e.g.:

$newobj | add-member -membertype noteproperty -name "Updates" -value $Updates

That will contain an array of objects, each of which will have properties hotfixid, description, installeby, installedOn. Then in your $current HTML fragment, I would iterate over each update and spit out each individual field. Perhaps a table within a table.

$current = @"
        <tr bgcolor=#CCCCCC>
        <td width='14%' align='center'>$htmlserver</td>
        <td width='14%' align='center'>$htmlrebootedby</td>
        <td width='16%' align='center'>$htmluptime</td>
        <td width='8%' align='center'>$htmlpendingreboot</td>
        </tr> 
        $(foreach ($update in $updates) {
          "<tr><td>$($update.hotfixid)</td>"
          "<td>$($update.description)</td>"
          "<td>$($update.installedby)</td>"
          "<td>$($update.installedon)</td></tr>"
        })
"@

Need Your Help

Stop the thread until the celery task finishes

python django celery

I have a django webserver, and a form in which the user enters information. Everytime the form information changes I update the model in my database, and at a certain point when something validates I

Nested Set Query to retrieve all ancestors of each node

mysql sql select sql-order-by nested-sets

I have a MySQL query that I thought was working fine to retrieve all the ancestors of each node, starting from the top node, down to its immediate node. However when I added a 5th level to the nest...