├── .github └── FUNDING.yml ├── Build └── Manage-Module.ps1 ├── CHANGELOG.MD ├── Enums └── Office365Health.ps1 ├── Examples ├── Example-Office365Status.ps1 ├── Example-Office365StatusUsingDashimo.ps1 └── Health.html ├── LICENSE ├── PSWinDocumentation.O365HealthService.psd1 ├── PSWinDocumentation.O365HealthService.psm1 ├── Private ├── Connect-O365ServiceHealth.ps1 ├── ConvertFrom-UTCTime.ps1 ├── Get-Office365ServiceHealthCurrentStatus.ps1 ├── Get-Office365ServiceHealthIssues.ps1 ├── Get-Office365ServiceHealthMessages.ps1 └── Get-Office365ServiceHealthServices.ps1 ├── Public └── Get-Office365Health.ps1 └── README.MD /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: PrzemyslawKlys 4 | custom: https://paypal.me/PrzemyslawKlys -------------------------------------------------------------------------------- /Build/Manage-Module.ps1: -------------------------------------------------------------------------------- 1 | Import-Module "C:\Support\GitHub\PSPublishModule\PSPublishModule.psd1" 2 | 3 | Build-Module -ModuleName 'PSWinDocumentation.O365HealthService' { 4 | # Usual defaults as per standard module 5 | $Manifest = [ordered] @{ 6 | # Version number of this module. 7 | ModuleVersion = '1.0.X' 8 | # Supported PSEditions 9 | CompatiblePSEditions = @('Desktop', 'Core') 10 | # ID used to uniquely identify this module 11 | GUID = '5879b6ed-e0da-4815-ad68-d345253bfe54' 12 | # Author of this module 13 | Author = 'Przemyslaw Klys' 14 | # Company or vendor of this module 15 | CompanyName = 'Evotec' 16 | # Copyright statement for this module 17 | Copyright = "(c) 2011 - $((Get-Date).Year) Przemyslaw Klys @ Evotec. All rights reserved." 18 | # Description of the functionality provided by this module 19 | Description = 'Office 365 Health Service' 20 | # Minimum version of the Windows PowerShell engine required by this module 21 | PowerShellVersion = '5.1' 22 | # Tags applied to this module. These help with module discovery in online galleries. 23 | Tags = @('Windows', 'Office365', 'O365', 'PSWinDocumentation', 'HealthService', 'Linux', 'Osx') 24 | # A URL to the main website for this project. 25 | ProjectUri = 'https://github.com/EvotecIT/PSWinDocumentation.O365HealthService' 26 | # A URL to an icon representing this module. 27 | IconUri = 'https://evotec.xyz/wp-content/uploads/2018/10/PSWinDocumentation.png' 28 | } 29 | New-ConfigurationManifest @Manifest 30 | 31 | # Add standard module dependencies (directly, but can be used with loop as well) 32 | New-ConfigurationModule -Type RequiredModule -Name 'PSSharedGoods' -Guid 'Auto' -Version 'Latest' 33 | New-ConfigurationModule -Type RequiredModule -Name 'Graphimo' -Guid 'Auto' -Version 'Latest' 34 | 35 | # Add approved modules, that can be used as a dependency, but only when specific function from those modules is used 36 | # And on that time only that function and dependant functions will be copied over 37 | # Keep in mind it has it's limits when "copying" functions such as it should not depend on DLLs or other external files 38 | New-ConfigurationModule -Type ApprovedModule -Name 'PSSharedGoods', 'PSWriteColor', 'Connectimo', 'PSUnifi', 'PSWebToolbox', 'PSMyPassword', 'PSPublishModule', 'Graphimo' 39 | 40 | New-ConfigurationModuleSkip -IgnoreModuleName @( 41 | # built-in modules in PowerShell 42 | 'Microsoft.PowerShell.Management' 43 | 'Microsoft.PowerShell.Utility' 44 | 'Microsoft.PowerShell.LocalAccounts' 45 | 'Microsoft.WSMan.Management' 46 | 'Microsoft.PowerShell.Security' 47 | 'NetTCPIP' 48 | # Graphimo uses it, but only in specific circumstances. This module doesn't 49 | 'MSAL.PS' 50 | ) 51 | 52 | $ConfigurationFormat = [ordered] @{ 53 | RemoveComments = $false 54 | 55 | PlaceOpenBraceEnable = $true 56 | PlaceOpenBraceOnSameLine = $true 57 | PlaceOpenBraceNewLineAfter = $true 58 | PlaceOpenBraceIgnoreOneLineBlock = $false 59 | 60 | PlaceCloseBraceEnable = $true 61 | PlaceCloseBraceNewLineAfter = $true 62 | PlaceCloseBraceIgnoreOneLineBlock = $false 63 | PlaceCloseBraceNoEmptyLineBefore = $true 64 | 65 | UseConsistentIndentationEnable = $true 66 | UseConsistentIndentationKind = 'space' 67 | UseConsistentIndentationPipelineIndentation = 'IncreaseIndentationAfterEveryPipeline' 68 | UseConsistentIndentationIndentationSize = 4 69 | 70 | UseConsistentWhitespaceEnable = $true 71 | UseConsistentWhitespaceCheckInnerBrace = $true 72 | UseConsistentWhitespaceCheckOpenBrace = $true 73 | UseConsistentWhitespaceCheckOpenParen = $true 74 | UseConsistentWhitespaceCheckOperator = $true 75 | UseConsistentWhitespaceCheckPipe = $true 76 | UseConsistentWhitespaceCheckSeparator = $true 77 | 78 | AlignAssignmentStatementEnable = $true 79 | AlignAssignmentStatementCheckHashtable = $true 80 | 81 | UseCorrectCasingEnable = $true 82 | } 83 | # format PSD1 and PSM1 files when merging into a single file 84 | # enable formatting is not required as Configuration is provided 85 | New-ConfigurationFormat -ApplyTo 'OnMergePSM1', 'OnMergePSD1' -Sort None @ConfigurationFormat 86 | # format PSD1 and PSM1 files within the module 87 | # enable formatting is required to make sure that formatting is applied (with default settings) 88 | New-ConfigurationFormat -ApplyTo 'DefaultPSD1', 'DefaultPSM1' -EnableFormatting -Sort None 89 | # when creating PSD1 use special style without comments and with only required parameters 90 | New-ConfigurationFormat -ApplyTo 'DefaultPSD1', 'OnMergePSD1' -PSD1Style 'Minimal' 91 | 92 | # configuration for documentation, at the same time it enables documentation processing 93 | New-ConfigurationDocumentation -Enable:$false -StartClean -UpdateWhenNew -PathReadme 'Docs\Readme.md' -Path 'Docs' 94 | 95 | New-ConfigurationImportModule -ImportSelf -ImportRequiredModules 96 | 97 | New-ConfigurationBuild -Enable:$true -SignModule:$true -DeleteTargetModuleBeforeBuild -MergeFunctionsFromApprovedModules -MergeModuleOnBuild -CertificateThumbprint '483292C9E317AA13B07BB7A96AE9D1A5ED9E7703' 98 | 99 | New-ConfigurationArtefact -Type Unpacked -Enable -Path "$PSScriptRoot\..\Artefacts\Unpacked" #-RequiredModulesPath "$PSScriptRoot\..\Artefacts\Modules" 100 | New-ConfigurationArtefact -Type Packed -Enable -Path "$PSScriptRoot\..\Artefacts\Packed" -IncludeTagName 101 | 102 | # global options for publishing to github/psgallery 103 | #New-ConfigurationPublish -Type PowerShellGallery -FilePath 'C:\Support\Important\PowerShellGalleryAPI.txt' -Enabled:$true 104 | #New-ConfigurationPublish -Type GitHub -FilePath 'C:\Support\Important\GitHubAPI.txt' -UserName 'EvotecIT' -Enabled:$true 105 | } 106 | -------------------------------------------------------------------------------- /CHANGELOG.MD: -------------------------------------------------------------------------------- 1 | ### PSWinDocumentation.O365HealthService Release History 2 | 3 | #### 1.0.4 - 2023.07.06 4 | - Fixes DateTime related issues 5 | - Improves DateTime conversion 6 | - Updates overall 7 | - Change of certificate which may require `Install-Module PSWinDocumentation.O365HealthService -Force -Vebose -SkipPublisherCheck` 8 | 9 | #### 1.0.3 - 31.01.2021 10 | - Brings back StartDate and EndDate for issues 11 | 12 | #### 1.0.2 - 31.01.2022 13 | - Fixes cross-platform timezone issue [#10](https://github.com/EvotecIT/PSWinDocumentation.O365HealthService/issues/10) - this time for real 14 | 15 | #### 1.0.1 - 31.01.2022 16 | - Fixes cross-platform timezone issue [#10](https://github.com/EvotecIT/PSWinDocumentation.O365HealthService/issues/10) 17 | 18 | #### 1.0.0 - 29.01.2022 19 | - Microsoft disabled the Health Service API. Migrated code to Graph API. 20 | - There are **breaking changes** on the output (aka a bit differently formatted information), less types, different columns, etc. 21 | - Check examples for more information. 22 | - Permission requirements changed 23 | 24 | ![https://evotec.xyz/wp-content/uploads/2022/01/img_61f59e2b000c3.png](https://evotec.xyz/wp-content/uploads/2022/01/img_61f59e2b000c3.png) 25 | 26 | #### 0.2.4. -13.12.2019 27 | - Enforces TLS 1.2 as it may be problematic otherwise. Hopefully doesn't break anything 28 | - Added parameter `TlsDefault` to `Get-Office365Health -TlsDefault` as a way to circumvent that new feature, just in case. Subject to removal later on 29 | #### 0.2.3 - 7.11.2019 30 | - Optimized module removing depedencies (PSSharedGoods) on release 31 | - It's still used during development 32 | #### 0.2.2 - 13.05.2019 33 | - Fix for mispelled extended word (sorry again..) 34 | #### 0.2.1 - 08.05.2019 35 | - Fix for mispelled extended word (sorry) 36 | #### 0.2.0 - 03.05.2019 37 | - Fix for date changes that Microsoft introduced 38 | #### 0.1.0 - 22.04.2019 39 | - First public release 40 | 41 | ![Image](https://evotec.xyz/wp-content/uploads/2019/05/img_5cd34ae647da9.png) -------------------------------------------------------------------------------- /Enums/Office365Health.ps1: -------------------------------------------------------------------------------- 1 | Add-Type -TypeDefinition @" 2 | using System; 3 | 4 | namespace PSWinDocumentation 5 | { 6 | [Flags] 7 | public enum Office365Health { 8 | All, 9 | Services, 10 | CurrentStatus, 11 | CurrentStatusExtended, 12 | MessageCenterInformation, 13 | MessageCenterInformationExtended, 14 | Incidents, 15 | IncidentsExtended, 16 | IncidentsUpdates 17 | } 18 | } 19 | "@ -------------------------------------------------------------------------------- /Examples/Example-Office365Status.ps1: -------------------------------------------------------------------------------- 1 | Import-Module PSWinDocumentation.O365HealthService -Force 2 | 3 | $ApplicationID = '' 4 | $ApplicationKey = '' 5 | $TenantDomain = 'evotec.pl' # CustomDomain (onmicrosoft.com won't work), alternatively you can use DirectoryID 6 | 7 | $O365 = Get-Office365Health -ApplicationID $ApplicationID -ApplicationKey $ApplicationKey -TenantDomain $TenantDomain 8 | $O365 -------------------------------------------------------------------------------- /Examples/Example-Office365StatusUsingDashimo.ps1: -------------------------------------------------------------------------------- 1 | Import-Module PSWinDocumentation.O365HealthService -Force 2 | Import-Module PSWriteHTML -Force 3 | 4 | $ApplicationID = '' 5 | $ApplicationKey = '' 6 | $TenantDomain = 'evotec.pl' # CustomDomain (onmicrosoft.com won't work), alternatively you can use DirectoryID 7 | 8 | $O365 = Get-Office365Health -ApplicationID $ApplicationID -ApplicationKey $ApplicationKey -TenantDomain $TenantDomain -Verbose 9 | 10 | Dashboard -FilePath $PSScriptRoot\Health.html { 11 | TabOption -BorderRadius 0px -BackgroundColorActive DimGrey 12 | SectionOption -BorderRadius 0px -HeaderBackGroundColor DimGrey 13 | TableOption -DataStore JavaScript -ArrayJoinString "; " -ArrayJoin -BoolAsString 14 | Tab -Name 'Services' { 15 | Section -Name 'Service List' { 16 | Table -DataTable $O365.Services -Filtering 17 | } 18 | } 19 | Tab -Name 'Current Status' { 20 | Section -Invisible { 21 | Section -Name 'Current Status' { 22 | Table -DataTable $O365.CurrentStatus { 23 | TableCondition -Name 'ServiceStatus' -Value 'serviceOperational' -BackgroundColor MintGreen -FailBackgroundColor Salmon 24 | } -Filtering 25 | } 26 | Section -Name 'Current Status Extended' { 27 | Table -DataTable $O365.CurrentStatusExtended { 28 | TableCondition -Name 'ServiceStatus' -Value 'serviceOperational' -BackgroundColor MintGreen -FailBackgroundColor Salmon 29 | } -Filtering 30 | } 31 | } 32 | } 33 | Tab -Name 'Message Center Information' { 34 | #Section -Invisible { 35 | Section -Name 'Message Center' { 36 | Table -DataTable $O365.MessageCenterInformation -Filtering 37 | } 38 | Section -Name 'Message Center Extended' { 39 | Table -DataTable $O365.MessageCenterInformationExtended -InvokeHTMLTags -Filtering 40 | } 41 | #} 42 | } 43 | Tab -Name 'Incidents' { 44 | Section -Invisible { 45 | Section -Name 'Incidents' { 46 | Table -DataTable $O365.Incidents -Filtering { 47 | TableCondition -Name 'IsResolved' -Value $true -BackgroundColor MintGreen -FailBackgroundColor Salmon -ComparisonType bool 48 | } 49 | } 50 | Section -Name 'Incidents Extended' { 51 | Table -DataTable $O365.IncidentsExtended -Filtering { 52 | TableCondition -Name 'IsResolved' -Value $true -BackgroundColor MintGreen -FailBackgroundColor Salmon -ComparisonType bool 53 | } 54 | } 55 | } 56 | Section -Name 'Incidents Messages' { 57 | Table -DataTable $O365.IncidentsUpdates -InvokeHTMLTags -Filtering 58 | } 59 | } 60 | } -Online -ShowHTML -------------------------------------------------------------------------------- /Examples/Health.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
Services
Current Status
Message Center Information
Incidents
Name
Name
Name
Name
Name
Name
Name
Name
876 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Evotec 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PSWinDocumentation.O365HealthService.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | AliasesToExport = @() 3 | Author = 'Przemyslaw Klys' 4 | CmdletsToExport = @() 5 | CompanyName = 'Evotec' 6 | CompatiblePSEditions = @('Desktop', 'Core') 7 | Copyright = '(c) 2011 - 2023 Przemyslaw Klys @ Evotec. All rights reserved.' 8 | Description = 'Office 365 Health Service' 9 | FunctionsToExport = 'Get-Office365Health' 10 | GUID = '5879b6ed-e0da-4815-ad68-d345253bfe54' 11 | ModuleVersion = '1.0.4' 12 | PowerShellVersion = '5.1' 13 | PrivateData = @{ 14 | PSData = @{ 15 | Tags = @('Windows', 'Office365', 'O365', 'PSWinDocumentation', 'HealthService', 'Linux', 'Osx') 16 | IconUri = 'https://evotec.xyz/wp-content/uploads/2018/10/PSWinDocumentation.png' 17 | ProjectUri = 'https://github.com/EvotecIT/PSWinDocumentation.O365HealthService' 18 | } 19 | } 20 | RequiredModules = @(@{ 21 | ModuleName = 'PSSharedGoods' 22 | ModuleVersion = '0.0.264' 23 | Guid = 'ee272aa8-baaa-4edf-9f45-b6d6f7d844fe' 24 | }, @{ 25 | ModuleName = 'Graphimo' 26 | ModuleVersion = '0.0.18' 27 | Guid = '48605140-a2a9-44f3-b682-3efc5cc9f2c1' 28 | }) 29 | RootModule = 'PSWinDocumentation.O365HealthService.psm1' 30 | } -------------------------------------------------------------------------------- /PSWinDocumentation.O365HealthService.psm1: -------------------------------------------------------------------------------- 1 | #Get public and private function definition files. 2 | $Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue -Recurse ) 3 | $Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue -Recurse ) 4 | $Classes = @( Get-ChildItem -Path $PSScriptRoot\Classes\*.ps1 -ErrorAction SilentlyContinue -Recurse ) 5 | $Enums = @( Get-ChildItem -Path $PSScriptRoot\Enums\*.ps1 -ErrorAction SilentlyContinue -Recurse ) 6 | 7 | $AssemblyFolders = Get-ChildItem -Path $PSScriptRoot\Lib -Directory -ErrorAction SilentlyContinue 8 | if ($AssemblyFolders.BaseName -contains 'Standard') { 9 | $Assembly = @( Get-ChildItem -Path $PSScriptRoot\Lib\Standard\*.dll -ErrorAction SilentlyContinue ) 10 | } else { 11 | if ($PSEdition -eq 'Core') { 12 | $Assembly = @( Get-ChildItem -Path $PSScriptRoot\Lib\Core\*.dll -ErrorAction SilentlyContinue ) 13 | } else { 14 | $Assembly = @( Get-ChildItem -Path $PSScriptRoot\Lib\Default\*.dll -ErrorAction SilentlyContinue ) 15 | } 16 | } 17 | $FoundErrors = @( 18 | Foreach ($Import in @($Assembly)) { 19 | try { 20 | Add-Type -Path $Import.Fullname -ErrorAction Stop 21 | } catch [System.Reflection.ReflectionTypeLoadException] { 22 | Write-Warning "Processing $($Import.Name) Exception: $($_.Exception.Message)" 23 | $LoaderExceptions = $($_.Exception.LoaderExceptions) | Sort-Object -Unique 24 | foreach ($E in $LoaderExceptions) { 25 | Write-Warning "Processing $($Import.Name) LoaderExceptions: $($E.Message)" 26 | } 27 | $true 28 | #Write-Error -Message "StackTrace: $($_.Exception.StackTrace)" 29 | } catch { 30 | Write-Warning "Processing $($Import.Name) Exception: $($_.Exception.Message)" 31 | $LoaderExceptions = $($_.Exception.LoaderExceptions) | Sort-Object -Unique 32 | foreach ($E in $LoaderExceptions) { 33 | Write-Warning "Processing $($Import.Name) LoaderExceptions: $($E.Message)" 34 | } 35 | $true 36 | #Write-Error -Message "StackTrace: $($_.Exception.StackTrace)" 37 | } 38 | } 39 | #Dot source the files 40 | Foreach ($Import in @($Private + $Public + $Classes + $Enums)) { 41 | Try { 42 | . $Import.Fullname 43 | } Catch { 44 | Write-Error -Message "Failed to import functions from $($import.Fullname): $_" 45 | $true 46 | } 47 | } 48 | ) 49 | 50 | if ($FoundErrors.Count -gt 0) { 51 | $ModuleName = (Get-ChildItem $PSScriptRoot\*.psd1).BaseName 52 | Write-Warning "Importing module $ModuleName failed. Fix errors before continuing." 53 | break 54 | } 55 | 56 | Export-ModuleMember -Function '*' -Alias '*' -------------------------------------------------------------------------------- /Private/Connect-O365ServiceHealth.ps1: -------------------------------------------------------------------------------- 1 | function Connect-O365ServiceHealth { 2 | [cmdletBinding(DefaultParameterSetName = 'ClearText')] 3 | param( 4 | [parameter(Mandatory, ParameterSetName = 'Encrypted')] 5 | [parameter(Mandatory, ParameterSetName = 'ClearText')][string][alias('ClientID')] $ApplicationID, 6 | [parameter(Mandatory, ParameterSetName = 'ClearText')][string][alias('ClientSecret')] $ApplicationKey, 7 | [parameter(Mandatory, ParameterSetName = 'Encrypted')][string][alias('ClientSecretEncrypted')] $ApplicationKeyEncrypted, 8 | [parameter(Mandatory, ParameterSetName = 'Credential')][PSCredential] $Credential, 9 | 10 | [parameter(Mandatory, ParameterSetName = 'Encrypted')] 11 | [parameter(Mandatory, ParameterSetName = 'ClearText')] 12 | [parameter(Mandatory, ParameterSetName = 'Credential')] 13 | [string] $TenantDomain 14 | ) 15 | 16 | $connectGraphSplat = @{ 17 | ApplicationID = $ApplicationID 18 | ApplicationKey = $ApplicationKey 19 | ApplicationKeyEncrypted = $ApplicationKeyEncrypted 20 | Credential = $Credential 21 | TenantDomain = $TenantDomain 22 | Resource = 'https://graph.microsoft.com/.default' 23 | } 24 | Remove-EmptyValue -Hashtable $connectGraphSplat 25 | Connect-Graphimo @connectGraphSplat 26 | } -------------------------------------------------------------------------------- /Private/ConvertFrom-UTCTime.ps1: -------------------------------------------------------------------------------- 1 | function ConvertFrom-UTCTime { 2 | [CmdLetbinding()] 3 | param( 4 | [Object] $Time, 5 | [switch] $ToLocalTime 6 | ) 7 | if ($null -eq $Script:TimeZoneBias) { 8 | try { 9 | $TimeZoneBias = (Get-TimeZone -ErrorAction Stop).BaseUtcOffset.TotalMinutes 10 | } catch { 11 | Write-Warning "ConvertFrom-UTCTime - couldn't get timezone. Please report on GitHub." 12 | $TimeZoneBias = 0 13 | } 14 | } else { 15 | $TimeZoneBias = $Script:TimeZoneBias 16 | } 17 | if ($Time -is [DateTime]) { 18 | $ConvertedTime = $Time 19 | } else { 20 | if ($null -eq $Time -or $Time -eq '') { 21 | return 22 | } else { 23 | #Write-Verbose -Message "ConvertFrom-UTCTime - Converting time: $Time" 24 | $NewTime = $Time -replace ', at', '' -replace ' by', '' -replace 'UTC', '' -replace ' at', '' 25 | $NewTIme = $NewTime -replace 'Monday,', '' -replace 'Tuesday,', '' -replace 'Wednesday,', '' -replace 'Thursday,', '' -replace 'Friday,', '' -replace 'Saturday,', '' -replace 'Sunday,', '' 26 | try { 27 | [DateTime] $ConvertedTime = [DateTime]::Parse($NewTime) 28 | } catch { 29 | Write-Warning "ConvertFrom-UTCTime - couldn't convert time $Time (after conversion $NewTime). Exception: $($_.Exception.Message). Skipping conversion..." 30 | return $Time 31 | } 32 | } 33 | } 34 | if ($ToLocal) { 35 | $ConvertedTime.AddMinutes($TimeZoneBias) 36 | } else { 37 | $ConvertedTime 38 | } 39 | } -------------------------------------------------------------------------------- /Private/Get-Office365ServiceHealthCurrentStatus.ps1: -------------------------------------------------------------------------------- 1 | function Get-Office365ServiceHealthCurrentStatus { 2 | [CmdLetbinding()] 3 | param( 4 | [System.Collections.IDictionary] $Authorization, 5 | [string] $TenantDomain, 6 | [switch] $ToLocalTime 7 | ) 8 | try { 9 | $CurrentStatus = Invoke-Graphimo -Uri "https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/healthOverviews?`$expand=issues" -Method GET -Headers $Authorization -FullUri 10 | } catch { 11 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 12 | Write-Warning -Message "Get-Office365ServiceHealthCurrentStatus - Error: $ErrorMessage" 13 | return 14 | } 15 | $Output = @{ } 16 | $Output.Simple = foreach ($Status in $CurrentStatus) { 17 | [PSCustomObject][ordered] @{ 18 | ID = $Status.ID 19 | Service = $Status.Service 20 | ServiceStatus = $Status.Status 21 | StatusTime = $Script:Today 22 | Incidents = ($Status.issues | Where-Object { $_.IsResolved -eq $false }).id 23 | } 24 | } 25 | 26 | $Output.Extended = foreach ($Status in $CurrentStatus) { 27 | [PSCustomObject][ordered] @{ 28 | ID = $Status.ID 29 | Service = $Status.Service 30 | ServiceStatus = $Status.Status 31 | StatusTime = $Script:Today 32 | Incidents = ($Status.issues | Where-Object { $_.IsResolved -eq $false }).id 33 | FeaturesAffected = ($Status.issues | Where-Object { $_.IsResolved -eq $false }).feature 34 | FeaturesAffectedGroup = ($Status.issues | Where-Object { $_.IsResolved -eq $false }).featureGroup 35 | } 36 | } 37 | return $Output 38 | } -------------------------------------------------------------------------------- /Private/Get-Office365ServiceHealthIssues.ps1: -------------------------------------------------------------------------------- 1 | function Get-Office365ServiceHealthIssues { 2 | [CmdLetbinding()] 3 | param( 4 | [System.Collections.IDictionary] $Authorization, 5 | [switch] $ToLocalTime 6 | ) 7 | try { 8 | $AllMessages = Invoke-Graphimo -Uri "https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/issues" -Method GET -Headers $Authorization -FullUri 9 | } catch { 10 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 11 | Write-Warning -Message "Get-Office365ServiceHealthIssues - Error: $ErrorMessage" 12 | return 13 | } 14 | $Output = @{ } 15 | $Output.Incidents = foreach ($Message in $AllMessages) { 16 | [PSCustomObject] @{ 17 | Id = $Message.Id 18 | Title = $Message.Title 19 | Impact = $Message.impactDescription 20 | IsResolved = $Message.IsResolved 21 | StartTime = ConvertFrom-UTCTime -Time $Message.startDateTime -ToLocalTime:$ToLocalTime.IsPresent 22 | EndTime = ConvertFrom-UTCTime -Time $Message.endDateTime -ToLocalTime:$ToLocalTime.IsPresent 23 | # HighImpact = $Message.highImpact 24 | Classification = $Message.classification 25 | Origin = $Message.origin 26 | Service = $Message.service 27 | LastUpdatedTime = ConvertFrom-UTCTime -Time $Message.lastModifiedDateTime -ToLocalTime:$ToLocalTime.IsPresent 28 | LastUpdatedDays = Convert-TimeToDays -StartTime $Message.lastModifiedDateTime -EndTime $Script:Today 29 | Status = $Message.status 30 | Feature = $Message.feature 31 | FeatureGroup = $Message.featureGroup 32 | NotifyInApp = ($Message.details | Where-Object { $_.Name -eq 'NotifyInApp' }).Value -eq $true 33 | UpdatesCount = $Message.posts.count 34 | } 35 | } 36 | $Output.IncidentsExtended = foreach ($Message in $AllMessages) { 37 | [PSCustomObject] @{ 38 | Id = $Message.Id 39 | Title = $Message.Title 40 | Impact = $Message.impactDescription 41 | IsResolved = $Message.IsResolved 42 | StartTime = ConvertFrom-UTCTime -Time $Message.startDateTime -ToLocalTime 43 | EndTime = ConvertFrom-UTCTime -Time $Message.endDateTime -ToLocalTime 44 | # HighImpact = $Message.highImpact 45 | Classification = $Message.classification 46 | Origin = $Message.origin 47 | Service = $Message.service 48 | LastUpdatedTime = ConvertFrom-UTCTime -Time $Message.lastModifiedDateTime -ToLocalTime:$ToLocalTime.IsPresent 49 | LastUpdatedDays = Convert-TimeToDays -StartTime $Message.lastModifiedDateTime -EndTime $Script:Today 50 | Status = $Message.status 51 | Feature = $Message.feature 52 | FeatureGroup = $Message.featureGroup 53 | NotifyInApp = ($Message.details | Where-Object { $_.Name -eq 'NotifyInApp' }).Value -eq $true 54 | UpdatesCount = $Message.posts.count 55 | Updates = $Message.Posts | ForEach-Object { 56 | $Object = [ordered] @{} 57 | foreach ($SubMessage in $_.description.content.Split("`n")) { 58 | if ($SubMessage -like 'Title: *') { 59 | $Object.Title = $SubMessage -replace 'Title: ', '' 60 | } elseif ($SubMessage -like 'User Impact: *') { 61 | $Object.UserImpact = $SubMessage -replace 'User Impact: ', '' 62 | } elseif ($SubMessage -like 'More info: *') { 63 | $Object.MoreInfo = $SubMessage -replace 'More info: ', '' 64 | } elseif ($SubMessage -like 'Current status: *') { 65 | $Object.CurrentStatus = $SubMessage -replace 'Current status: ', '' 66 | } elseif ($SubMessage -like 'Scope of impact: *') { 67 | $Object.ScopeOfImpact = $SubMessage -replace 'Scope of impact: ', '' 68 | } elseif ($SubMessage -like 'Start time: *') { 69 | $Time = $SubMessage -replace 'Start time: ', '' 70 | $Object.StartTime = ConvertFrom-UTCTime -Time $Time -ToLocalTime:$ToLocalTime 71 | } elseif ($SubMessage -like 'Preliminary root cause: *') { 72 | $Object.PreliminaryRootCause = $SubMessage -replace 'Preliminary root cause: ', '' 73 | } elseif ($SubMessage -like 'Root cause: *') { 74 | $Object.RootCause = $SubMessage -replace 'Root cause: ', '' 75 | } elseif ($SubMessage -like 'Next update by: *') { 76 | $Time = ($SubMessage -replace 'Next update by: ', '').Trim() 77 | $Object.NextUpdateBy = ConvertFrom-UTCTime -Time $Time -ToLocalTime:$ToLocalTime 78 | } elseif ($SubMessage -like 'Final status: *') { 79 | $Object.FinalStatus = ($SubMessage -replace 'Final status: ', '').Trim() 80 | } else { 81 | $Object.Other = $SubMessage.Trim() 82 | } 83 | } 84 | [PSCustomObject] @{ 85 | Id = $Message.Id 86 | Service = $Message.service 87 | Created = if ($_.createdDateTime) { [datetime]::Parse($_.createdDateTime) } else { $null } 88 | Type = $_.postType 89 | Title = $Object.Title 90 | UserImpact = $Object.UserImpact 91 | MoreInfo = $Object.MoreInfo 92 | CurrentStatus = $Object.CurrentStatus 93 | ScopeOfImpact = $Object.ScopeOfImpact 94 | StartTime = $Object.StartTime 95 | PreliminaryRootCause = $Object.PreliminaryRootCause 96 | RootCause = $Object.RootCause 97 | FinalStatus = $Object.FinalStatus 98 | NextUpdateBy = $Object.NextUpdateBy 99 | Other = $Object.Other 100 | } 101 | } 102 | } 103 | } 104 | $Output.IncidentsUpdates = foreach ($Message in $Output.IncidentsExtended) { 105 | foreach ($Post in $Message.Updates) { 106 | $Post 107 | } 108 | } 109 | $Output 110 | } -------------------------------------------------------------------------------- /Private/Get-Office365ServiceHealthMessages.ps1: -------------------------------------------------------------------------------- 1 | function Get-Office365ServiceHealthMessages { 2 | [CmdLetbinding()] 3 | param( 4 | [System.Collections.IDictionary] $Authorization 5 | ) 6 | try { 7 | $AllMessages = Invoke-Graphimo -Uri "https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/messages" -Method GET -Headers $Authorization -FullUri 8 | } catch { 9 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 10 | Write-Warning -Message "Get-Office365ServiceHealthMessages - Error: $ErrorMessage" 11 | return 12 | } 13 | $Output = @{ } 14 | $Output.MessageCenterInformation = foreach ($Message in $AllMessages) { 15 | $ActionRequiredDays = Convert-TimeToDays -StartTime $Message.actionRequiredByDateTime -EndTime $Script:Today 16 | [PSCustomObject] @{ 17 | Id = $Message.Id 18 | Title = $Message.Title 19 | Service = $Message.services 20 | LastUpdatedTime = if ($Message.lastModifiedDateTime) { [DateTime]::Parse($Message.lastModifiedDateTime) } else { $null } 21 | LastUpdatedDays = Convert-TimeToDays -StartTime $Message.lastModifiedDateTime -EndTime $Script:Today 22 | ActionRequiredByDateTime = if ( $Message.actionRequiredByDateTime) { [DateTime]::Parse($Message.actionRequiredByDateTime) } else { $null } 23 | ActionRequiredDays = if ($ActionRequiredDays -eq 0) { $null } else { - $ActionRequiredDays } 24 | Tags = $Message.Tags 25 | RoadmapId = ($Message.details | Where-Object { $_.name -eq 'roadmapids' }).Value 26 | Category = $Message.category 27 | } 28 | } 29 | $Output.MessageCenterInformationExtended = foreach ($Message in $AllMessages) { 30 | $ActionRequiredDays = Convert-TimeToDays -StartTime $Message.actionRequiredByDateTime -EndTime $Script:Today 31 | [PSCustomObject] @{ 32 | Id = $Message.Id 33 | Title = $Message.Title 34 | Service = $Message.services 35 | LastUpdatedTime = if ($Message.lastModifiedDateTime) { [DateTime]::Parse($Message.lastModifiedDateTime) } else { $null } 36 | LastUpdatedDays = Convert-TimeToDays -StartTime $Message.lastModifiedDateTime -EndTime $Script:Today 37 | ActionRequiredByDateTime = if ($Message.actionRequiredByDateTime) { [DateTime]::Parse($Message.actionRequiredByDateTime) } else { $null } 38 | ActionRequiredDays = if ($ActionRequiredDays -eq 0) { $null } else { - $ActionRequiredDays } 39 | Tags = $Message.Tags 40 | Bloglink = ($Message.details | Where-Object { $_.name -eq 'bloglink' }).Value 41 | RoadmapId = ($Message.details | Where-Object { $_.name -eq 'roadmapids' }).Value 42 | RoadmapIdLinks = ($Message.details | Where-Object { $_.name -eq 'roadmapids' }).Value | ForEach-Object { 43 | "https://www.microsoft.com/en-us/microsoft-365/roadmap?filters=&searchterms=$_" 44 | } 45 | Category = $Message.category 46 | IsMajorChange = $Message.isMajorChange 47 | Severity = $Message.Severity 48 | StartTime = If ($Message.startDateTime) { [DateTime]::Parse($Message.startDateTime) } else { $null } 49 | EndTime = if ($Message.endDateTime) { [DateTime]::Parse($Message.endDateTime) } else { $null } 50 | Message = $Message.body.content 51 | } 52 | } 53 | $Output 54 | } -------------------------------------------------------------------------------- /Private/Get-Office365ServiceHealthServices.ps1: -------------------------------------------------------------------------------- 1 | function Get-Office365ServiceHealthServices { 2 | [CmdLetbinding()] 3 | param( 4 | [System.Collections.IDictionary] $Authorization, 5 | [string] $TenantDomain 6 | ) 7 | try { 8 | $Services = Invoke-Graphimo -Uri "https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/healthOverviews" -Method GET -Headers $Authorization -FullUri 9 | } catch { 10 | $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " 11 | Write-Warning -Message "Get-Office365ServiceHealthServices - Error: $ErrorMessage" 12 | return 13 | } 14 | $Output = @{ } 15 | $Output.Simple = foreach ($Service in $Services) { 16 | [PSCustomObject][ordered] @{ 17 | ID = $Service.ID 18 | Service = $Service.service 19 | } 20 | } 21 | return $Output 22 | } 23 | -------------------------------------------------------------------------------- /Public/Get-Office365Health.ps1: -------------------------------------------------------------------------------- 1 | function Get-Office365Health { 2 | [CmdLetbinding()] 3 | param( 4 | [string][alias('ClientID')] $ApplicationID, 5 | [string][alias('ClientSecret')] $ApplicationKey, 6 | [string] $TenantDomain, 7 | [PSWinDocumentation.Office365Health[]] $TypesRequired = [PSWinDocumentation.Office365Health]::All, 8 | [switch] $ToLocalTime 9 | ) 10 | $StartTime = Start-TimeLog 11 | try { 12 | $Script:TimeZoneBias = (Get-TimeZone -ErrorAction Stop).BaseUtcOffset.TotalMinutes 13 | } catch { 14 | Write-Warning "ConvertFrom-UTCTime - couldn't get timezone. Please report on GitHub." 15 | $Script:TimeZoneBias = 0 16 | } 17 | $Script:Today = Get-Date 18 | if ($null -eq $TypesRequired -or $TypesRequired -contains [PSWinDocumentation.Office365Health]::All) { 19 | $TypesRequired = Get-Types -Types ([PSWinDocumentation.Office365Health]) 20 | } 21 | $Authorization = Connect-O365ServiceHealth -ApplicationID $ApplicationID -ApplicationKey $ApplicationKey -TenantDomain $TenantDomain 22 | if ($null -eq $Authorization) { 23 | return 24 | } 25 | if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::Services)) { 26 | $Services = Get-Office365ServiceHealthServices -Authorization $Authorization -TenantDomain $TenantDomain 27 | } 28 | if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @( 29 | [PSWinDocumentation.Office365Health]::CurrentStatus, 30 | [PSWinDocumentation.Office365Health]::CurrentStatusExtended 31 | )) { 32 | $CurrentStatus = Get-Office365ServiceHealthCurrentStatus -Authorization $Authorization -TenantDomain $TenantDomain -ToLocalTime:$ToLocalTime 33 | } 34 | if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @( 35 | [PSWinDocumentation.Office365Health]::Incidents, 36 | [PSWinDocumentation.Office365Health]::IncidentsExtended 37 | [PSWinDocumentation.Office365Health]::IncidentsUpdates 38 | )) { 39 | $Issues = Get-Office365ServiceHealthIssues -Authorization $Authorization -ToLocalTime:$ToLocalTime 40 | } 41 | if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @( 42 | [PSWinDocumentation.Office365Health]::MessageCenterInformation, 43 | [PSWinDocumentation.Office365Health]::MessageCenterInformationExtended 44 | )) { 45 | $Messages = Get-Office365ServiceHealthMessages -Authorization $Authorization 46 | } 47 | $Output = [ordered] @{} 48 | if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::Services)) { 49 | $Output.Services = $Services.Simple 50 | } 51 | if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::CurrentStatus)) { 52 | $Output.CurrentStatus = $CurrentStatus.Simple 53 | } 54 | if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::CurrentStatusExtended)) { 55 | $Output.CurrentStatusExtended = $CurrentStatus.Extended 56 | } 57 | if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::MessageCenterInformation)) { 58 | $Output.MessageCenterInformation = $Messages.MessageCenterInformation | Sort-Object -Property LastUpdatedTime -Descending 59 | } 60 | if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::MessageCenterInformationExtended)) { 61 | $Output.MessageCenterInformationExtended = $Messages.MessageCenterInformationExtended | Sort-Object -Property LastUpdatedTime -Descending 62 | } 63 | if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::Incidents)) { 64 | $Output.Incidents = $Issues.Incidents | Sort-Object -Property LastUpdatedTime -Descending 65 | } 66 | if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::IncidentsExtended)) { 67 | $Output.IncidentsExtended = $Issues.IncidentsExtended | Sort-Object -Property LastUpdatedTime -Descending 68 | } 69 | if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded @([PSWinDocumentation.Office365Health]::IncidentsUpdates)) { 70 | $Output.IncidentsUpdates = $Issues.IncidentsUpdates | Sort-Object -Property LastUpdatedTime -Descending 71 | } 72 | $EndTime = Stop-TimeLog -Time $StartTime -Option OneLiner 73 | Write-Verbose "Get-Office365Health - Time to process: $EndTime" 74 | return $Output 75 | } -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | 
2 | 3 |

4 | 5 | 6 | 7 |

8 | 9 |

10 | 11 | 12 | 13 | 14 |

15 | 16 |

17 | 18 | 19 | 20 |

21 | 22 |
23 | 24 | # PSWinDocumentation.O365HealthService - PowerShell Module 25 | 26 | `PSWinDocumentation.O365HealthService` is a Powershell module that has a single goal of getting Office 365 Health Status 27 | 28 | ## Overview 29 | 30 | - How to/What it really use and how you can use it: https://evotec.xyz/powershell-way-to-get-all-information-about-office-365-service-health/ 31 | - Step by Step to Get App ID and App Key: https://evotec.xyz/preparing-azure-app-registrations-permissions-for-office-365-health-service/ 32 | 33 | ### Required Permissions 34 | 35 | Please not that Microsoft deprecates the old way of accessing Service Health API. Since version 1.0+ you need to modify permissions for it to work properly. 36 | 37 | ![https://evotec.xyz/wp-content/uploads/2022/01/img_61f59e2b000c3.png](https://evotec.xyz/wp-content/uploads/2022/01/img_61f59e2b000c3.png) 38 | 39 | ### Install 40 | 41 | ```powershell 42 | Install-Module PSWinDocumentation.O365HealthService -Force 43 | ``` 44 | 45 | 46 | ### Example 1 47 | 48 | Here's a live demo generated using Dashimo: https://evotec.xyz/wp-content/uploads/2019/05/Health.html 49 | 50 | ```powershell 51 | Import-Module PSWinDocumentation.O365HealthService -Force 52 | Import-Module PSWriteHTML -Force 53 | 54 | $ApplicationID = '' 55 | $ApplicationKey = '' 56 | $TenantDomain = 'evotec.pl' # CustomDomain (onmicrosoft.com won't work), alternatively you can use DirectoryID 57 | 58 | $O365 = Get-Office365Health -ApplicationID $ApplicationID -ApplicationKey $ApplicationKey -TenantDomain $TenantDomain -Verbose 59 | 60 | Dashboard -FilePath $PSScriptRoot\Health.html { 61 | TabOption -BorderRadius 0px -BackgroundColorActive DimGrey 62 | SectionOption -BorderRadius 0px -HeaderBackGroundColor DimGrey 63 | TableOption -DataStore JavaScript -ArrayJoinString "; " -ArrayJoin -BoolAsString 64 | Tab -Name 'Services' { 65 | Section -Name 'Service List' { 66 | Table -DataTable $O365.Services -Filtering 67 | } 68 | } 69 | Tab -Name 'Current Status' { 70 | Section -Invisible { 71 | Section -Name 'Current Status' { 72 | Table -DataTable $O365.CurrentStatus { 73 | TableCondition -Name 'ServiceStatus' -Value 'serviceOperational' -BackgroundColor MintGreen -FailBackgroundColor Salmon 74 | } -Filtering 75 | } 76 | Section -Name 'Current Status Extended' { 77 | Table -DataTable $O365.CurrentStatusExtended { 78 | TableCondition -Name 'ServiceStatus' -Value 'serviceOperational' -BackgroundColor MintGreen -FailBackgroundColor Salmon 79 | } -Filtering 80 | } 81 | } 82 | } 83 | Tab -Name 'Message Center Information' { 84 | #Section -Invisible { 85 | Section -Name 'Message Center' { 86 | Table -DataTable $O365.MessageCenterInformation -Filtering 87 | } 88 | Section -Name 'Message Center Extended' { 89 | Table -DataTable $O365.MessageCenterInformationExtended -InvokeHTMLTags -Filtering 90 | } 91 | #} 92 | } 93 | Tab -Name 'Incidents' { 94 | Section -Invisible { 95 | Section -Name 'Incidents' { 96 | Table -DataTable $O365.Incidents -Filtering { 97 | TableCondition -Name 'IsResolved' -Value $true -BackgroundColor MintGreen -FailBackgroundColor Salmon -ComparisonType bool 98 | } 99 | } 100 | Section -Name 'Incidents Extended' { 101 | Table -DataTable $O365.IncidentsExtended -Filtering { 102 | TableCondition -Name 'IsResolved' -Value $true -BackgroundColor MintGreen -FailBackgroundColor Salmon -ComparisonType bool 103 | } 104 | } 105 | } 106 | Section -Name 'Incidents Messages' { 107 | Table -DataTable $O365.IncidentsUpdates -InvokeHTMLTags -Filtering 108 | } 109 | } 110 | } -Online -ShowHTML 111 | ``` 112 | 113 | ### Example 2 114 | 115 | ``` PowerShell 116 | Import-Module PSWinDocumentation.O365HealthService -Force 117 | 118 | $ApplicationID = '' 119 | $ApplicationKey = '' 120 | $TenantDomain = 'evotec.pl' # CustomDomain (onmicrosoft.com won't work), alternatively you can use DirectoryID 121 | 122 | $O365 = Get-Office365Health -ApplicationID $ApplicationID -ApplicationKey $ApplicationKey -TenantDomain $TenantDomain -Verbose 123 | $O365.CurrentStatus | Format-Table -AutoSize 124 | 125 | ``` 126 | 127 | Output: 128 | 129 | ``` 130 | Service ServiceStatus StatusTime IncidentIds 131 | ------- ------------- ---------- ----------- 132 | Exchange Online Restoring service 21.04.2019 16:54:19 EX177902 133 | Microsoft Kaizala Normal service 21.04.2019 16:54:19 134 | Skype for Business Service degradation 21.04.2019 16:54:19 LY177449 135 | Microsoft Teams Normal service 21.04.2019 16:54:19 136 | Mobile Device Management for Office 365 Normal service 21.04.2019 16:54:19 137 | Office Online Normal service 21.04.2019 16:54:19 138 | OneDrive for Business Normal service 21.04.2019 16:54:19 139 | Identity Service Normal service 21.04.2019 16:54:19 140 | Office 365 Portal Normal service 21.04.2019 16:54:19 141 | Planner Normal service 21.04.2019 16:54:19 142 | SharePoint Online Normal service 21.04.2019 16:54:19 143 | Microsoft StaffHub Normal service 21.04.2019 16:54:19 144 | Sway Normal service 21.04.2019 16:54:19 145 | Yammer Enterprise Normal service 21.04.2019 16:54:19 146 | ``` 147 | 148 | ### Example 3 149 | 150 | 151 | ``` PowerShell 152 | Import-Module PSWinDocumentation.O365HealthService -Force 153 | 154 | $ApplicationID = '' 155 | $ApplicationKey = '' 156 | $TenantDomain = 'evotec.pl' # CustomDomain (onmicrosoft.com won't work), alternatively you can use DirectoryID 157 | 158 | $O365 = Get-Office365Health -ApplicationID $ApplicationID -ApplicationKey $ApplicationKey -TenantDomain $TenantDomain -Verbose 159 | $O365.CurrentStatus | Format-Table -AutoSize 160 | 161 | ``` 162 | 163 | Output: 164 | 165 | ``` 166 | 167 | ID Service ServiceStatus StatusTime Incidents 168 | -- ------- ------------- ---------- --------- 169 | Exchange Exchange Online serviceDegradation 29.01.2022 21:14:47 {EX316072, EX316697} 170 | OrgLiveID Identity Service serviceOperational 29.01.2022 21:14:47 171 | OSDPPlatform Microsoft 365 suite serviceOperational 29.01.2022 21:14:47 172 | Lync Skype for Business serviceOperational 29.01.2022 21:14:47 173 | SharePoint SharePoint Online serviceOperational 29.01.2022 21:14:47 174 | DynamicsCRM Dynamics 365 Apps serviceOperational 29.01.2022 21:14:47 175 | RMS Azure Information Protection serviceOperational 29.01.2022 21:14:47 176 | yammer Yammer Enterprise serviceOperational 29.01.2022 21:14:47 177 | MobileDeviceManagement Mobile Device Management for Office 365 serviceOperational 29.01.2022 21:14:47 178 | Planner Planner serviceOperational 29.01.2022 21:14:47 179 | SwayEnterprise Sway serviceOperational 29.01.2022 21:14:47 180 | PowerBIcom Power BI serviceOperational 29.01.2022 21:14:47 181 | Intune Microsoft Intune serviceOperational 29.01.2022 21:14:47 182 | OneDriveForBusiness OneDrive for Business serviceOperational 29.01.2022 21:14:47 183 | microsoftteams Microsoft Teams serviceOperational 29.01.2022 21:14:47 184 | StaffHub Microsoft StaffHub serviceOperational 29.01.2022 21:14:47 185 | kaizalamessagingservices Microsoft Kaizala serviceOperational 29.01.2022 21:14:47 186 | Bookings Microsoft Bookings serviceOperational 29.01.2022 21:14:47 187 | officeonline Office for the web serviceOperational 29.01.2022 21:14:47 188 | O365Client Microsoft 365 Apps serviceOperational 29.01.2022 21:14:47 189 | PowerAppsM365 Power Apps in Microsoft 365 serviceOperational 29.01.2022 21:14:47 190 | MicrosoftFlow Microsoft Power Automate serviceOperational 29.01.2022 21:14:47 191 | MicrosoftFlowM365 Microsoft Power Automate in Microsoft 365 serviceOperational 29.01.2022 21:14:47 192 | Forms Microsoft Forms serviceOperational 29.01.2022 21:14:47 193 | Microsoft365Defender Microsoft 365 Defender serviceOperational 29.01.2022 21:14:47 194 | Stream Microsoft Stream serviceOperational 29.01.2022 21:14:47 195 | Viva Microsoft Viva serviceOperational 29.01.2022 21:14:47 196 | cloudappsecurity Microsoft Defender for Cloud Apps serviceOperational 29.01.2022 21:14:47 197 | ``` --------------------------------------------------------------------------------