├── DLMonthlyInactivityReport-Public.ps1 ├── DLQuarterlyInactivityReport-Public.ps1 ├── DLWeeklyInactivityReport-Public.ps1 └── README.md /DLMonthlyInactivityReport-Public.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | =========================================================================== 4 | Updated on: 8/31/2018 5 | Created by: /u/ascIVV 6 | =========================================================================== 7 | 8 | Exchange Online Powershell is required for message trace. 9 | https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/connect-to-exchange-online-powershell?view=exchange-ps 10 | 11 | ReportHTML Moduile is required 12 | Install-Module -Name ReportHTML 13 | https://www.powershellgallery.com/packages/ReportHTML/ 14 | 15 | .DESCRIPTION 16 | Compare four weeks of DLWeeklyInactivity report results from your O365 tenant. Removes Weekly reports older than 5 weeks, sends detailed HTML report on unused distribution lists. 17 | 18 | 19 | #> 20 | 21 | #Connection info 22 | $Username = "admin.account@domain.com" 23 | $PasswordPath = "\\path\to\secure\password.txt" 24 | 25 | #Read the password from the file and convert to SecureString 26 | $SecurePassword = Get-Content $PasswordPath | ConvertTo-SecureString 27 | 28 | #Build a Credential Object from the password file and the $username constant 29 | $Credential = New-Object System.Management.Automation.PSCredential -ArgumentList $Username, $SecurePassword 30 | 31 | #Open a session to O365 32 | $ExOSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $Credential -Authentication Basic -AllowRedirection 33 | import-PSSession $ExOSession -AllowClobber 34 | 35 | #Set the constants 36 | $Date = get-date -format MMddyyyy 37 | $ReportsFolder = "\\server\share\reports\" 38 | $CompanyLogo = "https://www.freelogodesign.org/Content/img/logo-ex-4.png" 39 | $Table = New-Object 'System.Collections.Generic.List[System.Object]' 40 | $RemovedFilesTable = New-Object 'System.Collections.Generic.List[System.Object]' 41 | 42 | #Get report run date for previous weekly reports 43 | $Week1Date = (get-date).AddDays(-21).ToString("MMddyyyy") 44 | $Week2Date = (get-date).AddDays(-14).ToString("MMddyyyy") 45 | $Week3Date = (get-date).AddDays(-7).ToString("MMddyyyy") 46 | $Week4Date = (get-date).ToString("MMddyyyy") 47 | 48 | #Clean up weekly reports created more than 35 days ago 49 | $ToOldFiles = ("$ReportsFolder"+"Inactive*"+".txt") 50 | $FilestoRemove = Get-ChildItem -Path $ToOldFiles -Force | Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-35) } 51 | 52 | Foreach ($File in $FilestoRemove) { 53 | Remove-Item $File -Force 54 | if (!$?) { 55 | $ReportName = "$($File.name)" 56 | $Status = "Failed to delete the file automatically." 57 | } 58 | 59 | Else { 60 | $ReportName = "$($File.name)" 61 | $Status = "Successfully deleted the file automatically." 62 | } 63 | 64 | $obj = [PSCustomObject]@{ 65 | 'File Name' = $ReportName 66 | 'Deleted Status' = $Status 67 | } 68 | 69 | $RemovedFilesTable.add($obj) 70 | } 71 | 72 | If (($RemovedFilesTable).count -eq 0) 73 | { 74 | $RemovedFilesTable = [PSCustomObject]@{ 75 | 'Information' = 'Information: No Inactive Weekly Lists were found to remove.' 76 | } 77 | } 78 | 79 | #Set up the weekly report file paths 80 | $Week1Path = ("$ReportsFolder"+"Inactive"+"$Week1Date"+".txt") 81 | $Week2Path = ("$ReportsFolder"+"Inactive"+"$Week2Date"+".txt") 82 | $Week3Path = ("$ReportsFolder"+"Inactive"+"$Week3Date"+".txt") 83 | $Week4Path = ("$ReportsFolder"+"Inactive"+"$Week4Date"+".txt") 84 | 85 | #Input weekly report files 86 | $Week1Report = Get-Content $Week1Path 87 | $Week2Report = Get-Content $Week2Path 88 | $Week3Report = Get-Content $Week3Path 89 | $Week4Report = Get-Content $Week4Path 90 | 91 | #Compare weekly report files 92 | $Week12Results = Compare-Object -ReferenceObject $Week1Report -DifferenceObject $Week2Report -ExcludeDifferent -IncludeEqual 93 | $Week23Results = Compare-Object -ReferenceObject $Week12Results.InputObject -DifferenceObject $Week3Report -ExcludeDifferent -IncludeEqual 94 | $Week34Results = Compare-Object -ReferenceObject $Week23Results.InputObject -DifferenceObject $Week4Report -ExcludeDifferent -IncludeEqual 95 | 96 | #Filter slider object out of the results 97 | $MonthlyInactive = $Week34Results.InputObject 98 | 99 | #Set export file name for plain text file to be used by quarterly report 100 | $DLMonthlyActivityTxt = ("$ReportsFolder"+"MonthlyInactive"+"$date"+".txt") 101 | 102 | #Export the findings to the text file 103 | $MonthlyInactive | Out-File $DLMonthlyActivityTxt 104 | 105 | #Get inactive distribution list details and create HTML report 106 | Foreach ($List in $MonthlyInactive) { 107 | 108 | $ListDetails = get-DistributionGroup $List 109 | $DisplayName = $ListDetails.DisplayName 110 | $Email = $ListDetails.PrimarySMTPAddress 111 | $Synced = $ListDetails.IsDirSynced 112 | $Owner = ($ListDetails.ManagedBy) -join ", " 113 | $Members = (Get-DistributionGroupMember $List | Sort-Object Name | Select-Object -ExpandProperty Name) -join ", " 114 | $MeasureMembers = $Members | measure 115 | $NumberofMembers = $MeasureMembers.count 116 | 117 | $obj = [PSCustomObject]@{ 118 | 'Name' = $DisplayName 119 | 'Email Address' = $Email 120 | 'AD Synced' = $Synced 121 | 'Owners' = $Owner 122 | 'Members' = $Members 123 | } 124 | 125 | $Table.add($obj) 126 | } 127 | 128 | If (($Table).count -eq 0) 129 | { 130 | $Table = [PSCustomObject]@{ 131 | 'Information' = 'Information: No distribution lists are inactive.' 132 | } 133 | } 134 | 135 | $rpt = New-Object 'System.Collections.Generic.List[System.Object]' 136 | $rpt += get-htmlopenpage -TitleText 'Monthly Inactive Distribution List Report' -LeftLogoString $CompanyLogo 137 | 138 | $rpt += Get-HTMLContentOpen -HeaderText "Distribution lists that have not been emailed in 4 weeks." 139 | $rpt += get-htmlcontentdatatable $Table -HideFooter 140 | $rpt += Get-HTMLContentClose 141 | $rpt += Get-HTMLContentOpen -HeaderText "Weekly Inactive Reports not created in the past 5 weeks." 142 | $rpt += get-htmlcontentdatatable $RemovedFilesTable -HideFooter 143 | $rpt += Get-HTMLContentClose 144 | 145 | $rpt += Get-HTMLClosePage 146 | 147 | $rpt += Get-HTMLClosePage 148 | $ReportName = ("DLMonthlyInactiveReport" + "$Date") 149 | Save-HTMLReport -ReportContent $rpt -ShowReport -ReportName $ReportName -ReportPath $ReportsFolder 150 | $MonthlyReport = ("$ReportsFolder"+"$ReportName"+".html") 151 | 152 | #Send an email with the findings 153 | $From = "admin.account@domain.com" 154 | $To = "helpdesk@domain.com" 155 | $Subject = "Monthly Inactive Distribution List Report" 156 | $Body = "See the attached report for distribution lists that have not been emailed in the past 4 weeks. A .txt file has been saved in the file share to be accessed by the Quarterly DL Inactivity Report script. Do not modify any of the weekly or monthly .txt file master copies in the share." 157 | $SMTPServer = "smtp.office365.com" 158 | $SMTPPort = "587" 159 | 160 | Send-MailMessage -From $From -to $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer -port $SMTPPort -UseSsl -Credential $Credential -Attachments $MonthlyReport 161 | 162 | #Close the session to O365 163 | Remove-PSSession $ExOSession 164 | -------------------------------------------------------------------------------- /DLQuarterlyInactivityReport-Public.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | =========================================================================== 4 | Updated on: 8/31/2018 5 | Created by: /u/ascIVV 6 | =========================================================================== 7 | 8 | Exchange Online Powershell is required for message trace. 9 | https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/connect-to-exchange-online-powershell?view=exchange-ps 10 | 11 | ReportHTML Moduile is required 12 | Install-Module -Name ReportHTML 13 | https://www.powershellgallery.com/packages/ReportHTML/ 14 | 15 | .DESCRIPTION 16 | Compare three months of DLMonthlyInactivity report results from your O365 tenant. Removes Monthly reports older than 4 months, sends detailed HTML report on unused distribution lists. 17 | 18 | #> 19 | #Connection info 20 | $Username = "admin.account@domain.com" 21 | $PasswordPath = "\\path\to\secure\password.txt" 22 | 23 | #Read the password from the file and convert to SecureString 24 | $SecurePassword = Get-Content $PasswordPath | ConvertTo-SecureString 25 | 26 | #Build a Credential Object from the password file and the $username constant 27 | $Credential = New-Object System.Management.Automation.PSCredential -ArgumentList $Username, $SecurePassword 28 | 29 | #Open a session to O365 30 | $ExOSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $Credential -Authentication Basic -AllowRedirection 31 | import-PSSession $ExOSession -AllowClobber 32 | 33 | #Set the constants 34 | $Date = get-date -format MMddyyyy 35 | $ReportsFolder = "\\server\share\reports\" 36 | $CompanyLogo = "https://www.freelogodesign.org/Content/img/logo-ex-4.png" 37 | $Table = New-Object 'System.Collections.Generic.List[System.Object]' 38 | $RemovedFilesTable = New-Object 'System.Collections.Generic.List[System.Object]' 39 | 40 | #This will input past three months of reports and find lists that are on each report. 41 | #Get report run date for previous weekly reports 42 | $Month1Date = (get-date).AddDays(-56).ToString("MMddyyyy") 43 | $Month2Date = (get-date).AddDays(-28).ToString("MMddyyyy") 44 | $Month3Date = (get-date).ToString("MMddyyyy") 45 | 46 | #Clean up monthly reports created more than 4 months ago 47 | $ToOldFiles = ($ReportsFolder+"MonthlyInactive*"+".txt") 48 | $FilestoRemove = Get-ChildItem -Path $ToOldFiles -Force | Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-84) } 49 | 50 | Foreach ($File in $FilestoRemove) { 51 | Remove-Item $File -Force 52 | if (!$?) { 53 | $ReportName = "$($File.name)" 54 | $Status = "Failed to delete the file automatically." 55 | } 56 | 57 | Else { 58 | $ReportName = "$($File.name)" 59 | $Status = "Successfully deleted the file automatically." 60 | } 61 | 62 | $obj = [PSCustomObject]@{ 63 | 'File Name' = $ReportName 64 | 'Deleted Status' = $Status 65 | } 66 | 67 | $RemovedFilesTable.add($obj) 68 | } 69 | 70 | If (($RemovedFilesTable).count -eq 0) 71 | { 72 | $RemovedFilesTable = [PSCustomObject]@{ 73 | 'Information' = 'Information: No Inactive Monthly Lists were found to remove.' 74 | } 75 | } 76 | 77 | #Set report file path 78 | $Month1Path = ($ReportsFolder+"MonthlyInactive"+$Month1Date+".txt") 79 | $Month2Path = ($ReportsFolder+"MonthlyInactive"+$Month2Date+".txt") 80 | $Month3Path = ($ReportsFolder+"MonthlyInactive"+$Month3Date+".txt") 81 | 82 | #Input weekly report files 83 | $Month1Report = Get-Content $Month1Path 84 | $Month2Report = Get-Content $Month2Path 85 | $Month3Report = Get-Content $Month3Path 86 | 87 | #Compare weekly report files 88 | $Month12Results = Compare-Object -ReferenceObject $Month1Report -DifferenceObject $Month2Report -ExcludeDifferent -IncludeEqual 89 | $Month23Results = Compare-Object -ReferenceObject $Month12Results.InputObject -DifferenceObject $Month3Report -ExcludeDifferent -IncludeEqual 90 | 91 | #Filter slider object out of the results 92 | $QuarterlyInactive = $Month23Results.InputObject 93 | 94 | #Set export file name for plain text file to be used by yearly report 95 | $DLQuarterlyActivityTxt = ("$ReportsFolder"+"QuarterlyInactive"+"$date"+".txt") 96 | 97 | #Export the findings to a file 98 | $QuarterlyInactive | Out-File $DLQuarterlyActivityTxt 99 | 100 | #Get inactive distribution list details and create HTML report 101 | Foreach ($List in $QuarterlyInactive) { 102 | 103 | $ListDetails = get-DistributionGroup $List 104 | $DisplayName = $ListDetails.DisplayName 105 | $Email = $ListDetails.PrimarySMTPAddress 106 | $Synced = $ListDetails.IsDirSynced 107 | $Owner = ($ListDetails.ManagedBy) -join ", " 108 | $Members = (Get-DistributionGroupMember $List | Sort-Object Name | Select-Object -ExpandProperty Name) -join ", " 109 | $MeasureMembers = $Members | measure 110 | $NumberofMembers = $MeasureMembers.count 111 | 112 | $obj = [PSCustomObject]@{ 113 | 'Name' = $DisplayName 114 | 'Email Address' = $Email 115 | 'AD Synced' = $Synced 116 | 'Owners' = $Owner 117 | 'Members' = $Members 118 | } 119 | 120 | $Table.add($obj) 121 | } 122 | 123 | If (($Table).count -eq 0) 124 | { 125 | $Table = [PSCustomObject]@{ 126 | 'Information' = 'Information: No distribution lists have been inactive for 3 months.' 127 | } 128 | } 129 | 130 | $rpt = New-Object 'System.Collections.Generic.List[System.Object]' 131 | $rpt += get-htmlopenpage -TitleText 'Quarterly Inactive Distribution List Report' -LeftLogoString $CompanyLogo 132 | 133 | $rpt += Get-HTMLContentOpen -HeaderText "Distribution lists that have not been emailed in 3 months." 134 | $rpt += get-htmlcontentdatatable $Table -HideFooter 135 | $rpt += Get-HTMLContentClose 136 | $rpt += Get-HTMLContentOpen -HeaderText "Monthly Inactive Reports not created in the past 4 months." 137 | $rpt += get-htmlcontentdatatable $RemovedFilesTable -HideFooter 138 | $rpt += Get-HTMLContentClose 139 | 140 | $rpt += Get-HTMLClosePage 141 | 142 | $rpt += Get-HTMLClosePage 143 | $ReportName = ("DLQuarterlyInactiveReport" + "$Date") 144 | Save-HTMLReport -ReportContent $rpt -ShowReport -ReportName $ReportName -ReportPath $ReportsFolder 145 | $QuarterlyReport = ("$ReportsFolder"+"$ReportName"+".html") 146 | 147 | #Send an email with the findings 148 | $From = "admin.account@domain.com" 149 | $To = "helpdesk@domain.com" 150 | $Subject = "Quarterly Distribution List Inactivity Report" 151 | $Body = "See the attached file for distribution lists that have not been emailed in the past 3 months. A .txt file has been saved in the file share to be accessed by the Yearly DL Inactivity Report script. Do not modify any of the weekly, monthly, or quarterly .txt file master copies in the share." 152 | $SMTPServer = "smtp.office365.com" 153 | $SMTPPort = "587" 154 | 155 | Send-MailMessage -From $From -to $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer -port $SMTPPort -UseSsl -Credential $Credential -Attachments $QuarterlyReport 156 | 157 | #Close the session to O365 158 | Remove-PSSession $ExOSession -------------------------------------------------------------------------------- /DLWeeklyInactivityReport-Public.ps1: -------------------------------------------------------------------------------- 1 | 2 | <# 3 | .NOTES 4 | =========================================================================== 5 | Updated on: 8/31/2018 6 | Created by: /u/ascIVV 7 | =========================================================================== 8 | 9 | . 10 | Exchange Online Powershell is required for message trace. 11 | https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/connect-to-exchange-online-powershell?view=exchange-ps 12 | 13 | .DESCRIPTION 14 | Generate a basic report of unused Distrobution Lists in your O365 tenant. Save the results and then compare four weeks of results with the DLMonthlyInactivty report. 15 | 16 | 17 | #> 18 | 19 | 20 | #Connection info 21 | $Username = "admin@email.com" 22 | $PasswordPath = "c:\path\to\mysecure\password.txt" 23 | 24 | #Set the constants 25 | $Date = get-date -format MMddyyyy 26 | $ReportsFolder = "\\fileshare\reportsfolder\" 27 | 28 | #Read the password from the file and convert to SecureString 29 | $SecurePassword = Get-Content $PasswordPath | ConvertTo-SecureString 30 | 31 | #Build a Credential Object from the password file and the $username constant 32 | $Credential = New-Object System.Management.Automation.PSCredential -ArgumentList $Username, $SecurePassword 33 | 34 | #Open a session to O365 35 | $ExOSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $Credential -Authentication Basic -AllowRedirection 36 | import-PSSession $ExOSession -AllowClobber 37 | 38 | #This will run a message activity report on all distribution lists for the past week and output the inactive lists. 39 | #Get all Distribution Lists. 40 | $DistroLists = Get-DistributionGroup -ResultSize Unlimited 41 | 42 | #Run message trace on each Distribution List to see if it recieved mail in the past x days. 43 | $DistroListsInUse = $DistroLists | select -ExpandProperty primarysmtpaddress | Foreach-Object { Get-MessageTrace -RecipientAddress $_ -Status expanded -startdate (Get-Date).AddDays(-8) -EndDate (Get-Date) -pagesize 1| select -first 1} 44 | 45 | #Check to see if the message trace shows recieved mail vs. not returning anything and output active status respectivly. 46 | $Results = Compare-Object -ReferenceObject $DistroListsinUse.RecipientAddress -DifferenceObject $DistroLists.primarySMTPaddress -PassThru 47 | 48 | #Set export file name 49 | $DLActivityReport = ("$ReportsFolder"+"Inactive"+"$Date"+".txt") 50 | 51 | #Export the findings to a file 52 | $Results | Out-File $DLActivityReport 53 | 54 | #Send an email with the findings 55 | $From = "admin@email.com" 56 | $To = @("email1@email.com , email2@email.com") 57 | $Subject = "Weekly Distribution List Inactivity Report" 58 | $Body = "This is a confirmation the Weekly DL Inactivity Report script has completed successfully. See the attached file for distribution lists that have not been emailed this week. This file has also been saved in the file share so it can be accessed by the Monthly DL Inactivity Report script." 59 | $SMTPServer = "smtp.office365.com" 60 | $SMTPPort = "587" 61 | 62 | Send-MailMessage -From $From -to $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer -port $SMTPPort -UseSsl -Credential $Credential -Attachments $DLActivityReport 63 | 64 | #Close the session to O365 65 | Remove-PSSession $ExOSession 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DLActivityScripts 2 | The following scripts are used to create reports on distribution lists that do not recive emails in your organization. 3 | 4 | ## Description - DLWeeklyInactiveReport 5 | This script gets all distribution lists in your Office 365 tenant and then runs a message trace on each to see which have been emailed in the past 7 days. It then outputs the emails of the lists that have not recieved email to a text file, this allows the DLMonthlyInactiveReport to compare 4 weeks of results for a monthly report. The script ends by sending an email confirmation that it ran successfully. 6 | 7 | ## Description - DLMonthlyInactiveReport 8 | This script imports the last 4 weeks of DLWeeklyInactiveReport text file results and compares each to find Distribution Lists that are on each report. The output is saved in a text file so it can be accessed by the DLQuarterlyInactiveReport. The script then gets details for each of the inactive lists such as display name, primary email, owner, and members. Next, the script checks for weekly report text files older than 5 weeks and removes them - keeping your report folder cleaned up. The details of the inactive lists and removed weekly reports are then formatted in an HTML report that is emailed to you. 9 | 10 | ## Description - DLQuarterlyInactiveReport 11 | This script imports the last 3 months of DLMonthlyInactiveReport text file results and compares each to find Distribution Lists that are on each report. The output is saved in a text file so it can be accessed by the DLYearlyInactiveReport. The script then gets details for each of the inactive lists such as display name, primary email, owner, and members. Next, the script checks for monthly report text files older than 4 months and removes them - keeping your report folder cleaned up. The details of the inactive lists and removed monthly reports are then formatted in an HTML report that is emailed to you. 12 | 13 | ## Requirements 14 | 1. Exchange Online PowerShell module is required. Instructions for the module can be found here: https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/connect-to-exchange-online-powershell?view=exchange-ps. 15 | 16 | 2. ReportHTML module is required. Insctructions for the module can be found here: https://www.powershellgallery.com/packages/ReportHTML/. 17 | 18 | 3. The scripts are set up to use a secure stored credential. Instructions on creating a stored credential can be found here: https://practical365.com/blog/saving-credentials-for-office-365-powershell-scripts-and-scheduled-tasks/. 19 | 20 | 4. Create a Scheduled task for each of the scripts. The weekly report should run every 7 days. The monthly report should run on the same day as the weekly report every 28 days. The quarterly report should run on the same day as the daily and monthly reports every 84 days. 21 | --------------------------------------------------------------------------------