From c2f85dbd3685ea917bc0f95d58239a11ba3c940a Mon Sep 17 00:00:00 2001 From: Shane Ferrell Date: Wed, 1 May 2024 12:14:04 -0700 Subject: [PATCH 1/4] Break Timeline into functions --- Calendar/CalLogHelpers/CalLogCSVFunctions.ps1 | 1 + Calendar/CalLogHelpers/Invoke-GetCalLogs.ps1 | 1 + .../ShortClientNameFunctions.ps1 | 10 +- Calendar/CalLogHelpers/TimelineFunctions.ps1 | 737 ++++++++++-------- .../Get-CalendarDiagnosticObjectsSummary.ps1 | 16 +- .../Tests/ShortClientNameFunctions.Tests.ps1 | 12 +- 6 files changed, 414 insertions(+), 363 deletions(-) diff --git a/Calendar/CalLogHelpers/CalLogCSVFunctions.ps1 b/Calendar/CalLogHelpers/CalLogCSVFunctions.ps1 index 16be0f2cc7..f13bf2d19a 100644 --- a/Calendar/CalLogHelpers/CalLogCSVFunctions.ps1 +++ b/Calendar/CalLogHelpers/CalLogCSVFunctions.ps1 @@ -182,6 +182,7 @@ function BuildCSV { 'IsIgnorable' = $IsIgnorable 'SubjectProperty' = $CalLog.SubjectProperty 'Client' = $ShortClientName + 'ShortClientInfoString' = $CalLog.ShortClientInfoString 'ClientInfoString' = $CalLog.ClientInfoString 'TriggerAction' = $CalLog.CalendarLogTriggerAction 'ItemClass' = $CalLog.ItemClass diff --git a/Calendar/CalLogHelpers/Invoke-GetCalLogs.ps1 b/Calendar/CalLogHelpers/Invoke-GetCalLogs.ps1 index c44029b0ad..e24d9470bb 100644 --- a/Calendar/CalLogHelpers/Invoke-GetCalLogs.ps1 +++ b/Calendar/CalLogHelpers/Invoke-GetCalLogs.ps1 @@ -23,6 +23,7 @@ $script:CustomPropertyNameList = "IsAllDayEvent", "IsCancelled", "IsMeeting", +"IsOrganizerProperty", "NormalizedSubject", "SendMeetingMessagesDiagnostics", "SentRepresentingDisplayName", diff --git a/Calendar/CalLogHelpers/ShortClientNameFunctions.ps1 b/Calendar/CalLogHelpers/ShortClientNameFunctions.ps1 index e2426d04bc..125d567ae1 100644 --- a/Calendar/CalLogHelpers/ShortClientNameFunctions.ps1 +++ b/Calendar/CalLogHelpers/ShortClientNameFunctions.ps1 @@ -18,7 +18,7 @@ function FindMatch { $ShortClientNameProcessor = @{ 'Client=Hub Transport' = "Transport" - 'Client=MSExchangeRPC' = "Outlook : Desktop" + 'Client=MSExchangeRPC' = "Outlook : Desktop : MAPI" 'OneOutlook' = "OneOutlook" 'Lync for Mac' = "LyncMac" 'AppId=00000004-0000-0ff1-ce00-000000000000' = "SkypeMMS" @@ -124,16 +124,16 @@ function CreateShortClientName { if ($ClientInfoString -like "*InternalCalendarSharing*" -and $ClientInfoString -like "*OWA*" -and $ClientInfoString -notlike "*OneOutlook*") { - $ShortClientName = "Owa-ModernCalendarSharing" + $ShortClientName = "OWA : REST" } if ($ClientInfoString -like "*InternalCalendarSharing*" -and $ClientInfoString -like "*MacOutlook*") { - $ShortClientName = "MacOutlook-ModernCalendarSharing" + $ShortClientName = "MacOutlook : REST" } if ($ClientInfoString -like "*InternalCalendarSharing*" -and $ClientInfoString -like "*Outlook*") { - $ShortClientName = "Outlook-ModernCalendarSharing" + $ShortClientName = "Outlook : Desktop : REST" } if ($ClientInfoString -like "Client=ActiveSync*" -and $ClientInfoString -like "*Outlook*") { - $ShortClientName = "Outlook-ModernCalendarSharing" + $ShortClientName = "Outlook : ActiveSync" } if ($ClientInfoString -like "*OneOutlook*") { $ShortClientName = "OneOutlook" diff --git a/Calendar/CalLogHelpers/TimelineFunctions.ps1 b/Calendar/CalLogHelpers/TimelineFunctions.ps1 index ead6f2bfb5..d1577fca99 100644 --- a/Calendar/CalLogHelpers/TimelineFunctions.ps1 +++ b/Calendar/CalLogHelpers/TimelineFunctions.ps1 @@ -27,6 +27,174 @@ please let me know or fix it yourself on GitHub. I use a iterative approach to building this, so it will get better over time. #> + +function FindOrganizer { + $Script:Organizer = "" + # find the first IPM.Appointment in the CalLogs and set the Organizer + foreach ($CalLog in $script:GCDO){ + if ($CalendarItemTypes.($CalLog.ItemClass) -eq "IpmAppointment" -and + $CalLog.ExternalSharingMasterId -eq "NotFound" -and + $null -ne $CalLog.From) { + Write-Host "Found Organizer of meeting as : [$($CalLog.From)]" + + if ($null -ne $CalLog.From.SMTP) { + $Script:Organizer = $($CalLog.From.SMTP) + } + elseif ($null -ne $CalLog.From.DisplayName) { + $Script:Organizer = $($CalLog.From.DisplayName) + } + else { + $Script:Organizer = $($CalLog.From) + } + break + } + } + Write-Host "Setting Organizer to : [$Script:Organizer]" +} + +function FindFirstMeeting { + [array]$FirstMeeting = $script:GCDO | Where-Object { $_.ItemClass -eq "IPM.Appointment" -and $_.IsFromSharedCalendar -eq $False } + if ($FirstMeeting.count -eq 0) { + Write-Host "All CalLogs are from shared Calendar, getting values from first IPM.Appointment." + $FirstMeeting = $script:GCDO | Where-Object { $_.ItemClass -eq "IPM.Appointment" } + } + if ($FirstMeeting.count -eq 0) { + Write-Error "Cannot find any IPM.Apptointments, if this is the Organizer, check for the Outlook Bifurcation issue." + Write-Error "No IPM.Appointment found, cannot set initial values." + } else { + Write-Host "Found $($script:GCDO.count) Log entries, looking at the first IPM.Appointment." + return $FirstMeeting[0] + } +} +<# +.SYNOPSIS + Determines if key properties of the calendar log have changed. +.DESCRIPTION + This function checks if the properties of the calendar log have changed by comparing the current + Calendar log to the Previous calendar log (where it was an IPM.Appointment - i.e. the meeting) + + Changed properties will be added to the Timeline. +#> +function FindChangedProperties { + if ($CalLog.Client -ne "LocationProcessor" -or $CalLog.Client -notlike "EBA:*" -or $CalLog.Client -notlike "TBA:*") { + if ($script:PreviousCalLog -and $script:AddChangedProperties) { + if ($CalLog.StartTime.ToString() -ne $script:PreviousCalLog.StartTime.ToString()) { + [Array]$TimeLineText = "The StartTime changed from [$($script:PreviousCalLog.StartTime)] to: [$($CalLog.StartTime)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.EndTime.ToString() -ne $script:PreviousCalLog.EndTime.ToString()) { + [Array]$TimeLineText = "The EndTime changed from [$($script:PreviousCalLog.EndTime)] to: [$($CalLog.EndTime)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.SubjectProperty -ne $script:PreviousCalLog.SubjectProperty) { + [Array]$TimeLineText = "The SubjectProperty changed from [$($script:PreviousCalLog.SubjectProperty)] to: [$($CalLog.SubjectProperty)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.NormalizedSubject -ne $script:PreviousCalLog.NormalizedSubject) { + [Array]$TimeLineText = "The NormalizedSubject changed from [$($script:PreviousCalLog.NormalizedSubject)] to: [$($CalLog.NormalizedSubject)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.Location -ne $script:PreviousCalLog.Location) { + [Array]$TimeLineText = "The Location changed from [$($script:PreviousCalLog.Location)] to: [$($CalLog.Location)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.TimeZone -ne $script:PreviousCalLog.TimeZone) { + [Array]$TimeLineText = "The TimeZone changed from [$($script:PreviousCalLog.TimeZone)] to: [$($CalLog.TimeZone)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.DisplayAttendeesAll -ne $script:PreviousCalLog.DisplayAttendeesAll) { + [Array]$TimeLineText = "The All Attendees changed from [$($script:PreviousCalLog.DisplayAttendeesAll)] to: [$($CalLog.DisplayAttendeesAll)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.AppointmentRecurring -ne $script:PreviousCalLog.AppointmentRecurring) { + [Array]$TimeLineText = "The Appointment Recurrence changed from [$($script:PreviousCalLog.AppointmentRecurring)] to: [$($CalLog.AppointmentRecurring)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.HasAttachment -ne $script:PreviousCalLog.HasAttachment) { + [Array]$TimeLineText = "The Meeting has Attachment changed from [$($script:PreviousCalLog.HasAttachment)] to: [$($CalLog.HasAttachment)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.IsCancelled -ne $script:PreviousCalLog.IsCancelled) { + [Array]$TimeLineText = "The Meeting is Cancelled changed from [$($script:PreviousCalLog.IsCancelled)] to: [$($CalLog.IsCancelled)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.IsAllDayEvent -ne $script:PreviousCalLog.IsAllDayEvent) { + [Array]$TimeLineText = "The Meeting is an All Day Event changed from [$($script:PreviousCalLog.IsAllDayEvent)] to: [$($CalLog.IsAllDayEvent)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.IsException -ne $script:PreviousCalLog.IsException) { + [Array]$TimeLineText = "The Meeting Is Exception changed from [$($script:PreviousCalLog.IsException)] to: [$($CalLog.IsException)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.IsSeriesCancelled -ne $script:PreviousCalLog.IsSeriesCancelled) { + [Array]$TimeLineText = "The Is Series Cancelled changed from [$($script:PreviousCalLog.IsSeriesCancelled)] to: [$($CalLog.IsSeriesCancelled)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.EventEmailReminderTimer -ne $script:PreviousCalLog.EventEmailReminderTimer) { + [Array]$TimeLineText = "The Email Reminder changed from [$($script:PreviousCalLog.EventEmailReminderTimer)] to: [$($CalLog.EventEmailReminderTimer)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.FreeBusyStatus -ne $script:PreviousCalLog.FreeBusyStatus) { + [Array]$TimeLineText = "The FreeBusy Status changed from [$($script:PreviousCalLog.FreeBusyStatus)] to: [$($CalLog.FreeBusyStatus)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.AppointmentState -ne $script:PreviousCalLog.AppointmentState) { + [Array]$TimeLineText = "The Appointment State changed from [$($script:PreviousCalLog.AppointmentState)] to: [$($CalLog.AppointmentState)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.MeetingRequestType -ne $script:PreviousCalLog.MeetingRequestType) { + [Array]$TimeLineText = "The Meeting Request Type changed from [$($script:PreviousCalLog.MeetingRequestType.Value)] to: [$($CalLog.MeetingRequestType.Value)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.CalendarItemType -ne $script:PreviousCalLog.CalendarItemType) { + [Array]$TimeLineText = "The Calendar Item Type changed from [$($script:PreviousCalLog.CalendarItemType)] to: [$($CalLog.CalendarItemType)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.ResponseType -ne $script:PreviousCalLog.ResponseType) { + [Array]$TimeLineText = "The ResponseType changed from [$($script:PreviousCalLog.ResponseType)] to: [$($CalLog.ResponseType)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.SenderSMTPAddress -ne $script:PreviousCalLog.SenderSMTPAddress) { + [Array]$TimeLineText = "The Sender Email Address changed from [$($script:PreviousCalLog.SenderSMTPAddress)] to: [$($CalLog.SenderSMTPAddress)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.From -ne $script:PreviousCalLog.From) { + [Array]$TimeLineText = "The From changed from [$($script:PreviousCalLog.From)] to: [$($CalLog.From)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.ReceivedBy -ne $script:PreviousCalLog.ReceivedBy) { + [Array]$TimeLineText = "The Received By changed from [$($script:PreviousCalLog.ReceivedBy)] to: [$($CalLog.ReceivedBy)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + + if ($CalLog.ReceivedRepresenting -ne $script:PreviousCalLog.ReceivedRepresenting) { + [Array]$TimeLineText = "The Received Representing changed from [$($script:PreviousCalLog.ReceivedRepresenting)] to: [$($CalLog.ReceivedRepresenting)]" + MeetingSummary -Time " " -MeetingChanges $TimeLineText + } + } + } +} function BuildTimeline { param ( [string] $Identity @@ -39,13 +207,17 @@ function BuildTimeline { $ShortName = $ShortName.Substring(0, [System.Math]::Min(20, $ShortName.Length)) $Script:TimeLineFilename = "$($ShortName)_TimeLine_$ShortMeetingID.csv" + FindOrganizer + Write-DashLineBoxColor " TimeLine for [$Identity]:", " Subject: $($script:GCDO[0].NormalizedSubject)", - " Organizer: $($script:GCDO[0].SentRepresentingDisplayName)", + " Organizer: $Script:Organizer", " MeetingID: $($script:GCDO[0].CleanGlobalObjectId)" [Array]$Header = ("Subject: " + ($script:GCDO[0].NormalizedSubject) + " | MeetingID: "+ ($script:GCDO[0].CleanGlobalObjectId)) MeetingSummary -Time "Calendar Log Timeline for Meeting with" -MeetingChanges $Header - MeetingSummary -Time "Initial Message Values" -Entry $script:GCDO[0] -LongVersion + + MeetingSummary -Time "Initial Message Values" -Entry $(FindFirstMeeting) -LongVersion + # Ignorable and items from Shared Calendars are not included in the TimeLine. $MeetingTimeLine = $Results | Where-Object { $_.IsIgnorable -eq "False" -and $_.IsFromSharedCalendar -eq $False } @@ -57,405 +229,280 @@ function BuildTimeline { } foreach ($CalLog in $MeetingTimeLine) { - [bool] $MeetingSummaryNeeded = $False - [bool] $AddChangedProperties = $False - - <# - .SYNOPSIS - Determines if key properties of the calendar log have changed. - .DESCRIPTION - This function checks if the properties of the calendar log have changed by comparing the current - Calendar log to the Previous calendar log (where it was an IPM.Appointment - i.e. the meeting) - - Changed properties will be added to the Timeline. - #> - function ChangedProperties { - if ($CalLog.Client -ne "LocationProcessor" -or $CalLog.Client -notlike "EBA:*" -or $CalLog.Client -notlike "TBA:*") { - if ($PreviousCalLog -and $AddChangedProperties) { - if ($CalLog.StartTime.ToString() -ne $PreviousCalLog.StartTime.ToString()) { - [Array]$TimeLineText = "The StartTime changed from [$($PreviousCalLog.StartTime)] to: [$($CalLog.StartTime)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.EndTime.ToString() -ne $PreviousCalLog.EndTime.ToString()) { - [Array]$TimeLineText = "The EndTime changed from [$($PreviousCalLog.EndTime)] to: [$($CalLog.EndTime)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.SubjectProperty -ne $PreviousCalLog.SubjectProperty) { - [Array]$TimeLineText = "The SubjectProperty changed from [$($PreviousCalLog.SubjectProperty)] to: [$($CalLog.SubjectProperty)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.NormalizedSubject -ne $PreviousCalLog.NormalizedSubject) { - [Array]$TimeLineText = "The NormalizedSubject changed from [$($PreviousCalLog.NormalizedSubject)] to: [$($CalLog.NormalizedSubject)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.Location -ne $PreviousCalLog.Location) { - [Array]$TimeLineText = "The Location changed from [$($PreviousCalLog.Location)] to: [$($CalLog.Location)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.TimeZone -ne $PreviousCalLog.TimeZone) { - [Array]$TimeLineText = "The TimeZone changed from [$($PreviousCalLog.TimeZone)] to: [$($CalLog.TimeZone)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.DisplayAttendeesAll -ne $PreviousCalLog.DisplayAttendeesAll) { - [Array]$TimeLineText = "The All Attendees changed from [$($PreviousCalLog.DisplayAttendeesAll)] to: [$($CalLog.DisplayAttendeesAll)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.AppointmentRecurring -ne $PreviousCalLog.AppointmentRecurring) { - [Array]$TimeLineText = "The Appointment Recurrence changed from [$($PreviousCalLog.AppointmentRecurring)] to: [$($CalLog.AppointmentRecurring)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.HasAttachment -ne $PreviousCalLog.HasAttachment) { - [Array]$TimeLineText = "The Meeting has Attachment changed from [$($PreviousCalLog.HasAttachment)] to: [$($CalLog.HasAttachment)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.IsCancelled -ne $PreviousCalLog.IsCancelled) { - [Array]$TimeLineText = "The Meeting is Cancelled changed from [$($PreviousCalLog.IsCancelled)] to: [$($CalLog.IsCancelled)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.IsAllDayEvent -ne $PreviousCalLog.IsAllDayEvent) { - [Array]$TimeLineText = "The Meeting is an All Day Event changed from [$($PreviousCalLog.IsAllDayEvent)] to: [$($CalLog.IsAllDayEvent)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.IsException -ne $PreviousCalLog.IsException) { - [Array]$TimeLineText = "The Meeting Is Exception changed from [$($PreviousCalLog.IsException)] to: [$($CalLog.IsException)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.IsSeriesCancelled -ne $PreviousCalLog.IsSeriesCancelled) { - [Array]$TimeLineText = "The Is Series Cancelled changed from [$($PreviousCalLog.IsSeriesCancelled)] to: [$($CalLog.IsSeriesCancelled)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.EventEmailReminderTimer -ne $PreviousCalLog.EventEmailReminderTimer) { - [Array]$TimeLineText = "The Email Reminder changed from [$($PreviousCalLog.EventEmailReminderTimer)] to: [$($CalLog.EventEmailReminderTimer)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.FreeBusyStatus -ne $PreviousCalLog.FreeBusyStatus) { - [Array]$TimeLineText = "The FreeBusy Status changed from [$($PreviousCalLog.FreeBusyStatus)] to: [$($CalLog.FreeBusyStatus)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } + [bool] $script:MeetingSummaryNeeded = $False + [bool] $script:AddChangedProperties = $False - if ($CalLog.AppointmentState -ne $PreviousCalLog.AppointmentState) { - [Array]$TimeLineText = "The Appointment State changed from [$($PreviousCalLog.AppointmentState)] to: [$($CalLog.AppointmentState)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.MeetingRequestType -ne $PreviousCalLog.MeetingRequestType) { - [Array]$TimeLineText = "The Meeting Request Type changed from [$($PreviousCalLog.MeetingRequestType.Value)] to: [$($CalLog.MeetingRequestType.Value)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.CalendarItemType -ne $PreviousCalLog.CalendarItemType) { - [Array]$TimeLineText = "The Calendar Item Type changed from [$($PreviousCalLog.CalendarItemType)] to: [$($CalLog.CalendarItemType)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.ResponseType -ne $PreviousCalLog.ResponseType) { - [Array]$TimeLineText = "The ResponseType changed from [$($PreviousCalLog.ResponseType)] to: [$($CalLog.ResponseType)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.SenderSMTPAddress -ne $PreviousCalLog.SenderSMTPAddress) { - [Array]$TimeLineText = "The Sender Email Address changed from [$($PreviousCalLog.SenderSMTPAddress)] to: [$($CalLog.SenderSMTPAddress)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.From -ne $PreviousCalLog.From) { - [Array]$TimeLineText = "The From changed from [$($PreviousCalLog.From)] to: [$($CalLog.From)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.ReceivedBy -ne $PreviousCalLog.ReceivedBy) { - [Array]$TimeLineText = "The Received By changed from [$($PreviousCalLog.ReceivedBy)] to: [$($CalLog.ReceivedBy)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } + [array] $Output = TimelineRow + # Create the Timeline by adding to Time to the generated Output + $Time = "$($CalLog.LogRow) -- $($CalLog.LastModifiedTime)" - if ($CalLog.ReceivedRepresenting -ne $PreviousCalLog.ReceivedRepresenting) { - [Array]$TimeLineText = "The Received Representing changed from [$($PreviousCalLog.ReceivedRepresenting)] to: [$($CalLog.ReceivedRepresenting)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } + if ($Output) { + if ($script:MeetingSummaryNeeded) { + MeetingSummary -Time $Time -MeetingChanges $Output + MeetingSummary -Time " " -ShortVersion -Entry $CalLog + } else { + MeetingSummary -Time $Time -MeetingChanges $Output + if ($script:AddChangedProperties) { + FindChangedProperties } } } - <# - .SYNOPSIS - This is the part that generates the heart of the timeline, a Giant Switch statement based on the ItemClass. - #> - switch -Wildcard ($CalendarItemTypes.($CalLog.ItemClass)) { - MeetingRequest { - switch ($CalLog.TriggerAction) { - Create { - if ($IsOrganizer) { - if ($CalLog.IsException -eq $True) { - [array] $Output = "[$($CalLog.ResponsibleUser)] Created an Exception Meeting Request with $($CalLog.Client) for [$($CalLog.StartTime)]." - } else { - [array] $Output = "[$($CalLog.ResponsibleUser)] Created a Meeting Request was with $($CalLog.Client)" - } + # Setup Previous log (if current logs is an IPM.Appointment) + if ($CalendarItemTypes.($CalLog.ItemClass) -eq "IpmAppointment" -or $CalendarItemTypes.($CalLog.ItemClass) -eq "ExceptionMsgClass") { + $script:PreviousCalLog = $CalLog + } + } + + $Results = @() +} + + <# + .SYNOPSIS + This is the part that generates the heart of the timeline, a Giant Switch statement based on the ItemClass. + #> +function TimelineRow { + switch -Wildcard ($CalendarItemTypes.($CalLog.ItemClass)) { + MeetingRequest { + switch ($CalLog.TriggerAction) { + Create { + if ($IsOrganizer) { + if ($CalLog.IsException -eq $True) { + [array] $Output = "[$($CalLog.ResponsibleUser)] Created an Exception Meeting Request with $($CalLog.Client) for [$($CalLog.StartTime)]." + } else { + [array] $Output = "[$($CalLog.ResponsibleUser)] Created a Meeting Request was with $($CalLog.Client)" + } + } else { + if ($CalLog.DisplayAttendeesTo -ne $script:PreviousCalLog.DisplayAttendeesTo -or $CalLog.DisplayAttendeesCc -ne $script:PreviousCalLog.DisplayAttendeesCc) { + [array] $Output = "The user Forwarded a Meeting Request with $($CalLog.Client)." } else { - if ($CalLog.DisplayAttendeesTo -ne $PreviousCalLog.DisplayAttendeesTo -or $CalLog.DisplayAttendeesCc -ne $PreviousCalLog.DisplayAttendeesCc) { - [array] $Output = "The user Forwarded a Meeting Request with $($CalLog.Client)." + if ($CalLog.Client -eq "Transport") { + if ($CalLog.IsException -eq $True) { + [array] $Output = "Transport delivered a new Meeting Request from [$($CalLog.SentRepresentingDisplayName)] for an exception starting on [$($CalLog.StartTime)]" + $(if ($null -ne $($CalLog.ReceivedRepresenting)) { " for user [$($CalLog.ReceivedRepresenting)]" }) + "." + $script:MeetingSummaryNeeded = $True + } else { + [Array] $Output = "Transport delivered a new Meeting Request from [$($CalLog.SentRepresentingDisplayName)]" + + $(if ($null -ne $($CalLog.ReceivedRepresenting) -and $CalLog.ReceivedRepresenting -ne $CalLog.ReceivedBy) + { " for user [$($CalLog.ReceivedRepresenting)]" }) + "." + } + } elseif ($CalLog.Client -eq "CalendarRepairAssistant") { + if ($CalLog.IsException -eq $True) { + [array] $Output = "CalendarRepairAssistant Created a new Meeting Request to repair an inconsistency with an exception starting on [$($CalLog.StartTime)]." + } else { + [array] $Output = "CalendarRepairAssistant Created a new Meeting Request to repair an inconsistency." + } } else { - if ($CalLog.Client -eq "Transport") { - if ($CalLog.IsException -eq $True) { - [array] $Output = "Transport delivered a new Meeting Request from [$($CalLog.SentRepresentingDisplayName)] for an exception starting on [$($CalLog.StartTime)]" + $(if ($null -ne $($CalLog.ReceivedRepresenting)) { " for user [$($CalLog.ReceivedRepresenting)]" }) + "." - $MeetingSummaryNeeded = $True - } else { - [Array]$Output = "Transport delivered a new Meeting Request from [$($CalLog.SentRepresentingDisplayName)]" + - $(if ($null -ne $($CalLog.ReceivedRepresenting) -and $CalLog.ReceivedRepresenting -ne $CalLog.ReceivedBy) - { " for user [$($CalLog.ReceivedRepresenting)]" }) + "." - } - } elseif ($CalLog.Client -eq "CalendarRepairAssistant") { - if ($CalLog.IsException -eq $True) { - [array] $Output = "CalendarRepairAssistant Created a new Meeting Request to repair an inconsistency with an exception starting on [$($CalLog.StartTime)]." - } else { - [array] $Output = "CalendarRepairAssistant Created a new Meeting Request to repair an inconsistency." - } + if ($CalLog.IsException -eq $True) { + [array] $Output = "[$($CalLog.ResponsibleUser)] Created a new Meeting Request with $($CalLog.Client) for an exception starting on [$($CalLog.StartTime)]." } else { - if ($CalLog.IsException -eq $True) { - [array] $Output = "[$($CalLog.ResponsibleUser)] Created a new Meeting Request with $($CalLog.Client) for an exception starting on [$($CalLog.StartTime)]." - } else { - [array] $Output = "[$($CalLog.ResponsibleUser)] Created a new Meeting Request with $($CalLog.Client)." - } + [array] $Output = "[$($CalLog.ResponsibleUser)] Created a new Meeting Request with $($CalLog.Client)." } } } } - Update { - [array] $Output = "[$($CalLog.ResponsibleUser)] Updated on the $($CalLog.MeetingRequestType.Value) Meeting Request with $($CalLog.Client)." - } - MoveToDeletedItems { - if ($CalLog.ResponsibleUser -eq "Calendar Assistant") { - [array] $Output = "$($CalLog.Client) Deleted the Meeting Request." - } else { - [array] $Output = "[$($CalLog.ResponsibleUser)] Deleted the Meeting Request with $($CalLog.Client)." - } + } + Update { + [array] $Output = "[$($CalLog.ResponsibleUser)] Updated on the $($CalLog.MeetingRequestType.Value) Meeting Request with $($CalLog.Client)." + } + MoveToDeletedItems { + if ($CalLog.ResponsibleUser -eq "Calendar Assistant") { + [array] $Output = "$($CalLog.Client) Deleted the Meeting Request." + } else { + [array] $Output = "[$($CalLog.ResponsibleUser)] Deleted the Meeting Request with $($CalLog.Client)." } + } + default { + [array] $Output = "[$($CalLog.ResponsibleUser)] Deleted the $($CalLog.MeetingRequestType.Value) Meeting Request with $($CalLog.Client)." + } + } + } + Resp* { + switch ($CalLog.ItemClass) { + "IPM.Schedule.Meeting.Resp.Tent" { $MeetingRespType = "Tentative" } + "IPM.Schedule.Meeting.Resp.Neg" { $MeetingRespType = "DECLINE" } + "IPM.Schedule.Meeting.Resp.Pos" { $MeetingRespType = "ACCEPT" } + } + + if ($CalLog.AppointmentCounterProposal -eq "True") { + [array] $Output = "[$($CalLog.SentRepresentingDisplayName)] send a $($MeetingRespType) response message with a New Time Proposal: $($CalLog.StartTime) to $($CalLog.EndTime)" + } else { + switch -Wildcard ($CalLog.TriggerAction) { + "Update" { $Action = "Updated" } + "Create" { $Action = "Sent" } + "*Delete*" { $Action = "Deleted" } default { - [array] $Output = "[$($CalLog.ResponsibleUser)] Deleted the $($CalLog.MeetingRequestType.Value) Meeting Request with $($CalLog.Client)." + $Action = "Updated" } } - } - Resp* { - switch ($CalLog.ItemClass) { - "IPM.Schedule.Meeting.Resp.Tent" { $MeetingRespType = "Tentative" } - "IPM.Schedule.Meeting.Resp.Neg" { $MeetingRespType = "DECLINE" } - "IPM.Schedule.Meeting.Resp.Pos" { $MeetingRespType = "ACCEPT" } + + $Extra = "" + if ($CalLog.IsException) { + $Extra = " to the meeting starting $($CalLog.StartTime)" + } elseif ($CalLog.AppointmentRecurring) { + $Extra = " to the meeting series" } - if ($CalLog.AppointmentCounterProposal -eq "True") { - [array] $Output = "[$($CalLog.SentRepresentingDisplayName)] send a $($MeetingRespType) response message with a New Time Proposal: $($CalLog.StartTime) to $($CalLog.EndTime)" + if ($IsOrganizer) { + [array] $Output = "[$($CalLog.SentRepresentingDisplayName)] $($Action) a $($MeetingRespType) Meeting Response message$($Extra)." } else { - switch -Wildcard ($CalLog.TriggerAction) { - "Update" { $Action = "Updated" } - "Create" { $Action = "Sent" } - "*Delete*" { $Action = "Deleted" } - default { - $Action = "Updated" + switch ($CalLog.Client) { + ResourceBookingAssistant { + [array] $Output = "ResourceBookingAssistant $($Action) a $($MeetingRespType) Meeting Response message." } - } - - $Extra = "" - if ($CalLog.IsException) { - $Extra = " to the meeting starting $($CalLog.StartTime)" - } elseif ($CalLog.AppointmentRecurring) { - $Extra = " to the meeting series" - } - - if ($IsOrganizer) { - [array] $Output = "[$($CalLog.SentRepresentingDisplayName)] $($Action) a $($MeetingRespType) Meeting Response message$($Extra)." - } else { - switch ($CalLog.Client) { - ResourceBookingAssistant { - [array] $Output = "ResourceBookingAssistant $($Action) a $($MeetingRespType) Meeting Response message." - } - Transport { - [array] $Output = "[$($CalLog.From)] $($Action) $($MeetingRespType) Meeting Response message." - } - default { - [array] $Output = "[$($CalLog.ResponsibleUser)] $($Action) [$($CalLog.SentRepresentingDisplayName)]'s $($MeetingRespType) Meeting Response with $($CalLog.Client)." - } + Transport { + [array] $Output = "[$($CalLog.From)] $($Action) $($MeetingRespType) Meeting Response message." + } + default { + [array] $Output = "[$($CalLog.ResponsibleUser)] $($Action) [$($CalLog.SentRepresentingDisplayName)]'s $($MeetingRespType) Meeting Response with $($CalLog.Client)." } } } } - ForwardNotification { - [array] $Output = "The meeting was FORWARDED by [$($CalLog.SentRepresentingDisplayName)]." - } - ExceptionMsgClass { - if ($CalLog.ResponsibleUser -ne "Calendar Assistant") { - [array] $Output = "[$($CalLog.ResponsibleUser)] $($CalLog.TriggerAction)d Exception to the meeting series with $($CalLog.Client)." - } + } + ForwardNotification { + [array] $Output = "The meeting was FORWARDED by [$($CalLog.SentRepresentingDisplayName)]." + } + ExceptionMsgClass { + if ($CalLog.ResponsibleUser -ne "Calendar Assistant") { + [array] $Output = "[$($CalLog.ResponsibleUser)] $($CalLog.TriggerAction)d Exception to the meeting series with $($CalLog.Client)." } - IpmAppointment { - switch ($CalLog.TriggerAction) { - Create { - if ($IsOrganizer) { - if ($CalLog.Client -eq "Transport") { - [array] $Output = "Transport Created a new meeting." - } else { - [array] $Output = "[$($CalLog.ResponsibleUser)] Created a new Meeting with $($CalLog.Client)." - } + } + IpmAppointment { + switch ($CalLog.TriggerAction) { + Create { + if ($IsOrganizer) { + if ($CalLog.Client -eq "Transport") { + [array] $Output = "Transport Created a new meeting." } else { - switch ($CalLog.Client) { - Transport { - [array] $Output = "Transport Created a new Meeting on the calendar from [$($CalLog.SentRepresentingDisplayName)] and marked it Tentative." - } - ResourceBookingAssistant { - [array] $Output = "ResourceBookingAssistant Created a new Meeting on the calendar from [$($CalLog.SentRepresentingDisplayName)] and marked it Tentative." - } - default { - [array] $Output = "[$($CalLog.ResponsibleUser)] Created the Meeting with $($CalLog.Client)." - } - } + [array] $Output = "[$($CalLog.ResponsibleUser)] Created a new Meeting with $($CalLog.Client)." } - } - Update { + } else { switch ($CalLog.Client) { Transport { - if ($CalLog.ResponsibleUser -eq "Calendar Assistant") { - [array] $Output = "Transport Updated the meeting based on changes made to the meeting on [$($CalLog.Sender)] calendar." - } else { - [array] $Output = "Transport $($CalLog.TriggerAction)d the meeting based on changes made by [$($CalLog.ResponsibleUser)]." - } - } - LocationProcessor { - [array] $Output = "" + [array] $Output = "Transport Created a new Meeting on the calendar from [$($CalLog.SentRepresentingDisplayName)] and marked it Tentative." } ResourceBookingAssistant { - [array] $Output = "ResourceBookingAssistant $($CalLog.TriggerAction)d the Meeting." - } - CalendarRepairAssistant { - [array] $Output = "CalendarRepairAssistant $($CalLog.TriggerAction)d the Meeting to repair an inconsistency." + [array] $Output = "ResourceBookingAssistant Created a new Meeting on the calendar from [$($CalLog.SentRepresentingDisplayName)] and marked it Tentative." } default { - if ($CalLog.ResponsibleUser -eq "Calendar Assistant") { - [array] $Output = "The Exchange System $($CalLog.TriggerAction)d the meeting via the Calendar Assistant." - } else { - [array] $Output = "[$($CalLog.ResponsibleUser)] $($CalLog.TriggerAction)d the Meeting with $($CalLog.Client)." - $AddChangedProperties = $True - } + [array] $Output = "[$($CalLog.ResponsibleUser)] Created the Meeting with $($CalLog.Client)." } } - - if ($CalLog.FreeBusyStatus -eq 2 -and $PreviousCalLog.FreeBusyStatus -ne 2) { - if ($CalLog.ResponsibleUserName -eq "Calendar Assistant") { - [array] $Output = "$($CalLog.Client) Accepted the meeting." + } + } + Update { + switch ($CalLog.Client) { + Transport { + if ($CalLog.ResponsibleUser -eq "Calendar Assistant") { + [array] $Output = "Transport Updated the meeting based on changes made to the meeting on [$($CalLog.Sender)] calendar." } else { - [array] $Output = "[$($CalLog.ResponsibleUser)] Accepted the meeting with $($CalLog.Client)." + [array] $Output = "Transport $($CalLog.TriggerAction)d the meeting based on changes made by [$($CalLog.ResponsibleUser)]." } - $AddChangedProperties = $False - } elseif ($CalLog.FreeBusyStatus -ne 2 -and $PreviousCalLog.FreeBusyStatus -eq 2) { - if ($IsOrganizer) { - [array] $Output = "[$($CalLog.ResponsibleUser)] Cancelled the Meeting with $($CalLog.Client)." + } + LocationProcessor { + [array] $Output = "" + } + ResourceBookingAssistant { + [array] $Output = "ResourceBookingAssistant $($CalLog.TriggerAction)d the Meeting." + } + CalendarRepairAssistant { + [array] $Output = "CalendarRepairAssistant $($CalLog.TriggerAction)d the Meeting to repair an inconsistency." + } + default { + if ($CalLog.ResponsibleUser -eq "Calendar Assistant") { + [array] $Output = "The Exchange System $($CalLog.TriggerAction)d the meeting via the Calendar Assistant." } else { - if ($CalLog.ResponsibleUser -ne "Calendar Assistant") { - [array] $Output = "[$($CalLog.ResponsibleUser)] Declined the meeting with $($CalLog.Client)." - } + [array] $Output = "[$($CalLog.ResponsibleUser)] $($CalLog.TriggerAction)d the Meeting with $($CalLog.Client)." + $script:AddChangedProperties = $True } - $AddChangedProperties = $False } } - SoftDelete { - switch ($CalLog.Client) { - Transport { - [array] $Output = "Transport $($CalLog.TriggerAction)d the meeting based on changes by [$($CalLog.SentRepresentingDisplayName)]." - } - LocationProcessor { - [array] $Output = "" - } - ResourceBookingAssistant { - [array] $Output = "ResourceBookingAssistant $($CalLog.TriggerAction)d the Meeting." - } - default { - if ($CalLog.ResponsibleUser -eq "Calendar Assistant") { - [array] $Output = "The Exchange System $($CalLog.TriggerAction)d the meeting via the Calendar Assistant." - } else { - [array] $Output = "[$($CalLog.ResponsibleUser)] $($CalLog.TriggerAction)d the meeting with $($CalLog.Client)." - $AddChangedProperties = $True - } - } - } - if ($CalLog.FreeBusyStatus -eq 2 -and $PreviousCalLog.FreeBusyStatus -ne 2) { - [array] $Output = "[$($CalLog.ResponsibleUser)] Accepted the Meeting with $($CalLog.Client)." - $AddChangedProperties = $False - } elseif ($CalLog.FreeBusyStatus -ne 2 -and $PreviousCalLog.FreeBusyStatus -eq 2) { - [array] $Output = "[$($CalLog.ResponsibleUser)] Declined the Meeting with $($CalLog.Client)." - $AddChangedProperties = $False + if ($CalLog.FreeBusyStatus -eq 2 -and $script:PreviousCalLog.FreeBusyStatus -ne 2) { + if ($CalLog.ResponsibleUserName -eq "Calendar Assistant") { + [array] $Output = "$($CalLog.Client) Accepted the meeting." + } else { + [array] $Output = "[$($CalLog.ResponsibleUser)] Accepted the meeting with $($CalLog.Client)." } - } - MoveToDeletedItems { - [array] $Output = "[$($CalLog.ResponsibleUser)] Deleted the Meeting with $($CalLog.Client) (Moved the Meeting to the Deleted Items)." - } - default { - [array] $Output = "[$($CalLog.ResponsibleUser)] $($CalLog.TriggerAction) the Meeting with $($CalLog.Client)." - $MeetingSummaryNeeded = $False - } - } - } - Cancellation { - switch ($CalLog.Client) { - Transport { - if ($CalLog.IsException -eq $True) { - [array] $Output = "Transport $($CalLog.TriggerAction)d a Meeting Cancellation based on changes by [$($CalLog.SenderSMTPAddress)] for the exception starting on [$($CalLog.StartTime)]" + $script:AddChangedProperties = $False + } elseif ($CalLog.FreeBusyStatus -ne 2 -and $script:PreviousCalLog.FreeBusyStatus -eq 2) { + if ($IsOrganizer) { + [array] $Output = "[$($CalLog.ResponsibleUser)] Cancelled the Meeting with $($CalLog.Client)." } else { - [array] $Output = "Transport $($CalLog.TriggerAction)d a Meeting Cancellation based on changes by [$($CalLog.SenderSMTPAddress)]." + if ($CalLog.ResponsibleUser -ne "Calendar Assistant") { + [array] $Output = "[$($CalLog.ResponsibleUser)] Declined the meeting with $($CalLog.Client)." + } } + $script:AddChangedProperties = $False } - default { - if ($CalLog.IsException -eq $True) { - [array] $Output = "[$($CalLog.ResponsibleUser)] $($CalLog.TriggerAction)d a Cancellation with $($CalLog.Client) for the exception starting on [$($CalLog.StartTime)]." - } elseif ($CalLog.CalendarItemType -eq "RecurringMaster") { - [array] $Output = "[$($CalLog.ResponsibleUser)] $($CalLog.TriggerAction)d a Cancellation for the Series with $($CalLog.Client)." - } else { - [array] $Output = "[$($CalLog.ResponsibleUser)] $($CalLog.TriggerAction)d the Cancellation with $($CalLog.Client)." + } + SoftDelete { + switch ($CalLog.Client) { + Transport { + [array] $Output = "Transport $($CalLog.TriggerAction)d the meeting based on changes by [$($CalLog.SentRepresentingDisplayName)]." } + LocationProcessor { + [array] $Output = "" + } + ResourceBookingAssistant { + [array] $Output = "ResourceBookingAssistant $($CalLog.TriggerAction)d the Meeting." + } + default { + if ($CalLog.ResponsibleUser -eq "Calendar Assistant") { + [array] $Output = "The Exchange System $($CalLog.TriggerAction)d the meeting via the Calendar Assistant." + } else { + [array] $Output = "[$($CalLog.ResponsibleUser)] $($CalLog.TriggerAction)d the meeting with $($CalLog.Client)." + $script:AddChangedProperties = $True + } + } + } + + if ($CalLog.FreeBusyStatus -eq 2 -and $script:PreviousCalLog.FreeBusyStatus -ne 2) { + [array] $Output = "[$($CalLog.ResponsibleUser)] Accepted the Meeting with $($CalLog.Client)." + $script:AddChangedProperties = $False + } elseif ($CalLog.FreeBusyStatus -ne 2 -and $script:PreviousCalLog.FreeBusyStatus -eq 2) { + [array] $Output = "[$($CalLog.ResponsibleUser)] Declined the Meeting with $($CalLog.Client)." + $script:AddChangedProperties = $False } } - } - default { - if ($CalLog.TriggerAction -eq "Create") { - $Action = "New" - } else { - $Action = "$($CalLog.TriggerAction)" + MoveToDeletedItems { + [array] $Output = "[$($CalLog.ResponsibleUser)] Deleted the Meeting with $($CalLog.Client) (Moved the Meeting to the Deleted Items)." + } + default { + [array] $Output = "[$($CalLog.ResponsibleUser)] $($CalLog.TriggerAction) the Meeting with $($CalLog.Client)." + $script:MeetingSummaryNeeded = $False } - [array] $Output = "[$($CalLog.ResponsibleUser)] performed a $($Action) on the $($CalLog.ItemClass) with $($CalLog.Client)." } } - - # Create the Timeline by adding to Time to the generated Output - $Time = "$($CalLog.LogRow) -- $($CalLog.LastModifiedTime)" - - if ($Output) { - if ($MeetingSummaryNeeded) { - MeetingSummary -Time $Time -MeetingChanges $Output - MeetingSummary -Time " " -ShortVersion -Entry $CalLog - } else { - MeetingSummary -Time $Time -MeetingChanges $Output - if ($AddChangedProperties) { - ChangedProperties + Cancellation { + switch ($CalLog.Client) { + Transport { + if ($CalLog.IsException -eq $True) { + [array] $Output = "Transport $($CalLog.TriggerAction)d a Meeting Cancellation based on changes by [$($CalLog.SenderSMTPAddress)] for the exception starting on [$($CalLog.StartTime)]" + } else { + [array] $Output = "Transport $($CalLog.TriggerAction)d a Meeting Cancellation based on changes by [$($CalLog.SenderSMTPAddress)]." + } + } + default { + if ($CalLog.IsException -eq $True) { + [array] $Output = "[$($CalLog.ResponsibleUser)] $($CalLog.TriggerAction)d a Cancellation with $($CalLog.Client) for the exception starting on [$($CalLog.StartTime)]." + } elseif ($CalLog.CalendarItemType -eq "RecurringMaster") { + [array] $Output = "[$($CalLog.ResponsibleUser)] $($CalLog.TriggerAction)d a Cancellation for the Series with $($CalLog.Client)." + } else { + [array] $Output = "[$($CalLog.ResponsibleUser)] $($CalLog.TriggerAction)d the Cancellation with $($CalLog.Client)." + } } } } - - # Setup Previous log (if current logs is an IPM.Appointment) - if ($CalendarItemTypes.($CalLog.ItemClass) -eq "IpmAppointment" -or $CalendarItemTypes.($CalLog.ItemClass) -eq "ExceptionMsgClass") { - $PreviousCalLog = $CalLog + default { + if ($CalLog.TriggerAction -eq "Create") { + $Action = "New" + } else { + $Action = "$($CalLog.TriggerAction)" + } + [array] $Output = "[$($CalLog.ResponsibleUser)] performed a $($Action) on the $($CalLog.ItemClass) with $($CalLog.Client)." } } - $Results = @() -} + return $Output +} \ No newline at end of file diff --git a/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 b/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 index dc797e7afb..40b727738f 100644 --- a/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 +++ b/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 @@ -27,6 +27,8 @@ # # Get-CalendarDiagnosticObjectsSummary.ps1 -Identity User1, User2, Delegate -MeetingID $MeetingID # +# Get-CalendarDiagnosticObjectsSummary.ps1 -Identity $Users -MeetingID $MeetingID -TrackingLogs -Exceptions +# [CmdletBinding(DefaultParameterSetName = 'Subject')] param ( @@ -109,12 +111,12 @@ if (-not ([string]::IsNullOrEmpty($Subject)) ) { Write-Host -ForegroundColor Cyan "Found $($LogToExamine.count) CalLogs to examine for Exception Logs." if ($LogToExamine.count -gt 100) { Write-Host -ForegroundColor Cyan "`t This is a large number of logs to examine, this may take a while." - Write-Host -ForegroundColor Blue "`Press Y to continue..." - $Answer = [console]::ReadKey($true).Key - if ($Answer -ne "Y") { - Write-Host -ForegroundColor Cyan "User chose not to continue, skipping Exception Logs." - $LogToExamine = $null - } + # Write-Host -ForegroundColor Blue "`Press Y to continue..." + # $Answer = [console]::ReadKey($true).Key + # if ($Answer -ne "Y") { + # Write-Host -ForegroundColor Cyan "User chose not to continue, skipping Exception Logs." + # $LogToExamine = $null + # } } Write-Host -ForegroundColor Cyan "`t Ignore the next [$($LogToExamine.count)] warnings..." $logLeftCount = $LogToExamine.count @@ -123,7 +125,7 @@ if (-not ([string]::IsNullOrEmpty($Subject)) ) { $logLeftCount -= 1 Write-Verbose "Getting Exception Logs for [$($_.ItemId.ObjectId)]" Get-CalendarDiagnosticObjects -Identity $ID -ItemIds $_.ItemId.ObjectId -ShouldFetchRecurrenceExceptions $true -CustomPropertyNames $CustomPropertyNameList - if ($logLeftCount % 50 -eq 0) { + if ($logLeftCount % 20 -eq 0) { Write-Host -ForegroundColor Cyan "`t [$($logLeftCount)] logs left to examine..." } } diff --git a/Calendar/Tests/ShortClientNameFunctions.Tests.ps1 b/Calendar/Tests/ShortClientNameFunctions.Tests.ps1 index ef80f8b8c1..9835473984 100644 --- a/Calendar/Tests/ShortClientNameFunctions.Tests.ps1 +++ b/Calendar/Tests/ShortClientNameFunctions.Tests.ps1 @@ -17,14 +17,14 @@ Describe "CreateShortClientName" { } Context "When ClientInfoString is Client=MSExchangeRPC" { - It "Should return 'Outlook : Desktop'" { + It "Should return 'Outlook : Desktop : MAPI'" { $result = CreateShortClientName -ClientInfoString "Client=MSExchangeRPC" - $result | Should -Be "Outlook : Desktop" + $result | Should -Be "Outlook : Desktop : MAPI" } } Context "When ClientInfoString is Client=Hub Transport" { - It "Should return 'Outlook : Desktop'" { + It "Should return 'Transport'" { $result = CreateShortClientName -ClientInfoString "Client=Hub Transport" $result | Should -Be "Transport" } @@ -70,9 +70,9 @@ Describe "CreateShortClientName" { $result | Should -Be "ActiveSyncUnknown" } - It "Should return 'Outlook-ModernCalendarSharing' if ClientInfoString FileContentMatch 'Outlook-iOS-Android'" { + It "Should return 'Outlook : ActiveSync' if ClientInfoString FileContentMatch 'Outlook-iOS-Android'" { $result = CreateShortClientName "Client=ActiveSync;UserAgent=Outlook-iOS-Android/1.0;Action=/Microsoft-Server-ActiveSync/Proxy/default.eas?User=test%40microsoft.com&DeviceId=BF36923991ADFBA9&DeviceType=Outlook&Cmd=SendMail" - $result | Should -Be "Outlook-ModernCalendarSharing" + $result | Should -Be "Outlook : ActiveSync" } It "Should return 'ActiveSyncUnknown' if ClientInfoString does not match any conditions" { @@ -151,7 +151,7 @@ Describe "CreateShortClientName-FindMatch" { Context 'Test CreateShortClientName focusing on the FindMatch function' -ForEach @( @{ ClientInfoString = 'Client=Hub Transport'; Expected = "Transport" }, - @{ ClientInfoString = 'Client=MSExchangeRPC'; Expected = "Outlook : Desktop" }, + @{ ClientInfoString = 'Client=MSExchangeRPC'; Expected = "Outlook : Desktop : MAPI" }, @{ ClientInfoString = 'OneOutlook'; Expected = "OneOutlook" }, @{ ClientInfoString = 'Lync for Mac'; Expected = "LyncMac" }, @{ ClientInfoString = 'AppId=00000004-0000-0ff1-ce00-000000000000'; Expected = "SkypeMMS" }, From 6cae7efb212a12526e6427b4e2b2c08e85f5d129 Mon Sep 17 00:00:00 2001 From: Shane Ferrell Date: Wed, 1 May 2024 13:33:15 -0700 Subject: [PATCH 2/4] clean functions --- Calendar/CalLogHelpers/TimelineFunctions.ps1 | 158 +++++++++---------- 1 file changed, 75 insertions(+), 83 deletions(-) diff --git a/Calendar/CalLogHelpers/TimelineFunctions.ps1 b/Calendar/CalLogHelpers/TimelineFunctions.ps1 index d1577fca99..2c73c2b2db 100644 --- a/Calendar/CalLogHelpers/TimelineFunctions.ps1 +++ b/Calendar/CalLogHelpers/TimelineFunctions.ps1 @@ -29,24 +29,15 @@ #> function FindOrganizer { - $Script:Organizer = "" - # find the first IPM.Appointment in the CalLogs and set the Organizer - foreach ($CalLog in $script:GCDO){ - if ($CalendarItemTypes.($CalLog.ItemClass) -eq "IpmAppointment" -and - $CalLog.ExternalSharingMasterId -eq "NotFound" -and - $null -ne $CalLog.From) { - Write-Host "Found Organizer of meeting as : [$($CalLog.From)]" - - if ($null -ne $CalLog.From.SMTP) { - $Script:Organizer = $($CalLog.From.SMTP) - } - elseif ($null -ne $CalLog.From.DisplayName) { - $Script:Organizer = $($CalLog.From.DisplayName) - } - else { + $Script:Organizer = "Unknown" + $CalLog = FindFirstMeeting + if ($null -ne $CalLog.From) { + if ($null -ne $CalLog.From.SmtpEmailAddress) { + $Script:Organizer = $($CalLog.From.SmtpEmailAddress) + } elseif ($null -ne $CalLog.From.DisplayName) { + $Script:Organizer = $($CalLog.From.DisplayName) + } else { $Script:Organizer = $($CalLog.From) - } - break } } Write-Host "Setting Organizer to : [$Script:Organizer]" @@ -195,72 +186,11 @@ function FindChangedProperties { } } } -function BuildTimeline { - param ( - [string] $Identity - ) - $ThisMeetingID = $script:GCDO.CleanGlobalObjectId | Select-Object -Unique - $ShortMeetingID = $ThisMeetingID.Substring($ThisMeetingID.length - 6) - if ($Identity -like "*@*") { - $ShortName = $Identity.Split('@')[0] - } - $ShortName = $ShortName.Substring(0, [System.Math]::Min(20, $ShortName.Length)) - $Script:TimeLineFilename = "$($ShortName)_TimeLine_$ShortMeetingID.csv" - - FindOrganizer - Write-DashLineBoxColor " TimeLine for [$Identity]:", - " Subject: $($script:GCDO[0].NormalizedSubject)", - " Organizer: $Script:Organizer", - " MeetingID: $($script:GCDO[0].CleanGlobalObjectId)" - [Array]$Header = ("Subject: " + ($script:GCDO[0].NormalizedSubject) + " | MeetingID: "+ ($script:GCDO[0].CleanGlobalObjectId)) - MeetingSummary -Time "Calendar Log Timeline for Meeting with" -MeetingChanges $Header - - MeetingSummary -Time "Initial Message Values" -Entry $(FindFirstMeeting) -LongVersion - - # Ignorable and items from Shared Calendars are not included in the TimeLine. - $MeetingTimeLine = $Results | Where-Object { $_.IsIgnorable -eq "False" -and $_.IsFromSharedCalendar -eq $False } - - Write-Host "`n`n`nThis is the meetingID $ThisMeetingID`nThis is Short MeetingID $ShortMeetingID" - if ($MeetingTimeLine.count -eq 0) { - Write-Host "All CalLogs are Ignorable, nothing to create a timeline with, displaying initial values." - } else { - Write-Host "Found $($script:GCDO.count) Log entries, only the $($MeetingTimeLine.count) Non-Ignorable entries will be analyzed in the TimeLine." - } - - foreach ($CalLog in $MeetingTimeLine) { - [bool] $script:MeetingSummaryNeeded = $False - [bool] $script:AddChangedProperties = $False - - [array] $Output = TimelineRow - # Create the Timeline by adding to Time to the generated Output - $Time = "$($CalLog.LogRow) -- $($CalLog.LastModifiedTime)" - - if ($Output) { - if ($script:MeetingSummaryNeeded) { - MeetingSummary -Time $Time -MeetingChanges $Output - MeetingSummary -Time " " -ShortVersion -Entry $CalLog - } else { - MeetingSummary -Time $Time -MeetingChanges $Output - if ($script:AddChangedProperties) { - FindChangedProperties - } - } - } - - # Setup Previous log (if current logs is an IPM.Appointment) - if ($CalendarItemTypes.($CalLog.ItemClass) -eq "IpmAppointment" -or $CalendarItemTypes.($CalLog.ItemClass) -eq "ExceptionMsgClass") { - $script:PreviousCalLog = $CalLog - } - } - - $Results = @() -} - - <# - .SYNOPSIS - This is the part that generates the heart of the timeline, a Giant Switch statement based on the ItemClass. - #> +<# +.SYNOPSIS + This is the part that generates the heart of the timeline, a Giant Switch statement based on the ItemClass. +#> function TimelineRow { switch -Wildcard ($CalendarItemTypes.($CalLog.ItemClass)) { MeetingRequest { @@ -505,4 +435,66 @@ function TimelineRow { } return $Output -} \ No newline at end of file +} + +function BuildTimeline { + param ( + [string] $Identity + ) + $ThisMeetingID = $script:GCDO.CleanGlobalObjectId | Select-Object -Unique + $ShortMeetingID = $ThisMeetingID.Substring($ThisMeetingID.length - 6) + if ($Identity -like "*@*") { + $ShortName = $Identity.Split('@')[0] + } + $ShortName = $ShortName.Substring(0, [System.Math]::Min(20, $ShortName.Length)) + $Script:TimeLineFilename = "$($ShortName)_TimeLine_$ShortMeetingID.csv" + + FindOrganizer + + Write-DashLineBoxColor " TimeLine for [$Identity]:", + " Subject: $($script:GCDO[0].NormalizedSubject)", + " Organizer: $Script:Organizer", + " MeetingID: $($script:GCDO[0].CleanGlobalObjectId)" + [Array]$Header = ("Subject: " + ($script:GCDO[0].NormalizedSubject) + " | MeetingID: "+ ($script:GCDO[0].CleanGlobalObjectId)) + MeetingSummary -Time "Calendar Log Timeline for Meeting with" -MeetingChanges $Header + + MeetingSummary -Time "Initial Message Values" -Entry $(FindFirstMeeting) -LongVersion + + # Ignorable and items from Shared Calendars are not included in the TimeLine. + $MeetingTimeLine = $Results | Where-Object { $_.IsIgnorable -eq "False" -and $_.IsFromSharedCalendar -eq $False } + + Write-Host "`n`n`nThis is the meetingID $ThisMeetingID`nThis is Short MeetingID $ShortMeetingID" + if ($MeetingTimeLine.count -eq 0) { + Write-Host "All CalLogs are Ignorable, nothing to create a timeline with, displaying initial values." + } else { + Write-Host "Found $($script:GCDO.count) Log entries, only the $($MeetingTimeLine.count) Non-Ignorable entries will be analyzed in the TimeLine." + } + + foreach ($CalLog in $MeetingTimeLine) { + [bool] $script:MeetingSummaryNeeded = $False + [bool] $script:AddChangedProperties = $False + + [array] $Output = TimelineRow + # Create the Timeline by adding to Time to the generated Output + $Time = "$($CalLog.LogRow) -- $($CalLog.LastModifiedTime)" + + if ($Output) { + if ($script:MeetingSummaryNeeded) { + MeetingSummary -Time $Time -MeetingChanges $Output + MeetingSummary -Time " " -ShortVersion -Entry $CalLog + } else { + MeetingSummary -Time $Time -MeetingChanges $Output + if ($script:AddChangedProperties) { + FindChangedProperties + } + } + } + + # Setup Previous log (if current logs is an IPM.Appointment) + if ($CalendarItemTypes.($CalLog.ItemClass) -eq "IpmAppointment" -or $CalendarItemTypes.($CalLog.ItemClass) -eq "ExceptionMsgClass") { + $script:PreviousCalLog = $CalLog + } + } + + $Results = @() +} From 804b871ce3848619c1274fd460304177f0bf2f0b Mon Sep 17 00:00:00 2001 From: Shane Ferrell Date: Wed, 1 May 2024 13:36:16 -0700 Subject: [PATCH 3/4] remove commented out code --- Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 b/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 index 40b727738f..5b64785305 100644 --- a/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 +++ b/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 @@ -111,12 +111,6 @@ if (-not ([string]::IsNullOrEmpty($Subject)) ) { Write-Host -ForegroundColor Cyan "Found $($LogToExamine.count) CalLogs to examine for Exception Logs." if ($LogToExamine.count -gt 100) { Write-Host -ForegroundColor Cyan "`t This is a large number of logs to examine, this may take a while." - # Write-Host -ForegroundColor Blue "`Press Y to continue..." - # $Answer = [console]::ReadKey($true).Key - # if ($Answer -ne "Y") { - # Write-Host -ForegroundColor Cyan "User chose not to continue, skipping Exception Logs." - # $LogToExamine = $null - # } } Write-Host -ForegroundColor Cyan "`t Ignore the next [$($LogToExamine.count)] warnings..." $logLeftCount = $LogToExamine.count From e1f9bac5ee8d682014ab576d0ea8ff1e804c6cc4 Mon Sep 17 00:00:00 2001 From: Shane Ferrell Date: Thu, 2 May 2024 11:29:50 -0700 Subject: [PATCH 4/4] Spelling --- Calendar/CalLogHelpers/TimelineFunctions.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Calendar/CalLogHelpers/TimelineFunctions.ps1 b/Calendar/CalLogHelpers/TimelineFunctions.ps1 index 2c73c2b2db..4bda49db27 100644 --- a/Calendar/CalLogHelpers/TimelineFunctions.ps1 +++ b/Calendar/CalLogHelpers/TimelineFunctions.ps1 @@ -50,7 +50,7 @@ function FindFirstMeeting { $FirstMeeting = $script:GCDO | Where-Object { $_.ItemClass -eq "IPM.Appointment" } } if ($FirstMeeting.count -eq 0) { - Write-Error "Cannot find any IPM.Apptointments, if this is the Organizer, check for the Outlook Bifurcation issue." + Write-Error "Cannot find any IPM.Appointment, if this is the Organizer, check for the Outlook Bifurcation issue." Write-Error "No IPM.Appointment found, cannot set initial values." } else { Write-Host "Found $($script:GCDO.count) Log entries, looking at the first IPM.Appointment."