OK. Dealing with calendars is a little odd.
A single “view” of a calendar cannot exceed 2 years, nor can it contain more
than 1,000 items. The code below supports only that single view.
If you want to go back further (or forward further), then you start “paging”,
i.e., go a month at a time or a week at a time. You still have that 1,000 item
limit to deal with.
To open a user’s calendar requires that you have: [a] full control, [b]
receive-as, or [c] impersonation privileges. The easiest thing to do is to give
yourself (or a service account) receive-as on the relevant mailbox databases.
Run this script under that service account.
I sanitized this rather quickly from a much larger script. It seems to work for
me, but it isn’t my prettiest work. Note that it outputs “objects” so you can
search and manipulate the objects as you would expect from any PowerShell
solution.
Enjoy.
param
(
[DateTime]$StartDate = ( Get-Date -Year 1970 -Month 1 -Day 1
-Hour 8 -Minute 0 -Second 0 ),
[DateTime]$EndDate = ( Get-Date ),
[bool]$useDefaultCredentials = $true,
[string]$ewsURL = 'https://server2/ews/exchange.asmx'
)
Set-StrictMode -Version 2.0
function Connect-EWS
{
## Load EWS Managed API
Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web
Services\2.2\Microsoft.Exchange.WebServices.dll"
## Set minimum EWS managed API Version
$Version =
[Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2
## Create Exchange Service Object
$script:service = New-Object
Microsoft.Exchange.WebServices.Data.ExchangeService( $Version )
if( $service -eq $null )
{
throw $error[ 0 ]
}
if( $useDefaultCredentials )
{
$script:service.useDefaultCredentials = $true
}
else
{
## FIXME
## $service.Credentials = ????
}
## define a couple of well-known folders
$script:wkf_Inbox =
[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox
$script:wkf_Calendar =
[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Calendar
}
function Set-myCertificatePolicy
{
## Choose to ignore any SSL Warning issues caused by Self
Signed Certificates
## Code From http://poshcode.org/624
## Create a compilation environment
$Provider = New-Object Microsoft.CSharp.CSharpCodeProvider
$Compiler = $Provider.CreateCompiler()
$Params = New-Object
System.CodeDom.Compiler.CompilerParameters
$Params.GenerateExecutable = $false
$Params.GenerateInMemory = $true
$Params.IncludeDebugInformation = $false
$Params.ReferencedAssemblies.Add( 'System.DLL' ) | Out-Null
$TASource = @'
namespace Local.CertificatePolicy
{
public class TrustAll :
System.Net.ICertificatePolicy
{
public
TrustAll()
{
}
public bool
CheckValidationResult(
System.Net.ServicePoint sp,
System.Security.Cryptography.X509Certificates.X509Certificate cert,
System.Net.WebRequest req,
int problem)
{
return true;
}
}
}
'@
$TAResults = $Provider.CompileAssemblyFromSource( $Params,
$TASource )
$TAAssembly = $TAResults.CompiledAssembly
## We now create an instance of the TrustAll and attach it to
the ServicePointManager
$script:TrustAll = $TAAssembly.CreateInstance(
'Local.CertificatePolicy.TrustAll' )
[System.Net.ServicePointManager]::CertificatePolicy =
$script:TrustAll
## end code from http://poshcode.org/624
}
## Main
Connect-EWS
Set-myCertificatePolicy
$mailboxes = Get-Mailbox -ResultSize Unlimited
## Get the EWS URL. Use either AutoD or a hardcoded EWS URL
if( [String]::IsNullOrEmpty( $ewsURL ) )
{
$mailboxSmtp = $mailboxes[ 0
].PrimarySmtpAddress.ToString()
$service.AutodiscoverUrl( $mailboxSmtp, $true )
Write-Host "Using AutoD EWS Server :"
$Service.url
}
else
{
$uri = [System.URI] $ewsURL
$service.Url = $uri
Write-Host "Using parameterized EWS server :"
$ewsURL
}
$rptcollection = @()
$start = Get-Date
$i = 0
foreach( $mailbox in $mailboxes )
{
$i += 1
$Duration = ( New-TimeSpan -Start ($start) -End
(Get-Date) ).TotalSeconds
$TimeLeft = ( $Duration / $i ) * (
$mailboxes.Count - $i )
Write-Progress -Status $mailbox.DisplayName `
-Activity
"Mailbox $i of $($mailboxes.Count)" `
-PercentComplete ( $i / $mailboxes.Count * 100 ) `
-SecondsRemaining $timeleft `
-Id 100
## FIXME - impersonation? or admin perms? I
don't care, but decide
## Optional section for Exchange Impersonation
## $service.ImpersonatedUserId = new-object
Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress,
$Mailbox.PrimarySMTPAddress)
$folderid = $null ## clear value (if any) from
prior iteration
$calendar = $null ## clear value (if any) from
prior iteration
try
{
$folderid = New-Object
Microsoft.Exchange.WebServices.Data.FolderId( $wkf_Calendar,
$mailbox.PrimarySMTPAddress.ToString() )
$calendar =
[Microsoft.Exchange.WebServices.Data.Folder]::Bind( $service, $folderid )
}
catch
{
Write-Host "Could not bind to
Calendar for" $mailbox.PrimarySMTPAddress.ToString()
continue
}
##$calendar | fl * -force
##$global:saveCal = $calendar
##$global:saveEWS = $service
##$global:propSet = $calPropSet
Write-Host "Bound to Calendar for"
$mailbox.PrimarySMTPAddress.ToString()
Write-Host ".... total items in Calendar
$($calendar.TotalCount)"
if( $calendar.TotalCount -eq 0 )
{
continue
}
$calPropSet = New-Object
Microsoft.Exchange.WebServices.Data.PropertySet( `
[Microsoft.Exchange.WebServices.Data.BasePropertySet ]::IdOnly,
`
[Microsoft.Exchange.WebServices.Data.ItemSchema ]::Subject,
`
[Microsoft.Exchange.WebServices.Data.AppointmentSchema]::AppointmentState,
`
[Microsoft.Exchange.WebServices.Data.AppointmentSchema]::AppointmentType,
`
[Microsoft.Exchange.WebServices.Data.AppointmentSchema]::End,
`
[Microsoft.Exchange.WebServices.Data.AppointmentSchema]::Start,
`
[Microsoft.Exchange.WebServices.Data.AppointmentSchema]::IsRecurring,
`
[Microsoft.Exchange.WebServices.Data.AppointmentSchema]::Location,
`
[Microsoft.Exchange.WebServices.Data.AppointmentSchema]::Organizer
)
##
[Microsoft.Exchange.WebServices.Data.AppointmentSchema]::
### a calendar view is limited to two years
### so to look at an entire calendar is a bit
of a hassle
### we just examine $EndDate - 730 days worth
of data (or up to 1000 calendar items)
$StartDate = $EndDate.AddDays( -730 )
$calView = $null
$calView = New-Object
Microsoft.Exchange.WebServices.Data.CalendarView( $StartDate, $EndDate, 1000 )
$calView.PropertySet = $calPropSet
$global:Collection = $null
$global:Collection =
$calendar.FindAppointments( $calView )
$count = 0
foreach( $appointment in $Collection.Items )
{
if( $appointment.IsRecurring
-eq $false )
{
continue
}
##$appointment | ft Subject,
IsRecurring,
##
AppointmentType, AppointmentState,
##
Location, Organizer
$count += 1
Write-Progress -Status
$mailbox.DisplayName `
-Activity "Mailbox $i of $($mailboxes.Count)" `
-PercentComplete ( $i/ $mailboxes.count * 100 ) `
-SecondsRemaining $timeleft `
-Id 100 `
-CurrentOperation "Processing calendarItem $count of $($Collection.Items.Count)"
$obj = "" | Select Subject,
`
AppointmentState, AppointmentType, `
Start, End,
`
IsRecurring,
`
Location,
Organizer
$obj.Subject =
$appointment.Subject
$obj.AppointmentState =
$appointment.AppointmentState
$obj.AppointmentType =
$appointment.AppointmentType
$obj.Start =
$appointment.Start
$obj.End =
$appointment.End
$obj.IsRecurring =
$appointment.IsRecurring
$obj.Location =
$appointment.Location
$obj.Organizer =
$appointment.Organizer
Write-Output $obj
}
} ## foreach( $mailbox in $mailboxes )