PSWinDocumentation.O365HealthService.psm1
function Connect-O365ServiceHealth { param([string][alias('ClientID')] $ApplicationID, [string][alias('ClientSecret')] $ApplicationKey, [string] $TenantDomain) $Body = @{grant_type = "client_credentials" resource = "https://manage.office.com" client_id = $ApplicationID client_secret = $ApplicationKey } try {$Authorization = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$($TenantDomain)/oauth2/token?api-version=1.0" -Body $body -ErrorAction Stop} catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " Write-Warning -Message "Connect-O365ServiceHealth - Error: $ErrorMessage" } if ($Authorization) {@{'Authorization' = "$($Authorization.token_type) $($Authorization.access_token)"} } else {$null} } function ConvertFrom-UTCTime { [CmdLetbinding()] param([Object] $Time, [switch] $ToLocalTime) if ($null -eq $Script:TimeZoneBias) {$TimeZoneBias = (Get-CimInstance -ClassName Win32_TimeZone).Bias} else {$TimeZoneBias = $Script:TimeZoneBias} if ($Time -is [DateTime]) {$ConvertedTime = $Time} else { if ($null -eq $Time -or $Time -eq '') {return} else { $NewTime = $Time -replace ', at', '' -replace 'UTC', '' -replace 'at' -replace '(^.+?,)' try {[DateTime] $ConvertedTime = [DateTime]::Parse($NewTime)} catch { Write-Warning "ConvertFrom-UTCTime - couldn't convert time. Please report on GitHub - $Time. Skipping conversion..." return $Time } } } if ($ToLocal) {$ConvertedTime.AddMinutes($TimeZoneBias)} else {$ConvertedTime} } function Get-Office365Health { [CmdLetbinding()] param([string][alias('ClientID')] $ApplicationID, [string][alias('ClientSecret')] $ApplicationKey, [string] $TenantDomain, [PSWinDocumentation.Office365Health[]] $TypesRequired = [PSWinDocumentation.Office365Health]::All, [switch] $ToLocalTime) $StartTime = Start-TimeLog $Script:TimeZoneBias = (Get-CimInstance -ClassName Win32_TimeZone).Bias $Script:Today = Get-Date if ($null -eq $TypesRequired -or $TypesRequired -contains [PSWinDocumentation.Office365Health]::All) {$TypesRequired = Get-Types -Types ([PSWinDocumentation.Office365Health])} $Authorization = Connect-O365ServiceHealth -ApplicationID $ApplicationID -ApplicationKey $ApplicationKey -TenantDomain $TenantDomain if ($null -ne $Authorization) { if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::Services, [PSWinDocumentation.Office365Health]::ServicesExteneded)) {$Services = Get-Office365ServiceHealthServices -Authorization $Authorization -TenantDomain $TenantDomain} if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::CurrentStatus, [PSWinDocumentation.Office365Health]::CurrentStatusExteneded)) {$CurrentStatus = Get-Office365ServiceHealthCurrentStatus -Authorization $Authorization -TenantDomain $TenantDomain -ToLocalTime:$ToLocalTime} if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::HistoricalStatus, [PSWinDocumentation.Office365Health]::HistoricalStatusExteneded)) {$HistoricalStatus = Get-Office365ServiceHealthHistoricalStatus -Authorization $Authorization -TenantDomain $TenantDomain -ToLocalTime:$ToLocalTime} if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::Incidents, [PSWinDocumentation.Office365Health]::IncidentsExteneded, [PSWinDocumentation.Office365Health]::MessageCenterInformation, [PSWinDocumentation.Office365Health]::MessageCenterInformationExtended, [PSWinDocumentation.Office365Health]::PlannedMaintenance, [PSWinDocumentation.Office365Health]::PlannedMaintenanceExteneded, [PSWinDocumentation.Office365Health]::Messages)) {$Messages = Get-Office365ServiceHealthMessages -Authorization $Authorization -TenantDomain $TenantDomain -ToLocalTime:$ToLocalTime} $Output = [ordered] @{} if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::Services)) {$Output.Services = $Services.Simple} if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::ServicesExteneded)) {$Output.ServicesExteneded = $Services.Exteneded} if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::CurrentStatus)) {$Output.CurrentStatus = $CurrentStatus.Simple} if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::CurrentStatusExteneded)) {$Output.CurrentStatusExteneded = $CurrentStatus.Exteneded} if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::HistoricalStatus)) {$Output.HistoricalStatus = $HistoricalStatus.Simple} if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::HistoricalStatusExteneded)) {$Output.HistoricalStatusExteneded = $HistoricalStatus.Exteneded} if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::MessageCenterInformation)) {$Output.MessageCenterInformation = $Messages.MessageCenterInformationSimple | Sort-Object -Property LastUpdatedTime -Descending} if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::MessageCenterInformationExtended)) {$Output.MessageCenterInformationExtended = $Messages.MessageCenterInformation | Sort-Object -Property LastUpdatedTime -Descending} if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::Incidents)) {$Output.Incidents = $Messages.IncidentsSimple | Sort-Object -Property LastUpdatedTime -Descending} if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::Messages)) {$Output.IncidentsMessages = $Messages.Messages | Sort-Object -Property PublishedTime -Descending} if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::IncidentsExteneded)) {$Output.IncidentsExteneded = $Messages.Incidents | Sort-Object -Property LastUpdatedTime -Descending} if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::PlannedMaintenance)) {$Output.PlannedMaintenance = $Messages.PlannedMaintenanceSimple | Sort-Object -Property LastUpdatedTime -Descending} if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::PlannedMaintenanceExteneded)) {$Output.PlannedMaintenanceExteneded = $Messages.PlannedMaintenance | Sort-Object -Property LastUpdatedTime -Descending} $EndTime = Stop-TimeLog -Time $StartTime -Option OneLiner Write-Verbose "Get-Office365Health - Time to process: $EndTime" return $Output } else {return} } function Get-Office365ServiceHealthCurrentStatus { param([System.Collections.IDictionary] $Authorization, [string] $TenantDomain, [switch] $ToLocalTime) $CurrentStatus = (Invoke-RestMethod -Uri "https://manage.office.com/api/v1.0/$($TenantDomain)/ServiceComms/CurrentStatus" -Headers $Authorization -Method Get) $Output = @{} $Output.Simple = foreach ($Status in $CurrentStatus.Value) { [PSCustomObject][ordered] @{Service = $Status.WorkloadDisplayName ServiceStatus = $Status.StatusDisplayName StatusTime = ConvertFrom-UTCTime -ToLocalTime:$ToLocalTime -Time $Status.StatusTime IncidentIds = $Status.IncidentIds -join ', ' } } $Output.Exteneded = foreach ($Status in $CurrentStatus.Value) { foreach ($Feature in $Status.FeatureStatus) { [PSCustomObject][ordered] @{Service = $Status.WorkloadDisplayName ServiceStatus = $Status.StatusDisplayName Feature = $Feature.FeatureDisplayName FeatureStatus = $Feature.FeatureServiceStatusDisplayName IncidentIds = $Status.IncidentIds -join ', ' StatusTime = ConvertFrom-UTCTime -ToLocalTime:$ToLocalTime -Time $Status.StatusTime } } } return $Output } function Get-Office365ServiceHealthHistoricalStatus { [CmdLetbinding()] param([System.Collections.IDictionary] $Authorization, [string] $TenantDomain, [switch] $ToLocalTime) $HistoricalStatus = (Invoke-RestMethod -Uri "https://manage.office.com/api/v1.0/$($TenantDomain)/ServiceComms/HistoricalStatus" -Headers $Authorization -Method Get) $Output = @{} $Output.Simple = foreach ($Status in $HistoricalStatus.Value) { $StatusTime = ConvertFrom-UTCTime -ToLocalTime:$ToLocalTime -Time $Status.StatusTime [PSCustomObject][ordered] @{Service = $Status.WorkloadDisplayName ServiceStatus = $Status.StatusDisplayName IncidentIds = $Status.IncidentIds -join ', ' StatusTime = $StatusTime StatusDaysAgo = Convert-TimeToDays -StartTime $StatusTime -EndTime $Script:Today } } $Output.Exteneded = foreach ($Status in $HistoricalStatus.Value) { foreach ($Feature in $Status.FeatureStatus) { $StatusTime = ConvertFrom-UTCTime -ToLocalTime:$ToLocalTime -Time $Status.StatusTime [PSCustomObject][ordered] @{Service = $Status.WorkloadDisplayName ServiceStatus = $Status.StatusDisplayName Feature = $Feature.FeatureDisplayName FeatureStatus = $Feature.FeatureServiceStatusDisplayName IncidentIds = $Status.IncidentIds -join ', ' StatusTime = $StatusTime StatusDaysAgo = Convert-TimeToDays -StartTime $StatusTime -EndTime $Script:Today } } } return $Output } function Get-Office365ServiceHealthMessages { param([System.Collections.IDictionary] $Authorization, [string] $TenantDomain, [switch] $ToLocalTime) $AllMessages = (Invoke-RestMethod -Uri "https://manage.office.com/api/v1.0/$($TenantDomain)/ServiceComms/Messages" -Headers $Authorization -Method Get) $Output = @{} $Simple = foreach ($Message in $AllMessages.Value) { $LastUpdatedTime = ConvertFrom-UTCTime -ToLocalTime:$ToLocalTime -Time $Message.LastUpdatedTime [PSCustomObject][ordered] @{Id = $Message.Id Title = $Message.Title ImpactDescription = $Message.ImpactDescription LastUpdatedTime = $LastUpdatedTime LastUpdatedDaysAgo = Convert-TimeToDays -StartTime $LastUpdatedTime -EndTime $Script:Today MessageType = $Message.MessageType Status = $Message.Status Severity = $Message.Severity StartTime = ConvertFrom-UTCTime -ToLocalTime:$ToLocalTime -Time $Message.StartTime Workload = $Message.WorkloadDisplayName ActionType = $Message.ActionType Classification = $Message.Classification EndTime = ConvertFrom-UTCTime -ToLocalTime:$ToLocalTime -Time $Message.EndTime Feature = $Message.FeatureDisplayName UserFunctionalImpact = $Message.UserFunctionalImpact PostIncidentDocumentUrl = $Message.PostIncidentDocumentUrl AffectedTenantCount = $Message.AffectedTenantCount AffectedUserCount = $Message.AffectedUserCount AffectedWorkload = $Message.AffectedWorkloadDisplayNames -join ',' } } $Exteneded = foreach ($Message in $AllMessages.Value) { $Messages = $Message.Messages foreach ($M in $Messages) { $LastUpdatedTime = ConvertFrom-UTCTime -ToLocalTime:$ToLocalTime -Time $Message.LastUpdatedTime $PublishedTime = ConvertFrom-UTCTime -ToLocalTime:$ToLocalTime -Time $M.PublishedTime [PSCustomObject][ordered] @{Id = $Message.Id Title = $Message.Title ImpactDescription = $Message.ImpactDescription LastUpdatedTime = $LastUpdatedTime LastUpdatedDaysAgo = Convert-TimeToDays -StartTime $LastUpdatedTime -EndTime $Script:Today MessageType = $Message.MessageType Status = $Message.Status Severity = $Message.Severity StartTime = ConvertFrom-UTCTime -Time $Message.StartTime -ToLocalTime:$ToLocalTime Message = $M.MessageText PublishedTime = ConvertFrom-UTCTime -ToLocalTime:$ToLocalTime -Time $M.PublishedTime PublishedDaysAgo = Convert-TimeToDays -StartTime $PublishedTime -EndTime $Script:Today Workload = $Message.WorkloadDisplayName ActionType = $Message.ActionType Classification = $Message.Classification EndTime = ConvertFrom-UTCTime -ToLocalTime:$ToLocalTime -Time $Message.EndTime Feature = $Message.FeatureDisplayName UserFunctionalImpact = $Message.UserFunctionalImpact PostIncidentDocumentUrl = $Message.PostIncidentDocumentUrl AffectedTenantCount = $Message.AffectedTenantCount AffectedUserCount = $Message.AffectedUserCount AffectedWorkload = $Message.AffectedWorkloadDisplayNames -join ',' } } } $MessageCenterInformationSimple = foreach ($_ in $Simple) {if ($_.MessageType -eq 'MessageCenter') {$_}} $Output.MessageCenterInformationSimple = foreach ($_ in $MessageCenterInformationSimple) { [PSCustomObject][ordered] @{ID = $_.ID Title = $_.Title LastUpdatedTime = $_.LastUpdatedTime LastUpdatedDaysAgo = $_.LastUpdatedDaysAgo Severity = $_.Severity StartTime = $_.StartTime EndTime = $_.EndTime ActionType = $_.ActionType Classification = $_.Classification AffectedService = $_.AffectedWorkload MessageType = $_.MessageType } } $MessageCenterInformation = foreach ($_ in $Exteneded) {if ($_.MessageType -eq 'MessageCenter') {$_}} $Output.MessageCenterInformation = foreach ($_ in $MessageCenterInformation) { [PSCustomObject][Ordered] @{ID = $_.ID PublishedTime = $_.PublishedTime PublishedDaysAgo = $_.PublishedDaysAgo Title = $_.Title Message = $_.Message LastUpdatedTime = $_.LastUpdatedTime LastUpdatedDaysAgo = $_.LastUpdatedDaysAgo Severity = $_.Severity StartTime = $_.StartTime EndTime = $_.EndTime ActionType = $_.ActionType Classification = $_.Classification AffectedService = $_.AffectedWorkload MessageType = $_.MessageType } } $IncidentsSimple = foreach ($_ in $Simple) {if ($_.MessageType -eq 'Incident') {$_}} $Output.IncidentsSimple = foreach ($_ in $IncidentsSimple) { [PSCustomObject][ordered] @{Service = $_.Workload Feature = $_.Feature ID = $_.ID Title = $_.Title ImpactDescription = $_.ImpactDescription LastUpdatedTime = $_.LastUpdatedTime LastUpdatedDaysAgo = $_.LastUpdatedDaysAgo UserFunctionalImpact = $_.UserFunctionalImpact PostIncidentDocumentUrl = $_.PostIncidentDocumentUrl Severity = $_.Severity StartTime = $_.StartTime EndTime = $_.EndTime Classification = $_.Classification AffectedTenantCount = $_.AffectedTenantCount AffectedUserCount = $_.AffectedUserCount MessageType = $_.MessageType } } $Incidents = foreach ($_ in $Exteneded) {if ($_.MessageType -eq 'Incident') {$_}} $Output.Incidents = foreach ($_ in $Incidents) { [PSCustomObject][Ordered] @{Service = $_.Workload Feature = $_.Feature ID = $_.ID Title = $_.Title ImpactDescription = $_.ImpactDescription PublishedTime = $_.PublishedTime PublishedDaysAgo = $_.PublishedDaysAgo Message = $_.Message LastUpdatedTime = $_.LastUpdatedTime LastUpdatedDaysAgo = $_.LastUpdatedDaysAgo UserFunctionalImpact = $_.UserFunctionalImpact PostIncidentDocumentUrl = $_.PostIncidentDocumentUrl Severity = $_.Severity StartTime = $_.StartTime EndTime = $_.EndTime Classification = $_.Classification AffectedTenantCount = $_.AffectedTenantCount AffectedUserCount = $_.AffectedUserCount MessageType = $_.MessageType } } $Output.Messages = foreach ($Entry in $Exteneded) { $LimitedEntry = foreach ($_ in $Entry) {if ($_.MessageType -eq 'Incident') {$_}} foreach ($_ in $LimitedEntry) { $Object = [PsCustomObject][Ordered] @{Service = $_.Workload Status = $_.Status PublishedTime = $_.PublishedTime PublishedDaysAgo = $_.PublishedDaysAgo Title = '' UserImpact = '' MoreInfo = '' CurrentStatus = '' ScopeOfImpact = '' StartTime = '' PreliminaryRootCause = '' NextUpdateBy = '' FinalStatus = '' Other = '' } foreach ($SubMessage in $_.Message.Split([Environment]::NewLine)) { if ($SubMessage -like 'Title: *') {$Object.Title = $SubMessage -replace 'Title: ', ''} elseif ($SubMessage -like 'User Impact: *') {$Object.UserImpact = $SubMessage -replace 'User Impact: ', ''} elseif ($SubMessage -like 'More info: *') {$Object.MoreInfo = $SubMessage -replace 'More info: ', ''} elseif ($SubMessage -like 'Current status: *') {$Object.CurrentStatus = $SubMessage -replace 'Current status: ', ''} elseif ($SubMessage -like 'Scope of impact: *') {$Object.ScopeOfImpact = $SubMessage -replace 'Scope of impact: ', ''} elseif ($SubMessage -like 'Start time: *') { $Time = $SubMessage -replace 'Start time: ', '' $Object.StartTime = ConvertFrom-UTCTime -Time $Time -ToLocalTime:$ToLocalTime } elseif ($SubMessage -like 'Preliminary root cause: *') {$Object.PreliminaryRootCause = $SubMessage -replace 'Preliminary root cause: ', ''} elseif ($SubMessage -like 'Next update by: *') { $Time = ($SubMessage -replace 'Next update by: ', '').Trim() $Object.NextUpdateBy = ConvertFrom-UTCTime -Time $Time -ToLocalTime:$ToLocalTime } elseif ($SubMessage -like 'Final status: *') {$Object.FinalStatus = ($SubMessage -replace 'Final status: ', '').Trim()} else {$Object.Other = $SubMessage.Trim()} } $Object } } $Output.PlannedMaintenanceSimple = foreach ($_ in $Simple) {if ($_.MessageType -eq 'PlannedMaintenance') {$_}} $Output.PlannedMaintenance = foreach ($_ in $Exteneded) {if ($_.MessageType -eq 'PlannedMaintenance') {$_}} return $Output } function Get-Office365ServiceHealthServices { param([System.Collections.IDictionary] $Authorization, [string] $TenantDomain) $Services = (Invoke-RestMethod -Uri "https://manage.office.com/api/v1.0/$($TenantDomain)/ServiceComms/Services" -Headers $Authorization -Method Get) $Output = @{} $Output.Simple = foreach ($Service in $Services.Value) {[PSCustomObject][ordered] @{Service = $Service.DisplayName} } $Output.Exteneded = foreach ($Service in $Services.Value) { foreach ($Feature in $Service.Features) { [PSCustomObject][ordered] @{Service = $Service.DisplayName Feature = $Feature.DisplayName } } } return $Output } Add-Type -TypeDefinition @" using System; namespace PSWinDocumentation { [Flags] public enum Office365Health { All, Services, ServicesExteneded, CurrentStatus, CurrentStatusExteneded, HistoricalStatus, HistoricalStatusExteneded, MessageCenterInformation, MessageCenterInformationExtended, Incidents, IncidentsExteneded, PlannedMaintenance, PlannedMaintenanceExteneded, Messages } } "@ Export-ModuleMember -Function @('Get-Office365Health') -Alias @() |