Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 1-19-24 #1950

Merged
merged 15 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 [email protected] -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