Private/Kinds/FolderSize.ps1

# The FolderSize Kind: a cache or profile folder that has grown into the problem.
#
# Previously an "extra" with its own dispatch. It is an ordinary Kind now, selected by a
# Check Definition like any other, which is the whole of what retiring extras meant.

function Get-FolderSizeData {
    [CmdletBinding()]
    [OutputType([psobject])]
    param([hashtable]$Parameters = @{})

    $configured = Get-Parameter $Parameters 'Path' ''

    # A Check Definition is written by hand and names folders that only exist relative to
    # a user, so %LOCALAPPDATA% and its kin have to survive the trip through JSON.
    $path = ''
    if ($configured) { $path = [Environment]::ExpandEnvironmentVariables($configured) }

    $exists = $false
    $bytes  = $null
    $files  = $null
    if ($path -and (Test-Path -LiteralPath $path)) {
        $exists = $true
        $measured = Get-ChildItem -LiteralPath $path -Recurse -File -Force -ErrorAction SilentlyContinue |
            Measure-Object Length -Sum
        $bytes = $measured.Sum
        $files = $measured.Count
        # A folder that exists and holds nothing measures as zero rather than as absent.
        if ($null -eq $bytes) { $bytes = 0 }
    }

    [pscustomobject]@{
        PSTypeName     = 'Gutcheck.Data.FolderSize'
        ConfiguredPath = $configured
        Path           = $path
        Exists         = $exists
        SizeBytes      = $bytes
        FileCount      = $files
    }
}

function ConvertTo-FolderSizeFinding {
    [CmdletBinding()]
    [OutputType([psobject])]
    param(
        [AllowNull()]$Data,
        [hashtable]$Parameters = @{}
    )

    $warnAboveGB = Get-Parameter $Parameters 'FolderSizeWarnAboveGB' 5
    $failAboveGB = Get-Parameter $Parameters 'FolderSizeFailAboveGB' ([double]::MaxValue)

    $configured = Get-DataProperty $Data 'ConfiguredPath'
    $path       = Get-DataProperty $Data 'Path'
    if (-not $path) { $path = $configured }

    $check = 'Folder size {0}' -f $path

    if (-not $configured) {
        return New-Finding -Category Apps -Check (Get-Text 'Check.FolderSize.FolderSize') -Severity INFO -Value (Get-Text 'Value.FolderSize.NoPathConfigured') `
            -Hint (Get-Text 'Hint.FolderSize.ThisCheckDefinitionNamesNo')
    }

    if (-not (Get-DataProperty $Data 'Exists')) {
        # The script said nothing at all here, so a mistyped path in a Definition and a
        # folder that was cleaned up read identically - which is to say, not at all.
        return New-Finding -Category Apps -Check $check -Severity INFO -Value (Get-Text 'Value.FolderSize.NotPresent') `
            -Hint (Get-Text 'Hint.FolderSize.TheFolderIsNotOn')
    }

    $bytes = ConvertTo-Number (Get-DataProperty $Data 'SizeBytes')
    if ($null -eq $bytes) {
        return New-UnavailableFinding -Category Apps -Check $check `
            -Hint (Get-Text 'Hint.FolderSize.TheFolderCouldNotBe')
    }

    $gb = $bytes / 1GB
    New-Finding -Category Apps -Check $check -Severity (Get-Severity $gb $warnAboveGB $failAboveGB) `
        -Value ('{0:N2} GB' -f $gb) `
        -Hint (Get-Text 'Hint.FolderSize.VeryLargeCacheProfileFolder')
}