Skip to content

Commit

Permalink
Merge pull request #1950 from microsoft/main
Browse files Browse the repository at this point in the history
Release 1-19-24
  • Loading branch information
dpaulson45 authored Jan 19, 2024
2 parents 75dddc8 + 196cdea commit 05f9e04
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 8 deletions.
34 changes: 28 additions & 6 deletions Calendar/Get-CalendarDiagnosticObjectsSummary.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
# .PARAMETER MeetingID
# The MeetingID of the meeting to query.
#
# .PARAMETER TrackingLogs
# Include specific tracking logs in the output.
#
# .EXAMPLE
# Get-CalendarDiagnosticObjectsSummary.ps1 -Identity someuser@microsoft.com -MeetingID 040000008200E00074C5B7101A82E008000000008063B5677577D9010000000000000000100000002FCDF04279AF6940A5BFB94F9B9F73CD
#
Expand All @@ -27,11 +30,12 @@ param (
[Parameter(Mandatory, Position = 0)]
[string[]]$Identity,

[Parameter(Mandatory, ParameterSetName = 'Subject', Position = 1)]
[string]$Subject,

[Parameter(Mandatory, ParameterSetName = 'MeetingID', Position = 1)]
[string]$MeetingID
[string]$MeetingID,
[switch]$TrackingLogs,

[Parameter(Mandatory, ParameterSetName = 'Subject', Position = 1)]
[string]$Subject
)

# ===================================================================================================
Expand All @@ -54,7 +58,7 @@ Write-Verbose "Script Versions: $BuildVersion"
# Constants to support the script
# ===================================================================================================

$CustomPropertyNameList =
$script:CustomPropertyNameList =
"AppointmentCounterProposal",
"AppointmentLastSequenceNumber",
"AppointmentRecurring",
Expand Down Expand Up @@ -151,13 +155,21 @@ function GetCalendarDiagnosticObjects {

$params = @{
Identity = $Identity
CustomPropertyName = $CustomPropertyNameList
CustomPropertyName = $script:CustomPropertyNameList
WarningAction = "Ignore"
MaxResults = $LogLimit
ResultSize = $LogLimit
ShouldBindToItem = $true
}

if ($TrackingLogs.IsPresent) {
Write-Host -ForegroundColor Yellow "Including Tracking Logs in the output."
$script:CustomPropertyNameList += "AttendeeListDetails", "AttendeeCollection"
$params.Add("ShouldFetchAttendeeCollection", $true)
$params.Remove("CustomPropertyName")
$params.Add("CustomPropertyName", $script:CustomPropertyNameList)
}

if ($Identity -and $MeetingID) {
Write-Verbose "Getting CalLogs for [$Identity] with MeetingID [$MeetingID]."
$CalLogs = Get-CalendarDiagnosticObjects @params -MeetingID $MeetingID
Expand Down Expand Up @@ -801,6 +813,8 @@ function BuildCSV {
'IsOrganizer' = $GetIsOrganizer
'IsOrganizerProperty' = $CalLog.IsOrganizerProperty
'EventEmailReminderTimer' = $CalLog.EventEmailReminderTimer
'AttendeeListDetails' = MultiLineFormat($CalLog.AttendeeListDetails)
'AttendeeCollection' = MultiLineFormat($CalLog.AttendeeCollection)
'CleanGlobalObjectId' = $CalLog.CleanGlobalObjectId
}
}
Expand All @@ -827,6 +841,14 @@ function BuildCSV {
}
}

function MultiLineFormat {
param(
$PassedString
)
$PassedString = $PassedString -replace "},", "},`n"
return $PassedString
}

# ===================================================================================================
# Write Out one line of the Meeting Summary (Time + Meeting Changes)
# ===================================================================================================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ function Invoke-AnalyzerIISInformation {

Write-Verbose "Working on IIS Web Sites"
$outputObjectDisplayValue = New-Object System.Collections.Generic.List[object]
$problemCertList = New-Object System.Collections.Generic.List[string]
$iisWebSites = $exchangeInformation.IISSettings.IISWebSite | Sort-Object ID
$bindingsPropertyName = "Protocol - Bindings - Certificate"

Expand All @@ -92,9 +93,28 @@ function Invoke-AnalyzerIISInformation {
$hstsEnabled = $webSite.Hsts.NativeHstsSettings.enabled -eq $true -or $webSite.Hsts.HstsViaCustomHeader.enabled -eq $true

$value = @($webSite.Bindings | ForEach-Object {
$certHash = $(if ($null -ne $_.certificateHash) { $_.certificateHash } else { "NULL" })
$pSpace = [string]::Empty
$biSpace = [string]::Empty
$certHash = "NULL"

if (-not ([string]::IsNullOrEmpty($_.certificateHash))) {
$certHash = $_.certificateHash
$cert = $exchangeInformation.ExchangeCertificates | Where-Object { $_.Thumbprint -eq $certHash }

if ($null -eq $cert) {
$problemCertList.Add("'$certHash' Doesn't exist on the server and this will cause problems.")
} elseif ($cert.LifetimeInDays -lt 0) {
$problemCertList.Add("'$certHash' Has expired and will cause problems.")
} elseif ($_.bindingInformation -eq "*:444:") {
$namespaces = $cert.Namespaces | ForEach-Object { $_.ToString() }

if ($namespaces -notcontains $exchangeInformation.GetExchangeServer.Fqdn -or
$namespaces -notcontains $exchangeInformation.GetExchangeServer.Name) {
$problemCertList.Add("'$certHash' Exchange Back End does not have hostname or FQDN for the namespaces. This can cause connectivity issues.")
}
}
}

1..(($protocolLength - $_.Protocol.Length) + 1) | ForEach-Object { $pSpace += " " }
1..(($bindingInformationLength - $_.bindingInformation.Length) + 1 ) | ForEach-Object { $biSpace += " " }
return "$($_.Protocol)$($pSpace)- $($_.bindingInformation)$($biSpace)- $certHash"
Expand Down Expand Up @@ -122,6 +142,18 @@ function Invoke-AnalyzerIISInformation {
}
Add-AnalyzedResultInformation @params

if ($problemCertList.Count -gt 0) {

foreach ($details in $problemCertList) {
$params = $baseParams + @{
Name = "Certificate Binding Issue Detected"
Details = $details
DisplayWriteType = "Red"
}
Add-AnalyzedResultInformation @params
}
}

########################
# IIS Web Sites - Issues
########################
Expand Down Expand Up @@ -462,11 +494,40 @@ function Invoke-AnalyzerIISInformation {
Where-Object { $_.Valid -eq $true -and $_.Exist -eq $true } |
ForEach-Object { $_.Location }

$iisWebApplications = $exchangeInformation.IISSettings.IISWebApplication

if ($null -ne $siteConfigPaths) {
$missingWebApplicationConfigFile = $exchangeInformation.IISSettings.IISWebApplication |
$missingWebApplicationConfigFile = $iisWebApplications |
Where-Object { $siteConfigPaths -contains "$($_.ConfigurationFileInfo.Location)" }
}

$correctLocations = @{
"Default Web Site/owa" = "FrontEnd\HttpProxy\owa"
"Default Web Site/ecp" = "FrontEnd\HttpProxy\ecp"
"Default Web Site/EWS" = "FrontEnd\HttpProxy\EWS"
"Default Web Site/API" = "FrontEnd\HttpProxy\Rest"
"Default Web Site/Autodiscover" = "FrontEnd\HttpProxy\Autodiscover"
"Default Web Site/Microsoft-Server-ActiveSync" = "FrontEnd\HttpProxy\sync"
"Default Web Site/OAB" = "FrontEnd\HttpProxy\OAB"
"Default Web Site/PowerShell" = "FrontEnd\HttpProxy\PowerShell"
"Default Web Site/mapi" = "FrontEnd\HttpProxy\mapi"
"Default Web Site/Rpc" = "FrontEnd\HttpProxy\rpc"
"Exchange Back End/PowerShell" = "ClientAccess\PowerShell-Proxy"
"Exchange Back End/mapi/emsmdb" = "ClientAccess\mapi\emsmdb"
"Exchange Back End/mapi/nspi" = "ClientAccess\mapi\nspi"
"Exchange Back End/API" = "ClientAccess\rest"
"Exchange Back End/owa" = "ClientAccess\owa"
"Exchange Back End/OAB" = "ClientAccess\OAB"
"Exchange Back End/ecp" = "ClientAccess\ecp"
"Exchange Back End/Autodiscover" = "ClientAccess\Autodiscover"
"Exchange Back End/Microsoft-Server-ActiveSync" = "ClientAccess\sync"
"Exchange Back End/EWS" = "ClientAccess\exchWeb\EWS"
"Exchange Back End/EWS/bin" = "ClientAccess\exchWeb\EWS\bin"
"Exchange Back End/Rpc" = "RpcProxy"
"Exchange Back End/RpcWithCert" = "RpcProxy"
"Exchange Back End/PushNotifications" = "ClientAccess\PushNotifications"
}

# Missing config file should really only occur for SharedWebConfig files, as the web application would go back to the parent site.
$missingSharedConfigFile = @($exchangeInformation.IISSettings.IISSharedWebConfig) | Where-Object { $_.Exist -eq $false }
$missingConfigFiles = $iisWebSettings | Where-Object { $_.ConfigurationFileInfo.Exist -eq $false }
Expand Down Expand Up @@ -561,6 +622,20 @@ function Invoke-AnalyzerIISInformation {
}
}

foreach ($webApp in $iisWebApplications) {
if ($correctLocations.ContainsKey($webApp.FriendlyName)) {
if ($webApp.PhysicalPath -notlike "*$($correctLocations[$webApp.FriendlyName])") {
$params = $baseParams + @{
Name = "Incorrect Virtual Directory Path"
Details = "Error: '$($webApp.FriendlyName)' location for the virtual directory configuration is incorrect." +
"`r`n`t`tCurrently pointing to '$($webApp.PhysicalPath)', which is incorrect for this protocol and will cause problems."
DisplayWriteType = "Red"
}
Add-AnalyzedResultInformation @params
}
}
}

if ($null -ne $missingWebApplicationConfigFile) {
$params = $baseParams + @{
Name = "Missing Web Application Configuration File"
Expand Down
5 changes: 5 additions & 0 deletions docs/Security/ExchangeExtendedProtectionManagement.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ Download the latest release: [ExchangeExtendedProtectionManagement.ps1](https://

The Exchange Extended Protection Management is a script to help automate the Extended Protection feature on the Windows Authentication Module on Exchange Servers. Prior to configuration, it validates that all servers that we are trying to enable Extended Protection on and the servers that already have Extended Protection enabled have the same TLS settings and other prerequisites that are required for Extended Protection to be enabled successfully.

!!! success "Tip"

The Exchange Server Extended Protection documentation can be found on the Microsoft Learn platform: [Configure Windows Extended Protection in Exchange Server](https://aka.ms/ExchangeEPDoc)


## Requirements

The user must be in `Organization Management` and must run this script from an
Expand Down

0 comments on commit 05f9e04

Please sign in to comment.