M365ServiceHealth.psm1
################################################################################# # M365ServiceHealh for PowerShell Console # Andrés Gorzelany @andresgorzelany # Requires AzureAD Application with this Application Permisssion: # - ServiceHealth.Read.All # V0.0.1 - Initial Version - Andrés Gorzelany # V0.0.2 - Code Rewrite - Andres Bohren @andresbohren ################################################################################# #Requires -Modules MSAL.PS ################################################################################# # Public Function Connect-M365ServiceHealth ################################################################################# Function Connect-M365ServiceHealth { <# .SYNOPSIS Connect to the M365 Service Communication API and get the AccessToken to Query the Service Communications API .DESCRIPTION Connect to the M365 Service Communication API and get the AccessToken to Query the Service Communications API .PARAMETER TenantId The Name of the Tenant .PARAMETER ApplicationId The Application ID .PARAMETER ClientSecret The Client Secret .PARAMETER CertificateThumbprint The Thumbprint of your Certificate .EXAMPLE Connect-M365ServiceHealth Connect-M365ServiceHealth -TenantId <Tenant.onmicrosoft.com> -ApplicationId <AppID> -ClientSecret <ClientSecret> Connect-M365ServiceHealth -TenantId <Tenant.onmicrosoft.com> -ApplicationId <AppID> -CertificateThumbprint <CertificateThumbprint> .LINK #> <# #AzureAD Connect-AzureAD -ApplicationId $AppID -CertificateThumbprint $CertificateThumbprint -TenantId $TenantId #ExchangeOnline Connect-ExchangeOnline -AppID $AppID -CertificateThumbprint $CertificateThumbprint -Organization $TenantId #MicrosoftTeams Connect-MicrosoftTeams -ApplicationId $AppID -CertificateThumbprint $CertificateThumbprint -TenantId $TenantId I guess we should use similar Parameters #> Param( [Parameter(Mandatory = $false)][String]$TenantId, [Parameter(Mandatory = $false)][String]$ApplicationId, [Parameter(Mandatory = $false)][String]$ClientSecret, [Parameter(Mandatory = $false)][String]$CertificateThumbprint ) Process { #Write-Host "DEBUG: TenantID: $TenantID" #Write-Host "DEBUG: ApplicationID: $ApplicationID" #Write-Host "DEBUG: ClientSecret: $ClientSecret" #Write-Host "DEBUG: CertificateThumbprint: $CertificateThumbprint" #Scope is always Microsoft Graph $Scope = "https://graph.microsoft.com/.default" <# #If ($TenantId -eq $NULL -and $ApplicationId -eq $NULL -AND $ClientSecret -eq $NULL -and $CertificateThumbprint -eq $NULL) If ($TenantId -eq "" -and $ApplicationId -eq "" -AND $ClientSecret -eq "" -and $CertificateThumbprint -eq "") { ############################################################################### #Interactive (authorization code flow) ############################################################################### Write-Host "DEBUG: SELECT > Interactive" $connectionDetails = @{ 'TenantId' = $TenantId 'ClientId' = $ApplicationId 'Scope' = $Scope 'Interactive' = $true } $Token = Get-MsalToken @connectionDetails $Global:AccessToken = $Token.AccessToken #DEBUG $Global:AccessToken } #> If ($TenantId -ne "" -and $ApplicationId -ne "" -and $ClientSecret -ne "" ) { ############################################################################### #Client Secret ############################################################################### Write-Host "DEBUG: SELECT > Client Secret" $ClientSecretSecure = ConvertTo-SecureString $ClientSecret -AsPlainText -Force $connectionDetails = @{ 'TenantId' = $TenantId 'ClientId' = $ApplicationId 'ClientSecret' = $ClientSecretSecure 'Scope' = $Scope } $Token = Get-MsalToken @connectionDetails $Global:AccessToken = $Token.AccessToken #DEBUG #$Global:AccessToken } If ($TenantId -ne "" -and $ApplicationId -ne "" -and $CertificateThumbprint -ne "") { ############################################################################### #Certificate ############################################################################### Write-Host "DEBUG: SELECT > Certificate" $ClientCertificate = Get-Item Cert:\CurrentUser\My\$CertificateThumbprint $connectionDetails = @{ 'TenantId' = $TenantId 'ClientId' = $ApplicationId 'ClientCertificate' = $ClientCertificate 'Scope' = $Scope } $Token = Get-MsalToken @connectionDetails $Global:AccessToken = $Token.AccessToken #DEBUG #$Global:AccessToken } } } ################################################################################# # Public Function Connect-M365ServiceHealth ################################################################################# Function Disconnect-M365ServiceHealth { <# .SYNOPSIS Disconnect to the M365 Service Communication API and clear the AccessToken .DESCRIPTION Disconnect to the M365 Service Communication API and clear the AccessToken .EXAMPLE Disconnect-M365ServiceHealth #> #Clear Tokens Write-Host "Clear Access Token and TokenCache" Clear-MsalTokenCache #Clear Global Variable $Global:AccessToken = $null } ################################################################################# # Public Function Get-M365ServiceHealthIssues ################################################################################# Function Get-M365ServiceHealthIssues { <# .SYNOPSIS Get Service Healh Issues for a Specific Service .DESCRIPTION Get Service Healh Issues for a Specific Service .PARAMETER ServiceName The ServiceName you want to Query .EXAMPLE Get-M365ServiceHealthIssues -ServiceName <ServiceName> Get-M365ServiceHealthIssues -ServiceName "Exchange Online" #> [CmdletBinding()] Param( [Parameter(Position = 0, Mandatory = $true)][String]$ServiceName ) Process { if($Global:AccessToken -eq $Null ){ Write-Host "Please run Connect-M365ServiceHealth, Tenant parameters not set." break } $apiUrlPart1 = 'https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/healthOverviews/' $apiUrlPart2 = '?$expand=issues' $apiUrl = $apiUrlPart1 + $ServiceName + $apiUrlPart2 $Data = Invoke-RestMethod -Headers @{Authorization = "Bearer $Global:AccessToken"} -Uri $apiUrl -Method Get $Data.issues | Where-Object {$_.IsResolved -ne 'True'} | Format-List id,featureGroup,title, lastModifiedDateTime } } ################################################################################# # Public Function Get-M365ServiceHealth ################################################################################# Function Get-M365ServiceHealth { [CmdletBinding()] Param( [Parameter(Position = 0, Mandatory = $false)][String]$Refresh = 60 ) Process { if($Global:AccessToken -eq $NULL){ Write-Host "Please run Connect-M365ServiceHealth, Tenant parameters not set." break } $processBeginTime=Get-Date $apiUrl = 'https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/healthOverviews' while($true){ $Data = Invoke-RestMethod -Headers @{Authorization = "Bearer $Global:AccessToken"} -Uri $apiUrl -Method Get $services = @() foreach ($entry in $data.value){ $obj = New-Object -TypeName PSObject $obj | Add-Member -MemberType NoteProperty -Name Service -value $entry.service $obj | Add-Member -MemberType NoteProperty -Name Status -value $entry.Status $services+=$obj } $services | Format-Table Service, @{ Label = "Status" Expression = { switch($_.status) { 'restoringService' { $color="96";break} 'serviceOperational' {$color="92"; break} 'serviceDegradation' {$color="41"; break} default { $color = "0" } } $e = [char]27 "$e[${color}m$($_.status)${e}[0m" } } $now=Get-Date Write-Host "Last updated $now" $now=$now.AddSeconds($refresh) Write-Host "Refreshing at $now" Start-Sleep -Seconds $Refresh Clear-Host #if(((get-date)-$processBeginTime).TotalMinutes -gt 55){ # $access_token=Get-M365ServiceHealthToken -ClientId $Global:M365ServiceHealthClientId -clientSecret $Global:M365ServiceHealthClientSecret -TenantName $Global:M365ServiceHealthTenantName # } } } } ################################################################################# # Main Script ################################################################################# Import-Module MSAL.PS #$Global:$AccessToken=$null #New-Alias -Name "Initialize-M365ServiceHealth" -Value "Connect-M365ServiceHealth" -Scope "Script" -PassThru |