Submitted by Chad Manzer on July 19, 2010 - 2:17pm
The other day my boss came over and asked me how many users are using Exchange Active Sync (EAS) for mobile email. Since we are in the process of moving to Exchange 2010 I tried to see if he could wait a few months since Get-ActiveSyncDevice or Get-ActiveSyncDeviceStatistics would have the info I was looking for, but he wanted it by the end of the week, so I got to work.
My first thoughts were to query AD for users enabled to use EAS with a LDAP query for something like "msExchOmaAdminWirelessEnable=*" but the problem with this is it does not tell me who is actually using the service or what devices they have. As far as I could tell the only place the data was available was in the IIS logs on our Exchange2003 Front-end OWA servers. I checked a sample log file, I was in luck it contained the info I needed.
2010-06-25 00:00:00 W3SVC1 OWAServerName x.x.x.x POST /Microsoft-Server-ActiveSync User=UserSAMAccountName&DeviceId=ApplXXXXXXXXXX&DeviceType=iPad&Cmd=MoveItems&Log=V4TNASNC:0A0C0D0FS:0A0C0D0SP:1C7I18230S462834R0S0L0H0P 443 domain\samaccountname x.x.x.x HTTP/1.1 Apple-iPad/702.367 - - ourwebmailaddress m 200 0 0 436 542 156
Note: I have removed my company specific info like User Names, server names and, IP Addresses
You can see the Users SAMAccountName, their DeviceID and DeviceType . Since we want to extract text from within a string the perfect tool for this is regular expression. We can use PowerShell to extract this info from a string with the -match " User=(.+)&DeviceID=(.+)&DeviceType=(.+)&Cmd" I won't get into the details of regular expression as it could be a whole series of posts by itself, but more details can be found all via your favorite search engine and at http://regexlib.com/
My environment generates about a 1GB of logs per day per OWA server (we have 5 OWA Servers and keep several weeks of IIS logs!) so I did not want to spend the time searching through all the files. I figured if they were actively using their EAS device then it should appear with in a few days of logs at least once. I copied a few days of IIS logs from each server locally to my workstation. If you want to search the logs on the servers with out copying them locally first you can set the path to search all the servers IIS log directories by using:
$searchdir = "\\Server1\c$\WINDOWS\system32\LogFiles\W3SVC1\", "\\Server2\c$\WINDOWS\system32\LogFiles\W3SVC1\"
My first attempt stored all matches of the regex expression in an array but I quickly exhausted the 8GB of RAM I have installed in my workstation since each device is continually talking with our webmail servers generating lines in the log files. A better approach is to use a PowerShell Hash Table; in VBS these were called Dictionary Objects. You may have also heard them referred to as Associative Arrays. An excellent primer on Hash Tables is available at http://technet.microsoft.com/en-us/library/ee692803.aspx The main strength is that a Hash Tables uses key-value pairs where the key has to be unique. The EAS DeviceId is a unique value per handheld. All we need to do is store the DeviceID as the key and the value as who it belongs to and what type it is.
The file that is set by $outfile generates a CSV file that is easily opened by Excel so you can gather any statics from it that you need.
#############################################################################
# Filename: CollectEASInfo.ps1
# Searches Exchange 2003 IIS log files for EAS user and Device info and
# writes it to a CSV
#
# Created by Chad Manzer
# phillyexug.org
#
# Version 1.0
# (7/15/2009) - CM Inital relase
#
# DISCLAIMER
# ==========
# THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE
# RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
#############################################################################
$startTime = Get-Date
$outfile = "e:\APPL.csv" #Where to save the results
$searchdir = "e:\OWAIIS\" #Directories to search for Exchange 2003 IIS logs
$Files = get-childitem $searchdir |%{$_.FullName}
[Hashtable]$Hash = @{} #defining the Hash table for use later
#Write-Progress -activity "Processing" -status "Getting content of the files..."
Get-Content $Files|%{
if ($_ -match " User=(.+)&DeviceID=(.+)&DeviceType=(.+)&Cmd")
{
$User = $Matches[1]
$DeviceID = $Matches[2]
$DeviceType = $Matches[3]
#if the item is already in the hash table do not try to add it again
if ($Hash.ContainsKey("$DeviceID,") -eq $False)
# adding commas between items so we can export as a CSV later on
{$Hash.Add("$DeviceID,", "$User, $DeviceType")}
#Show some type of progress, it drives me nuts staring at a blinking cursor
if ($i -lt 100)
{$i++
Write-Progress -activity "Reading in Files" -status "User: $User DeviceType $DeviceType DeviceID $DeviceID" -percentcomplete $i
}
else {$i=0}
}
}
#Write the hash file to out output file
Write-Progress -activity "Processing" -status "Writing to $outfile "
$Hash | out-file $outfile -Encoding ascii
#Clean up the output file since the hash table add's extra spaces in the csv we don't need
Write-Progress -activity "Processing" -status "Cleaning up output file $outfile "
(Get-Content $outfile) -replace ' ','' | Set-Content $outfile
#All done.
Write-Progress -Activity "Processing" -Completed -Status "All done."
Write-Host "Output file is located at: $outfile"
$Endtime = Get-Date
$RunTime = $Endtime - $startTime
Write-Host "Run time: "
$RunTime
»
- Chad Manzer's blog
- Login or register to post comments
