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-HTMLPanel -Invisible { $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 -Icon Information -Color Blue -TextHeader 'Information' -Text 'Everything is running smoothly!' } else { New-HTMLToast -Icon Exclamation -Color Orange -TextHeader 'Warning' -Text "Some systems are affected. We're hard at work fixing." } }
        New-HTMLHeading -Heading h1 -HeadingText 'Current Status' -Type 'central' -Color Black
        New-HTMLPanel -Invisible { 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' -Type 'central' -Color Black
        New-HTMLPanel -Invisible { foreach ($Maintenance in $Maintenances) {
                $Title = "$($Maintenance.Title) ($($Maintenance.DateStart) - $($Maintenance.DateEnd))"
                if ($Today -ge $Maintenance.DateStart -and $Today -le $Maintenance.DateEnd) { New-HTMLToast -Icon Exclamation -Color Orange -TextHeader $Title -Text $Maintenance.Overview } elseif ($Today -le $Maintenance.DateStart) { New-HTMLToast -Icon Information -Color Blue -TextHeader $Title -Text $Maintenance.Overview } else { New-HTMLToast -Icon Success -Color Green -TextHeader $Title -Text $Maintenance.Overview }
            } }
        New-HTMLHeading -Heading h1 -HeadingText 'Incidents per day' -Type 'central' -Color Black
        New-HTMLPanel -Invisible { $Data = foreach ($Element in 30..0) {
                $Date = (Get-Date).AddDays(-$Element).Date
                $IncidentsPerDay = $Incidents | Where-Object { ($_.Status -eq 'Partial Degradation' -or $_.Status -eq 'Down') -and $_.Date.Date -eq $Date }
                Get-ObjectCount -Object $IncidentsPerDay
            }
            $DataCategories = foreach ($Element in 30..0) { (Get-Date).AddDays(-$Element).ToShortDateString() }
            New-HTMLChart -Title 'Incidents per day' -TitleAlignment left -Positioning central { New-ChartCategory -Name $DataCategories
                New-ChartLine -Name 'Incidents' -Value $Data } }
        New-HTMLHeading -Heading h1 -HeadingText 'Timeline' -Type 'central' -Color Black
        New-HTMLPanel -Invisible { 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')