May 1, 2017

Script to create PC Environment Report

This Script generates a dynamic PC Environment Report. The report can include various information from Configuration Manager and Active Directory depending on your needs. There is an option to send this report as a mail to the specified recipient(s).

The information that can be collected from Configuration Manager is:

  • Patch Compliance overview showing a given past number of Software Update Groups (default 3 Groups)
  • Application categorization showing the number of applications that are either superseeded, without deployment or expired
  • Devices categorization showing the number of devices that are active, inactive, obsolete and without a configuration manager client
  • Computer reboot overview showing how many computers that have not been rebooted within a given time period (default 5 days)

The information that can be collected from Active Directory:

  • Computer password information – how many computers that have and have not changed their computer password within a given time period (default 90 days)
  • Operating system Overview – showing how many different Operating System versions that are present in the domain and how many there are of each
<#

.SYNOPSIS
    Returns a environment status report within the areas that have been selected as parameters running the report

.DESCRIPTION
    Queries the ConfigMgr to get information about applications, devices and software updates. Runs a query towards AD to find information about last computer password change.
    These information can be included or excluded using the parameters. All the information gathered from SCCM and AD will then ultamately be sent to the recipients specified in the mail section.

.PARAMETER runAppScan
    Scan SCCM for applications to find both used an unused applications

.PARAMETER runClientScan
    Scan SCCM Computer Clients to find out how many inactive clients there are

.PARAMETER runPatchCompScan
    SCCM 3 Month Patch Compliance

.PARAMETER runRebootCount
     Find computers that have not rebooted within the last X days

.PARAMETER runOSCount
    AD Count number of unique Operating Systems in OU specified in $ADSearchBase and  Count number of computers within different Operating Systems

.PARAMETER runComputerPasswordCount
    #Find info about when computers last changed Computer password

.PARAMETER runComputerPasswordCount
    #Create the report with everything included

.EXAMPLE
    PCManagementReport -runAppScan $true -runPatchCompScan $true
    Creates a report including SCCM Application Scan and Path Compliance Graph

.EXAMPLE
    PCManagementReport -runEverything $true
    Creates a report including everything

.NOTES
    Cmdlet name:      PCManagementReport
    Author:           Mikael Blomqvist
    DateCreated:      2017-04-19

#>


[CmdletBinding(SupportsShouldProcess = $True)]
param
(
    [Parameter(Mandatory = $False, HelpMessage = "Scan ConfigMgr Applications (True/False)")] 
    [boolean]$runAppScan = $false,
    [Parameter(Mandatory = $False, HelpMessage = "Scan ConfigMgr Devices (True/False)")] 
    [boolean]$runClientScan = $false,
    [Parameter(Mandatory = $False, HelpMessage = "Create Path Compliance Scan (True/False)")] 
    [boolean]$runPatchCompScan = $true,
    [Parameter(Mandatory = $False, HelpMessage = "Calculate Computer Reboot numbers (True/False)")]
    [boolean]$runRebootCount = $false,
    [Parameter(Mandatory = $False, HelpMessage = "Count number of unique Operating Systems and the number of Computers within each Operation Systems (True/False)")]  
    [boolean]$runOSCount = $false,
    [Parameter(Mandatory = $False, HelpMessage = "Calculate Computer password change numbers (True/False)")] 
    [boolean]$runComputerPasswordCount = $false,
    [Parameter(Mandatory = $False, HelpMessage = "Run everything (True/False)")]
    [boolean]$runEverything = $false
)


#Load the ActiveDirectory Module

$m = Get-Module -List ActiveDirectory
if (!$m) {
    Write-Host "AD Powershell Module is not installed can not continue."
    Exit
}

else {
    Import-Module ActiveDirectory
}

$CMSiteServerFQDN = 'siteserver.domain.com' #Configuration Manager Site Server FQDN

$CMSiteServer = $CMSiteServerFQDN.ToString().split(".") | Select -First 1

#Load Configuration Manager PowerShell Module

try {
    Import-Module "\\$CMSiteServer\d$\Program Files\Microsoft Configuration Manager\AdminConsole\bin\ConfigurationManager.psd1" -ErrorAction Stop
}
catch {
    $_.Exception.Message
    $_.Exception.ItemName
    Write-Host "Cannot load the Configuration Manager PowerShell Module from the specified location"
    break #Terminate if the module cannot be loaded
}

###############################################################################
#
#Edit these to the customer specific values and $CMSiteServer above
#
###############################################################################

#Mail
$smtpServer = "smtprelay.domain.com"
$mailinfo_to = "recipient1@domain.com", "recipient2@domain.com" 
$mailinfo_cc = ""
$mailinfo_from = "$env:computername@domain.com"
$logo = "logo.gif"
$Customername = "My Company"
$sendMail = $true

#Active Directory
[string]$ADSearchBase = "OU=ComputersWin10,DC=domain,DC=com" #Win10
[int]$ComputerPasswordAgeDays = 90
[int]$RebootTresholdDays = 5

#SCCM
$Collection = "All Windows 10" #Collection in SCCM which should be used as basis for the device count
$patchNumberOfMonth = 3 #Number of month contained in the patch compliance overview

#Graphic
$CorporateColor = "#780000"
$BackGroundColor = "#505A55"

#Misc
$ReportTitle = "System Report"
$printToConsole = $true #Write Output to console

##############################################################################
#
#Variables which should not be edited
#
##############################################################################

$File_ExpSuperseededApps = "$PSScriptRoot\ExpiredSuperseededApps.csv"
$File_CompNotBooted = "$PSScriptRoot\NotRebootedComputers.csv"

[string]$Attachments = "$OutFile"

#Mail
$OutFile = "$PSScriptRoot\StatusReport.html"
$subject = "$Customername : Status Report"

#AD
$OUName = (Get-ADOrganizationalUnit -Filter * -Properties CanonicalName -SearchBase $ADSearchBase -SearchScope Base).Name

#SCCM
$SiteCode = Get-PSDrive -PSProvider CMSITE #Configuration Manager Site Code
$SCCMNameSpace = "root\sms\site_$SiteCode"


$head = @"
<style>
H1{color: #000000}
H2{color: #FFFFFF}
H3{color: #000000}
p{color: $CorporateColor; font-size:70%}
TABLE {margin-left:50px;background-color: #FFFFFF;}
TR {padding: 0px}
TH {padding: 5px;background-color: $CorporateColor}
TD {padding: 15px;text-align: Center}
BODY {font-family: verdana;background-color: $BackGroundColor}
</style>
<Title>$ReportTitle</Title>
"@


#Build ADSummary table
$tbl_ADSummary = New-Object System.Data.DataTable ADSummary
$col_ADHeading = New-Object System.Data.DataColumn ADHeading, ([string])
$col_ADData = New-Object System.Data.DataColumn ADData, ([string])
$tbl_ADSummary.columns.Add($col_ADHeading)
$tbl_ADSummary.columns.Add($col_ADData)


#Build AppsSummary table
$tbl_AppsSummary = New-Object System.Data.DataTable AppsSummary
$col_AppsHeading = New-Object System.Data.DataColumn AppsHeading, ([string])
$col_AppsData = New-Object System.Data.DataColumn AppsData, ([string])
$tbl_AppsSummary.columns.Add($col_AppsHeading)
$tbl_AppsSummary.columns.Add($col_AppsData)


#Build DeviceSummary table
$tbl_DeviceSummary = New-Object System.Data.DataTable DeviceSummary
$col_DeviceHeading = New-Object System.Data.DataColumn DeviceHeading, ([string])
$col_DeviceData = New-Object System.Data.DataColumn DeviceData, ([string])
$tbl_DeviceSummary.columns.Add($col_DeviceHeading)
$tbl_DeviceSummary.columns.Add($col_DeviceData)

#Build OS Table
$tbl_ostable = New-Object System.Data.DataTable OS
$Col_OSName = New-Object System.Data.DataColumn OSName, ([string])
$Col_OSCount = New-Object System.Data.DataColumn OSCount, ([string])
$tbl_ostable.Columns.Add($Col_OSName)
$tbl_ostable.Columns.Add($Col_OSCount)

#create patch table and columns
$tbl_Compliance = New-Object System.Data.DataTable Patches
$Col_month = New-Object System.Data.DataColumn Month, ([string])
$Col_compliant = New-Object System.Data.DataColumn Compliant, ([decimal])
$Col_noncompliant = New-Object System.Data.DataColumn NonCompliant, ([decimal])
$Col_unknown = New-Object System.Data.DataColumn Unknown, ([decimal])
$tbl_Compliance.columns.Add($Col_month)
$tbl_Compliance.columns.Add($Col_compliant)
$tbl_Compliance.columns.Add($Col_noncompliant)
$tbl_Compliance.columns.Add($Col_unknown)

#Build PieChart for Last Computer PW Change
$tbl_piechart = New-Object System.Data.DataTable PWChange
$Col_category = New-Object System.Data.DataColumn Category, ([string])
$Col_amount = New-Object System.Data.DataColumn Amount, ([string])
$tbl_piechart.columns.Add($Col_category)
$tbl_piechart.columns.Add($Col_amount)

#Function to add rows to table
Function AddTo-Table {
    $tableName = $args[0]
    $tableHeading = $args[1]
    $tableHeadingValue = $args[2]
    $tableData = $args[3]
    $tableDataValue = $args[4]

    $row = $tableName.NewRow(); $row.$tableHeading = $tableHeadingValue; $row.$tableData = $tableDataValue
    $tableName.Rows.Add($row)

    If ($printToConsole) { Write-Host $tableHeadingValue ": " $tableDataValue }
}

#Function to add attachments to Sting that can be added to the mail 
Function Add-Attachment {

    [string]$file = $args[0]

    $Attachments = $Attachments + ',' + $file

    return $Attachments
}

#Create a Pie Chart with the supplied information
Function CreateChart {

    $datasource = $args[0]
    $title = $args[1]
    $ChartType = $args[2]
    $xValue = $args[3]
    $yValue = $args[4]
    $imagePath = $args[5]
    $imagewidth = $args[6]
    $imageheight = $args[7]
    $displayedinLegend = $args[8]


    [void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms.DataVisualization")
    $scriptpath = $PSScriptRoot
 
    # chart object
    $chart1 = New-object System.Windows.Forms.DataVisualization.Charting.Chart
    $chart1.Width = $imagewidth
    $chart1.Height = $imageheight
    $chart1.BackColor = [System.Drawing.Color]::White
 
    # title 
    [void]$chart1.Titles.Add("$title")
    $chart1.Titles[0].Font = "Verdana,14pt"
    $chart1.Titles[0].Alignment = "topCenter"

    $chart1.Titles[0].ForeColor = $CorporateColor
 
    # chart area 
    $chartarea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea
    $chartarea.Name = "ChartArea1"
    $chartarea.AxisY.MajorGrid.Enabled = $false
    $chartarea.AxisX.MajorGrid.Enabled = $false
    $chart1.ChartAreas.Add($chartarea)
 
    # legend 
    $legend = New-Object system.Windows.Forms.DataVisualization.Charting.Legend
    $legend.name = "Legend1"
    $chart1.Legends.Add($legend)

    # data series
    [void]$chart1.Series.Add("PWWithin")
    $chart1.Series["PWWithin"].ChartType = "$ChartType"
    $chart1.Series["PWWithin"].BorderWidth = 10
    $chart1.Series["PWWithin"].IsVisibleInLegend = $displayedinLegend
    $chart1.Series["PWWithin"].chartarea = "ChartArea1"
    $chart1.Series["PWWithin"].IsValueShownAsLabel = $true
   

    $datasource | ForEach-Object { $chart1.Series["PWWithin"].Points.addxy( $_.$xValue , $_.$yValue) }
 
    # save chart
    $chart1.SaveImage($imagePath, "png")
}

#Function to Create a stacked patch compliance graph showing the past software update groups
Function CreateComplianceChart {

    $datasource = $args[0]

    $Pic_PatchComp = "PatchCompliance_Stacked100.png"
    $Path_PatchComp = "$PSScriptRoot\$Pic_PatchComp"


    [void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms.DataVisualization")
    $scriptpath = $PSScriptRoot
 
    # chart object
    $chart1 = New-object System.Windows.Forms.DataVisualization.Charting.Chart
    $chart1.Width = 800
    $chart1.Height = 600
    $chart1.BackColor = [System.Drawing.Color]::White
 
    # title 
    [void]$chart1.Titles.Add("Past $patchNumberOfMonth Month Patch Compliance Development")
    $chart1.Titles[0].Font = "Verdana,20pt"
    $chart1.Titles[0].Alignment = "topCenter"

    $chart1.Titles[0].ForeColor = $CorporateColor
 
    # chart area 
    $chartarea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea
    $chartarea.Name = "ChartArea1"
    $chartarea.AxisY.Title = "Compliance %"
    $chartarea.AxisX.Title = "Month"
    $chartarea.AxisY.Interval = 10
    $chartarea.AxisX.Interval = 1
    $chart1.ChartAreas.Add($chartarea)
 
    # legend 
    $legend = New-Object system.Windows.Forms.DataVisualization.Charting.Legend
    $legend.name = "Legend1"
    $chart1.Legends.Add($legend)
 

    # data series
    [void]$chart1.Series.Add("Compliant")
    $chart1.Series["Compliant"].ChartType = "StackedColumn100"
    $chart1.Series["Compliant"].BorderWidth = 10
    $chart1.Series["Compliant"].IsVisibleInLegend = $true
    $chart1.Series["Compliant"].chartarea = "ChartArea1"
    $chart1.Series["Compliant"].Legend = "Legend1"
    $chart1.Series["Compliant"].color = "#2ECC71"
    $chart1.Series["Compliant"].IsValueShownAsLabel = $true
    $datasource | ForEach-Object { $chart1.Series["Compliant"].Points.addxy( $_.Month , $_.Compliant) }
 

 
    # data series
    [void]$chart1.Series.Add("NonCompliant")
    $chart1.Series["NonCompliant"].ChartType = "StackedColumn100"
    $chart1.Series["NonCompliant"].IsVisibleInLegend = $true
    $chart1.Series["NonCompliant"].BorderWidth = 10
    $chart1.Series["NonCompliant"].chartarea = "ChartArea1"
    $chart1.Series["NonCompliant"].Legend = "Legend1"
    $chart1.Series["NonCompliant"].color = "#E74C3C"
    $chart1.Series["NonCompliant"].IsValueShownAsLabel = $true
    $datasource | ForEach-Object { $chart1.Series["NonCompliant"].Points.addxy( $_.Month , $_.NonCompliant) }


    # data series
    [void]$chart1.Series.Add("Unknown")
    $chart1.Series["Unknown"].ChartType = "StackedColumn100"
    $chart1.Series["Unknown"].IsVisibleInLegend = $true
    $chart1.Series["Unknown"].BorderWidth = 10
    $chart1.Series["Unknown"].chartarea = "ChartArea1"
    $chart1.Series["Unknown"].Legend = "Legend1"
    $chart1.Series["Unknown"].color = "#CACFD2"
    $chart1.Series["Unknown"].IsValueShownAsLabel = $true
    $datasource | ForEach-Object { $chart1.Series["Unknown"].Points.addxy( $_.Month , $_.Unknown) }
 
    # save chart
    $chart1.SaveImage("$PSScriptRoot\PatchCompliance_Stacked100.png", "png")
}


# This function is used to send the email containing the report and attachments. 
# The reason this one is used instead of Send-MailMessage is that .NET allows images to be embedded in the email using the cid tag

Function SendMail {

    $mailbody = $args[0]
    $mailattachments = $args[1]

    $SmtpClient = New-Object System.Net.Mail.SmtpClient($smtpServer)
    $MailMessage = New-object System.Net.Mail.MailMessage($mailinfo_from, $mailinfo_to, $Subject, $mailbody)
    $MailMessage.IsBodyHtml = $true


    $trimlenght = $PSScriptRoot.Length + 1 #have to add 1 because of the extra / in the path

    Foreach ($attachment in $mailattachments) {

        $attachmentID = $attachment.SubString($trimlenght) #This is to use only the actualy filename as ID
        $obj_attachment = New-Object System.Net.Mail.Attachment($attachment)
        $obj_attachment.ContentID = $attachmentID
        $MailMessage.Attachments.Add($obj_attachment)

    }

    $SmtpClient.Send($MailMessage)

}

$Attachments = Add-Attachment "$PSScriptRoot\$logo"


#Get all Computers within the specified SearchBase excluding Servers
$Computers = Get-ADComputer -SearchBase $ADSearchBase -filter { (OperatingSystem -notlike "*Server*") } -properties Name, DistinguishedName, OperatingSystem, OperatingSystemServicePack, passwordLastSet, LastLogonDate, Description

AddTo-Table $tbl_ADSummary "ADHeading" "Number of computers in $OUName" "ADData" $Computers.Count

If ($printToConsole) {
    Write-Host "Overview:"
    Write-Host "--------------------"
    Write-Host "Total number of computers: "$Computers.Count
}



#Count number of unique OS
If ($runOSCount -or $runEverything) {
    #Change variable to UComputers and work with this
    $UComputers = $Computers | select-object Name, OperatingSystem, OperatingSystemServicePack, passwordLastSet, LastLogonDate, DistinguishedName, CountryOUADvariable

    $UniqueOS = $UComputers | Select-Object OperatingSystem | Sort OperatingSystem -Descending | Get-Unique -Asstring

    #Count number of unique OS
    $NumberofUniqueOS = 0
    foreach ($uos in $UniqueOS) { $NumberofUniqueOS++ }

    #AddTo-Table $tbl_ADSummary "ADHeading" "Number of different Operating Systems" "ADData" $NumberofUniqueOS


    #Meassure/Count how many computer object of each OS type

    foreach ($os in $UComputers | Select-Object OperatingSystem | Sort OperatingSystem -Descending | Get-Unique -Asstring) {
        $count = ($UComputers | where { $_.OperatingSystem.ToString() -eq $os.OperatingSystem } | measure).Count
        AddTo-Table $tbl_ostable "OSName" ($os.OperatingSystem.ToString()) "OSCount" $count
        $count = 0
    }
    #CreateOSChart $tbl_ostable
    CreateChart $tbl_ostable "Operating Systems" "Pie" "OSName" "OSCount" "$PSScriptRoot\OS_Pie.png" "400" "200" $true

    $Attachments = Add-Attachment "$PSScriptRoot\OS_Pie.png"

}

CD $SiteCode':'


#Finding Computers that are within and outside the treshold of when Computer password was last set
If ($runComputerPasswordCount -or $runEverything) {

    $ComputerStaleDate = (Get-Date).AddDays(-$ComputerPasswordAgeDays)

    $PWWithin = $Computers | Where { $_.passwordLastSet -ge $ComputerStaleDate }
    $PWOutside = $Computers | Where { $_.passwordLastSet -le $ComputerStaleDate }

    AddTo-Table $tbl_piechart "Category" "Within Treshold" "Amount" $PWWithin.Count
    AddTo-Table $tbl_piechart "Category" "Outside Treshhold" "Amount" $PWOutside.Count

    If ($printToConsole) {
        Write-Host "Computer Password:"
        Write-Host "--------------------"
        Write-Host "Within Treshold: "$PWWithin.Count
        Write-Host "Outside Treshhold: "$PWOutside.Count
    }

    #CreateComputerPWChart $tbl_piechart

    CreateChart $tbl_piechart "Computer Password" "Pie" "Category" "Amount" "$PSScriptRoot\ComputerPW_Pie.png" "400" "200" $true

    $ComputersinSCCM = $PWOutside | Where-Object { $_ -ne $null } | Foreach-Object { Get-CMDevice -Name $_.Name }
    AddTo-Table $tbl_ADSummary "ADHeading" "In SCCM but havent changed PW within $ComputerPasswordAgeDays days" "ADData" $ComputersinSCCM.Count

    $Attachments = Add-Attachment "$PSScriptRoot\ComputerPW_Pie.png"
}

#Count number of computers that havent been rebooted within the number of days specified in $RebootTresholdDays
If ($runRebootCount -or $runEverything) {
    $OUCanonicalName = (Get-ADOrganizationalUnit -Filter * -Properties CanonicalName -SearchBase "$ADSearchBase" -SearchScope Base).CanonicalName
    
    $computersNotRebooted = (Get-WmiObject -namespace $SCCMNameSpace -computer $CMSiteServerFQDN -query "SELECT DISTINCT SMS_R_System.Name, SMS_G_System_OPERATING_SYSTEM.LastBootUpTime, SMS_G_System_OPERATING_SYSTEM.Caption
    FROM SMS_R_System INNER JOIN SMS_G_System_OPERATING_SYSTEM ON SMS_G_System_OPERATING_SYSTEM.ResourceID = SMS_R_System.ResourceId
    WHERE (DateDiff(day, SMS_G_System_OPERATING_SYSTEM.LastBootUpTime, GetDate()) >$RebootTresholdDays) AND SMS_R_System.SystemOUName = '$OUCanonicalName'").SMS_R_System | Select Name

    AddTo-Table $tbl_ADSummary "ADHeading" "Not rebooted within the last $RebootTresholdDays days" "ADData" $computersNotRebooted.Count

    If ($printToConsole) {
        Write-Host "Computer Reboot:"
        Write-Host "Computers not rebooted with $RebootTresholdDays : " $computersNotRebooted.Count

    }

}

#Get the last 3 SoftwareUpdate Groups
If ($runPatchCompScan -or $runEverything) {

    
    $SUGs = Get-CMSoftwareUpdateGroup | Sort-Object { $_.datecreated } -Descending | Select -First $patchNumberOfMonth

    If ($printToConsole) {
        Write-Host "Software Update Groups:"
        Write-Host "-----------------------"
    }

    Foreach ($sug in $SUGs) {

        $month = $sug.LocalizedDisplayName
        $compliant = [math]::Round((($sug.NumCompliant / ($sug.NumTotal)) * 100), 2)
        $noncompliant = [math]::Round((($sug.NumNonCompliant / ($sug.NumTotal)) * 100), 2)
        $unknown = [math]::Round((($sug.NumUnknown / $sug.NumTotal) * 100), 2)

        If ($printToConsole) {
            Write-Host "Month: $month"
            Write-Host "-Compliant: $Compliant"
            Write-Host "-NonCompliant: $noncompliant"
            Write-Host "-Unknown: $unknown"
        }
        

        $row = $tbl_Compliance.NewRow(); $row.Month = $month; $row.Compliant = $compliant; $row.NonCompliant = $noncompliant; $row.Unknown = $unknown
        $tbl_Compliance.Rows.Add($row)

    }


    CreateComplianceChart $tbl_Compliance

    $Attachments = Add-Attachment "$PSScriptRoot\PatchCompliance_Stacked100.png"


}

#Count number of Applications in SCCM
If ($runAppScan -or $runEverything) {
    $AllApps = Get-CMApplication
    $DeployedSuperseeded = $AllApps | Where-Object { <#($_.IsDeployed -eq $true) -and #>($_.IsSuperseded -eq $true) } 
    $DeployedExpired = $AllApps | Where-Object { <#($_.IsDeployed -eq $true) -and#> ($_.IsExpired -eq $true) }
    $DeployedWorking = $AllApps | Where-Object { ($_.IsDeployed -eq $true) -and ($_.IsExpired -eq $false) -and ($_.IsSuperseded -eq $false) }
    $NotDeployed = $AllApps | Where-Object { ($_.IsDeployed -eq $false) }

  
    #AddTo-Table $tbl_AppsSummary "AppsHeading" "Total number of Applications in SCCM" "AppsData" $AllApps.Count
    AddTo-Table $tbl_AppsSummary "AppsHeading" "Superseeded Applications" "AppsData" $DeployedSuperseeded.Count
    AddTo-Table $tbl_AppsSummary "AppsHeading" "Expired Applications" "AppsData" $DeployedExpired.Count
    AddTo-Table $tbl_AppsSummary "AppsHeading" "Active Applications" "AppsData" $DeployedWorking.Count
    AddTo-Table $tbl_AppsSummary "AppsHeading" "Applications without deployment(s)" "AppsData" $NotDeployed.Count
    
    CreateChart $tbl_AppsSummary "All Applications" "Pie" "AppsHeading" "AppsData" "$PSScriptRoot\Applications_Pie.png" "400" "200" $true

    $Attachments = Add-Attachment "$PSScriptRoot\Applications_Pie.png"

    If ($printToConsole) {
        Write-Host "Applications:"
        Write-Host "--------------------"
        Write-Host "Superseeded Applications: "$DeployedSuperseeded.Count
        Write-Host "Expired Applications: "$DeployedExpired.Count
        Write-Host "Active Applications: "$DeployedWorking.Count
        Write-Host "Applications without deployment(s): "$NotDeployed.Count
    }

}

#Count devices in SCCM
If ($runClientScan -or $runEverything) {

    $AllDevicesinSCCM = Get-CMDevice -CollectionName "$Collection"
    $AciveDevices = $AllDevicesinSCCM | Where-Object { ($_.ClientActiveStatus -eq 1) }
    $InaciveDevices = $AllDevicesinSCCM | Where-Object { ($_.ClientActiveStatus -eq 0) }
    $ObsoleteDevices = $AllDevicesinSCCM | Where-Object { ($_.IsObsolete -eq $true) }
    $NoSCCMClient = $AllDevicesinSCCM | Where-Object { ($_.IsClient -eq $false) }

    AddTo-Table $tbl_DeviceSummary "DeviceHeading" "Active Devices" "DeviceData" $AciveDevices.Count
    AddTo-Table $tbl_DeviceSummary "DeviceHeading" "Obsolete devices" "DeviceData" $ObsoleteDevices.Count
    AddTo-Table $tbl_DeviceSummary "DeviceHeading" "Inactive Devices" "DeviceData" $InaciveDevices.Count
    AddTo-Table $tbl_DeviceSummary "DeviceHeading" "Devices without Client" "DeviceData" $NoSCCMClient.Count

    CreateChart $tbl_DeviceSummary "Devices in $Collection" "Pie" "DeviceHeading" "DeviceData" "$PSScriptRoot\Devices_Pie.png" "400" "200" $true

    $Attachments = Add-Attachment "$PSScriptRoot\Devices_Pie.png"

    If ($printToConsole) {
        Write-Host "Devices:"
        Write-Host "--------------------"
        Write-Host "Active Devices: "$AciveDevices.Count
        Write-Host "Obsolete devices: "$ObsoleteDevices.Count
        Write-Host "Inactive Devices: "$InaciveDevices.Count
        Write-Host "Devices without Client: "$NoSCCMClient.Count
    }
}

CreateChart $tbl_ADSummary "Computer Info" "Bar" "ADHeading" "ADData" "$PSScriptRoot\ComputerInfo_Bar.png" "800" "300" $false

$Attachments = Add-Attachment "$PSScriptRoot\ComputerInfo_Bar.png"


#Convert All tables to HTML
#--------------------------------------------------------

#Convert the ostable to a HTML Fragment that can be inserted into the html document.
$osfragment = $tbl_ostable | Select @{Name = "Operating System"; Expression = { $_.OSName } }, @{Name = "Count"; Expression = { $_.OSCount } } | ConvertTo-Html -Fragment
$adfragment = $tbl_ADSummary | Select ADHeading, ADData | ConvertTo-Html -Fragment
$sccmfragment = $tbl_AppsSummary | Select AppsHeading, AppsData | ConvertTo-Html -Fragment

#Write results depending on parameter set
$footer = "Report ran from {3} initiated by {1}\{2} at {0}" -f (Get-Date), $env:USERDOMAIN, $env:USERNAME, $env:COMPUTERNAME


$fragments = @()

#Insert a graphic header
$fragments += "<Center><table>"
$fragments += "<tr><td><Img src='cid:$logo'></td></tr>"
$fragments += "<tr><td><H1>$Customername - Environment Summary</H1></td></tr>"
$fragments += "<tr><td ><h3>Computers in: $OUName</h3></td></tr>"

#Only show this section if any of the elements in it are choosen to be calculated
If ($runRebootCount -or $runComputerPasswordCount -or $runOSCount -or $runEverything) { 
    $fragments += "<tr><th><H2>Active Directory Summary</H2></th></tr>"

    If ($runRebootCount -or $runEverything) { 
        $fragments += "<tr><td><Img src='cid:ComputerInfo_Bar.png'></td></tr>"

    }

    If ($runComputerPasswordCount -or $runOSCount -or $runEverything) { 
        $fragments += "<tr><td>"
        If ($runOSCount -or $runEverything) {
            $fragments += "<Img src='cid:OS_Pie.png'>"
        }
        If ($runComputerPasswordCount -or $runEverything) {           
            $fragments += "<Img src='cid:ComputerPW_Pie.png'>"
        }
        
        $fragments += "</td></tr>"
    }

}
#Only show the SCCM Summary in the report if either runAppScan or runClientScan is enabled.
If ($runAppScan -or $runClientScan -or $runEverything) {
    $fragments += "<tr><th><H2>SCCM Summary</H2></th></tr>"

   
    $fragments += "<tr><td>"
    If ($runAppScan -or $runEverything) {
        $fragments += "<Img src='cid:Applications_Pie.png'>"
    }
    If ($runClientScan -or $runEverything) {           
        $fragments += "<Img src='cid:Devices_Pie.png'>"
    }
        
    $fragments += "</td></tr>"
  
}

#Only show the Patch Compliance Overview if runPatchCompScan is enabled
If ($runPatchCompScan -or $runEverything) {
    $fragments += "<tr><th><H2>Patch Compliance Overview</H2></th></tr>"
    $fragments += "<tr><td><Img src='cid:PatchCompliance_Stacked100.png'></td></tr>"
}

$fragments += "<tr><td><p>$footer</p></td></tr>"
$fragments += "</table></Center>"


CD c:\


#Write to Files
$DeployedSuperseeded | Select @{Name = "Superseeded Applications"; Expression = { $_.LocalizedDisplayName } } | Out-File $File_ExpSuperseededApps
$DeployedExpired | Select @{Name = "Expired Applications"; Expression = { $_.LocalizedDisplayName } } | Out-File $File_ExpSuperseededApps -Append
$NotDeployed | Select @{Name = "Applications without Deployments"; Expression = { $_.LocalizedDisplayName } } | Out-File $File_ExpSuperseededApps -Append

$computersNotRebooted | Out-File $File_CompNotBooted

#Adding files to attachment array if they have been created.

If ($runRebootCount) {
    $Attachments = Add-Attachment $File_CompNotBooted
}

If ($runAppScan) {
    $Attachments = Add-Attachment $File_ExpSuperseededApps
}

$body = ConvertTo-Html -Head $head -Title $ReportTitle -Body $fragments

#For the html report the cid is removed so the image src path is correct
$report = $fragments -replace "cid:", ""

ConvertTo-Html -Head $head -Title $ReportTitle -Body $report | Out-File $OutFile

$ArrayAttachment = $Attachments.Split(",")

If ($sendMail) {
    sendmail $body $ArrayAttachment
}
Else {
    Write-Host "Send Mail is disabled so no mail were sent."
}