I don't know about you, but I've had my share of problems with Outlook caused by cached mode being enabled. I know this is controllable by Group Policy, but we have a lot of people that use Outlook Calendars extensively, and they need cached mode on. This is one of those cases where it's easier to run this monthly and keep things tight, than it would be for me to try and scope a group policy to omit people from all over the place, and remember to incorporate new hires that match this profile.
The trick here was to find out how I would know if a client connected and was on cached mode. The best option, it turned out, was to look in the RPC logs of the Exchange server itself.
#########################################################
# BEGIN SCRIPT
#########################################################
# Phase One: Preperation
#########################################################
#Import Active Directory Module
Import-Module activedirectory
#Function to find Hostnames from IP Addresses
Function Get-HostFromIP
{
$IP = $args[0]
$result = $null
$result = [System.Net.Dns]::gethostentry($ip)
If ($Result){
$DNS = [string]$Result.HostName
}
Else
{
$DNS = "No HostName Found"
}
$DNS
} #End Function
#Path Variables
$ExchangeLogFolder = "\\mailserver\c$\Program Files\Microsoft\Exchange Server\V14\Logging\RPC Client Access"
$LocalHoldingFolder = "C:\Logs\ExchangeCachedMode"
$OutputFile = "C:\Temp\Cached Mode On - Desktops.csv"
#Email Variables
$SMTPServer = "mail.contoso.com"
$To = "reporting@contoso.com"
$From = "helpdesk@contoso.com"
$Body = "See Attached"
#Remove any output file if it already exists
Remove-item $OutputFile -force -ErrorAction SilentlyContinue
#Delete any pre-existing file in the Local Holding Folder
Get-Childitem -Path $LocalHoldingFolder | remove-item -force -ErrorAction SilentlyContinue
#########################################################
# Phase Two: Copying over the RPC logs from Exchange
#########################################################
#Copy the files
$Files = get-childitem -Path $ExchangeLogFolder | select fullname
Foreach ($File in $Files){
Copy-Item $File.fullname -Destination $LocalHoldingFolder
}
#Remove the first 5 lines of each LOG file, change the fields row, and output in a consistent CSV format
$Files = get-childitem -Path $LocalHoldingFolder | select fullname
Foreach ($File in $Files){
$Text = Get-Content $File.Fullname
$Output = $Text[4..($Text.count)]
$Output[0] = $Output[0] -replace "`#Fields: ",""
$Newfile = (($File.Fullname)+"OUT.csv")
$Newerfile = (($File.Fullname)+"FINAL.csv")
$Output | %{$_ | Add-content $NewFile}
$NewFileContent = Import-csv $Newfile
$NewFileContent | select client-name,client-mode,client-ip | export-csv -NoTypeInformation $Newerfile
} #End Foreach
#Remove the old files that I don't need anymore
Get-childitem $LocalHoldingFolder -Filter "*.LOG" | %{Remove-Item $_.fullname -Force -ErrorAction SilentlyContinue}
Get-childitem $LocalHoldingFolder -Filter "*.LOGOUT.csv" | %{Remove-Item $_.fullname -Force -ErrorAction SilentlyContinue}
#########################################################
# Phase Three; Merging the CSV files
#########################################################
#Get some info
$CSVFilePath = $LocalHoldingFolder
#Get info from the CSV file path
$CSVFiles = get-childitem $CSVFilePath | select fullname, name
#Initialize/Clear the output array
$Output = @()
#Cycle through and add csv content to array
foreach($CSV in $CSVFiles) {
if(Test-Path $CSV.fullname) {
$FileName = [System.IO.Path]::GetFileName($CSV.FullName)
$temp = Import-CSV -Path $CSV.fullname | select *, @{Expression={$FileName};Label="FileName"}
$Output += $temp
} else {
Write-Warning "$CSV.fullname : No such file found"
}
} #End Foreach
#Export Array content to specified output file
$Output | Export-Csv -Path ($LocalHoldingFolder + "\temp.csv") -NoTypeInformation
#Remove the old files that I don't need anymore
Get-childitem $LocalHoldingFolder -Filter "*.LOGFINAL.csv" | %{Remove-Item $_.fullname -Force -ErrorAction SilentlyContinue}
#########################################################
# Phase 4: Getting the data together
#########################################################
#Import the data for further refinement
$Content = Import-CSV ($LocalHoldingFolder + "\temp.csv")
#Select only the properties I want
$Refined = $Content | select client-name,client-mode,client-ip
#Run through some filters
$Refined2 = $Refined | where-object {
#Don't care about entries that list no ip address
$_."client-ip" -ne "" -and
#Here's the interesting bit: Classic means cached exchange mode is NOT on
$_."client-mode" -ne "Classic" -and
#There are some IP scopes that I can't do anything about
($_."client-ip" -like "*192.168.98*" -or
$_."client-ip" -like "*192.168.99*") -and
#I don't care about Exchange traffic
$_."client-name" -notlike "*Exchange*"
}
#Removing duplicate IPs
$Refined2 = $Refined2 | Sort-Object client-ip -Unique
#Initialize a new array
$Refined3 = @()
#Put the same data into the new array, but also include the hostname based on the IP
Foreach ($Item in $Refined2){
$SubRefined3 = New-Object System.Object
$ClientHostName = Get-HostFromIP $Item."Client-IP"
$ClientDescription = (Get-ADComputer ($ClientHostname -replace (".contoso.com","")) -Properties * | select Description).Description
$SubRefined3 | Add-Member -type NoteProperty -name ClientName -value $Item."Client-Name"
$SubRefined3 | Add-Member -type NoteProperty -name ClientMode -value $Item."Client-Mode"
$SubRefined3 | Add-Member -type NoteProperty -name ClientIP -value $Item."Client-IP"
$SubRefined3 | Add-Member -type NoteProperty -name ClientHostName -value $ClientHostName
$SubRefined3 | Add-Member -type NoteProperty -name ClientDescription -value $ClientDescription
$Refined3 += $SubRefined3
} #End Foreach
#Remove any items where a DNS hostname could not be found
$Refined3 = $Refined3 | where-object {$_.ClientHostname -notlike "No Hostname Found"}
#Do AD Lookups to remove any computers that are laptops, based on AD OU. I have no issue with laptops being on cached exchange mode.
$Refined3 = $Refined3 | where-object {((get-adcomputer ($_.ClientHostName -replace (".contoso.com","")) | select DistinguishedName).DistinguishedName) -notlike "*OU=Laptop*"} | sort-object ClientHostName
#Filter out any hostnames that I don't want in the report
$Refined4 = $Refined3 | Where-Object {
$_.ClientHostName -notlike "def*" -and
$_.ClientHostName -notlike "ghi*" -and
$_.ClientHostName -notlike "No Hostname Found"}
#Final Export, excluding computers where Cached Exchange Mode is needed
$Refined4 | Where-Object {$_.ClientHostName -notlike "A123456*" -and
$_.ClientHostName -notlike "B4545875*"} | export-csv $OutputFile -NoTypeInformation
#Get some counts
$Count = (($Refined4 | Measure-Object).count)
$CountString = (($Refined4 | Measure-Object).count).ToString()
$Subject = "PS Report - Clients Using Cached Exchange Mode - $CountString"
#Only send an email if there are more than zero results
If ($Count -gt 0){
#Send Email
Send-Mailmessage -To $To -From $From -SMTPServer $SMTPServer -Subject $Subject -Body $Body -Attachments $OutputFile
} #End If
#Remove Temp Files
Remove-Item $OutputFile -Force -Erroraction SilentlyContinue
Remove-Item ($LocalHoldingFolder + "\temp.csv") -Force -Erroraction SilentlyContinue
#########################################################
# END SCRIPT
#########################################################
# END SCRIPT
#########################################################