Private/Kinds/OutlookData.ps1

# The OutlookData Kind: the mail file, the sync window, and which Office this is.
#
# An OST past about 20 GB is the single most common reason a Customer says "Outlook is
# slow" on a machine with nothing else wrong with it, and the fix - a shorter cached mode
# sync window - is why the window is read in the same Check rather than a different one.

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

    $documents = [Environment]::GetFolderPath('MyDocuments')

    # The German folder name is listed beside the English one because the estate is
    # German and Outlook names this folder in the installed language.
    $directories = @(
        Join-Path $env:LOCALAPPDATA 'Microsoft\Outlook'
        Join-Path $documents 'Outlook Files'
        Join-Path $documents 'Outlook-Dateien'
    )

    $files = @(foreach ($directory in $directories) {
        if (-not $directory -or -not (Test-Path -LiteralPath $directory)) { continue }
        Get-ChildItem -LiteralPath $directory -Include *.ost, *.pst -File -Recurse -ErrorAction SilentlyContinue |
            ForEach-Object {
                [pscustomobject]@{ Name = $_.Name; Path = $_.FullName; SizeBytes = $_.Length }
            }
    })

    # Policy first: a Customer whose administrator set the window centrally has an answer
    # a Technician cannot change on the machine, and it has to be the one reported.
    $syncWindow = $null
    foreach ($key in 'HKCU:\Software\Policies\Microsoft\Office\16.0\Outlook\Cached Mode',
                     'HKCU:\Software\Microsoft\Office\16.0\Outlook\Cached Mode') {
        $value = (Get-ItemProperty $key -ErrorAction SilentlyContinue).SyncWindowSetting
        if ($null -ne $value) { $syncWindow = $value; break }
    }

    $clickToRun = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration' -ErrorAction SilentlyContinue

    [pscustomobject]@{
        PSTypeName        = 'Gutcheck.Data.OutlookData'
        MailFiles         = @($files | Sort-Object Path -Unique)
        SyncWindowMonths  = $syncWindow
        OfficeVersion     = $clickToRun.VersionToReport
        OfficePlatform    = $clickToRun.Platform
        OfficeChannel     = $(if ($clickToRun.UpdateChannel) { $clickToRun.UpdateChannel } else { $clickToRun.CDNBaseUrl })
    }
}

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

    New-MailFileFinding   -Data $Data -Parameters $Parameters
    New-SyncWindowFinding -Data $Data -Parameters $Parameters
    New-OfficeBuildFinding -Data $Data -Parameters $Parameters
}

function New-MailFileFinding {
    [CmdletBinding()]
    param([AllowNull()]$Data, [hashtable]$Parameters)

    $warnAboveGB = Get-Parameter $Parameters 'MailFileWarnAboveGB' 20
    $failAboveGB = Get-Parameter $Parameters 'MailFileFailAboveGB' 45

    $files = Get-DataCollection $Data 'MailFiles'
    if (-not $files.Count) {
        return New-Finding -Category Apps -Check (Get-Text 'Check.OutlookData.MailFilesOSTPST') -Severity INFO `
            -Value (Get-Text 'Value.OutlookData.NoneForThisUser') `
            -Hint (Get-Text 'Hint.OutlookData.OnlineModeNewOutlookOr')
    }

    # One Finding per file. A mailbox at 8 GB beside an archive at 48 GB is not honestly
    # described by either of them, and only one of the two is the thing to act on.
    foreach ($file in $files) {
        $bytes = ConvertTo-Number $file.SizeBytes
        if ($null -eq $bytes) {
            New-UnavailableFinding -Category Apps -Check ((Get-Text 'Check.OutlookData.MailFile') -f $file.Name) `
                -Hint (Get-Text 'Hint.OutlookData.TheFileWouldNotReport')
            continue
        }
        $gb = $bytes / 1GB
        New-Finding -Category Apps -Check ((Get-Text 'Check.OutlookData.MailFile') -f $file.Name) `
            -Severity (Get-Severity $gb $warnAboveGB $failAboveGB) -Value ('{0:N1} GB' -f $gb) `
            -Hint (Get-Text 'Hint.OutlookData.LargeOSTPSTSlowOutlook')
    }
}

function New-SyncWindowFinding {
    [CmdletBinding()]
    param([AllowNull()]$Data, [hashtable]$Parameters)

    $months = ConvertTo-Number (Get-DataProperty $Data 'SyncWindowMonths')
    if ($null -eq $months) { return }

    # Never graded. All mail is the right setting for plenty of people and the wrong one
    # for anyone with a large mailbox, and this Check cannot tell which it is looking at -
    # the mail file Finding beside it is what says whether this matters.
    New-Finding -Category Apps -Check (Get-Text 'Check.OutlookData.CachedModeSyncWindow') -Severity INFO `
        -Value $(if ($months -eq 0) { 'All mail' } else { '{0:N0} months' -f $months })
}

function New-OfficeBuildFinding {
    [CmdletBinding()]
    param([AllowNull()]$Data, [hashtable]$Parameters)

    $version = Get-DataProperty $Data 'OfficeVersion'
    if (-not $version) { return }

    New-Finding -Category Apps -Check (Get-Text 'Check.OutlookData.Microsoft365Apps') -Severity INFO `
        -Value ('{0} ({1}) channel {2}' -f $version, (Get-DataProperty $Data 'OfficePlatform'),
                (Get-DataProperty $Data 'OfficeChannel'))
}