Statusimo.psm1

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)
    New-HTML -TitleText 'Services Status' -UseCssLinks:$true -UseJavaScriptLinks:$true -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')