Statusimo.psm1
function Get-FileName { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Extension Parameter description .PARAMETER Temporary Parameter description .PARAMETER TemporaryFileOnly Parameter description .EXAMPLE Get-FileName -Temporary Output: 3ymsxvav.tmp .EXAMPLE Get-FileName -Temporary Output: C:\Users\pklys\AppData\Local\Temp\tmpD74C.tmp .EXAMPLE Get-FileName -Temporary -Extension 'xlsx' Output: C:\Users\pklys\AppData\Local\Temp\tmp45B6.xlsx .NOTES General notes #> [CmdletBinding()] param([string] $Extension = 'tmp', [switch] $Temporary, [switch] $TemporaryFileOnly) if ($Temporary) { return "$($([System.IO.Path]::GetTempFileName()).Replace('.tmp','')).$Extension" } if ($TemporaryFileOnly) { return "$($([System.IO.Path]::GetRandomFileName()).Split('.')[0]).$Extension" } } function ConvertFrom-Color { [alias('Convert-FromColor')] [CmdletBinding()] param ([ValidateScript( { if ($($_ -in $Script:RGBColors.Keys -or $_ -match "^#([A-Fa-f0-9]{6})$" -or $_ -eq "") -eq $false) { throw "The Input value is not a valid colorname nor an valid color hex code." } else { $true } })] [alias('Colors')][string[]] $Color, [switch] $AsDecimal) $Colors = foreach ($C in $Color) { $Value = $Script:RGBColors."$C" if ($C -match "^#([A-Fa-f0-9]{6})$") { return $C } if ($null -eq $Value) { return } $HexValue = Convert-Color -RGB $Value Write-Verbose "Convert-FromColor - Color Name: $C Value: $Value HexValue: $HexValue" if ($AsDecimal) { [Convert]::ToInt64($HexValue, 16) } else { "#$($HexValue)" } } $Colors } function Convert-Color { <# .Synopsis This color converter gives you the hexadecimal values of your RGB colors and vice versa (RGB to HEX) .Description This color converter gives you the hexadecimal values of your RGB colors and vice versa (RGB to HEX). Use it to convert your colors and prepare your graphics and HTML web pages. .Parameter RBG Enter the Red Green Blue value comma separated. Red: 51 Green: 51 Blue: 204 for example needs to be entered as 51,51,204 .Parameter HEX Enter the Hex value to be converted. Do not use the '#' symbol. (Ex: 3333CC converts to Red: 51 Green: 51 Blue: 204) .Example .\convert-color -hex FFFFFF Converts hex value FFFFFF to RGB .Example .\convert-color -RGB 123,200,255 Converts Red = 123 Green = 200 Blue = 255 to Hex value #> param([Parameter(ParameterSetName = "RGB", Position = 0)] [ValidateScript( { $_ -match '^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$' })] $RGB, [Parameter(ParameterSetName = "HEX", Position = 0)] [ValidateScript( { $_ -match '[A-Fa-f0-9]{6}' })] [string] $HEX) switch ($PsCmdlet.ParameterSetName) { "RGB" { if ($null -eq $RGB[2]) { Write-Error "Value missing. Please enter all three values seperated by comma." } $red = [convert]::Tostring($RGB[0], 16) $green = [convert]::Tostring($RGB[1], 16) $blue = [convert]::Tostring($RGB[2], 16) if ($red.Length -eq 1) { $red = '0' + $red } if ($green.Length -eq 1) { $green = '0' + $green } if ($blue.Length -eq 1) { $blue = '0' + $blue } Write-Output $red$green$blue } "HEX" { $red = $HEX.Remove(2, 4) $Green = $HEX.Remove(4, 2) $Green = $Green.remove(0, 2) $Blue = $hex.Remove(0, 4) $Red = [convert]::ToInt32($red, 16) $Green = [convert]::ToInt32($green, 16) $Blue = [convert]::ToInt32($blue, 16) Write-Output $red, $Green, $blue } } } function Get-StatusimoData { [cmdletbinding()] param( [string] $FolderPath ) if ($FolderPath -ne '' -and (Test-Path -LiteralPath $FolderPath)) { $Files = Get-ChildItem -LiteralPath $FolderPath foreach ($File in $Files) { $Output = Get-Content -LiteralPath $File.FullName | ConvertFrom-Json $TimeZoneBias = (Get-CimInstance -ClassName Win32_TimeZone).Bias $Output.PSObject.Properties | Where-Object { $_.Name -like 'Date*' } | ForEach-Object { if ($_.Value -is [DateTime]) { $Output.($_.Name) = $_.Value.AddMinutes($TimeZoneBias) } } Add-Member -InputObject $Output -Name 'FullName' -Value $File.FullName -MemberType NoteProperty -Force $Output } } } function New-StatusimoEvent { [alias('New-StatusimoIncident')] [cmdletbinding()] param( [DateTime] $Date = (Get-Date), [string] $Service, [ValidateSet('Operational', 'Partial Degradation', 'Down')][string] $Status, [string] $Title, [string] $Overview, [alias('IncidentsPath', 'EventsPath')][string] $FolderPath ) $FileNameService = $Service -replace '[^a-zA-Z]', '_' $FileNameData = $Date.ToString("yyyy-MM-dd_HH_MM_ss") $FileNameEnd = Get-FileName -Extension 'json' -TemporaryFileOnly $FileName = $FileNameService + '_' + $FileNameData + '_' + $FileNameEnd $FilePath = [IO.Path]::Combine($FolderPath, $FileName) if ($Maintenance) { } else { $Incident = [ordered] @{ Date = $Date Service = $Service Status = $Status Title = $Title Overview = $Overview } $Output = $Incident | ConvertTo-Json $Output | Set-Content -LiteralPath $FilePath } } function New-StatusimoMaintenance { [cmdletbinding()] param( [DateTime] $DateStart, [DateTime] $DateEnd, [string] $Service, [ValidateSet('Operational', 'Partial Degradation', 'Down')][string] $Status, [string] $Title, [string] $Overview, [string] $FolderPath ) $FileNameService = $Service -replace '[^a-zA-Z]', '_' $FileNameData = $DateStart.ToString("yyyy-MM-dd_HH_MM_ss") $FileNameEnd = Get-FileName -Extension 'json' -TemporaryFileOnly $FileName = $FileNameService + '_' + $FileNameData + '_' + $FileNameEnd $FilePath = [IO.Path]::Combine($FolderPath, $FileName) $Maintenance = [ordered] @{ DateStart = $DateStart DateEnd = $DateEnd Service = $Service Status = $Status Title = $Title Overview = $Overview } $Output = $Maintenance | ConvertTo-Json $Output | Set-Content -LiteralPath $FilePath } function New-StatusimoPage { [cmdletbinding()] param( [string] $FilePath, [alias('Incident', 'Incidents', 'IncidentPath')][string] $IncidentsPath, [alias('Maintenance', 'MaintenancePath')][string] $MaintenancesPath, [int] $AutoRefresh, [switch] $Online ) New-HTML -TitleText 'Services Status' -Online:$Online -AutoRefresh $AutoRefresh -FilePath $FilePath { $Today = Get-Date $Incidents = Get-StatusimoData -FolderPath $IncidentsPath | Sort-Object -Property Date, Title -Descending $Maintenances = Get-StatusimoData -FolderPath $MaintenancesPath | Sort-Object -Property DateEnd, DateStart, Title -Descending $IncidentTypes = $Incidents.Service | Sort-Object -Unique New-HTMLSection -Invisible { New-HTMLContainer -Width '900px' -Margin 'auto' { $Statuses = foreach ($Type in $IncidentTypes) { $Incidents | Where-Object { $_.Service -eq $Type } | Select-Object -First 1 -ExpandProperty Status } if ($Statuses -notcontains 'Partial Degradation' -and $Statuses -notcontains 'Down') { New-HTMLToast -TextHeader 'Information' -Text 'Everything is running smoothly!' -BarColorLeft Blue -IconSolid info-circle -IconColor Blue } else { New-HTMLToast -TextHeader 'Warning' -Text "Some systems are affected. We're hard at work fixing." -BarColorLeft Orange -IconSolid exclamation-circle -IconColor Orange } New-HTMLHeading -Heading h1 -HeadingText 'Current Status' -Color Black New-HTMLStatus { foreach ($Type in $IncidentTypes) { $IncidentStatus = $Incidents | Where-Object { $_.Service -eq $Type } | Select-Object -First 1 if ($IncidentStatus.Status -eq 'Operational') { $Icon = 'Good' $Percentage = '100%' } elseif ($IncidentStatus.Status -eq 'Partial Degradation') { $Icon = 'Bad' $Percentage = '30%' } elseif ($IncidentStatus.Status -eq 'Down') { $Icon = 'Dead' $Percentage = '0%' } New-HTMLStatusItem -ServiceName $IncidentStatus.Service -ServiceStatus $IncidentStatus.Status -Icon $Icon -Percentage $Percentage } } New-HTMLHeading -Heading h1 -HeadingText 'Scheduled Maintenance' -Color Black foreach ($Maintenance in $Maintenances) { $Title = "$($Maintenance.Title) ($($Maintenance.DateStart) - $($Maintenance.DateEnd))" if ($Today -ge $Maintenance.DateStart -and $Today -le $Maintenance.DateEnd) { New-HTMLToast -TextHeader $Title -Text $Maintenance.Overview -BarColorLeft Orange -IconSolid exclamation-circle -IconColor Orange } elseif ($Today -le $Maintenance.DateStart) { New-HTMLToast -TextHeader $Title -Text $Maintenance.Overview -BarColorLeft Blue -IconSolid info-circle } else { New-HTMLToast -TextHeader $Title -Text $Maintenance.Overview -BarColorLeft Green -IconSolid check-circle -IconColor Green } } New-HTMLHeading -Heading h1 -HeadingText 'Incidents per day' -Color Black $Data = foreach ($Element in 30..0) { $Date = (Get-Date).AddDays(-$Element).Date [Array] $IncidentsPerDay = $Incidents | Where-Object { ($_.Status -eq 'Partial Degradation' -or $_.Status -eq 'Down') -and $_.Date.Date -eq $Date } $IncidentsPerDay.Count } $DataCategories = foreach ($Element in 30..0) { (Get-Date).AddDays(-$Element).ToShortDateString() } New-HTMLChart -Title 'Incidents per day' -TitleAlignment left { New-ChartCategory -Name $DataCategories New-ChartLine -Name 'Incidents' -Value $Data } New-HTMLHeading -Heading h1 -HeadingText 'Timeline' -Color Black New-HTMLTimeline { foreach ($Incident in $Incidents) { New-HTMLTimelineItem -HeadingText $Incident.Title -Text $Incident.Overview -Date $Incident.Date -Color Black } } } } } } function Remove-StatusimoMaintenance { [cmdletbinding()] param( [alias('Maintenance', 'MaintenancePath')][string] $MaintenancesPath, [int] $DaysOld ) $DateOld = (Get-Date).AddDays($DaysOld) $Maintenances = Get-StatusimoData -FolderPath $MaintenancesPath | Where-Object { $_.DateEnd -lt $DateOld } foreach ($Maintenance in $Maintenances) { Remove-Item -LiteralPath $Maintenance.FullName -Confirm:$false } } Export-ModuleMember -Function @('New-StatusimoEvent', 'New-StatusimoMaintenance', 'New-StatusimoPage', 'Remove-StatusimoMaintenance') -Alias @('New-StatusimoIncident') |