From 24bd9306cc9c466553f0993fb31bd6edf650af71 Mon Sep 17 00:00:00 2001 From: Shane Ferrell Date: Tue, 18 Jun 2024 17:06:45 -0700 Subject: [PATCH 1/3] Update CalLogs for easier processing cleanup Tests add Spellcheck words PR feeback Formatting --- .build/cspell-words.txt | 2 + Calendar/CalLogHelpers/CalLogCSVFunctions.ps1 | 86 +++++------- .../CalLogHelpers/CalLogExportFunctions.ps1 | 105 ++++++-------- .../CalLogHelpers/CalLogInfoFunctions.ps1 | 48 +++++-- Calendar/CalLogHelpers/CreateTimelineRow.ps1 | 36 ++--- Calendar/CalLogHelpers/Invoke-GetCalLogs.ps1 | 7 +- .../CalLogHelpers/MeetingSummaryFunctions.ps1 | 5 +- .../ShortClientNameFunctions.ps1 | 95 +++++++------ Calendar/CalLogHelpers/TimelineFunctions.ps1 | 6 +- Calendar/Check-SharingStatus.ps1 | 6 +- .../Get-CalendarDiagnosticObjectsSummary.ps1 | 15 +- .../Tests/ShortClientNameFunctions.Tests.ps1 | 130 ++++++++++-------- 12 files changed, 286 insertions(+), 255 deletions(-) diff --git a/.build/cspell-words.txt b/.build/cspell-words.txt index 8bb4f8b2dc..092acb7b59 100644 --- a/.build/cspell-words.txt +++ b/.build/cspell-words.txt @@ -10,6 +10,7 @@ bincirc BSTR cach cachtokn +Calendrier Clixml cmatch comparables @@ -45,6 +46,7 @@ FYDIBOHF GCDO Get-AuthenticodeSignature globalsequence +Kalender Hashtable HHMM HKCR diff --git a/Calendar/CalLogHelpers/CalLogCSVFunctions.ps1 b/Calendar/CalLogHelpers/CalLogCSVFunctions.ps1 index 37d7570843..92e7fa9c3c 100644 --- a/Calendar/CalLogHelpers/CalLogCSVFunctions.ps1 +++ b/Calendar/CalLogHelpers/CalLogCSVFunctions.ps1 @@ -8,31 +8,23 @@ $script:CalendarItemTypes = @{ 'IPM.Schedule.Meeting.Request.AttendeeListReplication' = "AttendeeList" 'IPM.Schedule.Meeting.Canceled' = "Cancellation" - 'IPM.OLE.CLASS.{00061055-0000-0000-C000-000000000046}' = "ExceptionMsgClass" - 'IPM.Schedule.Meeting.Notification.Forward' = "ForwardNotification" - 'IPM.Appointment' = "IpmAppointment" - 'IPM.Appointment.MP' = "IpmAppointment" - 'IPM.Schedule.Meeting.Request' = "MeetingRequest" + 'IPM.OLE.CLASS.{00061055-0000-0000-C000-000000000046}' = "Exception" + 'IPM.Schedule.Meeting.Notification.Forward' = "Forward.Notification" + 'IPM.Appointment' = "Ipm.Appointment" + 'IPM.Appointment.MP' = "Ipm.Appointment" + 'IPM.Schedule.Meeting.Request' = "Meeting.Request" 'IPM.CalendarSharing.EventUpdate' = "SharingCFM" 'IPM.CalendarSharing.EventDelete' = "SharingDelete" - 'IPM.Schedule.Meeting.Resp' = "RespAny" - 'IPM.Schedule.Meeting.Resp.Neg' = "RespNeg" - 'IPM.Schedule.Meeting.Resp.Tent' = "RespTent" - 'IPM.Schedule.Meeting.Resp.Pos' = "RespPos" + 'IPM.Schedule.Meeting.Resp' = "Resp.Any" + 'IPM.Schedule.Meeting.Resp.Neg' = "Resp.Neg" + 'IPM.Schedule.Meeting.Resp.Tent' = "Resp.Tent" + 'IPM.Schedule.Meeting.Resp.Pos' = "Resp.Pos" } # =================================================================================================== # Functions to support the script # =================================================================================================== -$ResponseTypeOptions = @{ - '0' = "None" - "1" = "Organizer" - '2' = "Tentative" - '3' = "Accept" - '4' = "Decline" - '5' = "Not Responded" -} <# .SYNOPSIS Looks to see if there is a Mapping of ExternalMasterID to FolderName @@ -69,7 +61,7 @@ Creates a Mapping of ExternalMasterID to FolderName #> function CreateExternalMasterIDMap { # This function will create a Map of the log folder to ExternalMasterID - $script:SharedFolders = @{} + $script:SharedFolders = [System.Collections.SortedList]::new() Write-Verbose "Starting CreateExternalMasterIDMap" foreach ($ExternalID in $script:GCDO.ExternalSharingMasterId | Select-Object -Unique) { @@ -80,8 +72,12 @@ function CreateExternalMasterIDMap { $AllFolderNames = @($script:GCDO | Where-Object { $_.ExternalSharingMasterId -eq $ExternalID } | Select-Object -ExpandProperty OriginalParentDisplayName | Select-Object -Unique) if ($AllFolderNames.count -gt 1) { - # We have 2+ FolderNames, Need to find the best one. #remove Calendar - $AllFolderNames = $AllFolderNames | Where-Object { $_ -notmatch 'Calendar' } # This will not work for non-english + # We have 2+ FolderNames, Need to find the best one. Remove 'Calendar' from possible names + $AllFolderNames = $AllFolderNames | Where-Object { + $_ -notmatch 'Calendar' -and + $_ -notmatch 'Calendrier' -and + $_ -notmatch 'Kalender' + } # Need a better way to do this for other languages... } if ($AllFolderNames.Count -eq 0) { @@ -104,6 +100,12 @@ function CreateExternalMasterIDMap { } } } + + Write-Host -ForegroundColor Green "Created the following Shared Calendar Mapping:" + foreach ($Key in $SharedFolders.Keys) { + Write-Host -ForegroundColor Green "$Key : $($SharedFolders[$Key])" + } + # ToDo: Need to check for multiple ExternalMasterIDs pointing to the same FolderName Write-Verbose "Created the following Mapping :" Write-Verbose $SharedFolders } @@ -133,7 +135,7 @@ function BuildCSV { Write-Host "Starting to Process Calendar Logs..." $GCDOResults = @() $IsFromSharedCalendar = @() - $IsIgnorable = @() + $LogType = @() $script:MailboxList = @{} Write-Host "Creating Map of Mailboxes to CNs..." CreateExternalMasterIDMap @@ -145,16 +147,12 @@ function BuildCSV { foreach ($CalLog in $script:GCDO) { $Index++ $ItemType = $CalendarItemTypes.($CalLog.ItemClass) - $ShortClientName = @() - $script:KeyInput = $CalLog.ClientInfoString - $ResponseType = $ResponseTypeOptions.($CalLog.ResponseType.ToString()) - $ShortClientName = CreateShortClientName($CalLog.ClientInfoString) - - $IsIgnorable = SetIsIgnorable($CalLog) + $ShortClientName = CreateShortClientName($CalLog.LogClientInfoString) + $LogType = SetLogType($CalLog) # CleanNotFounds - $PropsToClean = "FreeBusyStatus", "ClientIntent", "AppointmentLastSequenceNumber", "RecurrencePattern", "AppointmentAuxiliaryFlags", "EventEmailReminderTimer", "IsSeriesCancelled", "AppointmentCounterProposal", "MeetingRequestType", "SendMeetingMessagesDiagnostics" + $PropsToClean = "FreeBusyStatus", "ClientIntent", "AppointmentSequenceNumber", "AppointmentLastSequenceNumber", "RecurrencePattern", "AppointmentAuxiliaryFlags", "EventEmailReminderTimer", "IsSeriesCancelled", "AppointmentCounterProposal", "MeetingRequestType", "SendMeetingMessagesDiagnostics" foreach ($Prop in $PropsToClean) { # Exception objects, etc. don't have these properties. if ($null -ne $CalLog.$Prop) { @@ -167,20 +165,17 @@ function BuildCSV { # Record one row $GCDOResults += [PSCustomObject]@{ 'LogRow' = $Index - 'LastModifiedTime' = ConvertDateTime($CalLog.OriginalLastModifiedTime) - 'IsIgnorable' = $IsIgnorable + 'LogTimestamp' = ConvertDateTime($CalLog.LogTimestamp) + 'LogType' = $LogType 'SubjectProperty' = $CalLog.SubjectProperty 'Client' = $ShortClientName - 'ShortClientInfoString' = $CalLog.ShortClientInfoString - 'ClientInfoString' = $CalLog.ClientInfoString + 'LogClientInfoString' = $CalLog.LogClientInfoString 'TriggerAction' = $CalLog.CalendarLogTriggerAction - 'ItemClass' = $CalLog.ItemClass - 'ItemVersion' = $CalLog.ItemVersion - 'AppointmentSequenceNumber' = $CalLog.AppointmentSequenceNumber - 'AppointmentLastSequenceNumber' = $CalLog.AppointmentLastSequenceNumber # Need to find out how we can combine these two... + 'ItemClass' = $ItemType + 'Seq:Exp:ItemVersion' = $CalLog.AppointmentSequenceNumber.ToString() + ":" + $CalLog.AppointmentLastSequenceNumber.ToString() + ":" + $CalLog.ItemVersion.ToString() 'Organizer' = $CalLog.From.FriendlyDisplayName 'From' = GetBestFromAddress($CalLog.From) - 'FreeBusyStatus' = $CalLog.FreeBusyStatus.ToString() + 'FreeBusy' = $CalLog.FreeBusyStatus.ToString() 'ResponsibleUser' = GetSMTPAddress($CalLog.ResponsibleUserName) 'Sender' = GetSMTPAddress($CalLog.SenderEmailAddress) 'LogFolder' = $CalLog.ParentDisplayName @@ -193,9 +188,9 @@ function BuildCSV { 'MeetingRequestType' = $CalLog.MeetingRequestType.ToString() 'StartTime' = ConvertDateTime($CalLog.StartTime) 'EndTime' = ConvertDateTime($CalLog.EndTime) + 'OriginalStartDate' = ConvertDateTime($CalLog.OriginalStartDate) 'TimeZone' = $CalLog.TimeZone 'Location' = $CalLog.Location - 'ItemType' = $ItemType 'CalendarItemType' = $CalLog.CalendarItemType.ToString() 'IsException' = $CalLog.IsException 'RecurrencePattern' = $CalLog.RecurrencePattern @@ -203,27 +198,16 @@ function BuildCSV { 'DisplayAttendeesAll' = $CalLog.DisplayAttendeesAll 'AttendeeCount' = ($CalLog.DisplayAttendeesAll -split ';').Count 'AppointmentState' = $CalLog.AppointmentState.ToString() - 'ResponseType' = $ResponseType - 'SentRepresentingEmailAddress' = $CalLog.SentRepresentingEmailAddress - 'SentRepresentingSMTPAddress' = GetSMTPAddress($CalLog.SentRepresentingEmailAddress) - 'SentRepresentingDisplayName' = $CalLog.SentRepresentingDisplayName - 'ResponsibleUserSMTPAddress' = GetSMTPAddress($CalLog.ResponsibleUserName) - 'ResponsibleUserName' = $CalLog.ResponsibleUserName - 'SenderEmailAddress' = $CalLog.SenderEmailAddress - 'SenderSMTPAddress' = GetSMTPAddress($CalLog.SenderEmailAddress) + 'ResponseType' = $CalLog.ResponseType.ToString() 'ClientIntent' = $CalLog.ClientIntent.ToString() - 'NormalizedSubject' = $CalLog.NormalizedSubject 'AppointmentRecurring' = $CalLog.AppointmentRecurring 'HasAttachment' = $CalLog.HasAttachment 'IsCancelled' = $CalLog.IsCancelled 'IsAllDayEvent' = $CalLog.IsAllDayEvent 'IsSeriesCancelled' = $CalLog.IsSeriesCancelled - 'CreationTime' = ConvertDateTime($CalLog.CreationTime) - 'OriginalStartDate' = ConvertDateTime($CalLog.OriginalStartDate) 'SendMeetingMessagesDiagnostics' = $CalLog.SendMeetingMessagesDiagnostics - 'AttendeeListDetails' = MultiLineFormat($CalLog.AttendeeListDetails) 'AttendeeCollection' = MultiLineFormat($CalLog.AttendeeCollection) - 'CalendarLogRequestId' = $CalLog.CalendarLogRequestId.ToString() + 'CalendarLogRequestId' = $CalLog.CalendarLogRequestId.ToString() # Move to front.../ Format in groups??? 'CleanGlobalObjectId' = $CalLog.CleanGlobalObjectId } } diff --git a/Calendar/CalLogHelpers/CalLogExportFunctions.ps1 b/Calendar/CalLogHelpers/CalLogExportFunctions.ps1 index 0058cebd14..bcf74bc913 100644 --- a/Calendar/CalLogHelpers/CalLogExportFunctions.ps1 +++ b/Calendar/CalLogHelpers/CalLogExportFunctions.ps1 @@ -120,12 +120,14 @@ function GetExcelParams($path, $tabName) { AutoNameRange = $true Append = $true Title = "Enhanced Calendar Logs for $Identity" + $TitleExtra + " for MeetingID [$($script:GCDO[0].CleanGlobalObjectId)]." + TitleSize = 14 ConditionalText = $ConditionalFormatting } } +# Need better way of tagging cells than the Range. Every time one is updated, you need to update all the ones after it. $ConditionalFormatting = $( - # Client, ShortClientInfoString and ClientInfoString + # Client, ShortClientInfoString and LogClientInfoString New-ConditionalText "Outlook" -ConditionalTextColor Green -BackgroundColor $null New-ConditionalText "OWA" -ConditionalTextColor DarkGreen -BackgroundColor $null New-ConditionalText "Transport" -ConditionalTextColor Blue -BackgroundColor $null @@ -134,33 +136,40 @@ $ConditionalFormatting = $( New-ConditionalText "Other REST" -ConditionalTextColor DarkRed -BackgroundColor $null New-ConditionalText "ResourceBookingAssistant" -ConditionalTextColor Blue -BackgroundColor $null - #IsIgnorable + #LogType New-ConditionalText -Range "C3:C9999" -ConditionalType ContainsText -Text "Ignorable" -ConditionalTextColor DarkRed -BackgroundColor $null New-ConditionalText -Range "C:C" -ConditionalType ContainsText -Text "Cleanup" -ConditionalTextColor DarkRed -BackgroundColor $null New-ConditionalText -Range "C:C" -ConditionalType ContainsText -Text "Sharing" -ConditionalTextColor Blue -BackgroundColor $null # TriggerAction - New-ConditionalText -Range "H:H" -ConditionalType ContainsText -Text "Create" -ConditionalTextColor Green -BackgroundColor $null - New-ConditionalText -Range "H:H" -ConditionalType ContainsText -Text "Delete" -ConditionalTextColor Red -BackgroundColor $null + New-ConditionalText -Range "G:G" -ConditionalType ContainsText -Text "Create" -ConditionalTextColor Green -BackgroundColor $null + New-ConditionalText -Range "G:G" -ConditionalType ContainsText -Text "Delete" -ConditionalTextColor Red -BackgroundColor $null # ItemClass - New-ConditionalText -Range "I:I" -ConditionalType ContainsText -Text "IPM.Appointment" -ConditionalTextColor Blue -BackgroundColor $null - New-ConditionalText -Range "I:I" -ConditionalType ContainsText -Text "Canceled" -ConditionalTextColor Black -BackgroundColor Orange - New-ConditionalText -Range "I:I" -ConditionalType ContainsText -Text ".Request" -ConditionalTextColor DarkGreen -BackgroundColor $null - New-ConditionalText -Range "I:I" -ConditionalType ContainsText -Text ".Resp." -ConditionalTextColor Orange -BackgroundColor $null - New-ConditionalText -Range "I:I" -ConditionalType ContainsText -Text "IPM.OLE.CLASS" -ConditionalTextColor Plum -BackgroundColor $null + New-ConditionalText -Range "H:H" -ConditionalType ContainsText -Text "IPM.Appointment" -ConditionalTextColor Blue -BackgroundColor $null + New-ConditionalText -Range "H:H" -ConditionalType ContainsText -Text "Canceled" -ConditionalTextColor Black -BackgroundColor Orange + New-ConditionalText -Range "H:H" -ConditionalType ContainsText -Text ".Request" -ConditionalTextColor DarkGreen -BackgroundColor $null + New-ConditionalText -Range "H:H" -ConditionalType ContainsText -Text ".Resp." -ConditionalTextColor Orange -BackgroundColor $null + New-ConditionalText -Range "H:H" -ConditionalType ContainsText -Text "IPM.OLE.CLASS" -ConditionalTextColor Plum -BackgroundColor $null #FreeBusyStatus - New-ConditionalText -Range "O3:O9999" -ConditionalType ContainsText -Text "Free" -ConditionalTextColor Red -BackgroundColor $null - New-ConditionalText -Range "O3:O9999" -ConditionalType ContainsText -Text "Tentative" -ConditionalTextColor Orange -BackgroundColor $null - New-ConditionalText -Range "O3:O9999" -ConditionalType ContainsText -Text "Busy" -ConditionalTextColor Green -BackgroundColor $null + New-ConditionalText -Range "L3:L9999" -ConditionalType ContainsText -Text "Free" -ConditionalTextColor Red -BackgroundColor $null + New-ConditionalText -Range "L3:L9999" -ConditionalType ContainsText -Text "Tentative" -ConditionalTextColor Orange -BackgroundColor $null + New-ConditionalText -Range "L3:L9999" -ConditionalType ContainsText -Text "Busy" -ConditionalTextColor Green -BackgroundColor $null #Shared Calendar information - New-ConditionalText -Range "T3:T9999" -ConditionalType NotEqual -Text "Not Shared" -ConditionalTextColor Blue -BackgroundColor $null - New-ConditionalText -Range "U:U" -ConditionalType ContainsText -Text "TRUE" -ConditionalTextColor Blue -BackgroundColor $null - New-ConditionalText -Range "V3:V9999" -ConditionalType NotEqual -Text "NotFound" -ConditionalTextColor Blue -BackgroundColor $null + New-ConditionalText -Range "Q3:Q9999" -ConditionalType NotEqual -Text "Not Shared" -ConditionalTextColor Blue -BackgroundColor $null + New-ConditionalText -Range "R:R" -ConditionalType ContainsText -Text "TRUE" -ConditionalTextColor Blue -BackgroundColor $null + New-ConditionalText -Range "S:S" -ConditionalType NotEqual -Text "NotFound" -ConditionalTextColor Blue -BackgroundColor $null + + #MeetingRequestType + New-ConditionalText -Range "V:V" -ConditionalType ContainsText -Text "Outdated" -ConditionalTextColor DarkRed -BackgroundColor LightPink #AppointmentAuxiliaryFlags - New-ConditionalText -Range "AH3:AH9999" -ConditionalType ContainsText -Text "Copy" -ConditionalTextColor DarkRed -BackgroundColor LightPink + New-ConditionalText -Range "AE3:AE9999" -ConditionalType ContainsText -Text "Copy" -ConditionalTextColor DarkRed -BackgroundColor LightPink + + #ResponseType + New-ConditionalText -Range "AI3:AI9999" -ConditionalType ContainsText -Text "Organizer" -ConditionalTextColor Orange -BackgroundColor $null + ) function FormatHeader { @@ -174,33 +183,27 @@ function FormatHeader { # Static List of Columns for now... $sheet.Column(++$n) | Set-ExcelRange -Width 6 -HorizontalAlignment center # LogRow Set-CellComment -Text "This is the Enhanced Calendar Logs for [$Identity] for MeetingID `n [$($script:GCDO[0].CleanGlobalObjectId)]." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 20 -NumberFormat "m/d/yyyy h:mm:ss" -HorizontalAlignment center #LastModifiedTime - Set-CellComment -Text "LastModifiedTime: Time when the change was recorded in the CalLogs. This and all Times are in UTC." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 11 -HorizontalAlignment center # IsIgnorable - Set-CellComment -Text "IsIgnorable: Can this Log be safely ignored?" -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet + $sheet.Column(++$n) | Set-ExcelRange -Width 20 -NumberFormat "m/d/yyyy h:mm:ss" -HorizontalAlignment center #LogTimestamp + Set-CellComment -Text "LogTimestamp: Time when the change was recorded in the CalLogs. This and all Times are in UTC." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet + $sheet.Column(++$n) | Set-ExcelRange -Width 11 -HorizontalAlignment center # LogType + Set-CellComment -Text "LogType: Can this Log be safely ignored?" -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 20 -HorizontalAlignment Left # SubjectProperty Set-CellComment -Text "SubjectProperty: The Subject of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 20 -HorizontalAlignment Left # Client Set-CellComment -Text "Client: The 'friendly' Client name of the client that made the change." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 20 -HorizontalAlignment Left # ShortClientInfoString - Set-CellComment -Text "ShortClientInfoString: Short Client Info String." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 5 -HorizontalAlignment Left # ClientInfoString - Set-CellComment -Text "ClientInfoString: Full Client Info String of client that made the change." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet + $sheet.Column(++$n) | Set-ExcelRange -Width 5 -HorizontalAlignment Left # LogClientInfoString + Set-CellComment -Text "LogClientInfoString: Full Client Info String of client that made the change." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 12 -HorizontalAlignment Center # TriggerAction Set-CellComment -Text "TriggerAction: The action that caused the change." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 25 -HorizontalAlignment Left # ItemClass + $sheet.Column(++$n) | Set-ExcelRange -Width 18 -HorizontalAlignment Left # ItemClass Set-CellComment -Text "ItemClass: The Class of the Calendar Item" -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 5 -HorizontalAlignment center # ItemVersion - Set-CellComment -Text "ItemVersion: The Version of the Item." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 5 -HorizontalAlignment center # AppointmentSequenceNumber - Set-CellComment -Text "AppointmentSequenceNumber: The Sequence Number of the Appointment." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 5 -HorizontalAlignment center # AppointmentLastSequenceNumber - Set-CellComment -Text "AppointmentLastSequenceNumber: The Last Sequence Number of the Appointment." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet + $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment center # Seq:Exp:ItemVersion + Set-CellComment -Text "Seq:Exp:ItemVersion: The Sequence Version, the Exception Version, and the Item Version. Each type of item has its own count." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 20 -HorizontalAlignment Left # Organizer Set-CellComment -Text "Organizer: The Organizer of the Calendar Item." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 20 -HorizontalAlignment Left # From Set-CellComment -Text "From: The SMTP address of the Organizer of the Calendar Item." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 15 -HorizontalAlignment center # FreeBusyStatus + $sheet.Column(++$n) | Set-ExcelRange -Width 12 -HorizontalAlignment center # FreeBusyStatus Set-CellComment -Text "FreeBusyStatus: The FreeBusy Status of the Calendar Item." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 20 -HorizontalAlignment Left # ResponsibleUser Set-CellComment -Text "ResponsibleUser: The Responsible User of the change." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet @@ -214,7 +217,7 @@ function FormatHeader { Set-CellComment -Text "SharedFolderName: Was this from a Modern Sharing, and if so what Folder." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment center # IsFromSharedCalendar Set-CellComment -Text "IsFromSharedCalendar: Is this CalLog from a Modern Sharing relationship?" -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment Left # ExternalSharingMasterId + $sheet.Column(++$n) | Set-ExcelRange -Width 20 -HorizontalAlignment Left # ExternalSharingMasterId Set-CellComment -Text "ExternalSharingMasterId: If this is not [NotFound], then it is from a Modern Sharing relationship." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment Left # ReceivedBy Set-CellComment -Text "ReceivedBy: The Receiver of the Calendar Item. Should always be the owner of the Mailbox." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet @@ -222,23 +225,23 @@ function FormatHeader { Set-CellComment -Text "ReceivedRepresenting: Who the item was Received for, of then the Delegate." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment center # MeetingRequestType Set-CellComment -Text "MeetingRequestType: The Meeting Request Type of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 17 -NumberFormat "m/d/yyyy h:mm:ss" -HorizontalAlignment center # StartTime + $sheet.Column(++$n) | Set-ExcelRange -Width 20 -NumberFormat "m/d/yyyy h:mm:ss" -HorizontalAlignment center # StartTime Set-CellComment -Text "StartTime: The Start Time of the Meeting. This and all Times are in UTC." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 17 -NumberFormat "m/d/yyyy h:mm:ss" -HorizontalAlignment center # EndTime + $sheet.Column(++$n) | Set-ExcelRange -Width 20 -NumberFormat "m/d/yyyy h:mm:ss" -HorizontalAlignment center # EndTime Set-CellComment -Text "EndTime: The End Time of the Meeting. This and all Times are in UTC." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet + $sheet.Column(++$n) | Set-ExcelRange -Width 17 -NumberFormat "m/d/yyyy h:mm:ss" -HorizontalAlignment Left # OriginalStartDate + Set-CellComment -Text "OriginalStartDate: The Original Start Date of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment Left # TimeZone Set-CellComment -Text "TimeZone: The Time Zone of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment Left # Location Set-CellComment -Text "Location: The Location of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 20 -HorizontalAlignment Left # ItemType - Set-CellComment -Text "ItemType: The Type of the Calendar Item." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment Left # CalendarItemType + $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment center # CalendarItemType Set-CellComment -Text "CalendarItemType: The Calendar Item Type of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment center # IsException Set-CellComment -Text "IsException: Is this an Exception?" -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 20 -HorizontalAlignment Left # RecurrencePattern Set-CellComment -Text "RecurrencePattern: The Recurrence Pattern of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 30 -HorizontalAlignment Left # AppointmentAuxiliaryFlags + $sheet.Column(++$n) | Set-ExcelRange -Width 30 -HorizontalAlignment Center # AppointmentAuxiliaryFlags Set-CellComment -Text "AppointmentAuxiliaryFlags: The Appointment Auxiliary Flags of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 30 -HorizontalAlignment Left # DisplayAttendeesAll Set-CellComment -Text "DisplayAttendeesAll: List of the Attendees of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet @@ -248,24 +251,8 @@ function FormatHeader { Set-CellComment -Text "AppointmentState: The Appointment State of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment center # ResponseType Set-CellComment -Text "ResponseType: The Response Type of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment Right # SentRepresentingEmailAddress - Set-CellComment -Text "SentRepresentingEmailAddress: The Sent Representing Email Address of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment Right # SentRepresentingSMTPAddress - Set-CellComment -Text "SentRepresentingSMTPAddress: The Sent Representing SMTP Address of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 30 -HorizontalAlignment Right # SentRepresentingDisplayName - Set-CellComment -Text "SentRepresentingDisplayName: The Sent Representing Display Name of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 30 -HorizontalAlignment Right # ResponsibleUserSMTPAddress - Set-CellComment -Text "ResponsibleUserSMTPAddress: The Responsible User SMTP Address of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 20 -HorizontalAlignment Right # ResponsibleUserName - Set-CellComment -Text "ResponsibleUserName: The Responsible User Name of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 20 -HorizontalAlignment Right # SenderEmailAddress - Set-CellComment -Text "SenderEmailAddress: The Sender Email Address of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 30 -HorizontalAlignment Left # SenderSMTPAddress - Set-CellComment -Text "SenderSMTPAddress: The Sender SMTP Address of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 20 -HorizontalAlignment center # ClientIntent Set-CellComment -Text "ClientIntent: The Client Intent of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment Left # NormalizedSubject - Set-CellComment -Text "NormalizedSubject: The Normalized Subject of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment center # AppointmentRecurring Set-CellComment -Text "AppointmentRecurring: Is this a Recurring Meeting?" -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment center # HasAttachment @@ -276,17 +263,11 @@ function FormatHeader { Set-CellComment -Text "IsAllDayEvent: Is this an All Day Event?" -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 10 -HorizontalAlignment center # IsSeriesCancelled Set-CellComment -Text "IsSeriesCancelled: Is this a Series Cancelled Meeting?" -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 17 -NumberFormat "m/d/yyyy h:mm:ss" -HorizontalAlignment Left # CreationTime - Set-CellComment -Text "CreationTime: The Creation Time of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 17 -NumberFormat "m/d/yyyy h:mm:ss" -HorizontalAlignment Left # OriginalStartDate - Set-CellComment -Text "OriginalStartDate: The Original Start Date of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 30 -HorizontalAlignment Left # SendMeetingMessagesDiagnostics Set-CellComment -Text "SendMeetingMessagesDiagnostics: Compound Property to describe why meeting was or was not sent to everyone." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 50 -HorizontalAlignment Left # AttendeeListDetails - Set-CellComment -Text "AttendeeListDetails: The Attendee List Details of the Meeting, use -TrackingLogs to get values." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 50 -HorizontalAlignment Left # AttendeeCollection Set-CellComment -Text "AttendeeCollection: The Attendee Collection of the Meeting, use -TrackingLogs to get values." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet - $sheet.Column(++$n) | Set-ExcelRange -Width 40 -HorizontalAlignment Left # CalendarLogRequestId + $sheet.Column(++$n) | Set-ExcelRange -Width 40 -HorizontalAlignment Center # CalendarLogRequestId Set-CellComment -Text "CalendarLogRequestId: The Calendar Log Request ID of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet $sheet.Column(++$n) | Set-ExcelRange -Width 120 -HorizontalAlignment Left # CleanGlobalObjectId Set-CellComment -Text "CleanGlobalObjectId: The Clean Global Object ID of the Meeting." -Row $HeaderRow -ColumnNumber $n -Worksheet $sheet diff --git a/Calendar/CalLogHelpers/CalLogInfoFunctions.ps1 b/Calendar/CalLogHelpers/CalLogInfoFunctions.ps1 index 82d3364ee4..2f9224ace1 100644 --- a/Calendar/CalLogHelpers/CalLogInfoFunctions.ps1 +++ b/Calendar/CalLogHelpers/CalLogInfoFunctions.ps1 @@ -12,11 +12,11 @@ function SetIsOrganizer { [bool] $IsOrganizer = $false foreach ($CalLog in $CalLogs) { - if ($CalendarItemTypes.($CalLog.ItemClass) -eq "IpmAppointment" -and + if ($CalLog.ItemType -eq "Ipm.Appointment" -and $CalLog.ExternalSharingMasterId -eq "NotFound" -and - ($CalLog.ResponseType -eq "1" -or $CalLogs.ResponseType -eq "Organizer")) { + ($CalLog.ResponseType -eq "1" -or $CalLog.ResponseType -eq "Organizer")) { $IsOrganizer = $true - Write-Verbose "IsOrganizer: [$IsOrganizer]" + Write-Host -ForegroundColor Green "IsOrganizer: [$IsOrganizer]" return $IsOrganizer } } @@ -41,10 +41,10 @@ function SetIsRoom { # Simple logic is if RBA is running on the MB, it is a Room MB, otherwise it is not. foreach ($CalLog in $CalLogs) { - Write-Verbose "Checking if this is a Room Mailbox. [$($CalLog.ItemClass)] [$($CalLog.ExternalSharingMasterId)] [$($CalLog.ClientInfoString)]" - if ($CalLog.ItemClass -eq "IPM.Appointment" -and + Write-Verbose "Checking if this is a Room Mailbox. [$($CalLog.ItemType)] [$($CalLog.ExternalSharingMasterId)] [$($CalLog.LogClientInfoString)]" + if ($CalLog.ItemType -eq "IPM.Appointment" -and $CalLog.ExternalSharingMasterId -eq "NotFound" -and - $CalLog.ClientInfoString -like "*ResourceBookingAssistant*" ) { + $CalLog.LogClientInfoString -like "*ResourceBookingAssistant*" ) { $IsRoom = $true return $IsRoom } @@ -64,7 +64,7 @@ function SetIsRecurring { [bool] $IsRecurring = $false # See if this is a recurring meeting foreach ($CalLog in $CalLogs) { - if ($CalendarItemTypes.($CalLog.ItemClass) -eq "IpmAppointment" -and + if ($CalendarItemTypes.($CalLog.ItemClass) -eq "Ipm.Appointment" -and $CalLog.ExternalSharingMasterId -eq "NotFound" -and ($CalLog.CalendarItemType.ToString() -eq "RecurringMaster" -or $CalLog.IsException -eq $true)) { @@ -79,10 +79,35 @@ function SetIsRecurring { <# .SYNOPSIS -Checks to see if the Calendar Log is Ignorable. +Check for Bifurcation issue +#> +function CheckForBifurcation { + param ( + $CalLogs + ) + Write-Verbose "Looking for signs of the Bifurcation Issue." + [bool] $IsBifurcated = $false + # See if there is an IPM.Appointment in the CalLogs. + foreach ($CalLog in $CalLogs) { + if ($CalLog.ItemClass -eq "IPM.Appointment" -and + $CalLog.ExternalSharingMasterId -eq "NotFound") { + $IsBifurcated = $false + Write-Verbose "Found Ipm.Appointment, likely not a bifurcation issue." + return $IsBifurcated + } + } + Write-Host -ForegroundColor Red "Did not find any Ipm.Appointments in the CalLogs. If this is the Organizer of the meeting, this could the the Outlook Bifurcation issue." + Write-Host -ForegroundColor Yellow "`t This could be the Outlook Bifurcation issue, where Outlook saves to the Organizers Mailbox on one thread and send to the attendee via transport on another thread. If the save to Organizers mailbox failed, we get into the Bifurcated State, where the Organizer does not have the meeting but the Attendees do." + Write-Host -ForegroundColor Yellow "`t See https://support.microsoft.com/en-us/office/meeting-request-is-missing-from-organizers-calendar-c13c47cd-18f9-4ef0-b9d0-d9e174912c4a" + return $IsBifurcated +} + +<# +.SYNOPSIS +Sets the Calendar Log Type. Many updates are not interesting in the Calendar Log, marking these as ignorable. 99% of the time this is correct. #> -function SetIsIgnorable { +function SetLogType { param( $CalLog ) @@ -105,9 +130,10 @@ function SetIsIgnorable { } elseif ($CalLog.ItemClass -eq "IPM.OLE.CLASS.{00061055-0000-0000-C000-000000000046}" ) { return "Exception" } elseif (($CalendarItemTypes.($CalLog.ItemClass) -like "*Resp*" -and $CalLog.CalendarLogTriggerAction -ne "Create" ) -or - $CalendarItemTypes.($CalLog.ItemClass) -eq "AttendeeList" ) { + $CalendarItemTypes.($CalLog.ItemClass) -eq "AttendeeList" -or + ($CalLog.ItemClass -eq "IPM.Schedule.Meeting.Request" -and $CalLog.CalendarLogTriggerAction -like "*move*" ) ) { return "Cleanup" } else { - return "False" + return "Core" } } diff --git a/Calendar/CalLogHelpers/CreateTimelineRow.ps1 b/Calendar/CalLogHelpers/CreateTimelineRow.ps1 index fcfbf2fd5f..0df30ef4b9 100644 --- a/Calendar/CalLogHelpers/CreateTimelineRow.ps1 +++ b/Calendar/CalLogHelpers/CreateTimelineRow.ps1 @@ -6,15 +6,15 @@ This is the part that generates the heart of the timeline, a Giant Switch statement based on the ItemClass. #> function CreateTimelineRow { - switch -Wildcard ($CalendarItemTypes.($CalLog.ItemClass)) { - MeetingRequest { + switch -Wildcard ($CalLog.ItemClass) { + Meeting.Request { 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)" + [array] $Output = "[$($CalLog.ResponsibleUser)] Created a Meeting Request with $($CalLog.Client)" } } else { if ($CalLog.DisplayAttendeesTo -ne $script:PreviousCalLog.DisplayAttendeesTo -or $CalLog.DisplayAttendeesCc -ne $script:PreviousCalLog.DisplayAttendeesCc) { @@ -22,10 +22,10 @@ function CreateTimelineRow { } 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)]" }) + "." + [array] $Output = "Transport delivered a new Meeting Request from [$($CalLog.From)] 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)]" + + [Array] $Output = "Transport delivered a new Meeting Request from [$($CalLog.From)]" + $(if ($null -ne $($CalLog.ReceivedRepresenting) -and $CalLog.ReceivedRepresenting -ne $CalLog.ReceivedBy) { " for user [$($CalLog.ReceivedRepresenting)]" }) + "." } @@ -68,13 +68,13 @@ function CreateTimelineRow { } 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" } + "Resp.Tent" { $MeetingRespType = "Tentative" } + "Resp.Neg" { $MeetingRespType = "DECLINE" } + "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)" + [array] $Output = "[$($CalLog.Organizer)] send a $($MeetingRespType) response message with a New Time Proposal: $($CalLog.StartTime) to $($CalLog.EndTime)" } else { switch -Wildcard ($CalLog.TriggerAction) { "Update" { $Action = "Updated" } @@ -93,7 +93,7 @@ function CreateTimelineRow { } if ($IsOrganizer) { - [array] $Output = "[$($CalLog.SentRepresentingDisplayName)] $($Action) a $($MeetingRespType) Meeting Response message$($Extra)." + [array] $Output = "[$($CalLog.Organizer)] $($Action) a $($MeetingRespType) meeting Response message$($Extra)." } else { switch ($CalLog.Client) { ResourceBookingAssistant { @@ -103,21 +103,21 @@ function CreateTimelineRow { [array] $Output = "[$($CalLog.From)] $($Action) $($MeetingRespType) Meeting Response message." } default { - [array] $Output = "[$($CalLog.ResponsibleUser)] $($Action) [$($CalLog.SentRepresentingDisplayName)]'s $($MeetingRespType) Meeting Response with $($CalLog.Client)." + [array] $Output = "[$($CalLog.ResponsibleUser)] $($Action) [$($CalLog.Organizer)]'s $($MeetingRespType) Meeting Response with $($CalLog.Client)." } } } } } - ForwardNotification { - [array] $Output = "The meeting was FORWARDED by [$($CalLog.SentRepresentingDisplayName)]." + Forward.Notification { + [array] $Output = "The meeting was FORWARDED by [$($CalLog.Organizer)]." } - ExceptionMsgClass { + Exception { if ($CalLog.ResponsibleUser -ne "Calendar Assistant") { [array] $Output = "[$($CalLog.ResponsibleUser)] $($CalLog.TriggerAction)d Exception to the meeting series with $($CalLog.Client)." } } - IpmAppointment { + Ipm.Appointment { switch ($CalLog.TriggerAction) { Create { if ($IsOrganizer) { @@ -129,10 +129,10 @@ function CreateTimelineRow { } else { switch ($CalLog.Client) { Transport { - [array] $Output = "Transport Created a new Meeting on the calendar from [$($CalLog.SentRepresentingDisplayName)] and marked it Tentative." + [array] $Output = "Transport Created a new Meeting on the calendar from [$($CalLog.Organizer)] and marked it Tentative." } ResourceBookingAssistant { - [array] $Output = "ResourceBookingAssistant Created a new Meeting on the calendar from [$($CalLog.SentRepresentingDisplayName)] and marked it Tentative." + [array] $Output = "ResourceBookingAssistant Created a new Meeting on the calendar from [$($CalLog.Organizer)] and marked it Tentative." } default { [array] $Output = "[$($CalLog.ResponsibleUser)] Created the Meeting with $($CalLog.Client)." @@ -189,7 +189,7 @@ function CreateTimelineRow { SoftDelete { switch ($CalLog.Client) { Transport { - [array] $Output = "Transport $($CalLog.TriggerAction)d the meeting based on changes by [$($CalLog.SentRepresentingDisplayName)]." + [array] $Output = "Transport $($CalLog.TriggerAction)d the meeting based on changes by [$($CalLog.Organizer)]." } LocationProcessor { [array] $Output = "" diff --git a/Calendar/CalLogHelpers/Invoke-GetCalLogs.ps1 b/Calendar/CalLogHelpers/Invoke-GetCalLogs.ps1 index 4870099d17..b3df2d1ab4 100644 --- a/Calendar/CalLogHelpers/Invoke-GetCalLogs.ps1 +++ b/Calendar/CalLogHelpers/Invoke-GetCalLogs.ps1 @@ -12,6 +12,8 @@ $script:CustomPropertyNameList = "CalendarItemType", "CalendarProcessed", "ClientIntent", +"ChangeList", +"CalendarLogTriggerAction", "DisplayAttendeesCc", "DisplayAttendeesTo", "EventEmailReminderTimer", @@ -28,10 +30,9 @@ $script:CustomPropertyNameList = "SendMeetingMessagesDiagnostics", "SentRepresentingDisplayName", "SentRepresentingEmailAddress", -"OriginalLastModifiedTime", -"ClientInfoString", +"LogTimestamp", +"LogClientInfoString", "OriginalStartDate", -"LastModifiedTime", "CreationTime", "TimeZone" diff --git a/Calendar/CalLogHelpers/MeetingSummaryFunctions.ps1 b/Calendar/CalLogHelpers/MeetingSummaryFunctions.ps1 index 0e1f6cf17a..2dd8efb1ee 100644 --- a/Calendar/CalLogHelpers/MeetingSummaryFunctions.ps1 +++ b/Calendar/CalLogHelpers/MeetingSummaryFunctions.ps1 @@ -80,7 +80,7 @@ function CreateMeetingSummary { } if (!$Time) { - $Time = $CalLog.LastModifiedTime.ToString() + $Time = $Entry.LogTimestamp } if (!$MeetingChanges) { @@ -94,7 +94,4 @@ function CreateMeetingSummary { } $script:TimeLineOutput += Convert-Data -ArrayNames "Time", "MeetingChanges" - - # $TimeLineData = Convert-Data -ArrayNames "Time", "MeetingChanges" - # $script:TimeLineOutput += $TimeLineData } diff --git a/Calendar/CalLogHelpers/ShortClientNameFunctions.ps1 b/Calendar/CalLogHelpers/ShortClientNameFunctions.ps1 index b04dc20b0a..914ef5eb4b 100644 --- a/Calendar/CalLogHelpers/ShortClientNameFunctions.ps1 +++ b/Calendar/CalLogHelpers/ShortClientNameFunctions.ps1 @@ -44,105 +44,116 @@ $ShortClientNameProcessor = @{ <# .SYNOPSIS -Creates friendly / short client names from the ClientInfoString +Creates friendly / short client names from the LogClientInfoString #> function CreateShortClientName { param( - $ClientInfoString + $LogClientInfoString ) $ShortClientName= "" - # Map ClientInfoString to ShortClientName - if ([string]::IsNullOrEmpty($ClientInfoString)) { + # Map LogClientInfoString to ShortClientName + if ([string]::IsNullOrEmpty($LogClientInfoString)) { $ShortClientName = "NotFound" return $ShortClientName } - if ($ClientInfoString -like "Client=EBA*" -or $ClientInfoString -like "Client=TBA*") { - if ($ClientInfoString -like "*ResourceBookingAssistant*") { + if ($LogClientInfoString -like "Client=EBA*" -or $LogClientInfoString -like "Client=TBA*") { + if ($LogClientInfoString -like "*ResourceBookingAssistant*") { $ShortClientName = "ResourceBookingAssistant" - } elseif ($ClientInfoString -like "*CalendarRepairAssistant*") { + } elseif ($LogClientInfoString -like "*CalendarRepairAssistant*") { $ShortClientName = "CalendarRepairAssistant" - } elseif ($ClientInfoString -like "*SharingSyncAssistant*") { + } elseif ($LogClientInfoString -like "*SharingSyncAssistant*") { $ShortClientName = "CalendarSyncAssistant" } else { - if ($ClientInfoString -like "*EBA*") { + if ($LogClientInfoString -like "*EBA*") { $ShortClientName = "Other EBA" } else { $ShortClientName = "Other TBA" } } - } elseif ($ClientInfoString -like "Client=ActiveSync*") { - if ($ClientInfoString -match 'UserAgent=(\w*-\w*)') { - $ShortClientName = ($ClientInfoString -split "UserAgent=")[-1].Split("/")[0] - } elseif ($ClientInfoString -like "*Outlook-iOS-Android*") { + } elseif ($LogClientInfoString -like "Client=ActiveSync*") { + if ($LogClientInfoString -match 'UserAgent=(\w*-\w*)') { + $ShortClientName = ($LogClientInfoString -split "UserAgent=")[-1].Split("/")[0] + } elseif ($LogClientInfoString -like "*Outlook-iOS-Android*") { $ShortClientName = "OutlookMobile" } else { $ShortClientName = "ActiveSyncUnknown" } - } elseif ($ClientInfoString -like "Client=Rest*") { - if ($ClientInfoString -like "*LocationAssistantProcessor*") { + } elseif ($LogClientInfoString -like "Client=Rest*") { + if ($LogClientInfoString -like "*LocationAssistantProcessor*") { $ShortClientName = "LocationProcessor" - } elseif ($ClientInfoString -like "*AppId=6326e366-9d6d-4c70-b22a-34c7ea72d73d*") { + } elseif ($LogClientInfoString -like "*AppId=6326e366-9d6d-4c70-b22a-34c7ea72d73d*") { $ShortClientName = "CalendarReplication" - } elseif ($ClientInfoString -like "*AppId=1e3faf23-d2d2-456a-9e3e-55db63b869b0*") { + } elseif ($LogClientInfoString -like "*AppId=1e3faf23-d2d2-456a-9e3e-55db63b869b0*") { $ShortClientName = "CiscoWebex" - } elseif ($ClientInfoString -like "*AppId=1c3a76cc-470a-46d7-8ba9-713cfbb2c01f*") { + } elseif ($LogClientInfoString -like "*AppId=1c3a76cc-470a-46d7-8ba9-713cfbb2c01f*") { $ShortClientName = "TimeService" - } elseif ($ClientInfoString -like "*AppId=48af08dc-f6d2-435f-b2a7-069abd99c086*") { + } elseif ($LogClientInfoString -like "*AppId=48af08dc-f6d2-435f-b2a7-069abd99c086*") { $ShortClientName = "RestConnector" - } elseif ($ClientInfoString -like "*Client=OutlookService;Outlook-Android*") { + } elseif ($LogClientInfoString -like "*Client=OutlookService;Outlook-Android*") { $ShortClientName = "OutlookAndroid" - } elseif ($ClientInfoString -like "*GriffinRestClient*") { + } elseif ($LogClientInfoString -like "*GriffinRestClient*") { $ShortClientName = "GriffinRestClient" - } elseif ($ClientInfoString -like "*MacOutlook*") { + } elseif ($LogClientInfoString -like "*MacOutlook*") { $ShortClientName = "MacOutlookRest" - } elseif ($ClientInfoString -like "*Microsoft Outlook 16*") { + } elseif ($LogClientInfoString -like "*Microsoft Outlook 16*") { $ShortClientName = "Outlook-ModernCalendarSharing" - } elseif ($ClientInfoString -like "*SkypeSpaces*") { + } elseif ($LogClientInfoString -like "*SkypeSpaces*") { $ShortClientName = "Teams" - } elseif ($ClientInfoString -like "*AppId=7b7fdad6-df9d-4cd5-a4f2-b5f749350419*") { + } elseif ($LogClientInfoString -like "*AppId=7b7fdad6-df9d-4cd5-a4f2-b5f749350419*") { $ShortClientName = "Bookings B2 Service" - } elseif ($ClientInfoString -like "*bcad1a65-78eb-4725-9bce-ce1a8ed30b95*" -or - $ClientInfoString -like "*43375d74-c6a5-4d4e-a0a3-de139860ea75*" -or - $ClientInfoString -like "*af9fc99a-5ae5-46e1-bbd7-fa25088e16c9*") { + } elseif ($LogClientInfoString -like "*bcad1a65-78eb-4725-9bce-ce1a8ed30b95*" -or + $LogClientInfoString -like "*43375d74-c6a5-4d4e-a0a3-de139860ea75*" -or + $LogClientInfoString -like "*af9fc99a-5ae5-46e1-bbd7-fa25088e16c9*") { $ShortClientName = "ELC-B2" - } elseif ($ClientInfoString -like "*NoUserAgent*") { + } elseif ($LogClientInfoString -like "*Outlook-iOS*") { + $ShortClientName = "OutlookiOS" + } elseif ($LogClientInfoString -like "*Outlook-Android*") { + $ShortClientName = "OutlookAndroid" + } elseif ($LogClientInfoString -like "*NoUserAgent*") { $ShortClientName = "RestUnknown" } else { $ShortClientName = "[Unknown Rest Client]" } # Client=WebServices;Mozilla/5.0 (ZoomPresence.Android 8.1.0 x86); } elseif ($ShortClientName -eq "") { - $ShortClientName = findMatch -KeyInput $ClientInfoString + $ShortClientName = findMatch -KeyInput $LogClientInfoString } - if ($ShortClientName -eq "" -And $ClientInfoString -like "Client=WebServices*") { - if ($ClientInfoString -like "*ZoomPresence*") { + # if ($ShortClientName -eq "" -And $LogClientInfoString -like "Client=WebServices*") { + if ($LogClientInfoString -like "Client=WebServices*") { + if ($LogClientInfoString -like "*ZoomPresence*") { $ShortClientName = "ZoomPresence" + } elseif ($LogClientInfoString -like "*MacOutlook*") { + $ShortClientName = "Outlook : Mac : EWS" + } elseif ($LogClientInfoString -like "*Outlook*") { + $ShortClientName = "Outlook : Desktop" + } elseif ($LogClientInfoString -like "*Ninja*") { + $ShortClientName = "Teams" } else { $ShortClientName = "Unknown EWS App" } } - if ($ClientInfoString -like "*InternalCalendarSharing*" ) { - if ($ClientInfoString -like "*OWA*" -and - $ClientInfoString -notlike "*OneOutlook*") { + if ($LogClientInfoString -like "*InternalCalendarSharing*" ) { + if ($LogClientInfoString -like "*OWA*" -and + $LogClientInfoString -notlike "*OneOutlook*") { $ShortClientName = "OWA : REST" - } elseif ($ClientInfoString -like "*Outlook*" -and - $ClientInfoString -notlike "*OneOutlook*" -and - $ClientInfoString -notlike "*Outlook-Android*" -and - $ClientInfoString -notlike "*Outlook-iOS*") { + } elseif ($LogClientInfoString -like "*Outlook*" -and + $LogClientInfoString -notlike "*OneOutlook*" -and + $LogClientInfoString -notlike "*Outlook-Android*" -and + $LogClientInfoString -notlike "*Outlook-iOS*") { $ShortClientName = "Outlook : Desktop : REST" - } elseif ($ClientInfoString -like "*OneOutlook*") { + } elseif ($LogClientInfoString -like "*OneOutlook*") { $ShortClientName = "OneOutlook" } } - if ($ClientInfoString -like "Client=ActiveSync*" -and $ClientInfoString -like "*Outlook*") { + if ($LogClientInfoString -like "Client=ActiveSync*" -and $LogClientInfoString -like "*Outlook*") { $ShortClientName = "Outlook : ActiveSync" } - if ($ClientInfoString -like "*OneOutlook*") { + if ($LogClientInfoString -like "*OneOutlook*") { $ShortClientName = "OneOutlook" } if ($ShortClientName -eq "") { diff --git a/Calendar/CalLogHelpers/TimelineFunctions.ps1 b/Calendar/CalLogHelpers/TimelineFunctions.ps1 index d1cbc4622d..eb22ce5cbb 100644 --- a/Calendar/CalLogHelpers/TimelineFunctions.ps1 +++ b/Calendar/CalLogHelpers/TimelineFunctions.ps1 @@ -67,7 +67,7 @@ function BuildTimeline { FindOrganizer($script:FirstLog) # Ignorable and items from Shared Calendars are not included in the TimeLine. - [array]$InterestingCalLogs = $script:EnhancedCalLogs | Where-Object { $_.IsIgnorable -eq "False" -and $_.IsFromSharedCalendar -eq $False } + [array]$InterestingCalLogs = $script:EnhancedCalLogs | Where-Object { $_.LogType -eq "Core" -and $_.IsFromSharedCalendar -eq $False } if ($InterestingCalLogs.count -eq 0) { Write-Host "All CalLogs are Ignorable, nothing to create a timeline with, displaying initial values." @@ -93,7 +93,7 @@ function BuildTimeline { $MeetingChanges = CreateTimelineRow # Create the Timeline by adding to Time to the generated MeetingChanges - $Time = "$($CalLog.LogRow) -- $($CalLog.LastModifiedTime)" + $Time = "$($($CalLog.LogRow).toString().PadRight(5)) -- $(ConvertDateTime($CalLog.LogTimestamp))" if ($MeetingChanges) { if ($script:MeetingSummaryNeeded) { @@ -108,7 +108,7 @@ function BuildTimeline { } # Setup Previous log (if current logs is an IPM.Appointment) - if ($CalendarItemTypes.($CalLog.ItemClass) -eq "IpmAppointment" -or $CalendarItemTypes.($CalLog.ItemClass) -eq "ExceptionMsgClass") { + if ($CalendarItemTypes.($CalLog.ItemClass) -eq "Ipm.Appointment" -or $CalendarItemTypes.($CalLog.ItemClass) -eq "Exception") { $script:PreviousCalLog = $CalLog } } diff --git a/Calendar/Check-SharingStatus.ps1 b/Calendar/Check-SharingStatus.ps1 index e73c8d2a36..c11b57880b 100644 --- a/Calendar/Check-SharingStatus.ps1 +++ b/Calendar/Check-SharingStatus.ps1 @@ -383,17 +383,17 @@ function GetReceiverInformation { # Note $Owner has a * at the end in case we have had multiple setup for the same user, they will be appended with a " 1", etc. if (($CalStats | Where-Object Name -Like $owner*) -or ($CalStats | Where-Object Name -Like "$($ownerMB.DisplayName)*" )) { - Write-Host -ForegroundColor Green "Looks like we might have found a copy of the Owner Calendar in the Receiver Calendar." + Write-Host -ForegroundColor Green "Looks like we might have found a copy of the Owner Calendar in the Receiver Mailbox." Write-Host -ForegroundColor Green "This is a good indication the there is a Modern Sharing Relationship between these users." Write-Host -ForegroundColor Green "If the clients use the Modern Sharing or not is a up to the client." $script:ModernSharing = $true $CalStats | Where-Object Name -Like $owner* | Format-Table -a FolderPath, ItemsInFolder, FolderAndSubfolderSize if (($CalStats | Where-Object Name -Like $owner*).count -gt 1) { - Write-Host -ForegroundColor Yellow "Warning: Might have found more than one copy of the Owner Calendar in the Receiver Calendar." + Write-Host -ForegroundColor Yellow "Warning: Might have found more than one copy of the Owner Calendar in the Receiver Mailbox." } } else { - Write-Host -ForegroundColor Yellow "Warning: Could not Identify the Owner's [$Owner] Calendar in the Receiver Calendar collection." + Write-Host -ForegroundColor Yellow "Warning: Could not Identify the Owner's [$Owner] Calendar in the Receiver Mailbox." } if ($ReceiverCalendarName -like "REDACTED-*" ) { diff --git a/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 b/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 index 65ceddb251..35a3680799 100644 --- a/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 +++ b/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 @@ -60,7 +60,7 @@ param ( # =================================================================================================== $BuildVersion = "" . $PSScriptRoot\..\Shared\ScriptUpdateFunctions\Test-ScriptVersion.ps1 -if (Test-ScriptVersion -AutoUpdate -Confirm:$false) { +if (Test-ScriptVersion -AutoUpdate -VersionsUrl "https://aka.ms/CL-VersionsUrl" -Confirm:$false) { # Update was downloaded, so stop here. Write-Host "Script was updated. Please rerun the command." -ForegroundColor Yellow return @@ -118,6 +118,10 @@ if (-not ([string]::IsNullOrEmpty($Subject)) ) { Write-Host -ForegroundColor Cyan "The user [$ID] is a Room Mailbox." } + if (CheckForBifurcation($script:GCDO) -ne false) { + Write-Host -ForegroundColor Red "Warning: No IPM.Appointment found. CalLogs start to expire after 31 days." + } + if ($Exceptions.IsPresent) { Write-Verbose "Looking for Exception Logs..." $IsRecurring = SetIsRecurring -CalLogs $script:GCDO @@ -148,7 +152,7 @@ if (-not ([string]::IsNullOrEmpty($Subject)) ) { $ExceptionLogs = $ExceptionLogs | Where-Object { $_.ItemClass -notlike "IPM.Appointment*" } Write-Host -ForegroundColor Cyan "Found $($ExceptionLogs.count) Exception Logs, adding them into the CalLogs." - $script:GCDO = $script:GCDO + $ExceptionLogs | Select-Object *, @{n='OrgTime'; e= { [DateTime]::Parse($_.OriginalLastModifiedTime.ToString()) } } | Sort-Object OrgTime + $script:GCDO = $script:GCDO + $ExceptionLogs | Select-Object *, @{n='OrgTime'; e= { [DateTime]::Parse($_.LogTimestamp.ToString()) } } | Sort-Object OrgTime $LogToExamine = $null $ExceptionLogs = $null } else { @@ -169,3 +173,10 @@ if (-not ([string]::IsNullOrEmpty($Subject)) ) { Write-DashLineBoxColor "Hope this script was helpful in getting and understanding the Calendar Logs.", "If you have issues or suggestion for this script, please send them to: ", "`t CalLogFormatterDevs@microsoft.com" -Color Yellow -DashChar = + +if ($ExportToExcel.IsPresent) { + Write-Host + Write-Host -ForegroundColor Blue -NoNewline "All Calendar Logs are saved to: " + Write-Host -ForegroundColor Yellow "$Filename" + Write-Host +} diff --git a/Calendar/Tests/ShortClientNameFunctions.Tests.ps1 b/Calendar/Tests/ShortClientNameFunctions.Tests.ps1 index 0e95c3611d..dfae426d3b 100644 --- a/Calendar/Tests/ShortClientNameFunctions.Tests.ps1 +++ b/Calendar/Tests/ShortClientNameFunctions.Tests.ps1 @@ -9,58 +9,71 @@ Describe "CreateShortClientName" { . $PSScriptRoot\..\CalLogHelpers\ShortClientNameFunctions.ps1 } - Context "When ClientInfoString is empty" { + Context "When LogClientInfoString is empty" { It "Should return 'NotFound'" { - $result = CreateShortClientName -ClientInfoString "" + $result = CreateShortClientName -LogClientInfoString "" $result | Should -Be "NotFound" } } - Context "When ClientInfoString is Client=MSExchangeRPC" { + Context "When LogClientInfoString is Client=MSExchangeRPC" { It "Should return 'Outlook : Desktop : MAPI'" { - $result = CreateShortClientName -ClientInfoString "Client=MSExchangeRPC" + $result = CreateShortClientName -LogClientInfoString "Client=MSExchangeRPC" $result | Should -Be "Outlook : Desktop : MAPI" } } - Context "When ClientInfoString is Client=Hub Transport" { + Context "When LogClientInfoString is Client=WebServices;Microsoft Office/16.0 (Windows NT 10.0; Microsoft Outlook 16.0.17328; Pro);;Client=WebServices;ExchangeServicesClient/0.9.248.0;" { + It "Should return 'Outlook : Desktop : MAPI' if LogClientInfoString FileContentMatch 'AppId=bcad1a65-78eb-4725-9bce-ce1a8ed30b95'" { + $result = CreateShortClientName "Client=WebServices;Microsoft Office/16.0 (Windows NT 10.0; Microsoft Outlook 16.0.17328; Pro);;Client=WebServices;ExchangeServicesClient/0.9.248.0;" + $result | Should -Be "Outlook : Desktop" + } + } + + Context "When LogClientInfoString is Client=Hub Transport" { It "Should return 'Transport'" { - $result = CreateShortClientName -ClientInfoString "Client=Hub Transport" + $result = CreateShortClientName -LogClientInfoString "Client=Hub Transport" $result | Should -Be "Transport" } } - Context "When ClientInfoString is Client=OutlookService;Outlook-iOS/2.0;;Outlook-iOS/2.0" { - It "Should return 'Outlook : Desktop'" { - $result = CreateShortClientName -ClientInfoString "Client=OutlookService;Outlook-iOS/2.0;;Outlook-iOS/2.0" + Context "When LogClientInfoString is Client=OutlookService;Outlook-iOS/2.0;;Outlook-iOS/2.0" { + It "Should return 'OutlookiOS'" { + $result = CreateShortClientName -LogClientInfoString "Client=OutlookService;Outlook-iOS/2.0;;Outlook-iOS/2.0" $result | Should -Be "OutlookiOS" } } - Context "When ClientInfoString FileContentMatch 'Client=EBA' or 'Client=TBA'" { - It "Should return 'ResourceBookingAssistant' if ClientInfoString FileContentMatch 'ResourceBookingAssistant'" { + Context "When LogClientInfoString is Client=REST;;;Client=REST;InternalCalendarSharing (Client=OutlookService;Outlook-iOS/2.0;)[AppId=1c06531d-b56d-4cfb-8ad0-53c87d70093e];" { + It "Should return 'OutlookiOS'" { + $result = CreateShortClientName -LogClientInfoString "Client=REST;;;Client=REST;InternalCalendarSharing (Client=OutlookService;Outlook-iOS/2.0;)[AppId=1c06531d-b56d-4cfb-8ad0-53c87d70093e];" + $result | Should -Be "OutlookiOS" + } + } + Context "When LogClientInfoString FileContentMatch 'Client=EBA' or 'Client=TBA'" { + It "Should return 'ResourceBookingAssistant' if LogClientInfoString FileContentMatch 'ResourceBookingAssistant'" { $result = CreateShortClientName "Client=EBA;Action=FreeBusyPublishingAssistant;ResourceBookingAssistant" $result | Should -Be "ResourceBookingAssistant" } - It "Should return 'CalendarRepairAssistant' if ClientInfoString FileContentMatch 'CalendarRepairAssistant'" { + It "Should return 'CalendarRepairAssistant' if LogClientInfoString FileContentMatch 'CalendarRepairAssistant'" { $result = CreateShortClientName "Client=TBA;Service=MSExchangeMailboxAssistants;Action=CalendarRepairAssistant" $result | Should -Be "CalendarRepairAssistant" } - It "Should return the concatenated client, action, and data if ClientInfoString does not contain 'ResourceBookingAssistant' or 'CalendarRepairAssistant'" { + It "Should return the concatenated client, action, and data if LogClientInfoString does not contain 'ResourceBookingAssistant' or 'CalendarRepairAssistant'" { $result = CreateShortClientName "Client=EBA;Action=Delete;Data=789" $result | Should -Be "Other EBA" } } - Context "When ClientInfoString FileContentMatch 'Client=ActiveSync'" { - It "Should return the user agent if ClientInfoString FileContentMatch 'UserAgent='" { + Context "When LogClientInfoString FileContentMatch 'Client=ActiveSync'" { + It "Should return the user agent if LogClientInfoString FileContentMatch 'UserAgent='" { $result = CreateShortClientName "Client=ActiveSync;UserAgent=Apple-iPhone9C1/1402.100;Version=160;Action=/Microsoft-Server-ActiveSync/Proxy/default.eas?User=test@Contoso.com&DeviceId=MyTestDevice&DeviceType=iPhone&Cmd=Sync" $result | Should -Be "Apple-iPhone9C1" } - It "Should return the user agent if ClientInfoString FileContentMatch 'UserAgent='" { + It "Should return the user agent if LogClientInfoString FileContentMatch 'UserAgent='" { $result = CreateShortClientName "Client=ActiveSync;UserAgent=Android-14/;Action=/Microsoft-Server-ActiveSync/Proxy/default.eas" $result | Should -Be "Android-14" } @@ -70,74 +83,79 @@ Describe "CreateShortClientName" { $result | Should -Be "ActiveSyncUnknown" } - It "Should return 'Outlook : ActiveSync' if ClientInfoString FileContentMatch 'Outlook-iOS-Android'" { + It "Should return 'Outlook : ActiveSync' if LogClientInfoString 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 : ActiveSync" } - It "Should return 'ActiveSyncUnknown' if ClientInfoString does not match any conditions" { + It "Should return 'ActiveSyncUnknown' if LogClientInfoString does not match any conditions" { $result = CreateShortClientName "Client=ActiveSync;UnknownClient" $result | Should -Be "ActiveSyncUnknown" } } - Context "When ClientInfoString FileContentMatch 'Client=Rest'" { - It "Should return 'LocationProcessor' if ClientInfoString FileContentMatch 'LocationAssistantProcessor'" { + Context "When LogClientInfoString FileContentMatch 'Client=Rest'" { + It "Should return 'LocationProcessor' if LogClientInfoString FileContentMatch 'LocationAssistantProcessor'" { $result = CreateShortClientName "Client=Rest;LocationAssistantProcessor" $result | Should -Be "LocationProcessor" } - It "Should return 'CalendarReplication' if ClientInfoString FileContentMatch 'AppId=6326e366-9d6d-4c70-b22a-34c7ea72d73d'" { + It "Should return 'CalendarReplication' if LogClientInfoString FileContentMatch 'AppId=6326e366-9d6d-4c70-b22a-34c7ea72d73d'" { $result = CreateShortClientName "Client=Rest;AppId=6326e366-9d6d-4c70-b22a-34c7ea72d73d" $result | Should -Be "CalendarReplication" } - It "Should return 'CiscoWebex' if ClientInfoString FileContentMatch 'AppId=1e3faf23-d2d2-456a-9e3e-55db63b869b0'" { + It "Should return 'CiscoWebex' if LogClientInfoString FileContentMatch 'AppId=1e3faf23-d2d2-456a-9e3e-55db63b869b0'" { $result = CreateShortClientName "Client=Rest;AppId=1e3faf23-d2d2-456a-9e3e-55db63b869b0" $result | Should -Be "CiscoWebex" } - It "Should return 'TimeService' if ClientInfoString FileContentMatch 'AppId=1c3a76cc-470a-46d7-8ba9-713cfbb2c01f'" { + It "Should return 'TimeService' if LogClientInfoString FileContentMatch 'AppId=1c3a76cc-470a-46d7-8ba9-713cfbb2c01f'" { $result = CreateShortClientName "Client=Rest;AppId=1c3a76cc-470a-46d7-8ba9-713cfbb2c01f" $result | Should -Be "TimeService" } - It "Should return 'RestConnector' if ClientInfoString FileContentMatch 'AppId=48af08dc-f6d2-435f-b2a7-069abd99c086'" { + It "Should return 'RestConnector' if LogClientInfoString FileContentMatch 'AppId=48af08dc-f6d2-435f-b2a7-069abd99c086'" { $result = CreateShortClientName "Client=Rest;AppId=48af08dc-f6d2-435f-b2a7-069abd99c086" $result | Should -Be "RestConnector" } - It "Should return 'OutlookAndroid' if ClientInfoString FileContentMatch 'Client=OutlookService;Outlook-Android'" { + It "Should return 'Teams' if LogClientInfoString FileContentMatch 'MicrosoftNinja'" { + $result = CreateShortClientName "Client=WebServices;MicrosoftNinja/1.0 Teams/1.0 (ExchangeServicesClient/1.0.0.0) SkypeSpaces/1.0a$*+;" + $result | Should -Be "Teams" + } + + It "Should return 'OutlookAndroid' if LogClientInfoString FileContentMatch 'Client=OutlookService;Outlook-Android'" { $result = CreateShortClientName "Client=Rest;Client=OutlookService;Outlook-Android" $result | Should -Be "OutlookAndroid" } - It "Should return 'GriffinRestClient' if ClientInfoString FileContentMatch 'GriffinRestClient'" { + It "Should return 'GriffinRestClient' if LogClientInfoString FileContentMatch 'GriffinRestClient'" { $result = CreateShortClientName "Client=Rest;GriffinRestClient" $result | Should -Be "GriffinRestClient" } - It "Should return 'MacOutlookRest' if ClientInfoString FileContentMatch 'MacOutlook'" { + It "Should return 'MacOutlookRest' if LogClientInfoString FileContentMatch 'MacOutlook'" { $result = CreateShortClientName "Client=Rest;MacOutlook" $result | Should -Be "MacOutlookRest" } - It "Should return 'Outlook-ModernCalendarSharing' if ClientInfoString FileContentMatch 'Microsoft Outlook 16'" { + It "Should return 'Outlook-ModernCalendarSharing' if LogClientInfoString FileContentMatch 'Microsoft Outlook 16'" { $result = CreateShortClientName "Client=Rest;Microsoft Outlook 16" $result | Should -Be "Outlook-ModernCalendarSharing" } - It "Should return 'Teams' if ClientInfoString FileContentMatch 'SkypeSpaces'" { + It "Should return 'Teams' if LogClientInfoString FileContentMatch 'SkypeSpaces'" { $result = CreateShortClientName "Client=Rest;SkypeSpaces" $result | Should -Be "Teams" } - It "Should return 'Bookings B2 Service' if ClientInfoString FileContentMatch 'AppId=7b7fdad6-df9d-4cd5-a4f2-b5f749350419'" { + It "Should return 'Bookings B2 Service' if LogClientInfoString FileContentMatch 'AppId=7b7fdad6-df9d-4cd5-a4f2-b5f749350419'" { $result = CreateShortClientName "Client=Rest;AppId=7b7fdad6-df9d-4cd5-a4f2-b5f749350419" $result | Should -Be "Bookings B2 Service" } - It "Should return 'ELC-B2' if ClientInfoString FileContentMatch 'AppId=bcad1a65-78eb-4725-9bce-ce1a8ed30b95'" { + It "Should return 'ELC-B2' if LogClientInfoString FileContentMatch 'AppId=bcad1a65-78eb-4725-9bce-ce1a8ed30b95'" { $result = CreateShortClientName "Client=Rest;AppId=bcad1a65-78eb-4725-9bce-ce1a8ed30b95" $result | Should -Be "ELC-B2" } @@ -150,35 +168,35 @@ Describe "CreateShortClientName-FindMatch" { } Context 'Test CreateShortClientName focusing on the FindMatch function' -ForEach @( - @{ ClientInfoString = 'Client=Hub Transport'; Expected = "Transport" }, - @{ 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" }, - @{ ClientInfoString = 'MicrosoftNinja'; Expected = "Teams" }, - @{ ClientInfoString = 'SkypeSpaces'; Expected = "Teams" }, - @{ ClientInfoString = 'Remove-CalendarEvents'; Expected = "RemoveCalendarEvent" }, - @{ ClientInfoString = 'Client=POP3/IMAP4'; Expected = "PopImap" }, - @{ ClientInfoString = 'Client=OWA'; Expected = "OWA" }, - @{ ClientInfoString = 'PublishedBookingCalendar'; Expected = "BookingAgent" }, - @{ ClientInfoString = 'LocationAssistantProcessor'; Expected = "LocationProcessor" }, - @{ ClientInfoString = 'AppId=6326e366-9d6d-4c70-b22a-34c7ea72d73d'; Expected = "CalendarReplication" }, - @{ ClientInfoString = 'AppId=1e3faf23-d2d2-456a-9e3e-55db63b869b0'; Expected = "CiscoWebex" }, - @{ ClientInfoString = 'AppId=1c3a76cc-470a-46d7-8ba9-713cfbb2c01f'; Expected = "Time Service" }, - @{ ClientInfoString = 'AppId=48af08dc-f6d2-435f-b2a7-069abd99c086'; Expected = "RestConnector" }, - @{ ClientInfoString = 'AppId=7b7fdad6-df9d-4cd5-a4f2-b5f749350419'; Expected = "Bookings B2 Service" }, - @{ ClientInfoString = 'GriffinRestClient'; Expected = "GriffinRestClient" }, - @{ ClientInfoString = 'MacOutlook'; Expected = "MacOutlookRest" }, - @{ ClientInfoString = 'Outlook-iOS-Android'; Expected = "OutlookMobile" }, - @{ ClientInfoString = 'Client=OutlookService;Outlook-Android'; Expected = "OutlookAndroid" }, - @{ ClientInfoString = 'Client=REST;;;Client=REST;InternalCalendarSharing (Client=OutlookService;Outlook-Android/2.0;)[AppId=1c06531d-b56d-4cfb-8ad0-53c87d70093e];'; Expected = "OutlookAndroid" }, - @{ ClientInfoString = 'Client=OutlookService;Outlook-iOS'; Expected = "OutlookiOS" } + @{ LogClientInfoString = 'Client=Hub Transport'; Expected = "Transport" }, + @{ LogClientInfoString = 'Client=MSExchangeRPC'; Expected = "Outlook : Desktop : MAPI" }, + @{ LogClientInfoString = 'OneOutlook'; Expected = "OneOutlook" }, + @{ LogClientInfoString = 'Lync for Mac'; Expected = "LyncMac" }, + @{ LogClientInfoString = 'AppId=00000004-0000-0ff1-ce00-000000000000'; Expected = "SkypeMMS" }, + @{ LogClientInfoString = 'MicrosoftNinja'; Expected = "Teams" }, + @{ LogClientInfoString = 'SkypeSpaces'; Expected = "Teams" }, + @{ LogClientInfoString = 'Remove-CalendarEvents'; Expected = "RemoveCalendarEvent" }, + @{ LogClientInfoString = 'Client=POP3/IMAP4'; Expected = "PopImap" }, + @{ LogClientInfoString = 'Client=OWA'; Expected = "OWA" }, + @{ LogClientInfoString = 'PublishedBookingCalendar'; Expected = "BookingAgent" }, + @{ LogClientInfoString = 'LocationAssistantProcessor'; Expected = "LocationProcessor" }, + @{ LogClientInfoString = 'AppId=6326e366-9d6d-4c70-b22a-34c7ea72d73d'; Expected = "CalendarReplication" }, + @{ LogClientInfoString = 'AppId=1e3faf23-d2d2-456a-9e3e-55db63b869b0'; Expected = "CiscoWebex" }, + @{ LogClientInfoString = 'AppId=1c3a76cc-470a-46d7-8ba9-713cfbb2c01f'; Expected = "Time Service" }, + @{ LogClientInfoString = 'AppId=48af08dc-f6d2-435f-b2a7-069abd99c086'; Expected = "RestConnector" }, + @{ LogClientInfoString = 'AppId=7b7fdad6-df9d-4cd5-a4f2-b5f749350419'; Expected = "Bookings B2 Service" }, + @{ LogClientInfoString = 'GriffinRestClient'; Expected = "GriffinRestClient" }, + @{ LogClientInfoString = 'MacOutlook'; Expected = "MacOutlookRest" }, + @{ LogClientInfoString = 'Outlook-iOS-Android'; Expected = "OutlookMobile" }, + @{ LogClientInfoString = 'Client=WebServices;Microsoft Office/16.0 (Windows NT 10.0; Microsoft Outlook 16.0.17328; Pro);;Client=WebServices;ExchangeServicesClient/0.9.248.0;;'; Expected = "Outlook : Desktop" }, + @{ LogClientInfoString = 'Client=OutlookService;Outlook-Android'; Expected = "OutlookAndroid" }, + @{ LogClientInfoString = 'Client=REST;;;Client=REST;InternalCalendarSharing (Client=OutlookService;Outlook-Android/2.0;)[AppId=1c06531d-b56d-4cfb-8ad0-53c87d70093e];'; Expected = "OutlookAndroid" }, + @{ LogClientInfoString = 'Client=OutlookService;Outlook-iOS'; Expected = "OutlookiOS" } ) { It 'Should return the expected value' { - $result = CreateShortClientName -ClientInfoString $ClientInfoString + $result = CreateShortClientName -LogClientInfoString $LogClientInfoString $result | Should -Be $Expected } } } - From a0e51e4dd7873c389fe449ec0341e16d019c0bdf Mon Sep 17 00:00:00 2001 From: Shane Ferrell Date: Wed, 19 Jun 2024 16:12:40 -0700 Subject: [PATCH 2/3] Add dot to filename display --- Calendar/CalLogHelpers/CalLogInfoFunctions.ps1 | 2 +- Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Calendar/CalLogHelpers/CalLogInfoFunctions.ps1 b/Calendar/CalLogHelpers/CalLogInfoFunctions.ps1 index 2f9224ace1..90d36ce7ef 100644 --- a/Calendar/CalLogHelpers/CalLogInfoFunctions.ps1 +++ b/Calendar/CalLogHelpers/CalLogInfoFunctions.ps1 @@ -12,7 +12,7 @@ function SetIsOrganizer { [bool] $IsOrganizer = $false foreach ($CalLog in $CalLogs) { - if ($CalLog.ItemType -eq "Ipm.Appointment" -and + if ($CalLog.ItemClass -eq "Ipm.Appointment" -and $CalLog.ExternalSharingMasterId -eq "NotFound" -and ($CalLog.ResponseType -eq "1" -or $CalLog.ResponseType -eq "Organizer")) { $IsOrganizer = $true diff --git a/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 b/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 index 35a3680799..8c4acac385 100644 --- a/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 +++ b/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 @@ -177,6 +177,6 @@ Write-DashLineBoxColor "Hope this script was helpful in getting and understandin if ($ExportToExcel.IsPresent) { Write-Host Write-Host -ForegroundColor Blue -NoNewline "All Calendar Logs are saved to: " - Write-Host -ForegroundColor Yellow "$Filename" + Write-Host -ForegroundColor Yellow ".\$Filename" Write-Host } From 5ebc2fa783babd401420d0b7483b19daf06a2962 Mon Sep 17 00:00:00 2001 From: Shane Ferrell Date: Thu, 20 Jun 2024 13:54:50 -0700 Subject: [PATCH 3/3] Revert spellchecker --- .build/cspell-words.txt | 2 -- Calendar/CalLogHelpers/CalLogCSVFunctions.ps1 | 6 +----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.build/cspell-words.txt b/.build/cspell-words.txt index 092acb7b59..8bb4f8b2dc 100644 --- a/.build/cspell-words.txt +++ b/.build/cspell-words.txt @@ -10,7 +10,6 @@ bincirc BSTR cach cachtokn -Calendrier Clixml cmatch comparables @@ -46,7 +45,6 @@ FYDIBOHF GCDO Get-AuthenticodeSignature globalsequence -Kalender Hashtable HHMM HKCR diff --git a/Calendar/CalLogHelpers/CalLogCSVFunctions.ps1 b/Calendar/CalLogHelpers/CalLogCSVFunctions.ps1 index 92e7fa9c3c..b5bbd0282d 100644 --- a/Calendar/CalLogHelpers/CalLogCSVFunctions.ps1 +++ b/Calendar/CalLogHelpers/CalLogCSVFunctions.ps1 @@ -73,11 +73,7 @@ function CreateExternalMasterIDMap { if ($AllFolderNames.count -gt 1) { # We have 2+ FolderNames, Need to find the best one. Remove 'Calendar' from possible names - $AllFolderNames = $AllFolderNames | Where-Object { - $_ -notmatch 'Calendar' -and - $_ -notmatch 'Calendrier' -and - $_ -notmatch 'Kalender' - } # Need a better way to do this for other languages... + $AllFolderNames = $AllFolderNames | Where-Object { $_ -notmatch 'Calendar' } # Need a better way to do this for other languages... } if ($AllFolderNames.Count -eq 0) {