systemchecks.psm1

#Requires -Version 5
<#
 .Synopsis
 Get a file count from a given path.
 
 .Description
 Get a file count from a given path. Can handle network shares as well.
 
 .Parameter
 
 .Example
Get-FileCount FilePath "c:\my\file"
 #>

function Get-FileCount {
    [CmdletBinding()]
    param (
        [string]$FilePath,
        [string]$SystemName,
        [string]$SystemDescription,
        [string]$AppendLeaf,
        [string]$LeafFormat
    )

    $HealthCheckType = 'FileCount'

    try {
        if (Test-Path -Path $FilePath) {

            $FolderName = Split-Path -Path $FilePath -Leaf

            if (-not [string]::IsNullOrEmpty($AppendLeaf)) {
                switch ($AppendLeaf) {
                    'Today' {
                        $ChildPath = Get-Date -Format $LeafFormat
                        $CheckPath = Join-Path -Path $FilePath -ChildPath $ChildPath
                        $FolderName += "\$ChildPath."
                    }
                    'Yesterday' {
                        $ChildPath = Get-Date -Date ((Get-Date).AddDays(-1)) -Format $LeafFormat
                        $CheckPath = Join-Path -Path $FilePath -ChildPath $ChildPath
                        $FolderName += "\$ChildPath."
                    }
                }
                Write-Verbose "AppendLeaf: $AppendLeaf"
                Write-Verbose "CheckPath: $CheckPath"
                Write-Verbose "FolderName: $FolderName"
            }
            else {
                $CheckPath = $FilePath
                Write-Verbose "Skipping - AppendLeaf"
            }

            if (Test-Path -Path $CheckPath) {
                $FileCount = Get-ChildItem -Path $CheckPath -File | Measure-Object | Select-Object -ExpandProperty Count
                $Comment = $CheckPath
                Write-Verbose "Good test path - value: $CheckPath"
            } else{
                $Exception = $Error[0].Exception.Message
                if ([string]::IsNullOrEmpty($Exception)) {
                    $Exception = "Path not found: $CheckPath"
                }
                Write-Verbose $Exception
                $FileCount = 0
                $Comment = $Exception
            }

            Write-Verbose "Comment: $Comment"

            return [PSCustomObject]@{
                SystemName        = $SystemName
                SystemDescription = $SystemDescription
                Name              = $FolderName
                Type              = $HealthCheckType
                Status            = $FileCount
                LastUpdate        = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                Comment           = $Comment
                ComputerName      = $ENV:COMPUTERNAME
            }
        }
        else {
            $Exception = $Error[0].Exception.Message
            if ([string]::IsNullOrEmpty($Exception)) {
                $Exception = "Path not found: $FilePath"
            }
            Write-Verbose $Exception

            return [PSCustomObject]@{
                SystemName        = $SystemName
                SystemDescription = $SystemDescription
                Name              = $FilePath
                Type              = $HealthCheckType
                Status            = 'ERROR'
                LastUpdate        = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                Comment           = $Exception
                ComputerName      = $ENV:COMPUTERNAME
            }
        }
    }
    catch {
        $Exception = $Error[0].Exception.Message
        if ([string]::IsNullOrEmpty($Exception)) {
            $Exception = "Path not found: $FilePath"
        }
        Write-Verbose $Exception

        return [PSCustomObject]@{
            SystemName        = $SystemName
            SystemDescription = $SystemDescription
            Name              = $FilePath
            Type              = $HealthCheckType
            Status            = 'ERROR'
            LastUpdate        = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
            Comment           = $Exception
            ComputerName      = $ENV:COMPUTERNAME
        }
    }
}

#Requires -Version 5
<#
 .Synopsis
 Analyze different components of a system.
 
 .Description
 Analyze different components of a system. A system can be any collection of items to check.
 
 .Parameter
 
 .Example
 
 #>

function Get-SystemHealth {
    [CmdletBinding()]
    param (
        [System.Object[]]$ConfigFileName
    )

    $ScriptDirectory = Split-Path $Script:MyInvocation.MyCommand.Path -Parent
    $IncludesPath = Join-Path -Path $ScriptDirectory -ChildPath "Includes"

    . (Join-Path -Path $IncludesPath -ChildPath "Get-Win32Error.ps1")
    . (Join-Path -Path $IncludesPath -ChildPath "Test-FileExists.ps1")
    . (Join-Path -Path $IncludesPath -ChildPath "Test-ShareExists.ps1")
    . (Join-Path -Path $IncludesPath -ChildPath "Test-ProcessHealth.ps1")
    . (Join-Path -Path $IncludesPath -ChildPath "Test-ScheduledTask.ps1")
    . (Join-Path -Path $IncludesPath -ChildPath "Test-ServiceHealth.ps1")
    . (Join-Path -Path $IncludesPath -ChildPath "Test-TimeSync.ps1")
    . (Join-Path -Path $IncludesPath -ChildPath "Test-URIHealth.ps1")
    . (Join-Path -Path $IncludesPath -ChildPath "Get-FileCount.ps1")

    $ConfigFileName | ForEach-Object {
        
        $ConfigFile = $_
        $SystemHealthData = @()

        $file = Get-Content -Path $ConfigFile.FullName | ConvertFrom-Json
        $SystemName = $file.systemName
        $SystemDescription = $file.description
        
        $file.Processes | ForEach-Object {
            $procSplat = @{
                ProcessName       = $_.name
                SystemName        = $SystemName
                SystemDescription = $SystemDescription
            }
            $SystemHealthData += Test-ProcessHealth @procSplat
        }

        $file.Services | ForEach-Object {
            $serviceSplat = @{
                ServiceName       = $_.name
                SystemName        = $SystemName
                SystemDescription = $SystemDescription
            }
            $SystemHealthData += Test-ServiceHealth @serviceSplat
        }

        $file.FilesExist | ForEach-Object {
            $checkfileSplat = @{
                FilePath          = $_.FilePath
                SystemName        = $SystemName
                SystemDescription = $SystemDescription
            }
            $SystemHealthData += Test-FileExists @checkfileSplat
        }

        $file.SharesExist | ForEach-Object {
            $checkshareSplat = @{
                SharePath         = $_.SharePath
                SystemName        = $SystemName
                SystemDescription = $SystemDescription
            }
            $SystemHealthData += Test-ShareExists @checkshareSplat

            $File.URIs | ForEach-Object {
                $checkURISplat = @{
                    URI               = $_.URI
                    SystemName        = $SystemName
                    SystemDescription = $SystemDescription
                    UseBasicParsing = $_.useBasicParsing
                    UseDefaultCredentials = $_.useDefaultCredentials
                }
                $SystemHealthData += Test-URIHealth @checkURISplat
            }

            $file.ScheduledTasks | ForEach-Object {
                $schedtaskSplat = @{
                    TaskPath          = $_.TaskPath
                    SystemName        = $SystemName
                    SystemDescription = $SystemDescription
                }
                $SystemHealthData += Test-ScheduledTask @schedtaskSplat
            }

            $file.FileCount | ForEach-Object {
                $filecountSplat = @{
                    FilePath          = $_.FilePath
                    SystemName        = $SystemName
                    SystemDescription = $SystemDescription
                    AppendLeaf        = $_.appendLeaf
                    LeafFormat        = $_.leafFormat
                }
                $SystemHealthData += Get-FileCount @filecountSplat
            }

            $OutFileName = ".\output_files\healthcheck_$($ENV:COMPUTERNAME)_$($ConfigFile.Name)"
            $SystemHealthData | ConvertTo-Json | Out-File (New-Item -Path $OutFileName -Force)
        }
        $SystemHealthData
    }
}
#Requires -Version 5
<#
 .Synopsis
 This function calls the error lookup tool to get detailed information about an error.
 
 .Description
 This function is intended to be used with Get-SystemHealth and relies on $ScriptDirectory for proper function.
 
 Requires the Microsoft Error Lookup Tool (err.exe), included in the project. For details
 on error lookup tool see article:
 https://www.microsoft.com/en-us/download/details.aspx?id=100432&msockid=2fd802363d216c82121f16d63c406d64
 
 The tool can also be installed by using winget (winget install Microsoft.err). This function expects
 the tool is NOT installed and runs it from the project folder.
 
 NOTE: By default, this function checks errors against the winerror.h file.
 
 .Parameter
 
 .Example
 Get-Win32Error 0x80070005 # Access Denied error
 #>

function Get-Win32Error {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [int]$ErrorCode
    )

    # Path to the Error Lookup Tool executable
    $errExe = Join-Path -Path $ScriptDirectory -ChildPath "Includes\err.exe"

    Write-Verbose "Error Tool Path: {$errExe}"

    # Check if the executable exists
    if (!(Test-Path $errExe)) {
        Write-Error "Error Lookup Tool not found at $errExe"
        return
    }

    # Run the tool and capture output
    $output = & $errExe "/winerror.h" $ErrorCode

    # Parse the output and return the message
    # this is a rough parse
    if ($output -match "winerror.h") {
        $returnvalue = $output -join " "
        $returnvalue = $returnvalue -replace "#", '`r`n'
        return $returnvalue
    }
    else {
        return "Error code not found"
    }
}

#Requires -Version 5
<#
 .Synopsis
 See if a file path exists.
 
 .Description
 See if a file path exists.
 
 .Parameter
 
 .Example
Test-FileExists -FilePath "c:\my\file"
 #>

function Test-FileExists {
    [CmdletBinding()]
    param (
        [string]$FilePath,
        [string]$SystemName,
        [string]$SystemDescription
    )

    $HealthCheckType = 'FileExists'

    $filename = Split-Path -Path $FilePath -Leaf

    try {
        if (Test-Path -Path $FilePath) {
            return [PSCustomObject]@{
                SystemName          = $SystemName
                SystemDescription   = $SystemDescription
                Name                = $filename
                Type                = $HealthCheckType
                Status              = 'Exists'
                LastUpdate          = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                Comment             = $FilePath
                ComputerName        = $ENV:COMPUTERNAME
            }
        } else {
            return [PSCustomObject]@{
                SystemName          = $SystemName
                SystemDescription   = $SystemDescription
                Name                = $filename
                Type                = $HealthCheckType
                Status              = 'Not Found'
                LastUpdate          = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                Comment             = $FilePath
                ComputerName        = $ENV:COMPUTERNAME
            }
        }
    } catch {
        return [PSCustomObject]@{
            SystemName          = $SystemName
            SystemDescription   = $SystemDescription
            Name                = $FilePath
            Type                = $HealthCheckType
            Status              = 'ERROR'
            LastUpdate          = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
            Comment             = $Error[0].Exception.Message
            ComputerName        = $ENV:COMPUTERNAME
        }
    }
}

#Requires -Version 5
<#
 .Synopsis
 See if a process is running.
 
 .Description
 See if a process is running.
 
 .Parameter
 
 .Example
Test-ProcessHealth -ProcessName "explorer"
 #>

 function Test-ProcessHealth {
    [CmdletBinding()]
    param (
        [string]$ProcessName,
        [string]$SystemName,
        [string]$SystemDescription
    )
    $HealthCheckType = 'Process'
    try {
        $process = Get-Process -Name $ProcessName -ErrorAction Stop
        if ($process.Responding -eq $true) {
            return [PSCustomObject]@{
                SystemName          = $SystemName
                SystemDescription   = $SystemDescription
                Name                = $ProcessName
                Type                = $HealthCheckType
                Status              = 'Responding'
                LastUpdate          = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                Comment             = ""
                ComputerName        = $ENV:COMPUTERNAME
            }
        } else {
            return [PSCustomObject]@{
                SystemName          = $SystemName
                SystemDescription   = $SystemDescription
                Name                = $ProcessName
                Type                = $HealthCheckType
                Status              = 'ERROR'
                LastUpdate          = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                Comment             = "Process not responding. Status: $($process.Responding)"
                ComputerName        = $ENV:COMPUTERNAME
            }
        }
    } catch {
        return [PSCustomObject]@{
            SystemName                  = $SystemName
            SystemDescription           = $SystemDescription
            Name                        = $ProcessName
            Type                        = $HealthCheckType
            Status                      = 'ERROR'
            LastUpdate                  = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
            Comment                     = $_.Exception.Message
            ComputerName                = $ENV:COMPUTERNAME
        }
    }
}

#Requires -Version 5
<#
 .Synopsis
 Get status of a scheduled task.
 
 .Description
 Get status of a scheduled task.
 
 .Parameter
 
 .Example
Test-ScheduledTask -TaskPath "\SLMPD\Send OnCallSchedule"
 #>

function Test-ScheduledTask {
    [CmdletBinding()]
    param (
        [string]$TaskPath,
        [string]$SystemName,
        [string]$SystemDescription
    )

    $HealthCheckType = 'ScheduledTask'

    $task = Split-Path -Path $TaskPath -Leaf
    $path = Split-Path -Path $TaskPath -Parent

    try {
        $taskdetail = Get-ScheduledTaskInfo -TaskName $task -TaskPath $path -ErrorAction Stop
        if ($taskdetail -and $taskdetail.LastTaskResult -eq '0') {
            return [PSCustomObject]@{
                SystemName          = $SystemName
                SystemDescription   = $SystemDescription
                Name                = $TaskPath
                Type                = $HealthCheckType
                Status              = 'OK'
                LastUpdate          = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                Comment             = "LastRunTime: $($taskdetail.LastRunTime) NextRunTime: $($taskdetail.NextRunTime) MissedRuns: $($taskdetail.NumberOfMissedRuns)"
                ComputerName        = $ENV:COMPUTERNAME
            }
        }
        else {
            if (!$null -eq $taskdetail) {
                $errorResult = Get-Win32Error -ErrorCode $taskdetail.LastTaskResult
                $parsedErrorMessage = $errorResult -split '`r`n'
    
                Write-Verbose "Parsed Error: {$parsedErrorMessage}"
    
                if (-not [string]::IsNullOrEmpty($parsedErrorMessage)) {
                    $errMessage = $parsedErrorMessage[2].Trim()
                    $errCodeConverted = $parsedErrorMessage[1].Trim() -replace '\s{2,}', ', '
                }
                else {
                    $errMessage = ""
                    $errCodeConverted = 0
                }
    
                return [PSCustomObject]@{
                    SystemName          = $SystemName
                    SystemDescription   = $SystemDescription
                    Name                = $TaskPath
                    Type                = $HealthCheckType
                    Status              = ("{0} - {1}" -f $taskdetail.LastTaskResult, $errCodeConverted)
                    LastUpdate          = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                    Comment             = $errMessage
                    ComputerName        = $ENV:COMPUTERNAME
                }
            }
            else {
                return [PSCustomObject]@{
                    SystemName          = $SystemName
                    SystemDescription   = $SystemDescription
                    Name                = $TaskPath
                    Type                = $HealthCheckType
                    Status              = 'ERROR'
                    LastUpdate          = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                    Comment             = "Task not found."
                    ComputerName        = $ENV:COMPUTERNAME
                }
            }
        }
    }
    catch {
        return [PSCustomObject]@{
            SystemName              = $SystemName
            SystemDescription       = $SystemDescription
            Name                    = $TaskPath
            Type                    = $HealthCheckType
            Status                  = 'ERROR'
            LastUpdate              = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
            Comment                 = "Task not found."
            ComputerName            = $ENV:COMPUTERNAME
        }
    }
}

#Requires -Version 5
<#
 .Synopsis
 Get status of a windows service.
 
 .Description
 Get status of a windows service.
 
 .Parameter
 
 .Example
Test-ServiceHealth -ServiceName 'w3svc'
 #>

function Test-ServiceHealth {
    [CmdletBinding()]
    param (
        [string]$ServiceName,
        [string]$SystemName,
        [string]$SystemDescription
    )

    $HealthCheckType = 'Service'

    try {
        $service = Get-Service -Name $ServiceName -ErrorAction Stop
        if ($service.Status -eq 'Running') {
            return [PSCustomObject]@{
                SystemName          = $SystemName
                SystemDescription   = $SystemDescription
                Name                = $ServiceName
                Type                = $HealthCheckType
                Status              = 'OK'
                LastUpdate          = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                Comment             = ""
                ComputerName        = $ENV:COMPUTERNAME
            }
        } else {
            return [PSCustomObject]@{
                SystemName          = $SystemName
                SystemDescription   = $SystemDescription
                Name                = $ServiceName
                Type                = $HealthCheckType
                Status              = 'ERROR'
                LastUpdate          = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                Comment             = $service.Status
                ComputerName        = $ENV:COMPUTERNAME
            }
        }
    } catch {
        return [PSCustomObject]@{
            SystemName              = $SystemName
            SystemDescription       = $SystemDescription
            Name                    = $ServiceName
            Type                    = $HealthCheckType
            Status                  = 'ERROR'
            LastUpdate              = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
            Comment                 = $_.Exception.Message
            ComputerName        = $ENV:COMPUTERNAME
        }
    }
}

#Requires -Version 5
<#
 .Synopsis
 See if a share path exists.
 
 .Description
 See if a share path exists.
 
 .Parameter
 
 .Example
Test-FileShare -SharePath "\\tapp1\e$"
 #>

function Test-ShareExists {
    [CmdletBinding()]
    param (
        [string]$SharePath,
        [string]$SystemName,
        [string]$SystemDescription
    )

    $HealthCheckType = 'ShareExists'

    # Extract share name - handle UNC paths, drive letters, and regular paths
    if ($SharePath -match '^\\\\[^\\]+\\([^\\]+)') {
        # UNC path like \\server\share
        $ShareName = $matches[1]
    }
    elseif ($SharePath -match '^([A-Z]:)') {
        # Drive letter like C:
        $ShareName = $matches[1]
    }
    else {
        # Fall back to GetFileName for other paths
        $ShareName = [System.IO.Path]::GetFileName($SharePath)
        if ([string]::IsNullOrEmpty($ShareName)) {
            $ShareName = $SharePath
        }
    }

    try {
        if (Test-Path -Path $SharePath) {
            return [PSCustomObject]@{
                SystemName        = $SystemName
                SystemDescription = $SystemDescription
                Name              = $ShareName
                Type              = $HealthCheckType
                Status            = 'Exists'
                LastUpdate        = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                Comment           = $SharePath
                ComputerName      = $ENV:COMPUTERNAME
            }
        }
        else {
            return [PSCustomObject]@{
                SystemName        = $SystemName
                SystemDescription = $SystemDescription
                Name              = $ShareName
                Type              = $HealthCheckType
                Status            = 'Not Found'
                LastUpdate        = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                Comment           = $SharePath
                ComputerName      = $ENV:COMPUTERNAME
            }
        }
    }
    catch {
        return [PSCustomObject]@{
            SystemName        = $SystemName
            SystemDescription = $SystemDescription
            Name              = $ShareName
            Type              = $HealthCheckType
            Status            = 'ERROR'
            LastUpdate        = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
            Comment           = $Error[0].Exception.Message
            ComputerName      = $ENV:COMPUTERNAME
        }
    }
}

#Requires -Version 5
<#
 .Synopsis
 Analyze different components of a system.
 
 .Description
 Analyze different components of a system. A system can be any collection of items to check.
 
 .Parameter
 
 .Example
Test-TimeSync -System1Name "netviewer1" -System2Name "cad1" -Verbose
 #>

function Test-TimeSync {
    [CmdletBinding()]
    param (
        [string]$System1Name,
        [string]$System2Name
    )

    $HealthCheckType = 'TimeSync'

    $session1 = New-PSSession -ComputerName $System1Name -ErrorAction SilentlyContinue
    if ($session1) {
        Write-Verbose "Collecting current date/time from $System1Name"
        $timedate = Invoke-Command -Session $session1 -ScriptBlock { Get-Date }
        $System1DateTime = [PSCustomObject]@{
            SystemName     = $System1Name
            SystemDateTime = $timedate
            Status         = 'Success'
            Comment        = ''
        }
    }
    else {
        $System1DateTime = [PSCustomObject]@{
            SystemName     = $System1Name
            SystemDateTime = ''
            Status         = 'ERROR'
            Comment        = "Unable to establish a session with '$System1Name'"
        }
    }

    $session2 = New-PSSession -ComputerName $System2Name -ErrorAction SilentlyContinue
    if ($session2) {
        Write-Verbose "Collecting current date/time from $System2Name"
        $timedate = Invoke-Command -Session $session2 -ScriptBlock { Get-Date }
        $System2DateTime = [PSCustomObject]@{
            SystemName     = $System2Name
            SystemDateTime = $timedate
            Status         = 'Success'
            Comment        = ''
        }
    }
    else {
        $System2DateTime = [PSCustomObject]@{
            SystemName     = $System2Name
            SystemDateTime = ''
            Status         = 'ERROR'
            Comment        = "Unable to establish a session with '$System2Name'"
        }
    }
    if ($System1DateTime.Status -eq 'error' -or $System2DateTime.Status -eq 'error') {
        $DateTimeDifference = 0
        $Status = "ERROR"
    }
    else {
        $difference = New-TimeSpan -Start $System1DateTime.SystemDateTime -End $System2DateTime.SystemDateTime
        $DateTimeDifference = $difference
        $Status = 'Success'
    }
    $System1DateTime | Format-Table -AutoSize | Out-String | Write-Verbose
    $System2DateTime  | Format-Table -AutoSize | Out-String | Write-Verbose

    return [PSCustomObject]@{
        System1Name     = $System1Name
        System1DateTime = $System1DateTime.SystemDateTime
        System2Name     = $System2Name
        System2DateTime = $System2DateTime.SystemDateTime
        Type            = $HealthCheckType
        Status          = $Status
        Difference      = $DateTimeDifference
        LastUpdate      = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
        Comment         = @($System1DateTime.Comment,$System2DateTime.Comment)
    }
}

#Requires -Version 5
<#
 .Synopsis
 Get status of a given URI.
 
 .Description
 Get status of a given URI.
 
 .Parameter
 
 .Example
Test-URIHealth -URI "\SLMPD\Send OnCallSchedule"
 #>

function Test-URIHealth {
    [CmdletBinding()]
    param (
        [string]$URI,
        [string]$SystemName,
        [string]$SystemDescription,
        [bool]$UseBasicParsing,
        [bool]$UseDefaultCredentials
    )

    $HealthCheckType = 'URI'

    try {
        $WebRequestSplat = @{
            URI                   = $URI
            UseBasicParsing       = $UseBasicParsing
            UseDefaultCredentials = $UseDefaultCredentials
        }
        $response = Invoke-WebRequest @WebRequestSplat
        if (!$null -eq $response) {
            if ($response.StatusCode -eq '200') {
                return [PSCustomObject]@{
                    SystemName        = $SystemName
                    SystemDescription = $SystemDescription
                    Name              = $URI
                    Type              = $HealthCheckType
                    Status            = 'OK'
                    LastUpdate        = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                    Comment           = ""
                    ComputerName      = $ENV:COMPUTERNAME
                }
            }
            else {
                return [PSCustomObject]@{
                    SystemName        = $SystemName
                    SystemDescription = $SystemDescription
                    Name              = $URI
                    Type              = $HealthCheckType
                    Status            = $response.StatusDescription
                    LastUpdate        = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                    Comment           = $response.StatusCode
                    ComputerName      = $ENV:COMPUTERNAME
                }
            }
        }
        else {
            return [PSCustomObject]@{
                SystemName        = $SystemName
                SystemDescription = $SystemDescription
                Name              = $URI
                Type              = $HealthCheckType
                Status            = 'ERROR'
                LastUpdate        = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                Comment           = $Error[0].Exception.Message
                ComputerName      = $ENV:COMPUTERNAME
            }
        }
    }
    catch {
        return [PSCustomObject]@{
            SystemName        = $SystemName
            SystemDescription = $SystemDescription
            Name              = $URI
            Type              = $HealthCheckType
            Status            = 'ERROR'
            LastUpdate        = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
            Comment           = $_.Exception.Message
            ComputerName      = $ENV:COMPUTERNAME
        }
    }
}