lib/core/tools/Read-IcingaFileSecure.psm1

<#
.SYNOPSIS
   Reads content of a file in read-only mode, ensuring no data corruption is happening
.DESCRIPTION
   Reads content of a file in read-only mode, ensuring no data corruption is happening
.FUNCTIONALITY
   Reads content of a file in read-only mode, ensuring no data corruption is happening
.EXAMPLE
   PS>Read-IcingaFileSecure -File 'config.json';
.EXAMPLE
   PS>Read-IcingaFileSecure -File 'config.json' -ExitOnReadError;
.OUTPUTS
   System.Object
.LINK
   https://github.com/Icinga/icinga-powershell-framework
#>


function Read-IcingaFileSecure()
{
    param (
        [string]$File,
        [switch]$ExitOnReadError = $FALSE
    );

    if ([string]::IsNullOrEmpty($File) -Or (Test-Path $File) -eq $FALSE) {
        return $null;
    }

    [int]$WaitTicks   = 0;
    [bool]$ConfigRead = $FALSE;

    # Lets wait 5 seconds before cancelling reading
    while ($WaitTicks -lt (($WaitTicks + 1) * 50)) {
        try {
            [System.IO.FileStream]$FileStream = [System.IO.File]::Open(
                $File,
                [System.IO.FileMode]::Open,
                [System.IO.FileAccess]::Read,
                [System.IO.FileShare]::Read
            );

            $ReadArray    = New-Object Byte[] $FileStream.Length;
            $UTF8Encoding = New-Object System.Text.UTF8Encoding $TRUE;
            $FileContent  = '';

            while ($FileStream.Read($ReadArray, 0 , $ReadArray.Length)) {
                $FileContent = [System.String]::Concat($FileContent, $UTF8Encoding.GetString($ReadArray));
            }

            $FileStream.Dispose();
            $ConfigRead = $TRUE;
            break;
        } catch {
            # File is still locked, wait for lock to vanish
        }

        $WaitTicks += 1;
        Start-Sleep -Milliseconds 100;
    }

    if ($ConfigRead -eq $FALSE -And $ExitOnReadError) {
        Write-IcingaEventMessage -EventId 1102 -Namespace 'Framework' -Objects $ConfigFile, $Content;
        Write-IcingaConsoleWarning -Message 'Your file "{0}" could not be read, as another process is locking it. Icinga for Windows will terminate itself after 5 seconds to prevent damage to this file.' -Objects $File;
        Start-Sleep -Seconds 5;
        exit 3;
    }

    return $FileContent;
}

Set-Alias -Name 'Read-IcingaFileContent' -Value 'Read-IcingaFileSecure';