function Get-IcingaProviderDataValuesProcess()
{
    param (
        [array]$IncludeFilter   = @(),
        [array]$ExcludeFilter   = @(),
        [switch]$IncludeDetails = $FALSE
    );

    # Fetch all required process information
    $ProviderName               = 'Process'
    $ProcessData                = New-IcingaProviderObject -Name $ProviderName;
    [array]$ProcessInformation  = Get-IcingaWindowsInformation Win32_Process;
    [array]$ProcessPerfDataList = Get-IcingaWindowsInformation Win32_PerfFormattedData_PerfProc_Process;
    [hashtable]$CPUProcessCache = @{ };
    [hashtable]$MEMProcessCache = @{ };

    # Read our process data and build our metrics object
    foreach ($entry in $ProcessInformation) {
        [string]$ProcessName = $entry.Name.Replace('.exe', '');
        [int]$ProcessId      = [int]$entry.ProcessId;

        if ((Test-IcingaArrayFilter -InputObject $ProcessName -Include $IncludeFilter -Exclude $ExcludeFilter) -eq $FALSE) {
            continue;
        }

        if ((Test-PSCustomObjectMember -PSObject $ProcessData.Metrics -Name $ProcessName) -eq $FALSE) {
            $ProcessData.Metrics                    | Add-Member -MemberType NoteProperty -Name $ProcessName     -Value (New-Object PSCustomObject);
            $ProcessData.Metrics.$ProcessName       | Add-Member -MemberType NoteProperty -Name 'List'           -Value (New-Object PSCustomObject);
            $ProcessData.Metrics.$ProcessName       | Add-Member -MemberType NoteProperty -Name 'Total'          -Value (New-Object PSCustomObject);
            $ProcessData.Metrics.$ProcessName.Total | Add-Member -MemberType NoteProperty -Name 'PageFileUsage'  -Value 0;
            $ProcessData.Metrics.$ProcessName.Total | Add-Member -MemberType NoteProperty -Name 'ThreadCount'    -Value 0;
            $ProcessData.Metrics.$ProcessName.Total | Add-Member -MemberType NoteProperty -Name 'WorkingSetSize' -Value 0;
            $ProcessData.Metrics.$ProcessName.Total | Add-Member -MemberType NoteProperty -Name 'ProcessCount'   -Value 0;
            $ProcessData.Metrics.$ProcessName.Total | Add-Member -MemberType NoteProperty -Name 'CpuUsage'       -Value 0;
            $ProcessData.Metrics.$ProcessName.Total | Add-Member -MemberType NoteProperty -Name 'MemoryUsage'    -Value 0;
        }

        # Detail for each single Process
        $ProcessData.Metrics.$ProcessName.List | Add-Member -MemberType NoteProperty -Name $ProcessId -Value (New-Object PSCustomObject);
        $ProcessData.Metrics.$ProcessName.List.$ProcessId | Add-Member -MemberType NoteProperty -Name 'Name'           -Value $ProcessName;
        $ProcessData.Metrics.$ProcessName.List.$ProcessId | Add-Member -MemberType NoteProperty -Name 'ProcessName'    -Value ([string]$entry.Name);
        $ProcessData.Metrics.$ProcessName.List.$ProcessId | Add-Member -MemberType NoteProperty -Name 'ProcessId'      -Value $ProcessId;
        $ProcessData.Metrics.$ProcessName.List.$ProcessId | Add-Member -MemberType NoteProperty -Name 'Priority'       -Value ([int]$entry.Priority);
        $ProcessData.Metrics.$ProcessName.List.$ProcessId | Add-Member -MemberType NoteProperty -Name 'PageFileUsage'  -Value ([decimal]$entry.PageFileUsage);
        $ProcessData.Metrics.$ProcessName.List.$ProcessId | Add-Member -MemberType NoteProperty -Name 'ThreadCount'    -Value ([int]$entry.ThreadCount);
        $ProcessData.Metrics.$ProcessName.List.$ProcessId | Add-Member -MemberType NoteProperty -Name 'KernelModeTime' -Value ([decimal]$entry.KernelModeTime);
        $ProcessData.Metrics.$ProcessName.List.$ProcessId | Add-Member -MemberType NoteProperty -Name 'UserModeTime'   -Value ([decimal]$entry.UserModeTime);
        $ProcessData.Metrics.$ProcessName.List.$ProcessId | Add-Member -MemberType NoteProperty -Name 'WorkingSetSize' -Value ([decimal]$entry.WorkingSetSize);
        $ProcessData.Metrics.$ProcessName.List.$ProcessId | Add-Member -MemberType NoteProperty -Name 'CommandLine'    -Value ([string]$entry.CommandLine);
        $ProcessData.Metrics.$ProcessName.List.$ProcessId | Add-Member -MemberType NoteProperty -Name 'CpuUsage'       -Value 0;
        $ProcessData.Metrics.$ProcessName.List.$ProcessId | Add-Member -MemberType NoteProperty -Name 'MemoryUsage'    -Value 0;

        # Total data for all processes with a given name
        $ProcessData.Metrics.$ProcessName.Total.PageFileUsage  += ([decimal]$entry.PageFileUsage);
        $ProcessData.Metrics.$ProcessName.Total.ThreadCount    += ([int]$entry.ThreadCount);
        $ProcessData.Metrics.$ProcessName.Total.WorkingSetSize += ([decimal]$entry.WorkingSetSize);
        $ProcessData.Metrics.$ProcessName.Total.ProcessCount   += 1;
    }

    # Process all process performance metrics and add memory and cpu usage to the correct process id
    foreach ($entry in $ProcessPerfDataList) {
        [string]$ProcessName = $entry.Name;
        [int]$ProcessId      = [int]$entry.IDProcess;

        if ($ProcessName.Contains('#')) {
            $ProcessName = $ProcessName.Substring(0, $ProcessName.IndexOf('#'));
        }

        if ((Test-IcingaArrayFilter -InputObject $ProcessName -Include $IncludeFilter -Exclude $ExcludeFilter) -eq $FALSE) {
            continue;
        }

        if ((Test-PSCustomObjectMember -PSObject $ProcessData.Metrics -Name $ProcessName) -eq $FALSE) {
            continue;
        }

        # Add a cache for our Process Data with all CPU loads for every single Process Id
        $CPUProcessCache.Add([string]::Format('{0}|{1}', $ProcessName, [string]$ProcessId), [int]$entry.PercentProcessorTime);
        $MEMProcessCache.Add([string]::Format('{0}|{1}', $ProcessName, [string]$ProcessId), [decimal]$entry.WorkingSetPrivate);

        # Just in case a process id is not present, we should ensure to add it to prevent exceptions
        if ((Test-PSCustomObjectMember -PSObject $ProcessData.Metrics.$ProcessName.List -Name $ProcessId) -eq $FALSE) {
            $ProcessData.Metrics.$ProcessName.List | Add-Member -MemberType NoteProperty -Name $ProcessId -Value (New-Object PSCustomObject);
            $ProcessData.Metrics.$ProcessName.List.$ProcessId | Add-Member -MemberType NoteProperty -Name 'CpuUsage'    -Value 0;
            $ProcessData.Metrics.$ProcessName.List.$ProcessId | Add-Member -MemberType NoteProperty -Name 'MemoryUsage' -Value 0;
        }

        $ProcessData.Metrics.$ProcessName.List.$ProcessId.CpuUsage     = [int]$entry.PercentProcessorTime;
        $ProcessData.Metrics.$ProcessName.List.$ProcessId.MemoryUsage  = [decimal]$entry.WorkingSetPrivate;
        $ProcessData.Metrics.$ProcessName.Total.CpuUsage              += [int]$entry.PercentProcessorTime;
        $ProcessData.Metrics.$ProcessName.Total.MemoryUsage           += [decimal]$entry.WorkingSetPrivate;
    }

    # Generaet a "hot" object for our 10 most CPU and Memory consuming process objects
    $ProcessData.Metadata     | Add-Member -MemberType NoteProperty -Name 'Hot'    -Value (New-Object PSCustomObject);
    $ProcessData.Metadata.Hot | Add-Member -MemberType NoteProperty -Name 'Cpu'    -Value (New-Object PSCustomObject);
    $ProcessData.Metadata.Hot | Add-Member -MemberType NoteProperty -Name 'Memory' -Value (New-Object PSCustomObject);

    [array]$TopCPUUsage  = $CPUProcessCache.GetEnumerator() | Sort-Object Value -Descending;
    [array]$TopMEMUsage  = $MEMProcessCache.GetEnumerator() | Sort-Object Value -Descending;
    [int]$IterationIndex = 0;

    while ($IterationIndex -lt 10) {
        if ($TopCPUUsage.Count -gt 0 -And (($TopCPUUsage.Count - 1) -ge $IterationIndex )) {

            if ($TopCPUUsage.Count -gt 1) {
                [string]$CPUProcessName = $TopCPUUsage.Key[$IterationIndex].Split('|')[0];
                [int]$CPUProcessId      = $TopCPUUsage.Key[$IterationIndex].Split('|')[1];
                [int]$CPUUsage          = $TopCPUUsage.Value[$IterationIndex];
            } else {
                [string]$CPUProcessName = $TopCPUUsage.Key.Split('|')[0];
                [int]$CPUProcessId      = $TopCPUUsage.Key.Split('|')[1];
                [int]$CPUUsage          = $TopCPUUsage.Value;
            }
 
            if ($TopCPUUsage.Value[$IterationIndex] -gt 0) {
                $ProcessData.Metadata.Hot.Cpu               | Add-Member -MemberType NoteProperty -Name $CPUProcessId -Value (New-Object PSCustomObject);
                $ProcessData.Metadata.Hot.Cpu.$CPUProcessId | Add-Member -MemberType NoteProperty -Name 'Name'        -Value $CPUProcessName;
                $ProcessData.Metadata.Hot.Cpu.$CPUProcessId | Add-Member -MemberType NoteProperty -Name 'ProcessId'   -Value $CPUProcessId;
                $ProcessData.Metadata.Hot.Cpu.$CPUProcessId | Add-Member -MemberType NoteProperty -Name 'CpuUsage'    -Value $CPUUsage;
            }
        }

        if ($TopMEMUsage.Count -gt 0 -And (($TopMEMUsage.Count - 1) -ge $IterationIndex )) {
            if ($TopMEMUsage.Count -gt 1) {
                [string]$MEMProcessName = $TopMEMUsage.Key[$IterationIndex].Split('|')[0];
                [int]$MEPProcessId      = $TopMEMUsage.Key[$IterationIndex].Split('|')[1];
                [decimal]$MemoryUsage   = $TopMEMUsage.Value[$IterationIndex];
            } else {
                [string]$MEMProcessName = $TopMEMUsage.Key.Split('|')[0];
                [int]$MEPProcessId      = $TopMEMUsage.Key.Split('|')[1];
                [decimal]$MemoryUsage   = $TopMEMUsage.Value;
            }

            if ($TopMEMUsage.Value[$IterationIndex] -gt 0) {
                $ProcessData.Metadata.Hot.Memory               | Add-Member -MemberType NoteProperty -Name $MEPProcessId -Value (New-Object PSCustomObject);
                $ProcessData.Metadata.Hot.Memory.$MEPProcessId | Add-Member -MemberType NoteProperty -Name 'Name'        -Value $MEMProcessName;
                $ProcessData.Metadata.Hot.Memory.$MEPProcessId | Add-Member -MemberType NoteProperty -Name 'ProcessId'   -Value $MEPProcessId;
                $ProcessData.Metadata.Hot.Memory.$MEPProcessId | Add-Member -MemberType NoteProperty -Name 'MemoryUsage' -Value $MemoryUsage;
            }
        }

        $IterationIndex += 1;
    }

    $CPUProcessCache     = $null;
    $MEMProcessCache     = $null;
    $ProcessInformation  = $null;
    $ProcessPerfDataList = $null;
    $TopCPUUsage         = $null;
    $TopMEMUsage         = $null;

    return $ProcessData;
}
