Public Folders in Microsoft Exchange are one of the most challenging parts in Exchange system administrators can face. Microsoft actually tried to get rid of them several times and still they are around. As from an administrative point of view, they often did grow wild and I saw environments with a huge amount of public folders and no one was able to tell if they are still in use or not.
About a year ago I faced the same challenge and had to determine for a few thousand folders if we could retire them or not. PowerShell commands seemed to be the best approach for this, but soon I found out this is actually not as easy as I hoped it would be. There is no direct command that would give me all I needed and there was no easy way to determine if the folder is in use or not, this is especially because you can’t go with attributes like ‘last accessed’ for this cause, simply because they might show you data that is not really helpful to determine whether the folder is still in use or not. The folder ‘last modified’ is not as accurate either due to a simple marked as read action could modify this attribute as well.
Drilling further down in what I could use, I decided to see when the newest object in the folder actually was created – so the last created object in the folder – whether it was an email folder or e.g. a calendar.
The script you will find below will actually export the following columns in to a CSV file that you can process further in e.g. Microsoft Excel”:
- Public Folder Path
- the path to this public folder
- Mail Enabled
- well – is direct email enabled on this folder yes or no – this can actually be quite important and might need further review or needs groups/distribution list to be created instead
- Mail address
- helps to determine if this might be somewhere in use on a website etc.
- Folder Class
- the class in most cases is either an email folder or an calendar
- Folder Size
- total size of the folder – some folders might be really small and this helps to determine if you will need to keep em or not
- Number of Items
- like size – this helps a lot to see if it is something to discard or not
- Top 1 object creation time
- if there are items in the folder, this is the newest created item – specifically it is the date / time the item was created, as mentioned, modified will not help you because a simple mark as read action through Outlook already would influence this – the most accurate information I was able to find is the creation time for this cause
Now to the script(s). We actually talk about two scripts here – this is simply due to the fact that I developed this against a Office 365 Exchange system that needed me to logon and load the PowerShell modules from Office 365. The script itself should work on respective against an on premise Exchange server as well.
Simply said, you need to create both script files in the same folder – the ConnectToO365.ps1 script that is called is just a central solution in a huge script folder that is called by each script if necessary. The top section of each script first determines if there is a active session against the Office 365 environment and it will reuse it if possible or call the connect script to establish a new connection.
1 2 3 4 5 6 | Import-module ActiveDirectory Import-Module MSOnline $LiveCred = Get-Credential $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell/ -Credential $LiveCred -Authentication Basic -AllowRedirection Import-PSSession $Session connect-msolservice -credential $LiveCred |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | Get-MsolDomain -ErrorAction SilentlyContinue > NULL if($?) { "Connection to Office 365 is established" } else { "Initiating connection to Office 365" .\ConnectToO365.ps1 } $OutputFile = "PublicFolderLists_" + (Get-Date -UFormat "%Y%m%d%_%H%M%S") + ".csv" Write "Writing to file: $OutputFile" Out-File -FilePath $OutputFile -InputObject "Public Folder path;Mail enabled;Mail address;Folder Class;Folder last modified;Folder Size;Number of items;Top 1 object creation time" -Encoding UTF8 $objPFs = Get-PublicFolder -Recurse Foreach ($objPF in $objPFs) { $objPFitemstats = PublicFolderItemStatistics -Identity $($objPF.Identity)|Sort-Object CreationTime -Descending|Select-Object -First 1 #|ft CreationTime,LastModificationTime $strMailAddreess = "" if ($objPF.MailEnabled -eq $true) { $objPFmail = Get-MailPublicFolder -Identity $($objPF.Identity) $strMailAddreess = $objPFmail.PrimarySmtpAddress } $objPFstats = Get-PublicFolderStatistics -Identity $($objPF.Identity) $strOutLine = "$($objPF.Identity);$($objPF.MailEnabled);$strMailAddreess;$($objPF.FolderClass);$($objPFstats.LastModificationTime);$($objPF.FolderSize);$($objPFstats.ItemCount);$($objPFitemstats.CreationTime)" Out-File -FilePath $OutputFile -InputObject "$strOutLine" -Encoding UTF8 -append Write-Host "`t$strOutLine" } #Get-PublicFolder -Recurse | Get-PublicFolderItemStatistics | Group-Object -Property ItemType -NoElement |