Pages/Dynamic/OverviewPage.ps1

#region >> Overview Page

$OverviewPageContent = {
    param($RemoteHost)

    $PUDRSSyncHT = $global:PUDRSSyncHT

    # Load PUDAdminCenter Module Functions Within ScriptBlock
    $ThisModuleFunctionsStringArray | Where-Object {$_ -ne $null} | foreach {Invoke-Expression $_ -ErrorAction SilentlyContinue}

    # For some reason, scriptblocks defined earlier can't be used directly here. They need to be a different objects before
    # they actually behave as expected. Not sure why.
    #$RecreatedDisconnectedPageContent = [scriptblock]::Create($DisconnectedPageContentString)

    $RHostIP = $($PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}).IPAddressList[0]

    #region >> Ensure $RemoteHost is Valid

    if ($PUDRSSyncHT.RemoteHostList.HostName -notcontains $RemoteHost) {
        $ErrorText = "The Remote Host $($RemoteHost.ToUpper()) is not a valid Host Name!"
    }

    if ($ErrorText) {
        New-UDRow -Columns {
            New-UDColumn -Size 4 -Content {
                New-UDHeading -Text ""
            }
            New-UDColumn -Size 4 -Content {
                New-UDHeading -Text $ErrorText -Size 6
            }
            New-UDColumn -Size 4 -Content {
                New-UDHeading -Text ""
            }
        }
    }

    # If $RemoteHost isn't valid, don't load anything else
    if ($ErrorText) {
        return
    }

    #endregion >> Ensure $RemoteHost is Valid

    #region >> Loading Indicator

    New-UDRow -Columns {
        New-UDColumn -Endpoint {
            $Session:OverviewPageLoadingTracker = [System.Collections.ArrayList]::new()
            $Session:RestartingRemoteHost = $False
            $Session:ShutdownRemoteHost = $False
            $Session:EnableDiskPerf = $False
            $Session:DisableDiskPerf = $False
            $Session:EnableRemoteDesktop = $False
            $Session:DisableRemoteDesktop = $False
            $Session:EnableSSH = $False
            $Session:DisableSSH = $False
        }
        New-UDColumn -AutoRefresh -RefreshInterval 10 -Endpoint {
            if ($Session:OverviewPageLoadingTracker -notcontains "FinishedLoading") {
                New-UDHeading -Text "Loading...Please wait..." -Size 5
                New-UDPreloader -Size small
            }
        }
    }

    #endregion >> Loading Indicator

    # Master Endpoint - All content will be within this Endpoint so that we can reference $Cache: and $Session: scope variables
    New-UDColumn -Size 12 -Endpoint {
        #region >> Ensure We Are Connected / Can Connect to $RemoteHost

        $PUDRSSyncHT = $global:PUDRSSyncHT

        # Load PUDAdminCenter Module Functions Within ScriptBlock
        $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -ne $null} | foreach {Invoke-Expression $_ -ErrorAction SilentlyContinue}

        # For some reason, scriptblocks defined earlier can't be used directly here. They need to be a different objects before
        # they actually behave as expected. Not sure why.
        #$RecreatedDisconnectedPageContent = [scriptblock]::Create($DisconnectedPageContentString)

        $RHostIP = $($PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}).IPAddressList[0]

        if ($Session:CredentialHT.$RemoteHost.PSRemotingCreds -eq $null) {
            Invoke-UDRedirect -Url "/Disconnected/$RemoteHost"
        }

        try {
            $ConnectionStatus = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {"Connected"}
        }
        catch {
            $ConnectionStatus = "Disconnected"
        }

        # If we're not connected to $RemoteHost, don't load anything else
        if ($ConnectionStatus -ne "Connected") {
            #Invoke-Command -ScriptBlock $RecreatedDisconnectedPageContent -ArgumentList $RemoteHost
            Invoke-UDRedirect -Url "/Disconnected/$RemoteHost"
        }
        else {
            New-UDRow -EndPoint {
                New-UDColumn -Size 3 -Content {
                    New-UDHeading -Text ""
                }
                New-UDColumn -Size 6 -Endpoint {
                    New-UDTable -Id "TrackingTable" -Headers @("RemoteHost","Status","CredSSP","DateTime") -AutoRefresh -RefreshInterval 2 -Endpoint {
                        $PUDRSSyncHT = $global:PUDRSSyncHT

                        # Load PUDAdminCenter Module Functions Within ScriptBlock
                        $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -ne $null} | foreach {Invoke-Expression $_ -ErrorAction SilentlyContinue}
                        
                        $RHostIP = $($PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}).IPAddressList[0]

                        #$WSMan5985Available = $(TestPort -HostName $RHostIP -Port 5985).Open
                        #$WSMan5986Available = $(TestPort -HostName $RHostIP -Port 5986).Open

                        $ConnectionStatus = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {"Connected"}

                        if ($ConnectionStatus -eq "Connected") {
                            $TableData = @{
                                RemoteHost      = $RemoteHost.ToUpper()
                                Status          = "Connected"
                            }
                        }
                        else {
                            <#
                            $TableData = @{
                                RemoteHost = $RemoteHost.ToUpper()
                                Status = "Disconnected"
                            }
                            #>

                            Invoke-UDRedirect -Url "/Disconnected/$RemoteHost"
                        }

                        # SUPER IMPORTANT NOTE: ALL Real-Time Enpoints on the Page reference LiveOutputClone!
                        if ($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count -gt 0) {
                            if ($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous -eq $null) {
                                $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Clone()
                            }
                            if ($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Current.Count -gt 0) {
                                $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Current.Clone()
                            }
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Current = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Clone()
                        }
                        
                        if ($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.Count -eq 0) {
                            if ($Session:ServerInventoryStatic.IsCredSSPEnabled) {
                                $CredSSPStatus = "Enabled"
                            }
                            else {
                                $CredSSPStatus = "Disabled"
                            }
                        }
                        elseif (@($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.ServerInventory).Count -gt 0) {
                            if (@($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.ServerInventory)[-1].IsCredSSPEnabled) {
                                $CredSSPStatus = "Enabled"
                            }
                            else {
                                $CredSSPStatus = "Disabled"
                            }
                        }
                        else {
                            $CredSSPStatus = "NotYetDetermined"
                        }
                        $TableData.Add("CredSSP",$CredSSPStatus)

                        $TableData.Add("DateTime",$(Get-Date -Format MM-dd-yy_hh:mm:sstt))

                        [PSCustomObject]$TableData | Out-UDTableData -Property @("RemoteHost","Status","CredSSP","DateTime")
                    }
                }
                New-UDColumn -Size 3 -Content {
                    New-UDHeading -Text ""
                }
            }
        }

        #region >> Ensure We Are Connected / Can Connect to $RemoteHost

        #region >> Gather Some Initial Info From $RemoteHost

        $GetServerInventoryFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function Get-ServerInventory" -and $_ -notmatch "function Get-PUDAdminCenter"}
        #$GetEnvVarsFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function Get-EnvironmentVariables" -and $_ -notmatch "function Get-PUDAdminCenter"}
        $StaticInfo = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
            Invoke-Expression $using:GetServerInventoryFunc
            #Invoke-Expression $using:GetEnvVarsFunc
            
            $SrvInv = Get-ServerInventory
            #$EnvVars = Get-EnvironmentVariables
            $RelevantNetworkInterfacesPrep = [System.Net.NetworkInformation.Networkinterface]::GetAllNetworkInterfaces() | Where-Object {
                $_.NetworkInterfaceType -eq "Ethernet" -or $_.NetworkInterfaceType -match "Wireless" -and $_.OperationalStatus -eq "Up"
            }
            $RelevantNetworkInterfaces = foreach ($NetInt in $RelevantNetworkInterfacesPrep) {
                $IPv4Stats = $NetInt.GetIPv4Statistics()
                [pscustomobject]@{
                    Name                = $NetInt.Name
                    Description         = $NetInt.Description
                    TotalSentBytes      = $IPv4Stats.BytesSent
                    TotalReceivedBytes  = $IPv4Stats.BytesReceived
                }
            }

            [pscustomobject]@{
                ServerInventoryStatic       = $SrvInv
                RelevantNetworkInterfaces   = $RelevantNetworkInterfaces
                #EnvironmentVariables = [pscustomobject]$EnvVars
            }
        }
        $Session:ServerInventoryStatic = $StaticInfo.ServerInventoryStatic
        $Session:RelevantNetworkInterfacesStatic = $StaticInfo.RelevantNetworkInterfaces
        #$Session:EnvironmentVariablesStatic = $StaticInfo.EnvironmentVariables
        if ($PUDRSSyncHT."$RemoteHost`Info".Overview.Keys -notcontains "ServerInventoryStatic") {
            $PUDRSSyncHT."$RemoteHost`Info".Overview.Add("ServerInventoryStatic",$Session:ServerInventoryStatic)
        }
        else {
            $PUDRSSyncHT."$RemoteHost`Info".Overview.ServerInventoryStatic = $Session:ServerInventoryStatic
        }
        if ($PUDRSSyncHT."$RemoteHost`Info".Overview.Keys -notcontains "RelevantNetworkInterfaces") {
            $PUDRSSyncHT."$RemoteHost`Info".Overview.Add("RelevantNetworkInterfaces",$Session:RelevantNetworkInterfacesStatic)
        }
        else {
            $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces = $Session:RelevantNetworkInterfacesStatic
        }
        <#
        if ($PUDRSSyncHT."$RemoteHost`Info".Overview.Keys -notcontains "EnvironmentVariablesStatic") {
            $PUDRSSyncHT."$RemoteHost`Info".Overview.Add("EnvironmentVariablesStatic",$Session:EnvironmentVariablesStatic)
        }
        else {
            $PUDRSSyncHT."$RemoteHost`Info".Overview.EnvironmentVariablesStatic = $Session:EnvironmentVariablesStatic
        }
        #>


        #endregion >> Gather Some Initial Info From $RemoteHost

        #region >> Page Name and Horizontal Nav

        New-UDRow -Endpoint {
            New-UDColumn -Content {
                New-UDHeading -Text "Overview" -Size 3
                New-UDHeading -Text "NOTE: Domain Group Policy trumps controls with an asterisk (*)" -Size 6
            }
        }
        New-UDRow -Endpoint {
            New-UDColumn -Size 12 -Content {
                New-UDCollapsible -Items {
                    New-UDCollapsibleItem -Title "More Tools" -Icon laptop -Active -Endpoint {
                        New-UDRow -Endpoint {
                            foreach ($ToolName in $($Cache:DynamicPages | Where-Object {$_ -notmatch "PSRemotingCreds|ToolSelect"})) {
                                New-UDColumn -Endpoint {
                                    $ToolNameNoSpaces = $ToolName -replace "[\s]",""
                                    New-UDLink -Text $ToolName -Url "/$ToolNameNoSpaces/$RemoteHost" -Icon dashboard
                                }
                            }
                            #New-UDCard -Links $Links
                        }
                    }
                }
            }
        }

        #endregion >> Page Name and Horizontal Nav

        #region >> Setup LiveData

        New-UDColumn -Endpoint {
            $PUDRSSyncHT = $global:PUDRSSyncHT

            $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -ne $null} | foreach {Invoke-Expression $_ -ErrorAction SilentlyContinue}

            $RHostIP = $($PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}).IPAddressList[0]

            <#
            if (!$Session:ServerInventoryStatic) {
                # Gather Basic Info From $RemoteHost
                $GetServerInventoryFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function Get-ServerInventory" -and $_ -notmatch "function Get-PUDAdminCenter"}
                $StaticInfoA = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                    Invoke-Expression $using:GetServerInventoryFunc

                    $SrvInv = Get-ServerInventory

                    [pscustomobject]@{
                        ServerInventoryStatic = $SrvInv
                    }
                }
                $Session:ServerInventoryStatic = $StaticInfoA.ServerInventoryStatic
                if ($PUDRSSyncHT."$RemoteHost`Info".Overview.Keys -notcontains "ServerInventoryStatic") {
                    $PUDRSSyncHT."$RemoteHost`Info".Overview.Add("ServerInventoryStatic",$Session:ServerInventoryStatic)
                }
                else {
                    $PUDRSSyncHT."$RemoteHost`Info".Overview.ServerInventoryStatic = $Session:ServerInventoryStatic
                }
            }
            #>


            # Remove Existing Runspace for LiveDataRSInfo if it exists as well as the PSSession Runspace within
            if ($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo -ne $null) {
                $PSSessionRunspacePrep = @(
                    Get-Runspace | Where-Object {
                        $_.RunspaceIsRemote -and
                        $_.Id -gt $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.ThisRunspace.Id -and
                        $_.OriginalConnectionInfo.ComputerName -eq $RemoteHost
                    }
                )
                if ($PSSessionRunspacePrep.Count -gt 0) {
                    $PSSessionRunspace = $($PSSessionRunspacePrep | Sort-Object -Property Id)[0]
                }
                $PSSessionRunspace.Dispose()
                $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.ThisRunspace.Dispose()
            }

            # Create a Runspace that creates a PSSession to $RemoteHost that is used once every second to re-gather data from $RemoteHost
            $GetEnvVarsFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function Get-EnvironmentVariables" -and $_ -notmatch "function Get-PUDAdminCenter"}
            $GetServerInventoryFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function Get-ServerInventory" -and $_ -notmatch "function Get-PUDAdminCenter"}
            $LiveDataFunctionsToLoad = @($GetEnvVarsFunc,$GetServerInventoryFunc)
            
            # The New-Runspace function handles scope for you behind the scenes, so just pretend that everything within -ScriptBlock {} is in the current scope
            New-Runspace -RunspaceName "Overview$RemoteHost`LiveData" -ScriptBlock {
                $PUDRSSyncHT = $global:PUDRSSyncHT
            
                $LiveDataPSSession = New-PSSession -Name "Overview$RemoteHost`LiveData" -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds

                # Load needed functions in the PSSession
                Invoke-Command -Session $LiveDataPSSession -ScriptBlock {
                    $using:LiveDataFunctionsToLoad | foreach {Invoke-Expression $_}
                }

                $RSLoopCounter = 0

                while ($PUDRSSyncHT) {
                    # $LiveOutput is a special ArrayList created and used by the New-Runspace function that collects output as it occurs
                    # We need to limit the number of elements this ArrayList holds so we don't exhaust memory
                    if ($LiveOutput.Count -gt 1000) {
                        $LiveOutput.RemoveRange(0,800)
                    }

                    # Stream Results to $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput
                    Invoke-Command -Session $LiveDataPSSession -ScriptBlock {
                        # Place most resource intensive operations first

                        # Operations that you only want running once every 30 seconds go withing this 'if; block
                        # Adjust the timing as needed with deference to $RemoteHost resource efficiency.
                        if ($using:RSLoopCounter -eq 0 -or $($using:RSLoopCounter % 30) -eq 0) {
                            # Server Inventory
                            @{ServerInventory = Get-ServerInventory}
                            #Start-Sleep -Seconds 3
                        
                            # Processes
                            #@{Processes = [System.Diagnostics.Process]::GetProcesses()}
                            #Start-Sleep -Seconds 3
                        }

                        # Operations that you want to run once every second go here

                        # Processes
                        @{ProcessesCount = $(Get-Counter "\Process(*)\ID Process" -ErrorAction SilentlyContinue).CounterSamples.Count}
                        @{HandlesCount = $(Get-Counter "\Process(_total)\handle count").CounterSamples.CookedValue}
                        @{ThreadsCount = $(Get-Counter "\Process(_total)\thread count").CounterSamples.CookedValue}

                        # Environment Variables
                        #@{EnvVars = [pscustomobject]@{EnvVarsCollection = Get-EnvironmentVariables}}

                        # RAM Utilization
                        $OSInfo = Get-CimInstance Win32_OperatingSystem
                        $TotalMemoryInGB = [Math]::Round($($OSInfo.TotalVisibleMemorySize / 1MB),2)
                        @{RamTotalGB = $TotalMemoryInGB}
                        
                        $FreeMemoryInGB = [Math]::Round($($(Get-Counter -Counter "\Memory\available bytes").CounterSamples.CookedValue / 1GB),2)
                        @{RamFreeGB = $FreeMemoryInGB}

                        $RamPct = [Math]::Round($($(Get-Counter -Counter "\Memory\% committed bytes in use").CounterSamples.CookedValue),2)
                        @{RamPct = $RamPct}
                        
                        $RamCommittedGB = [Math]::Round($($(Get-Counter -Counter "\Memory\committed bytes").CounterSamples.CookedValue / 1GB),2)
                        @{RamCommittedGB = $RamCommittedGB}

                        $RamCachedGB = $RamCommitted + [Math]::Round($($(Get-Counter -Counter "\Memory\cache bytes").CounterSamples.CookedValue / 1GB),2)
                        @{RamCachedGB = $RamCachedGB}

                        $RamInUseGB = $TotalMemoryInGB - $FreeMemoryInGB
                        @{RamInUseGB = $RamInUseGB}

                        $RamPagedPoolMB = [Math]::Round($($(Get-Counter -Counter "\Memory\pool paged bytes").CounterSamples.CookedValue / 1MB),2)
                        @{RamPagedPoolMB = $RamPagedPoolMB}

                        $RamNonPagedPoolMB = [Math]::Round($($(Get-Counter -Counter "\Memory\pool nonpaged bytes").CounterSamples.CookedValue / 1MB),2)
                        @{RamNonPagedPoolMB = $RamNonPagedPoolMB}

                        # CPU
                        $CPUInfo = Get-CimInstance Win32_Processor
                        @{CPUPct = $CPUInfo.LoadPercentage}
                        @{ClockSpeed = [Math]::Round($($CPUInfo.CurrentClockSpeed / 1KB),2)}

                        @{Uptime = "{0:c}" -f $($(Get-Date) - $OSInfo.LastBootUpTime)}

                        # Network Stats
                        $RelevantNetworkInterfaces = [System.Net.NetworkInformation.Networkinterface]::GetAllNetworkInterfaces() | Where-Object {
                            $_.NetworkInterfaceType -eq "Ethernet" -or $_.NetworkInterfaceType -match "Wireless" -and $_.OperationalStatus -eq "Up"
                        }
                        [System.Collections.ArrayList]$NetStatsInfo = @()
                        foreach ($NetInt in $RelevantNetworkInterfaces) {
                            $IPv4Stats = $NetInt.GetIPv4Statistics()
                            $NetStatsPSObj = [pscustomobject]@{
                                Name                = $NetInt.Name
                                Description         = $NetInt.Description
                                TotalSentBytes      = $IPv4Stats.BytesSent
                                TotalReceivedBytes  = $IPv4Stats.BytesReceived
                            }
                            $null = $NetStatsInfo.Add($NetStatsPSObj)
                        }
                        @{NetStats = $NetStatsInfo}

                    } | foreach {$null = $LiveOutput.Add($_)}

                    $RSLoopCounter++

                    [GC]::Collect()

                    Start-Sleep -Seconds 1
                }
            }
            # The New-Runspace function outputs / continually updates a Global Scope variable called $global:RSSyncHash. The results of
            # the Runspace we just created can be found in $global:RSSyncHash's "Overview$RemoteHost`LiveDataResult" Property - which is just
            # the -RunspaceName value plus the word 'Info'. By setting $PUDRSSyncHT."$RemoteHost`Info".Certificates.LiveDataRSInfo equal to
            # $RSSyncHash."Overview$RemoteHost`LiveDataResult", we can now reference $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput
            # to get the latest data from $RemoteHost.
            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo = $RSSyncHash."Overview$RemoteHost`LiveDataResult"
        }

        #endregion >> Setup LiveData

        #region >> Controls

        New-UDRow -Endpoint {
            # Restart $RemoteHost
            New-UDColumn -Size 3 -Endpoint {
                # Show-UDToast doesn't work in this context for some reason...
                <#
                New-UDElement -Id "RestartComputerToast" -Tag div -EndPoint {
                    Show-UDToast -Message "Restarting $RemoteHost..." -Duration 10
                }
                #>


                $CollapsibleId = $RemoteHost + "RestartComputer"
                New-UDCollapsible -Id $CollapsibleId -Items {
                    New-UDCollapsibleItem -Title "Restart" -Icon laptop -Endpoint {
                        New-UDElement -Id "RestartComputerMsg" -Tag div -EndPoint {
                            if ($Session:RestartingRemoteHost) {
                                New-UDHeading -Text "Restarting $RemoteHost..." -Size 6
                            }
                        }
                        New-UDButton -Text "Restart $RemoteHost" -OnClick {
                            $Session:RestartingRemoteHost = $True
                            Sync-UDElement -Id "RestartComputerMsg"

                            Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                Restart-Computer -Force
                            }

                            # Show-UDToast doesn't work in this context for some reason...
                            #Show-UDToast -Message "Restarting $RemoteHost..." -Duration 10
                            #Sync-UDElement -Id "RestartComputerToast"
                        }

                        <#
                        New-UDInput -SubmitText "Restart" -Id "RestartComputerForm" -Content {
                            $HName = $PUDRSSyncHT."$RemoteHost`Info".Overview.ServerInventoryStatic.ComputerSystem.Name
                            New-UDInputField -Name 'RestartComputer' -Type select -Values @($HName) -DefaultValue $HName
                        } -Endpoint {
                            #region >> Check Connection

                            $PUDRSSyncHT = $global:PUDRSSyncHT

                            $RHostIP = $($PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}).IPAddressList[0]

                            #endregion >> Check Connection

                            #region >> Main
                            
                            Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                Restart-Computer -Force
                            }

                            New-UDInputAction -Toast "Restarting $RemoteHost..." -Duration 10000
                            
                            New-UDInputAction -RedirectUrl "/Disconnected/$RemoteHost"

                            #endregion >> Main
                        }
                        #>

                    }
                }
            }

            # Shutdown $RemoteHost
            New-UDColumn -Size 3 -Endpoint {
                $CollapsibleId = $RemoteHost + "ShutdownComputer"
                New-UDCollapsible -Id $CollapsibleId -Items {
                    New-UDCollapsibleItem -Title "Shutdown" -Icon laptop -Endpoint {
                        New-UDElement -Id "ShutdownComputerMsg" -Tag div -EndPoint {
                            if ($Session:ShutdownRemoteHost) {
                                New-UDHeading -Text "Shutting down $RemoteHost..." -Size 6
                            }
                        }
                        New-UDButton -Text "Shutdown $RemoteHost" -OnClick {
                            $Session:ShutdownRemoteHost = $True
                            Sync-UDElement -Id "ShutdownComputerMsg"

                            Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                Stop-Computer -Force
                            }
                        }

                        <#
                        New-UDInput -SubmitText "Shutdown" -Id "ShutdownComputerForm" -Content {
                            $HName = $PUDRSSyncHT."$RemoteHost`Info".Overview.ServerInventoryStatic.ComputerSystem.Name
                            New-UDInputField -Name "ShutdownComputer" -Type select -Values @($HName) -DefaultValue $HName
                        } -Endpoint {
                            #region >> Check Connection

                            $PUDRSSyncHT = $global:PUDRSSyncHT

                            $RHostIP = $($PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}).IPAddressList[0]

                            #endregion >> Check Connection

                            #region >> Main

                            Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                Stop-Computer -Force
                            }

                            New-UDInputAction -Toast "Shutting down $RemoteHost..." -Duration 10000
                            
                            New-UDInputAction -RedirectUrl "/Disconnected/$RemoteHost"

                            #endregion >> Main
                        }
                        #>

                    }
                }
            }
            # Enable Disk Metrics
            New-UDColumn -Size 3 -Endpoint {
                $CollapsibleId = $RemoteHost + "SetDiskMetrics"
                New-UDCollapsible -Id $CollapsibleId -Items {
                    New-UDCollapsibleItem -Title "Set Disk Metrics" -Icon laptop -Endpoint {
                        New-UDRow -Endpoint {
                            New-UDColumn -Endpoint {
                                New-UDElement -Id "EnableDiskPerfMsg" -Tag div -EndPoint {
                                    if ($Session:EnableDiskPerf) {
                                        New-UDHeading -Text $Session:EnableDiskPerfMsg -Size 6
                                        Show-UDToast -Message $Session:EnableDiskPerfMsg -Position 'topRight' -Title "DiskPerfToast" -Duration 5000
                                    }
                                }
                                New-UDElement -Id "DisableDiskPerfMsg" -Tag div -EndPoint {
                                    if ($Session:DisableDiskPerf) {
                                        New-UDHeading -Text $Session:DisableDiskPerfMsg -Size 6
                                        Show-UDToast -Message $Session:DisableDiskPerfMsg -Position 'topRight' -Title "DiskPerfToast" -Duration 5000
                                    }
                                }
                                New-UDElement -Id "DiskPerfState" -Tag div -EndPoint {
                                    # TODO: Figure out a way to check if the disk performance counters are actually enabled or disabled.
                                    # Can't get consistent results using the below method
                                    <#
                                    $DiskPerfState = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                        try {
                                            $null = Get-Counter "\physicaldisk(0 c:)\disk writes/sec" -ErrorAction Stop
                                            $DiskPerfStatus = "Enabled"
                                        }
                                        catch {
                                            $DiskPerfStatus = "Disabled"
                                        }

                                        [pscustomobject]@{
                                            Status = $DiskPerfStatus
                                        }
                                    }
                                    #>


                                    New-UDHeading -Text "Status: $Session:DiskPerfState" -Size 6
                                }
                            }
                        }
                        New-UDRow -Endpoint {
                            New-UDColumn -EndPoint {
                                New-UDButton -Text "Enable" -OnClick {
                                    $Session:EnableDiskPerfMsg = "Enabling Disk Performance Metrics for $RemoteHost..."
                                    $Session:EnableDiskPerf = $True
                                    Sync-UDElement -Id "EnableDiskPerfMsg"

                                    $StartDiskPerfFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function Start-DiskPerf" -and $_ -notmatch "function Get-PUDAdminCenter"}
                                    $null = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                        Invoke-Expression $using:StartDiskPerfFunc
                                        $null = Start-DiskPerf
                                    }

                                    $Session:DiskPerfState = "Enabled"
                                    Sync-UDElement -Id "DiskPerfState"

                                    $Session:EnableDiskPerf = $False
                                    Sync-UDElement -Id "EnableDiskPerfMsg"
                                }
                            }
                            New-UDColumn -Endpoint {
                                New-UDButton -Text "Disable" -OnClick {
                                    $Session:DisableDiskPerfMsg = "Disabling Disk Performance Metrics for $RemoteHost..."
                                    $Session:DisableDiskPerf = $True
                                    Sync-UDElement -Id "DisableDiskPerfMsg"

                                    $StopDiskPerfFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function Stop-DiskPerf" -and $_ -notmatch "function Get-PUDAdminCenter"}
                                    $null = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                        Invoke-Expression $using:StopDiskPerfFunc
                                        Stop-DiskPerf
                                    }

                                    $Session:DiskPerfState = "Disabled"
                                    Sync-UDElement -Id "DiskPerfState"

                                    $Session:DisableDiskPerf = $False
                                    Sync-UDElement -Id "DisableDiskPerfMsg"
                                }
                            }
                        }
                    }
                }
            }

            # Disable CredSSP
            New-UDColumn -Size 3 -Endpoint {
                $CollapsibleId = $RemoteHost + "DisableCredSSP"
                New-UDCollapsible -Id $CollapsibleId -Items {
                    New-UDCollapsibleItem -Title "Disable CredSSP*" -Icon laptop -Endpoint {
                        New-UDRow -Endpoint {
                            New-UDColumn -Endpoint {
                                New-UDElement -Id "DisableCredSSPMsg" -Tag div -EndPoint {
                                    if ($Session:DisableCredSSP) {
                                        if (!$Session:DisableCredSSPMsg) {
                                            $Session:DisableCredSSPMsg = "Placeholder CredSSP Message"
                                        }
                                        New-UDHeading -Text $Session:DisableCredSSPMsg -Size 6
                                        Show-UDToast -Message $Session:DisableCredSSPMsg -Position 'topRight' -Title "CredSSPToast" -Duration 5000
                                    }
                                }
                                New-UDElement -Id "CredSSPState" -Tag div -EndPoint {
                                    if ($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.Count -eq 0) {
                                        if ($Session:ServerInventoryStatic.IsCredSSPEnabled) {
                                            $CredSSPStatus = "Enabled"
                                        }
                                        else {
                                            $CredSSPStatus = "Disabled"
                                        }
                                    }
                                    elseif (@($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.ServerInventory).Count -gt 0) {
                                        if (@($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.ServerInventory)[-1].IsCredSSPEnabled) {
                                            $CredSSPStatus = "Enabled"
                                        }
                                        else {
                                            $CredSSPStatus = "Disabled"
                                        }
                                    }
                                    else {
                                        $CredSSPStatus = "NotYetDetermined"
                                    }
                                    
                                    New-UDHeading -Text "Status: $CredSSPStatus" -Size 6
                                }
                            }
                        }
                        New-UDRow -Endpoint {
                            New-UDColumn -Endpoint {
                                New-UDButton -Text "Disable" -OnClick {
                                    if ($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.Count -eq 0) {
                                        if ($Session:ServerInventoryStatic.IsCredSSPEnabled) {
                                            $CredSSPStatus = "Enabled"
                                        }
                                        else {
                                            $CredSSPStatus = "Disabled"
                                        }
                                    }
                                    elseif (@($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.ServerInventory).Count -gt 0) {
                                        if (@($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.ServerInventory)[-1].IsCredSSPEnabled) {
                                            $CredSSPStatus = "Enabled"
                                        }
                                        else {
                                            $CredSSPStatus = "Disabled"
                                        }
                                    }
                                    else {
                                        $CredSSPStatus = "NotYetDetermined"
                                    }

                                    if ($CredSSPStatus -ne "Disabled") {
                                        $Session:DisableCredSSP = $True

                                        $CredSSPChanges = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                            $Output = @{}
                                            $GetCredSSPStatus = Get-WSManCredSSP
                                            if ($GetCredSSPStatus -match "The machine is configured to allow delegating fresh credentials.") {
                                                Disable-WSManCredSSP -Role Client
                                                $Output.Add("CredSSPClientChange",$True)
                                            }
                                            else {
                                                $Output.Add("CredSSPClientChange",$False)
                                            }
                                            if ($GetCredSSPStatus -match "This computer is configured to receive credentials from a remote client computer.") {
                                                Disable-WSManCredSSP -Role Server
                                                $Output.Add("CredSSPServerChange",$True)
                                            }
                                            else {
                                                $Output.Add("CredSSPServerChange",$False)
                                            }
                                            [PSCustomObject]$Output
                                        }

                                        [System.Collections.ArrayList]$ToastMessage = @()
                                        if ($CredSSPChanges.CredSSPClientChange -eq $True) {
                                            $null = $ToastMessage.Add("Disabled CredSSP Client.")
                                        }
                                        else {
                                            $null = $ToastMessage.Add("CredSSP Client is already disabled.")
                                        }
                                        if ($CredSSPChanges.CredSSPServerChange -eq $True) {
                                            $null = $ToastMessage.Add("Disabled CredSSP Server.")
                                        }
                                        else {
                                            $null = $ToastMessage.Add("CredSSP Server is already disabled.")
                                        }
                                        $Session:DisableCredSSPMsg = $ToastMessage -join " "

                                        Sync-UDElement -Id "DisableCredSSPMsg"
                                    }
                                    else {
                                        $Session:DisableCredSSP = $True

                                        $Session:DisableCredSSPMsg = "CredSSP is already Disabled!"

                                        Sync-UDElement -Id "DisableCredSSPMsg"
                                    }

                                    Sync-UDElement -Id "CredSSPState"

                                    Start-Sleep -Seconds 5
                                    $Session:DisableCredSSP = $False
                                    Sync-UDElement -Id "DisableCredSSPMsg"
                                }

                                <#
                                New-UDInput -SubmitText "Disable CredSSP" -Id "DisableCredSSPForm" -Content {
                                    $HName = $PUDRSSyncHT."$RemoteHost`Info".Overview.ServerInventoryStatic.ComputerSystem.Name
                                    New-UDInputField -Name "Disable_CredSSP" -Type select -Values @($HName) -DefaultValue $HName
                                } -Endpoint {
                                    param($Disable_CredSSP)

                                    #region >> Check Connection

                                    $PUDRSSyncHT = $global:PUDRSSyncHT

                                    $RHostIP = $($PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}).IPAddressList[0]

                                    #endregion >> Check Connection

                                    #region >> Main

                                    $CredSSPChanges = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                        $Output = @{}
                                        $GetCredSSPStatus = Get-WSManCredSSP
                                        if ($GetCredSSPStatus -match "The machine is configured to allow delegating fresh credentials.") {
                                            Disable-WSManCredSSP -Role Client
                                            $Output.Add("CredSSPClientChange",$True)
                                        }
                                        else {
                                            $Output.Add("CredSSPClientChange",$False)
                                        }
                                        if ($GetCredSSPStatus -match "This computer is configured to receive credentials from a remote client computer.") {
                                            Disable-WSManCredSSP -Role Server
                                            $Output.Add("CredSSPServerChange",$True)
                                        }
                                        else {
                                            $Output.Add("CredSSPServerChange",$False)
                                        }
                                        [PSCustomObject]$Output
                                    }

                                    [System.Collections.ArrayList]$ToastMessage = @()
                                    if ($CredSSPChanges.CredSSPClientChange -eq $True) {
                                        $null = $ToastMessage.Add("Disabled CredSSP Client.")
                                    }
                                    else {
                                        $null = $ToastMessage.Add("CredSSP Client is already disabled.")
                                    }
                                    if ($CredSSPChanges.CredSSPServerChange -eq $True) {
                                        $null = $ToastMessage.Add("Disabled CredSSP Server.")
                                    }
                                    else {
                                        $null = $ToastMessage.Add("CredSSP Server is already disabled.")
                                    }
                                    $ToastMessageFinal = $ToastMessage -join " "

                                    New-UDInputAction -Toast $ToastMessageFinal -Duration 2000
                                    Start-Sleep -Seconds 2

                                    #Sync-UDElement -Id 'TrackingTable'

                                    #New-UDInputAction -RedirectUrl "/Overview/$RemoteHost"

                                    Invoke-UDRedirect -Url "/Overview/$RemoteHost"

                                    #endregion >> Main
                                }
                                #>

                            }
                        }
                    }
                }
            }
        }
        New-UDRow -Endpoint {
            # Remote Desktop
            New-UDColumn -Size 3 -Endpoint {
                $CollapsibleId = $RemoteHost + "RemoteDesktop"
                New-UDCollapsible -Id $CollapsibleId -Items {
                    New-UDCollapsibleItem -Title "Remote Desktop*" -Icon laptop -Endpoint {
                        New-UDRow -Endpoint {
                            New-UDColumn -Endpoint {
                                New-UDElement -Id "EnableRemoteDesktopMsg" -Tag div -EndPoint {
                                    if ($Session:EnableRemoteDesktop) {
                                        New-UDHeading -Text $Session:EnableRemoteDesktopMsg -Size 6
                                        Show-UDToast -Message $Session:EnableRemoteDesktopMsg -Position 'topRight' -Title "RDToast" -Duration 5000
                                    }
                                }
                                New-UDElement -Id "DisableRemoteDesktopMsg" -Tag div -EndPoint {
                                    if ($Session:DisableRemoteDesktop) {
                                        New-UDHeading -Text $Session:DisableRemoteDesktopMsg -Size 6
                                        Show-UDToast -Message $Session:DisableRemoteDesktopMsg -Position 'topRight' -Title "RDToast" -Duration 5000
                                    }
                                }
                                New-UDElement -Id "RDState" -Tag div -EndPoint {
                                    $GetRDFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function Get-RemoteDesktop" -and $_ -notmatch "function Get-PUDAdminCenter"}
                                    $RemoteDesktopSettings = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                        Invoke-Expression $using:GetRDFunc
                                        Get-RemoteDesktop
                                    } -HideComputerName
                                    $RDState = if ($RemoteDesktopSettings.allowRemoteDesktop) {"Enabled"} else {"Disabled"}
                                    
                                    New-UDHeading -Text "Status: $RDState" -Size 6
                                }
                            }
                        }
                        New-UDRow -Endpoint {
                            New-UDColumn -Endpoint {
                                New-UDButton -Text "Enable" -OnClick {
                                    $Session:EnableRemoteDesktopMsg = "Enabling Remote Desktop on $($RemoteHost.ToUpper())..."
                                    $Session:EnableRemoteDesktop = $True
                                    Sync-UDElement -Id "EnableRemoteDesktopMsg"

                                    $SetRemoteDesktopSplatParams = @{
                                        AllowRemoteDesktop        = $True
                                        AllowRemoteDesktopWithNLA = $True
                                    }
                                    $SetRDFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function Set-RemoteDesktop" -and $_ -notmatch "function Get-PUDAdminCenter"}
                                    $null = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                        Invoke-Expression $using:SetRDFunc

                                        $SplatParams = $args[0]
                                        Set-RemoteDesktop @SplatParams
                                    } -ArgumentList $SetRemoteDesktopSplatParams

                                    Sync-UDElement -Id "RDState"

                                    $Session:EnableRemoteDesktop = $False
                                    Sync-UDElement -Id "EnableRemoteDesktopMsg"
                                }
                            }
                            
                            New-UDColumn -Endpoint {
                                New-UDButton -Text "Disable" -OnClick {
                                    $Session:DisableRemoteDesktopMsg = "Disabling Remote Desktop on $($RemoteHost.ToUpper())..."
                                    $Session:DisableRemoteDesktop = $True
                                    Sync-UDElement -Id "DisableRemoteDesktopMsg"

                                    $SetRemoteDesktopSplatParams = @{
                                        AllowRemoteDesktop        = $False
                                        AllowRemoteDesktopWithNLA = $False
                                    }
                                    $SetRDFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function Set-RemoteDesktop" -and $_ -notmatch "function Get-PUDAdminCenter"}
                                    $null = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                        Invoke-Expression $using:SetRDFunc

                                        $SplatParams = $args[0]
                                        Set-RemoteDesktop @SplatParams
                                    } -ArgumentList $SetRemoteDesktopSplatParams

                                    Sync-UDElement -Id "RDState"

                                    $Session:DisableRemoteDesktop = $False
                                    Sync-UDElement -Id "DisableRemoteDesktopMsg"
                                }

                                <#
                                New-UDInput -SubmitText "Submit" -Id "RemoteDesktopForm" -Content {
                                    $GetRDFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function Get-RemoteDesktop" -and $_ -notmatch "function Get-PUDAdminCenter"}
                                    $RemoteDesktopSettings = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                        Invoke-Expression $using:GetRDFunc
                                        Get-RemoteDesktop
                                    } -HideComputerName
                                    $DefaultValue = if ($RemoteDesktopSettings.allowRemoteDesktop) {"Enabled"} else {"Disabled"}
                                    New-UDInputField -Name "Remote_Desktop_Setting" -Type select -Values @("Enabled","Disabled") -DefaultValue $DefaultValue
                                } -Endpoint {
                                    param($Remote_Desktop_Setting)

                                    #region >> Check Connection

                                    $PUDRSSyncHT = $global:PUDRSSyncHT

                                    $RHostIP = $($PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}).IPAddressList[0]

                                    $SetRDFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function Set-RemoteDesktop" -and $_ -notmatch "function Get-PUDAdminCenter"}

                                    #endregion >> Check Connection

                                    #region >> Main

                                    if ($Remote_Desktop_Setting -eq "Enabled") {
                                        $SetRemoteDesktopSplatParams = @{
                                            AllowRemoteDesktop = $True
                                            AllowRemoteDesktopWithNLA = $True
                                        }
                                        $ToastMessage = "Remote Desktop Enabled for $RemoteHost!"
                                    }
                                    else {
                                        $SetRemoteDesktopSplatParams = @{
                                            AllowRemoteDesktop = $False
                                            AllowRemoteDesktopWithNLA = $False
                                        }
                                        $ToastMessage = "Remote Desktop Disabled for $RemoteHost!"
                                    }

                                    try {
                                        $SetRemoteDesktopResult = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                            Set-ItemProperty -Path "HKLM:\SYSTEM\Currentcontrolset\control\Terminal Server" -Name TSServerDrainMode -Value 1
                                        } -ArgumentList $SetRemoteDesktopSplatParams

                                        New-UDInputAction -Toast $ToastMessage -Duration 2000
                                    }
                                    catch {
                                        New-UDInputAction -Toast $_.Exception.Message -Duration 2000
                                    }
                                    Start-Sleep -Seconds 2

                                    Invoke-UDRedirect -Url "/Overview/$RemoteHost"

                                    #region >> Main
                                }
                                #>

                            }
                        }
                    }
                }
            }

            # Enable SSH
            New-UDColumn -Size 3 -Endpoint {
                $CollapsibleId = $RemoteHost + "SSH"
                New-UDCollapsible -Id $CollapsibleId -Items {
                    New-UDCollapsibleItem -Title "SSH" -Icon laptop -Endpoint {
                        New-UDRow -Endpoint {
                            New-UDColumn -Endpoint {
                                New-UDElement -Id "EnableSSHMsg" -Tag div -EndPoint {
                                    if ($Session:EnableSSH) {
                                        New-UDHeading -Text $Session:EnableSSHMsg -Size 6
                                        Show-UDToast -Message $Session:EnableSSHMsg -Position 'topRight' -Title "SSHToast" -Duration 5000
                                        New-UDColumn -AutoRefresh -RefreshInterval 10 -Endpoint {
                                            if ($Session:EnableSSH) {
                                                New-UDPreloader -Size small
                                            }
                                        }
                                    }
                                }
                                New-UDElement -Id "DisableSSHMsg" -Tag div -EndPoint {
                                    if ($Session:DisableSSH) {
                                        New-UDHeading -Text $Session:DisableSSHMsg -Size 6
                                        Show-UDToast -Message $Session:DisableSSHMsg -Position 'topRight' -Title "SSHToast" -Duration 5000
                                    }
                                }
                                New-UDElement -Id "SSHState" -Tag div -EndPoint {
                                    $SSHStatusInfo = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                        $SSHState = if ($(Get-Command ssh -ErrorAction SilentlyContinue) -or $(Test-Path "$env:ProgramFiles\OpenSSH-Win64\ssh.exe")) {"Enabled"} else {"Disabled"}
                                        $SSHDState = if ($(Get-Service sshd -ErrorAction SilentlyContinue).Status -eq "Running") {"Enabled"} else {"Disabled"}

                                        [pscustomobject]@{
                                            SSHState    = $SSHState
                                            SSHDState   = $SSHDState
                                        }
                                    }
                                    
                                    New-UDHeading -Text "SSH Client is: $($SSHStatusInfo.SSHState)" -Size 6
                                    New-UDHeading -Text "SSHD Server is: $($SSHStatusInfo.SSHDState)" -Size 6
                                }
                            }
                        }
                        New-UDRow -Endpoint {
                            New-UDColumn -Endpoint {
                                New-UDButton -Text "Enable" -OnClick {
                                    $Session:EnableSSHMsg = "Enabling SSH and SSHD on $($RemoteHost.ToUpper())..."
                                    $Session:EnableSSH = $True
                                    Sync-UDElement -Id "EnableSSHMsg"

                                    $null = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                        if ($(Get-Module -ListAvailable).Name -notcontains "WinSSH") {Install-Module WinSSH}
                                        if ($(Get-Module).Name -notcontains "WinSSH") {Import-Module WinSSH}

                                        Install-WinSSH -GiveWinSSHBinariesPathPriority -ConfigureSSHDOnLocalHost -DefaultShell pwsh
                                    }

                                    Sync-UDElement -Id "SSHState"

                                    $Session:EnableSSH = $False
                                    Sync-UDElement -Id "EnableSSHMsg"
                                }
                            }
                            
                            New-UDColumn -Endpoint {
                                New-UDButton -Text "Disable" -OnClick {
                                    $Session:DisableSSHMsg = "Disabling SSH and SSHD on $($RemoteHost.ToUpper())..."
                                    $Session:DisableSSH = $True
                                    Sync-UDElement -Id "DisableSSHMsg"

                                    $null = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                        if ($(Get-Module -ListAvailable).Name -notcontains "WinSSH") {Install-Module WinSSH}
                                        if ($(Get-Module).Name -notcontains "WinSSH") {Import-Module WinSSH}

                                        Uninstall-WinSSH
                                    }

                                    Sync-UDElement -Id "SSHState"

                                    $Session:DisableSSH = $False
                                    Sync-UDElement -Id "DisableSSHMsg"
                                }
                            }
                        }
                    }
                }
            }

            # Edit Computer ID
            New-UDColumn -Size 6 -Endpoint {
                $CollapsibleId = $RemoteHost + "EditComputerIDMenu"
                New-UDCollapsible -Id $CollapsibleId -Items {
                    New-UDCollapsibleItem -Title "Edit Computer ID" -Icon laptop -Endpoint {
                        New-UDInput -SubmitText "Edit Computer" -Id "ComputerIDForm" -Content {
                            $HName = $PUDRSSyncHT."$RemoteHost`Info".Overview.ServerInventoryStatic.ComputerSystem.Name
                            $DName = $PUDRSSyncHT."$RemoteHost`Info".Overview.ServerInventoryStatic.ComputerSystem.Domain
                            $WGName = $PUDRSSyncHT."$RemoteHost`Info".Overview.ServerInventoryStatic.ComputerSystem.Workgroup

                            New-UDInputField -Type textbox -Name 'Change_Host_Name' -DefaultValue $HName
                            New-UDInputField -Type textbox -Name 'Join_Domain' -DefaultValue $DName
                            New-UDInputField -Type textbox -Name 'NewDomain_UserName'
                            New-UDInputField -Type textbox -Name 'NewDomain_Password'
                            New-UDInputField -Type textbox -Name 'Join_Workgroup' -DefaultValue $WGName
                        } -Endpoint {
                            param($Change_Host_Name,$Join_Domain,$NewDomain_UserName,$NewDomain_Password,$Join_Workgroup)

                            #region >> Check Connection

                            $PUDRSSyncHT = $global:PUDRSSyncHT

                            $RHostIP = $($PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}).IPAddressList[0]

                            #endregion >> Check Connection

                            #region >> Main

                            $HName = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.ServerInventory[-1].ComputerSystem.Name
                            $DName = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.ServerInventory[-1].ComputerSystem.Domain
                            $WGName = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.ServerInventory[-1].ComputerSystem.Workgroup
                            $PartOfDomainCheck = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.ServerInventory[-1].ComputerSystem.PartOfDomain
                            $SetComputerIdFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function Set-ComputerIdentification" -and $_ -notmatch "function Get-PUDAdminCenter"}

                            # Make sure that $Join_Workgroup and $Join_Domain are NOT both filled out
                            if ($($Join_Domain -and $Join_Workgroup) -or $(!$Join_Domain -and !$Join_Workgroup)) {
                                New-UDInputAction -Toast "Please ensure that either Join_Domain or Join_Workgroup are filled out!" -Duration 10000
                                return
                            }

                            #region >> ONLY Change Host Name

                            if ($Change_Host_Name -ne $HName -and
                            $($Join_Domain -eq $null -or $Join_Domain -eq $DName) -and
                            $($Join_Workgroup -eq $null -or $Join_Workgroup -eq $WGName)
                            ) {
                                $SetComputerIdSplatParams = @{
                                    NewComputerName     = $Change_Host_Name
                                    Restart             = $True
                                }

                                # If the computer is on a Domain, we need DomainCreds. If not, we need LocalCreds.
                                if ($PartOfDomainCheck) {
                                    # If we don't have DomainCreds, prompt the user for them
                                    if ($Session:CredentialHT.$RemoteHost.DomainCreds -eq $null) {
                                        New-UDInputAction -Toast "Renaming '$RemoteHost' to '$Change_Host_Name' requires Domain Credentials!" -Duration 10000
                                        New-UDInputAction -RedirectUrl "/PSRemotingCreds/$RemoteHost"
                                        return
                                    }

                                    # Add the -Domain aprameter to SplatParams
                                    $SetComputerIdSplatParams.Add("Domain",$DName)

                                    # Authorization Credentials
                                    $AuthorizationUName = $Session:CredentialHT.$RemoteHost.DomainCreds.UserName
                                    $AuthorizationPwd = $Session:CredentialHT.$RemoteHost.DomainCreds.GetNetworkCredential().Password
                                }
                                else {
                                    # If we don't have LocalCreds, prompt the user for them
                                    if ($Session:CredentialHT.$RemoteHost.LocalCreds -eq $null) {
                                        New-UDInputAction -Toast "Renaming '$RemoteHost' to '$Change_Host_Name' requires Local Credentials!" -Duration 10000
                                        New-UDInputAction -RedirectUrl "/PSRemotingCreds/$RemoteHost"
                                        return
                                    }

                                    # Authorization Credentials
                                    $AuthorizationUName = $Session:CredentialHT.$RemoteHost.LocalCreds.UserName
                                    $AuthorizationPwd = $Session:CredentialHT.$RemoteHost.LocalCreds.GetNetworkCredential().Password
                                }

                                $SetComputerIdSplatParams.Add("UserName",$AuthorizationUName)
                                $SetComputerIdSplatParams.Add("Password",$AuthorizationPwd)

                                Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                    Invoke-Expression $using:SetComputerIdFunc

                                    $SplatParams = $args[0]
                                    Set-ComputerIdentification @SplatParams
                                } -ArgumentList $SetComputerIdSplatParams
                                
                                New-UDInputAction -Toast "Renaming '$HName' to '$Change_Host_Name' and restarting..." -Duration 10000

                                # Update $PUDRSSyncHT and Redirect to /Disconnected/$Change_Host_Name because the computer is restarting...
                                $NetworkInfoPrep = $PUDRSSyncHT."$RemoteHost`Info".NetworkInfo
                                $UpdatedNetworkInfoHT = @{}
                                $NetworkInfoPrep | Get-Member -MemberType NoteProperty | foreach {
                                    $key = $_.Name
                                    $value = $NetworkInfoPrep.$key
                                    $UpdatedNetworkInfoHT.Add($key,$value)
                                }
                                $UpdatedNetworkInfoHT.HostName = $Change_Host_Name
                                $UpdatedNetworkInfoHT.FQDN = $Change_Host_Name + '.' + $UpdatedNetworkInfoHT.Domain
                                # Add [pscustomobject]$UpdatedNetworkInfoHT to $PUDRSSyncHT.RemoteHostList and remove the old entry
                                $EntryToRemove = $PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}
                                $null = $PUDRSSyncHT.RemoteHostList.Remove($EntryToRemove)
                                $null = $PUDRSSyncHT.RemoteHostList.Add([pscustomobject]$UpdatedNetworkInfoHT)

                                if ($Session:CredentialHT.$RemoteHost.LocalCreds -ne $null) {
                                    $LocalUName = $Change_Host_Name + '\' + $($Session:CredentialHT.$RemoteHost.LocalCreds.UserName -split "\\")[-1]
                                    $UpdatedLocalCreds = [pscredential]::new($LocalUName,$Session:CredentialHT.$RemoteHost.LocalCreds.Password)
                                }
                                else {
                                    $UpdatedLocalCreds = $null
                                }

                                if ($Session:CredentialHT.$RemoteHost.PSRemotingCredType -eq "Local") {
                                    $UpdatedPSRemotingCreds = $UpdatedLocalCreds
                                }
                                else {
                                    $UpdatedPSRemotingCreds = $Session:CredentialHT.$RemoteHost.PSRemotingCreds
                                }

                                $UpdatedKey = $Change_Host_Name + "Info"
                                $UpdatedValue = @{
                                    NetworkInfo         = [pscustomobject]$UpdatedNetworkInfoHT
                                    Overview            = @{
                                        LiveDataRSInfo      = $RSSyncHash."Overview$RemoteHost`LiveDataResult"
                                        LiveDataTracker     = @{Current = $null; Previous = $null}
                                    }
                                }
                                foreach ($DynPage in $($Cache:DynamicPages | Where-Object {$_ -notmatch "PSRemotingCreds|ToolSelect"})) {
                                    $DynPageHT = @{
                                        LiveDataRSInfo      = $null
                                        LiveDataTracker     = @{Current = $null; Previous = $null}
                                    }
                                    $UpdatedValue.Add($DynPage,$DynPageHT)
                                }
                                $global:PUDRSSyncHT.Add($UpdatedKey,$UpdatedValue)

                                $UpdatedValue = @{
                                    DomainCreds         = $Session:CredentialHT.$RemoteHost.DomainCreds
                                    LocalCreds          = $UpdatedLocalCreds
                                    SSHCertPath         = $Session:CredentialHT.$RemoteHost.SSHCertPath
                                    PSRemotingCredType  = $Session:CredentialHT.$RemoteHost.PSRemotingCredType
                                    PSRemotingMethod    = $Session:CredentialHT.$RemoteHost.PSRemotingMethod
                                    PSRemotingCreds     = $UpdatedPSRemotingCreds
                                }
                                $Session:CredentialHT.$RemoteHost.Add($UpdatedKey,$UpdatedValue)

                                New-UDInputAction -RedirectUrl "/Disconnected/$Change_Host_Name"
                                return
                            }

                            #endregion >> ONLY Change Host Name

                            #region >> ONLY Join Domain

                            if ($($Change_Host_Name -eq $HName -or !$Change_Host_Name) -and
                            $($Join_Domain -ne $null -and $Join_Domain -ne $DName) -and
                            $($Join_Workgroup -eq $null -or $Join_Workgroup -eq $WGName)
                            ) {
                                # Check to make sure we have $NewDomain_UserName and $NewDomain_Password
                                if (!$NewDomain_UserName -or !$NewDomain_Password) {
                                    if (!$NewDomain_UserName) {
                                        New-UDInputAction -Toast "Joining '$Join_Domain' requires NewDomain_UserName!" -Duration 10000

                                    }
                                    if (!$NewDomain_Password) {
                                        New-UDInputAction -Toast "Joining '$Join_Domain' requires NewDomain_Password!" -Duration 10000
                                    }
                                    return
                                }

                                $SetComputerIdSplatParams = @{
                                    NewDomain           = $Join_Domain
                                    Restart             = $True
                                }

                                # If the computer is on a Domain, we need DomainCreds. If not, we need LocalCreds.
                                if ($PartOfDomainCheck) {
                                    # If we don't have DomainCreds, prompt the user for them
                                    if ($Session:CredentialHT.$RemoteHost.DomainCreds -eq $null) {
                                        New-UDInputAction -Toast "Joining '$Join_Domain' requires credentials from the current Domain ($DName)!" -Duration 10000
                                        New-UDInputAction -RedirectUrl "/PSRemotingCreds/$RemoteHost"
                                        return
                                    }

                                    # Add the -Domain aprameter to SplatParams
                                    $SetComputerIdSplatParams.Add("Domain",$DName)
                                    $SetComputerIdSplatParams.Add("UserNameNew",$NewDomain_UserName)
                                    $SetComputerIdSplatParams.Add("PasswordNew",$NewDomain_Password)

                                    # Authorization Credentials
                                    $AuthorizationUName = $Session:CredentialHT.$RemoteHost.DomainCreds.UserName
                                    $AuthorizationPwd = $Session:CredentialHT.$RemoteHost.DomainCreds.GetNetworkCredential().Password
                                    $SetComputerIdSplatParams.Add("UserName",$AuthorizationUName)
                                    $SetComputerIdSplatParams.Add("Password",$AuthorizationPwd)
                                }
                                else {
                                    # If the $RemoteHost is not part of Domain, then our PSRemoting Credentials must be Local Credentials
                                    # but we don't really need thm for anything in particular...
                                    #$AuthorizationUName = $Session:CredentialHT.$RemoteHost."$RemoteHost`Info".PSRemotingCreds.UserName
                                    #$AuthorizationPwd = $Session:CredentialHT.$RemoteHost."$RemoteHost`Info"..PSRemotingCreds.GetNetworkCredential().Password

                                    # In this situation, the Set-ComputerIdentification function interprets -UserName and -Password as
                                    # the New Domain Credentials
                                    $SetComputerIdSplatParams.Add("UserName",$NewDomain_UserName)
                                    $SetComputerIdSplatParams.Add("Password",$NewDomain_Password)
                                }

                                Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                    Invoke-Expression $using:SetComputerIdFunc

                                    $SplatParams = $args[0]
                                    Set-ComputerIdentification @SplatParams
                                } -ArgumentList $SetComputerIdSplatParams
                                
                                New-UDInputAction -Toast "Joining $RemoteHost to $Join_Domain and restarting..." -Duration 10000

                                # Update $PUDRSSyncHT and Redirect to /Disconnected/$RemoteHost because the computer is restarting...
                                $NetworkInfoPrep = $PUDRSSyncHT."$RemoteHost`Info".NetworkInfo
                                $UpdatedNetworkInfoHT = @{}
                                $NetworkInfoPrep | Get-Member -MemberType NoteProperty | foreach {
                                    $key = $_.Name
                                    $value = $NetworkInfoPrep.$key
                                    $UpdatedNetworkInfoHT.Add($key,$value)
                                }
                                $UpdatedNetworkInfoHT.FQDN = $RemoteHost + '.' + $Join_Domain
                                $UpdatedNetworkInfoHT.Domain = $Join_Domain
                                # Add [pscustomobject]$UpdatedNetworkInfoHT to $PUDRSSyncHT.RemoteHostList and remove the old entry
                                $EntryToRemove = $PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}
                                $null = $PUDRSSyncHT.RemoteHostList.Remove($EntryToRemove)
                                $null = $PUDRSSyncHT.RemoteHostList.Add([pscustomobject]$UpdatedNetworkInfoHT)
                                $PUDRSSyncHT."$RemoteHost`Info".NetworkInfo = [pscustomobject]$UpdatedNetworkInfoHT

                                $NewDomainPwdSecureString = ConvertTo-SecureString $NewDomain_Password -AsPlainText -Force
                                $UpdatedDomainCreds = [pscredential]::new($NewDomain_UserName,$NewDomainPwdSecureString)
                                $Session:CredentialHT.$RemoteHost.DomainCreds = $UpdatedDomainCreds

                                New-UDInputAction -RedirectUrl "/Disconnected/$RemoteHost"
                                return
                            }

                            #endregion >> ONLY Join Domain

                            #region >> ONLY Join Workgroup

                            if ($($Change_Host_Name -eq $HName -or !$Change_Host_Name) -and
                            $($Join_Workgroup -ne $null -and $Join_Workgroup -ne $WGName) -and
                            $Join_Domain -eq $null
                            ) {
                                $SetComputerIdSplatParams = @{
                                    Workgroup           = $Join_Workgroup
                                    Restart             = $True
                                }

                                # We need LocalCreds to ensure we can reestablish a PSSession after leaving the Domain
                                if ($Session:CredentialHT.$RemoteHost.LocalCreds -eq $null) {
                                    New-UDInputAction -Toast "Joining Workgroup $Join_Workgroup requires Local Credentials!" -Duration 10000
                                    New-UDInputAction -RedirectUrl "/PSRemotingCreds/$RemoteHost"
                                    return
                                }

                                # If the computer is on a Domain, we need DomainCreds.
                                if ($PartOfDomainCheck) {
                                    # If we don't have DomainCreds, prompt the user for them
                                    if ($Session:CredentialHT.$RemoteHost.DomainCreds -eq $null) {
                                        New-UDInputAction -Toast "Leaving the Domain $DName requires credentials from $DName!" -Duration 10000
                                        New-UDInputAction -RedirectUrl "/PSRemotingCreds/$RemoteHost"
                                        return
                                    }

                                    $SetComputerIdSplatParams.Add("Domain",$DName)
                                    $SetComputerIdSplatParams.Add("UserName",$Session:CredentialHT.$RemoteHost.DomainCreds.UserName)
                                    $SetComputerIdSplatParams.Add("Password",$Session:CredentialHT.$RemoteHost.DomainCreds.GetNetworkCredential().Password)
                                }

                                Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                    Invoke-Expression $using:SetComputerIdFunc

                                    $SplatParams = $args[0]
                                    Set-ComputerIdentification @SplatParams
                                } -ArgumentList $SetComputerIdSplatParams
                                
                                New-UDInputAction -Toast "Joining Workgroup $Join_Workgroup and restarting..." -Duration 10000

                                # Update $PUDRSSyncHT and Redirect to /Disconnected/$RemoteHost because the computer is restarting...
                                $NetworkInfoPrep = $PUDRSSyncHT."$RemoteHost`Info".NetworkInfo
                                $UpdatedNetworkInfoHT = @{}
                                $NetworkInfoPrep | Get-Member -MemberType NoteProperty | foreach {
                                    $key = $_.Name
                                    $value = $NetworkInfoPrep.$key
                                    $UpdatedNetworkInfoHT.Add($key,$value)
                                }
                                $UpdatedNetworkInfoHT.FQDN = $RemoteHost
                                $UpdatedNetworkInfoHT.Domain = $null
                                # Add [pscustomobject]$UpdatedNetworkInfoHT to $PUDRSSyncHT.RemoteHostList and remove the old entry
                                $EntryToRemove = $PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}
                                $null = $PUDRSSyncHT.RemoteHostList.Remove($EntryToRemove)
                                $null = $PUDRSSyncHT.RemoteHostList.Add([pscustomobject]$UpdatedNetworkInfoHT)
                                $PUDRSSyncHT."$RemoteHost`Info".NetworkInfo = [pscustomobject]$UpdatedNetworkInfoHT

                                New-UDInputAction -RedirectUrl "/Disconnected/$RemoteHost"
                                return
                            }

                            #endregion >> ONLY Join Workgroup

                            #region >> Join Domain AND Rename Computer

                            if ($Change_Host_Name -ne $HName -and
                            $($Join_Domain -ne $null -and $Join_Domain -ne $DName) -and
                            $($Join_Workgroup -eq $null -or $Join_Workgroup -eq $WGName)
                            ) {
                                # Check to make sure we have $NewDomain_UserName and $NewDomain_Password
                                if (!$NewDomain_UserName -or !$NewDomain_Password) {
                                    if (!$NewDomain_UserName) {
                                        New-UDInputAction -Toast "Joining '$Join_Domain' requires NewDomain_UserName!" -Duration 10000

                                    }
                                    if (!$NewDomain_Password) {
                                        New-UDInputAction -Toast "Joining '$Join_Domain' requires NewDomain_Password!" -Duration 10000
                                    }
                                    return
                                }

                                $SetComputerIdSplatParams = @{
                                    NewDomain           = $Join_Domain
                                    NewComputerName     = $Change_Host_Name
                                    Restart             = $True
                                }

                                # If the computer is on a Domain, we need DomainCreds. If not, we need LocalCreds.
                                if ($PartOfDomainCheck) {
                                    # If we don't have DomainCreds, prompt the user for them
                                    if ($Session:CredentialHT.$RemoteHost.DomainCreds -eq $null) {
                                        New-UDInputAction -Toast "Joining '$Join_Domain' requires credentials from the current Domain ($DName)!" -Duration 10000
                                        New-UDInputAction -RedirectUrl "/PSRemotingCreds/$RemoteHost"
                                        return
                                    }

                                    # Add the -Domain parameter to SplatParams
                                    $SetComputerIdSplatParams.Add("Domain",$DName)
                                    $SetComputerIdSplatParams.Add("UserNameNew",$NewDomain_UserName)
                                    $SetComputerIdSplatParams.Add("PasswordNew",$NewDomain_Password)

                                    # Authorization Credentials
                                    $AuthorizationUName = $Session:CredentialHT.$RemoteHost.DomainCreds.UserName
                                    $AuthorizationPwd = $Session:CredentialHT.$RemoteHost.DomainCreds.GetNetworkCredential().Password
                                }
                                else {
                                    # If we don't have LocalCreds, prompt the user for them
                                    if ($Session:CredentialHT.$RemoteHost.LocalCreds -eq $null) {
                                        New-UDInputAction -Toast "Renaming '$RemoteHost' to '$Change_Host_Name' requires Local Credentials!" -Duration 10000
                                        New-UDInputAction -RedirectUrl "/PSRemotingCreds/$RemoteHost"
                                        return
                                    }

                                    # Authorization Credentials
                                    $AuthorizationUName = $Session:CredentialHT.$RemoteHost.LocalCreds.UserName
                                    $AuthorizationPwd = $Session:CredentialHT.$RemoteHost.LocalCreds.GetNetworkCredential().Password
                                }

                                $SetComputerIdSplatParams.Add("UserName",$AuthorizationUName)
                                $SetComputerIdSplatParams.Add("Password",$AuthorizationPwd)

                                Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                    Invoke-Expression $using:SetComputerIdFunc

                                    $SplatParams = $args[0]
                                    Set-ComputerIdentification @SplatParams
                                } -ArgumentList $SetComputerIdSplatParams
                                
                                New-UDInputAction -Toast "Renaming $RemoteHost to $Change_Host_Name, joining Domain $Join_Domain, and restarting..." -Duration 10000

                                # Update $PUDRSSyncHT and Redirect to /Disconnected/$RemoteHost because the computer is restarting...
                                $NetworkInfoPrep = $PUDRSSyncHT."$RemoteHost`Info".NetworkInfo
                                $UpdatedNetworkInfoHT = @{}
                                $NetworkInfoPrep | Get-Member -MemberType NoteProperty | foreach {
                                    $key = $_.Name
                                    $value = $NetworkInfoPrep.$key
                                    $UpdatedNetworkInfoHT.Add($key,$value)
                                }
                                $UpdatedNetworkInfoHT.HostName = $Change_Host_Name
                                $UpdatedNetworkInfoHT.FQDN = $Change_Host_Name + '.' + $Join_Domain
                                $UpdatedNetworkInfoHT.Domain = $Join_Domain
                                # Add [pscustomobject]$UpdatedNetworkInfoHT to $PUDRSSyncHT.RemoteHostList and remove the old entry
                                $EntryToRemove = $PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}
                                $null = $PUDRSSyncHT.RemoteHostList.Remove($EntryToRemove)
                                $null = $PUDRSSyncHT.RemoteHostList.Add([pscustomobject]$UpdatedNetworkInfoHT)
                                $PUDRSSyncHT."$Change_Host_Name`Info".NetworkInfo = [pscustomobject]$UpdatedNetworkInfoHT

                                $NewDomainPwdSecureString = ConvertTo-SecureString $NewDomain_Password -AsPlainText -Force
                                $UpdatedDomainCreds = [pscredential]::new($NewDomain_UserName,$NewDomainPwdSecureString)
                                $Session:CredentialHT.$RemoteHost.DomainCreds = $UpdatedDomainCreds

                                New-UDInputAction -RedirectUrl "/Disconnected/$Change_Host_Name"
                                return
                            }

                            #endregion >> Join Domain AND Rename Computer

                            #region >> Join Workgroup AND Rename Computer

                            if ($Change_Host_Name -ne $HName -and
                            $($Join_Workgroup -ne $null -and $Join_Workgroup -ne $WGName) -and
                            $Join_Domain -eq $null
                            ) {
                                $SetComputerIdSplatParams = @{
                                    Workgroup           = $Join_Workgroup
                                    NewComputerName     = $Change_Host_Name
                                    Restart             = $True
                                }

                                # We need LocalCreds regardless
                                if ($Session:CredentialHT.$RemoteHost.LocalCreds -eq $null) {
                                    New-UDInputAction -Toast "Renaming '$RemoteHost' to '$Change_Host_Name' requires Local Credentials!" -Duration 10000
                                    New-UDInputAction -RedirectUrl "/PSRemotingCreds/$RemoteHost"
                                    return
                                }

                                # If the computer is on a Domain, we need DomainCreds to leave it.
                                if ($PartOfDomainCheck) {
                                    # If we don't have DomainCreds, prompt the user for them
                                    if ($Session:CredentialHT.$RemoteHost.DomainCreds -eq $null) {
                                        New-UDInputAction -Toast "Joining '$Join_Domain' requires credentials from the current Domain ($DName)!" -Duration 10000
                                        New-UDInputAction -RedirectUrl "/PSRemotingCreds/$RemoteHost"
                                        return
                                    }

                                    # Add the -Domain parameter to SplatParams
                                    $SetComputerIdSplatParams.Add("Domain",$DName)

                                    # Authorization Credentials
                                    $AuthorizationUName = $Session:CredentialHT.$RemoteHost.DomainCreds.UserName
                                    $AuthorizationPwd = $Session:CredentialHT.$RemoteHost.DomainCreds.GetNetworkCredential().Password
                                }
                                else {
                                    # Authorization Credentials
                                    $AuthorizationUName = $Session:CredentialHT.$RemoteHost.LocalCreds.UserName
                                    $AuthorizationPwd = $Session:CredentialHT.$RemoteHost.LocalCreds.GetNetworkCredential().Password
                                }

                                $SetComputerIdSplatParams.Add("UserName",$AuthorizationUName)
                                $SetComputerIdSplatParams.Add("Password",$AuthorizationPwd)

                                Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                    Invoke-Expression $using:SetComputerIdFunc

                                    $SplatParams = $args[0]
                                    Set-ComputerIdentification @SplatParams
                                } -ArgumentList $SetComputerIdSplatParams
                                
                                New-UDInputAction -Toast "Renaming $RemoteHost to $Change_Host_Name, joining Workgroup $Join_Workgroup, and restarting..." -Duration 10000

                                # Update $PUDRSSyncHT and Redirect to /Disconnected/$RemoteHost because the computer is restarting...
                                $NetworkInfoPrep = $PUDRSSyncHT."$RemoteHost`Info".NetworkInfo
                                $UpdatedNetworkInfoHT = @{}
                                $NetworkInfoPrep | Get-Member -MemberType NoteProperty | foreach {
                                    $key = $_.Name
                                    $value = $NetworkInfoPrep.$key
                                    $UpdatedNetworkInfoHT.Add($key,$value)
                                }
                                $UpdatedNetworkInfoHT.HostName = $Change_Host_Name
                                $UpdatedNetworkInfoHT.FQDN = $Change_Host_Name
                                $UpdatedNetworkInfoHT.Domain = $null
                                # Add [pscustomobject]$UpdatedNetworkInfoHT to $PUDRSSyncHT.RemoteHostList and remove the old entry
                                $EntryToRemove = $PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}
                                $null = $PUDRSSyncHT.RemoteHostList.Remove($EntryToRemove)
                                $null = $PUDRSSyncHT.RemoteHostList.Add([pscustomobject]$UpdatedNetworkInfoHT)
                                $PUDRSSyncHT."$Change_Host_Name`Info".NetworkInfo = [pscustomobject]$UpdatedNetworkInfoHT

                                New-UDInputAction -RedirectUrl "/Disconnected/$Change_Host_Name"
                                return
                            }

                            #endregion >> Join Workgroup AND Rename Computer

                            #endregion >> Main
                        }
                    }
                }
            }
        }

        New-UDRow -Endpoint {
            # Edit Environment Variables
            New-UDColumn -Size 12 -Endpoint {
                $CollapsibleId = $RemoteHost + "Environment Variables"
                New-UDCollapsible -Id $CollapsibleId -Items {
                    New-UDCollapsibleItem -Title "Environment Variables" -Icon laptop -Endpoint {
                        New-UDRow -Endpoint {
                            New-UDColumn -Size 12 -Endpoint {
                                $EnvVarsUdGridSplatParams = @{
                                    Title           = "Environment Variables"
                                    Id              = "EnvVarsGrid"
                                    Headers         = @("Type","Name","Value")
                                    Properties      = @("Type","Name","Value")
                                    PageSize        = 10
                                }
                                New-UdGrid @EnvVarsUdGridSplatParams -Endpoint {
                                    $PUDRSSyncHT = $global:PUDRSSyncHT

                                    $RHostIP = $($PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}).IPAddressList[0]

                                    $GetEnvVarsFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function Get-EnvironmentVariables" -and $_ -notmatch "function Get-PUDAdminCenter"}
                                    $StaticInfo = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                        Invoke-Expression $using:GetEnvVarsFunc
                                        
                                        $EnvVars = Get-EnvironmentVariables
                                        
                                        [pscustomobject]@{
                                            EnvironmentVariables        = [pscustomobject]$EnvVars
                                        }
                                    }
                                    $Session:EnvironmentVariablesStatic = $StaticInfo.EnvironmentVariables
                                    if ($PUDRSSyncHT."$RemoteHost`Info".Overview.Keys -notcontains "EnvironmentVariablesStatic") {
                                        $PUDRSSyncHT."$RemoteHost`Info".Overview.Add("EnvironmentVariablesStatic",$Session:EnvironmentVariablesStatic)
                                    }
                                    else {
                                        $PUDRSSyncHT."$RemoteHost`Info".Overview.EnvironmentVariablesStatic = $Session:EnvironmentVariablesStatic
                                    }

                                    $Session:EnvironmentVariablesStatic | Out-UDGridData
                                }
                            }
                        }

                        New-UDRow -Endpoint {
                            New-UDColumn -Size 4 -Endpoint {
                                New-UDHeading -Text "New Environment Variable" -Size 5
                                
                                New-UDTextbox -Id "EnvVarNameA" -Label "Name"
                                New-UDTextbox -Id "EnvVarValueA" -Label "Value"
                                New-UDSelect -Id "EnvVarTypeA" -Label "Type" -Option {
                                    New-UDSelectOption -Name "User" -Value "User" -Selected
                                    New-UDSelectOption -Name "Machine" -Value "Machine"
                                }
                                
                                New-UDButton -Text "New" -OnClick {
                                    $EnvVarNameTextBox = Get-UDElement -Id "EnvVarNameA"
                                    $EnvVarValueTextBox = Get-UDElement -Id "EnvVarValueA"
                                    $EnvVarTypeSelection = Get-UDElement -Id "EnvVarTypeA"

                                    $EnvVarName = $EnvVarNameTextBox.Attributes['value']
                                    $EnvVarValue = $EnvVarValueTextBox.Attributes['value']
                                    $EnvVarType = $($EnvVarTypeSelection.Content | foreach {
                                        $_.ToString() | ConvertFrom-Json
                                    } | Where-Object {$_.attributes.selected.isPresent}).attributes.value

                                    <#
                                    $PUDRSSyncHT."$RemoteHost`Info".Overview.Add("EnvVarInfo",@{})
                                    $PUDRSSyncHT."$RemoteHost`Info".Overview.EnvVarInfo.Add("EnvVarTypeObject",$EnvVarTypeSelection)
                                    $PUDRSSyncHT."$RemoteHost`Info".Overview.EnvVarInfo.Add("EnvVarName",$EnvVarName)
                                    $PUDRSSyncHT."$RemoteHost`Info".Overview.EnvVarInfo.Add("EnvVarNewName",$EnvVarNewName)
                                    $PUDRSSyncHT."$RemoteHost`Info".Overview.EnvVarInfo.Add("EnvVarValue",$EnvVarValue)
                                    $PUDRSSyncHT."$RemoteHost`Info".Overview.EnvVarInfo.Add("EnvVarType",$EnvVarType)
                                    $PUDRSSyncHT."$RemoteHost`Info".Overview.EnvVarInfo.Add("RemoteHost",$RemoteHost)
                                    $PUDRSSyncHT."$RemoteHost`Info".Overview.EnvVarInfo.Add("CredsUserName",$($Session:CredentialHT.$RemoteHost.PSRemotingCreds.UserName))
                                    #>


                                    $NewEnvVarFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function New-EnvironmentVariable" -and $_ -notmatch "function Get-PUDAdminCenter"}
                                    $null = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                        Invoke-Expression $using:NewEnvVarFunc
                                        New-EnvironmentVariable -name $using:EnvVarName -value $using:EnvVarValue -type $using:EnvVarType
                                    }

                                    Sync-UDElement -Id "EnvVarsGrid"
                                }
                            }
                            New-UDColumn -Size 4 -Endpoint {
                                New-UDHeading -Text "Edit Environment Variable" -Size 5
                                
                                New-UDTextbox -Id "EnvVarNameB" -Label "Name"
                                New-UDTextbox -Id "EnvVarNewNameB" -Label "New Name"
                                New-UDTextbox -Id "EnvVarValueB" -Label "Value"
                                New-UDSelect -Id "EnvVarTypeB" -Label "Type" -Option {
                                    New-UDSelectOption -Name "User" -Value "User" -Selected
                                    New-UDSelectOption -Name "Machine" -Value "Machine"
                                }

                                New-UDButton -Text "Edit" -OnClick {
                                    $EnvVarNameTextBox = Get-UDElement -Id "EnvVarNameB"
                                    $EnvVarNewNameTextBox = Get-UDElement -Id "EnvVarNewNameB"
                                    $EnvVarValueTextBox = Get-UDElement -Id "EnvVarValueB"
                                    $EnvVarTypeSelection = Get-UDElement -Id "EnvVarTypeB"

                                    $EnvVarName = $EnvVarNameTextBox.Attributes['value']
                                    $EnvVarNewName = $EnvVarNewNameTextBox.Attributes['value']
                                    $EnvVarValue = $EnvVarValueTextBox.Attributes['value']
                                    $EnvVarType = $($EnvVarTypeSelection.Content | foreach {
                                        $_.ToString() | ConvertFrom-Json
                                    } | Where-Object {$_.attributes.selected.isPresent}).attributes.value

                                    $SetEnvVarFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function Set-EnvironmentVariable" -and $_ -notmatch "function Get-PUDAdminCenter"}
                                    $SetEnvVarSplatParams = @{
                                        oldName     = $EnvVarName
                                        type        = $EnvVarType
                                    }
                                    if ($EnvVarValue) {
                                        $SetEnvVarSplatParams.Add("value",$EnvVarValue)
                                    }
                                    if ($EnvVarNewName) {
                                        $SetEnvVarSplatParams.Add("newName",$EnvVarNewName)
                                    }
                                    else {
                                        $SetEnvVarSplatParams.Add("newName",$EnvVarName)
                                    }

                                    # NOTE: Set-EnvironmentVariable outputs @{Status = "Succcess"} otherwise, Error
                                    $null = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                        Invoke-Expression $using:SetEnvVarFunc
                                        $SplatParams = $args[0]
                                        Set-EnvironmentVariable @SplatParams
                                    } -ArgumentList $SetEnvVarSplatParams
                                    
                                    Sync-UDElement -Id "EnvVarsGrid"
                                }
                            }
                            New-UDColumn -Size 4 -Endpoint {
                                New-UDHeading -Text "Remove Environment Variable" -Size 5
                                
                                New-UDTextbox -Id "EnvVarNameC" -Label "Name"
                                New-UDSelect -Id "EnvVarTypeC" -Label "Type" -Option {
                                    New-UDSelectOption -Name "User" -Value "User" -Selected
                                    New-UDSelectOption -Name "Machine" -Value "Machine"
                                }

                                New-UDButton -Text "Remove" -OnClick {
                                    $EnvVarNameTextBox = Get-UDElement -Id "EnvVarNameC"
                                    $EnvVarTypeSelection = Get-UDElement -Id "EnvVarTypeC"

                                    $EnvVarName = $EnvVarNameTextBox.Attributes['value']
                                    $EnvVarType = $($EnvVarTypeSelection.Content | foreach {
                                        $_.ToString() | ConvertFrom-Json
                                    } | Where-Object {$_.attributes.selected.isPresent}).attributes.value

                                    $RemoveEnvVarFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function Remove-EnvironmentVariable" -and $_ -notmatch "function Get-PUDAdminCenter"}
                                    $null = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                        Invoke-Expression $using:RemoveEnvVarFunc
                                        Remove-EnvironmentVariable -name $using:EnvVarName -type $using:EnvVarType
                                    }
                                    
                                    Sync-UDElement -Id "EnvVarsGrid"
                                }
                            }
                        }
                        
                        <#
                        New-UDRow -Endpoint {
                            New-UDColumn -Size 4 -Endpoint {
                                New-UDInput -Title "New Environment Variable" -SubmitText "Add" -Content {
                                    New-UDInputField -Name "Name" -Type textbox
                                    New-UDInputField -Name "Value" -Type textbox
                                    New-UDInputField -Name "Type" -Type select -Values @("User","Machine") -DefaultValue "User"
                                } -Endpoint {
                                    param($Name,$Value,$Type)

                                    #region >> Check Connection

                                    $PUDRSSyncHT = $global:PUDRSSyncHT

                                    $RHostIP = $($PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}).IPAddressList[0]

                                    $NewEnvVarFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function New-EnvironmentVariable" -and $_ -notmatch "function Get-PUDAdminCenter"}

                                    #endregion >> Check Connection

                                    #region >> SubMain

                                    if (!$Name) {
                                        New-UDInputAction -Toast "You must fill out the 'Name' field to indicate the name of the Environment Variable you would like to Add." -Duration 10000
                                        return
                                    }

                                    try {
                                        # NOTE: New-EnvironmentVariable does not output anything
                                        $null = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                            $using:NewEnvVarFunc

                                            New-EnvironmentVariable -name $using:Name -value $using:Value -type $using:Type
                                        }

                                        New-UDInputAction -Toast "New $Type Environment Variable $Name was successfully created. Please refresh the page to view updates in the Environment Variable Grid." -Duration 2000
                                    }
                                    catch {
                                        New-UDInputAction -Toast $_.Exception.Message -Duration 2000
                                    }
                                    Start-Sleep -Seconds 2

                                    # Reload the page
                                    Invoke-UDRedirect -Url "/Overview/$RemoteHost"

                                    #endregion >> SubMain
                                }
                            }
                            
                            New-UDColumn -Size 4 -Endpoint {
                                New-UDInput -Title "Remove Environment Variable" -SubmitText "Remove" -Content {
                                    New-UDInputField -Name "Name" -Type textbox
                                    New-UDInputField -Name "Type" -Type select -Values @("User","Machine") -DefaultValue "User"
                                } -Endpoint {
                                    param($Name,$Type)

                                    #region >> Check Connection

                                    $PUDRSSyncHT = $global:PUDRSSyncHT

                                    $RHostIP = $($PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}).IPAddressList[0]

                                    $NewEnvVarFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function New-EnvironmentVariable" -and $_ -notmatch "function Get-PUDAdminCenter"}

                                    #endregion >> Check Connection

                                    #region >> SubMain

                                    if (!$Name) {
                                        New-UDInputAction -Toast "You must fill out the 'Name' field to indicate which existing Environment Variable you would like to Remove." -Duration 10000
                                        return
                                    }

                                    try {
                                        # NOTE: Remove-EnvironmentVariable does not output anything
                                        $null = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                            Invoke-Expression $using:RemoveEnvVarFunc

                                            Remove-EnvironmentVariable -name $using:Name -type $using:Type
                                        }

                                        New-UDInputAction -Toast "Removed $Type Environment Variable $Name successfully. Please refresh the page to view updates in the Environment Variable Grid." -Duration 2000
                                    }
                                    catch {
                                        New-UDInputAction -Toast $_.Exception.Message -Duration 2000
                                    }
                                    Start-Sleep -Seconds 2

                                    # Reload the page
                                    Invoke-UDRedirect -Url "/Overview/$RemoteHost"

                                    #endregion >> SubMain
                                }
                            }

                            New-UDColumn -Size 4 -Endpoint {
                                New-UDInput -Title "Edit Environment Variable" -SubmitText "Edit" -Content {
                                    New-UDInputField -Name "Name" -Type textbox
                                    New-UDInputField -Name "NewName" -Type textbox
                                    New-UDInputField -Name "Value" -Type textbox
                                    New-UDInputField -Name "Type" -Type select -Values @("User","Machine") -DefaultValue "User"
                                } -Endpoint {
                                    param($Name,$NewName,$Value,$Type)

                                    #region >> Check Connection

                                    $PUDRSSyncHT = $global:PUDRSSyncHT

                                    $RHostIP = $($PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}).IPAddressList[0]

                                    $NewEnvVarFunc = $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -match "function New-EnvironmentVariable" -and $_ -notmatch "function Get-PUDAdminCenter"}

                                    #endregion >> Check Connection

                                    #region >> SubMain

                                    if (!$Name) {
                                        New-UDInputAction -Toast "You must fill out the 'Name' field to indicate which existing Environment Variable you would like to Edit." -Duration 10000
                                        return
                                    }

                                    $SetEnvVarSplatParams = @{
                                        oldName = $Name
                                        type = $Type
                                    }
                                    if ($Value) {
                                        $SetEnvVarSplatParams.Add("value",$Value)
                                    }
                                    if ($NewName) {
                                        $SetEnvVarSplatParams.Add("newName",$NewName)
                                    }
                                    else {
                                        $SetEnvVarSplatParams.Add("newName",$Name)
                                    }

                                    try {
                                        # NOTE: Set-EnvironmentVariable outputs @{Status = "Succcess"} otherwise, Error
                                        $null = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                                            Invoke-Expression $using:SetEnvVarFunc

                                            $SplatParams = $args[0]
                                            Set-EnvironmentVariable @SplatParams
                                        } -ArgumentList $SetEnvVarSplatParams

                                        New-UDInputAction -Toast "Successfully edited Environment Variable. Please refresh the page to view updates in the Environment Variable Grid." -Duration 2000
                                        
                                    }
                                    catch {
                                        New-UDInputAction -Toast $_.Exception.Message -Duration 2000
                                    }
                                    Start-Sleep -Seconds 2

                                    # Reload the page
                                    Invoke-UDRedirect -Url "/Overview/$RemoteHost"

                                    #endregion >> SubMain
                                }
                            }
                        }
                        #>

                        #endregion >> Main
                    }
                }
            }
        }

        #endregion >> Controls

        #region >> Summary Info

        New-UDRow -Endpoint {
            New-UDColumn -Size 12 -Endpoint {
                #region >> Check Connection

                $PUDRSSyncHT = $global:PUDRSSyncHT

                # Load PUDAdminCenter Module Functions Within ScriptBlock
                $Cache:ThisModuleFunctionsStringArray | Where-Object {$_ -ne $null} | foreach {Invoke-Expression $_ -ErrorAction SilentlyContinue}

                $RHostIP = $($PUDRSSyncHT.RemoteHostList | Where-Object {$_.HostName -eq $RemoteHost}).IPAddressList[0]

                #endregion >> Check Connection

                New-UDHeading -Text "Summary" -Size 4

                # Summary A
                $SummaryInfoAGridProperties = @("Computer_Name","Domain","Operating_System","Version","Installed_Memory")

                $SummaryInfoAGridEndpoint = {
                    $PUDRSSyncHT = $global:PUDRSSyncHT

                    $SrvInv = $Session:ServerInventoryStatic

                    [pscustomobject]@{
                        Computer_Name       = $SrvInv.ComputerSystem.Name
                        Domain              = $SrvInv.ComputerSystem.Domain
                        Operating_System    = $SrvInv.OperatingSystem.Caption
                        Version             = $SrvInv.OperatingSystem.Version
                        Installed_Memory    = [Math]::Round($SrvInv.ComputerSystem.TotalPhysicalMemory / 1GB).ToString() + " GB"
                    } | Out-UDTableData -Property $SummaryInfoAGridProperties
                }
                $SummaryInfoAUdGridSplatParams = @{
                    Id              = "SummaryInfoA"
                    Headers         = $SummaryInfoAGridProperties
                    Endpoint        = $SummaryInfoAGridEndpoint
                }
                New-UdTable @SummaryInfoAUdGridSplatParams

                # Summary B
                $SummaryInfoBGridProperties = @("C_DiskSpace_FreeVsTotal","Processors","Manufacturer","Model","Logical_Processors")
                
                $SummaryBInfo = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                    $CimDiskResult = Get-CimInstance Win32_LogicalDisk -Filter "DeviceID='C:'"
                    $CimDiskOutput = [Math]::Round($CimDiskResult.FreeSpace / 1GB).ToString() + "GB" +
                    ' / ' + [Math]::Round($CimDiskResult.Size / 1GB).ToString() + "GB"

                    $ProcessorsPrep = $($(
                        Get-CimInstance Win32_Processor | foreach {
                            $_.Name.Trim() + $_.Caption.Trim()
                        }
                    ) -replace "[\s]+"," ") | foreach {
                        $($_ -split "[0-9]GHz")[0] + "GHz"
                    }
                    $Processors = $ProcessorsPrep -join " | "

                    [pscustomobject]@{
                        ProcessorInfo       = $Processors
                        CimDiskInfo         = $CimDiskOutput
                    }
                }

                $SummaryInfoBGridEndpoint = {
                    $PUDRSSyncHT = $global:PUDRSSyncHT

                    $SrvInv = $Session:ServerInventoryStatic

                    [pscustomobject]@{
                        C_DiskSpace_FreeVsTotal     = $SummaryBInfo.CimDiskInfo
                        Processors                  = $SummaryBInfo.ProcessorInfo
                        Manufacturer                = $SrvInv.ComputerSystem.Manufacturer
                        Model                       = $SrvInv.ComputerSystem.Model
                        Logical_Processors          = $SrvInv.ComputerSystem.NumberOfLogicalProcessors.ToString()
                    } | Out-UDTableData -Property $SummaryInfoBGridProperties
                }
                $SummaryInfoBUdGridSplatParams = @{
                    Id              = "SummaryInfoB"
                    Headers         = $SummaryInfoBGridProperties
                    Endpoint        = $SummaryInfoBGridEndpoint
                }
                New-UdTable @SummaryInfoBUdGridSplatParams

                # Summary C
                $SummaryCInfo = Invoke-Command -ComputerName $RemoteHost -Credential $Session:CredentialHT.$RemoteHost.PSRemotingCreds -ScriptBlock {
                    $using:ThisModuleFunctionsStringArray | Where-Object {$_ -ne $null} | foreach {Invoke-Expression $_ -ErrorAction SilentlyContinue}
                    
                    $DefenderInfo = Get-MpComputerStatus
                    $NicCount = $([System.Net.NetworkInformation.NetworkInterface]::GetAllNetworkInterfaces() | Where-Object {
                        $_.NetworkInterfaceType -eq "Ethernet"
                    }).Count
                    $GetLocalUsersInfo = Get-LocalUsers

                    [pscustomobject]@{
                        RealTimeProtectionStatus    = $DefenderInfo.RealTimeProtectionEnabled
                        NicCount                    = $NicCount
                        LocalUserCount              = $GetLocalUsersInfo.Count
                    }
                }
                
                $SummaryInfoCGridProperties = @("Windows_Defender","NICs","Uptime","LocalUserCount")

                $SummaryInfoCGridEndpoint = {
                    $PUDRSSyncHT = $global:PUDRSSyncHT

                    $UptimeLiveOutputCount = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count
                    if ($UptimeLiveOutputCount -gt 0) {
                        # Clone the LiveOutput ArrayList Object because if we try to Enumerate (using Where-Object or other method) while elements are
                        # being added/removed from the ArrayList, things break
                        #$UptimeLiveOutputClone = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Clone()

                        $ArrayOfUptimeEntries = @(
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.Uptime
                        ) | Where-Object {$_ -ne $null}
                    }

                    if ($ArrayOfUptimeEntries.Count -eq 0) {
                        $FinalUptime = "00:00:00:00"
                    }
                    else {
                        $FinalUptime = $ArrayOfUptimeEntries[-1]

                        if ($($FinalUptime | Get-Member -Type Method).Name -contains "LastIndexOf" -and $FinalUptime -match "\.") {
                            $FinalUptime = $FinalUptime.Substring(0,$FinalUptime.LastIndexOf('.'))
                        }
                        else {
                            $FinalUptime = "00:00:00:00"
                        }
                    }

                    [pscustomobject]@{
                        Windows_Defender    = if ($SummaryCInfo.RealTimeProtectionStatus) {"Real-time protection: On"} else {"Real-time protection: Off"}
                        NICs                = $SummaryCInfo.NicCount
                        Uptime              = $FinalUptime
                        LocalUserCount      = $SummaryCInfo.LocalUserCount
                    } | Out-UDTableData -Property $SummaryInfoCGridProperties
                }
                $SummaryInfoCUdGridSplatParams = @{
                    Id              = "SummaryInfoC"
                    Headers         = $SummaryInfoCGridProperties
                    AutoRefresh     = $True
                    RefreshInterval = 2
                    Endpoint        = $SummaryInfoCGridEndpoint
                }
                New-UdTable @SummaryInfoCUdGridSplatParams
            }
        }

        #endregion >> Summary Info

        #region >> Monitors

        # CPU Utilization and Memory Usage
        New-UDRow -Columns {
            New-UDHeading -Text "Processor (CPU) and Memory (RAM) Info" -Size 4
            New-UDColumn -Size 6 -Endpoint {
                $CPUTableProperties =@("CPU_Utilization","ClockSpeed","Processes","Threads","Handles")
                New-UDTable -Id "CPUTable" -Headers $CPUTableProperties -AutoRefresh -RefreshInterval 5 -Endpoint {
                    $PUDRSSyncHT = $global:PUDRSSyncHT

                    $CPULiveOutputCount = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count
                    if ($CPULiveOutputCount -gt 0) {
                        # Clone the LiveOutput ArrayList Object because if we try to Enumerate (using Where-Object or other method) while elements are
                        # being added/removed from the ArrayList, things break
                        #$CPULiveOutputClone = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Clone()

                        $ArrayOfCPUPctEntries = @(
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.CPUPct
                        ) | Where-Object {$_ -ne $null}
                        if ($ArrayOfCPUPctEntries.Count -gt 0) {
                            $LatestCPUPctEntry = $ArrayOfCPUPctEntries[-1]
                        }

                        $ArrayOfClockSpeedEntries = @(
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.ClockSpeed
                        ) | Where-Object {$_ -ne $null}
                        if ($ArrayOfClockSpeedEntries.Count -gt 0) {
                            $LatestClockSpeedEntry = $ArrayOfClockSpeedEntries[-1]
                        }

                        $ArrayOfProcessesCountEntries = @(
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.ProcessesCount
                        ) | Where-Object {$_ -ne $null}
                        if ($ArrayOfProcessesCountEntries.Count -gt 0) {
                            $LatestProcessesEntry = $ArrayOfProcessesCountEntries[-1]
                        }

                        $ArrayOfHandlesCountEntries = @(
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.HandlesCount
                        ) | Where-Object {$_ -ne $null}
                        if ($ArrayOfHandlesCountEntries.Count -gt 0) {
                            $LatestHandlesEntry = $ArrayOfHandlesCountEntries[-1]
                        }

                        $ArrayOfThreadsCountEntries = @(
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.ThreadsCount
                        ) | Where-Object {$_ -ne $null}
                        if ($ArrayOfThreadsCountEntries.Count -gt 0) {
                            $LatestThreadsEntry = $ArrayOfThreadsCountEntries[-1]
                        }
                    }

                    $FinalCPUPct = if (!$LatestCPUPctEntry) {"0"} else {$LatestCPUPctEntry.ToString() + '%'}
                    $FinalSpeed = if (!$LatestClockSpeedEntry) {"0"} else {$LatestClockSpeedEntry.ToString() + 'GHz'}
                    $FinalProcesses = if (!$LatestProcessesEntry) {"0"} else {$LatestProcessesEntry}
                    $FinalHandles = if (!$LatestHandlesEntry) {"0"} else {$LatestHandlesEntry}
                    $FinalThreads = if (!$LatestThreadsEntry) {"0"} else {$LatestThreadsEntry}

                    [pscustomobject]@{
                        CPU_Utilization     = $FinalCPUPct
                        ClockSpeed          = $FinalSpeed
                        Processes           = $FinalProcesses
                        Threads             = $FinalThreads
                        Handles             = $FinalHandles
                    } | Out-UDTableData -Property $CPUTableProperties
                }

                $CPUMonitorEndpoint = {
                    $PUDRSSyncHT = $global:PUDRSSyncHT

                    $CPULiveOutputCount = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count
                    if ($CPULiveOutputCount -gt 0) {
                        # Clone the LiveOutput ArrayList Object because if we try to Enumerate (using Where-Object or other method) while elements are
                        # being added/removed from the ArrayList, things break
                        #$CPULiveOutputClone = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Clone()

                        $ArrayOfCPUPctEntries = @(
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.CPUPct
                            ) | Where-Object {$_ -ne $null}
                        if ($ArrayOfCPUPctEntries.Count -gt 0) {
                            $LatestCPUPctEntry = $ArrayOfCPUPctEntries[-1]
                        }
                    }

                    $FinalCPUPct = if (!$LatestCPUPctEntry) {"0"} else {$LatestCPUPctEntry}

                    $FinalCPUPct | Out-UDMonitorData
                }

                $CPUMonitorSplatParams = @{
                    Title                   = "CPU Utilization %"
                    Type                    = "Line"
                    DataPointHistory        = 20
                    ChartBackgroundColor    = "#80FF6B63"
                    ChartBorderColor        = "#FFFF6B63"
                    AutoRefresh             = $True
                    RefreshInterval         = 5
                    Endpoint                = $CPUMonitorEndpoint
                }
                New-UdMonitor @CPUMonitorSplatParams
            }
            New-UDColumn -Size 6 -Endpoint {
                #New-UDHeading -Text "Memory (RAM) Info" -Size 4
                #$RamTableProperties = @("RAM_Utilization","Total","InUse","Available","Committed","Cached","PagedPool","NonPagedPool")
                $RamTableProperties = @("RAM_Utilization","Total","InUse","Available","Committed","Cached")
                New-UDTable -Id "RamTable" -Headers $RamTableProperties -AutoRefresh -RefreshInterval 5 -Endpoint {
                    $PUDRSSyncHT = $global:PUDRSSyncHT

                    $RamLiveOutputCount = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count
                    if ($RamLiveOutputCount -gt 0) {
                        # Clone the LiveOutput ArrayList Object because if we try to Enumerate (using Where-Object or other method) while elements are
                        # being added/removed from the ArrayList, things break
                        #$RamLiveOutputClone = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Clone()

                        $ArrayOfRamPctEntries = @(
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.RamPct
                        ) | Where-Object {$_ -ne $null}
                        if ($ArrayOfRamPctEntries.Count -gt 0) {
                            $LatestRamPctEntry = $ArrayOfRamPctEntries[-1]
                        }

                        $ArrayOfRamTotalGBEntries = @(
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.RamTotalGB
                        ) | Where-Object {$_ -ne $null}
                        if ($ArrayOfRamTotalGBEntries.Count -gt 0) {
                            $LatestRamTotalGBEntry = $ArrayOfRamTotalGBEntries[-1]
                        }
                        
                        $ArrayOfRamInUseGBEntries = @(
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.RamInUseGB
                        ) | Where-Object {$_ -ne $null}
                        if ($ArrayOfRamInUseGBEntries.Count -gt 0) {
                            $LatestRamInUseGBEntry = $ArrayOfRamInUseGBEntries[-1]
                        }

                        $ArrayOfRamFreeGBEntries = @(
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.RamFreeGB
                        ) | Where-Object {$_ -ne $null}
                        if ($ArrayOfRamFreeGBEntries.Count -gt 0) {
                            $LatestRamFreeGBEntry = $ArrayOfRamFreeGBEntries[-1]
                        }

                        $ArrayOfRamCommittedGBEntries = @(
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.RamCommittedGB
                        ) | Where-Object {$_ -ne $null}
                        if ($ArrayOfRamCommittedGBEntries.Count -gt 0) {
                            $LatestRamCommittedGBEntry = $ArrayOfRamCommittedGBEntries[-1]
                        }

                        $ArrayOfRamCachedGBEntries = @(
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.RamCachedGB
                        ) | Where-Object {$_ -ne $null}
                        if ($ArrayOfRamCachedGBEntries.Count -gt 0) {
                            $LatestRamCachedGBEntry = $ArrayOfRamCachedGBEntries[-1]
                        }

                        $ArrayOfRamPagedPoolMBEntries = @(
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.RamPagedPoolMB
                        ) | Where-Object {$_ -ne $null}
                        if ($ArrayOfRamPagedPoolMBEntries.Count -gt 0) {
                            $LatestRamPagedPoolMBEntry = $ArrayOfRamPagedPoolMBEntries[-1]
                        }

                        $ArrayOfRamNonPagedPoolMBEntries = @(
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.RamNonPagedPoolMB
                        ) | Where-Object {$_ -ne $null}
                        if ($ArrayOfRamNonPagedPoolMBEntries.Count -gt 0) {
                            $LatestRamNonPagedPoolMBEntry = $ArrayOfRamNonPagedPoolMBEntries[-1]
                        }
                    }

                    $FinalRamPct = if (!$LatestRamPctEntry) {"0"} else {$LatestRamPctEntry.ToString() + '%'}
                    $FinalRamTotalGB = if (!$LatestRamTotalGBEntry) {"0"} else {$LatestRamTotalGBEntry.ToString() + 'GB'}
                    $FinalRamInUseGB = if (!$LatestRamInUseGBEntry) {"0"} else {$LatestRamInUseGBEntry.ToString() + 'GB'}
                    $FinalRamFreeGB = if (!$LatestRamFreeGBEntry) {"0"} else {$LatestRamFreeGBEntry.ToString() + 'GB'}
                    $FinalRamCommittedGB = if (!$LatestRamCommittedGBEntry) {"0"} else {$LatestRamCommittedGBEntry.ToString() + 'GB'}
                    $FinalRamCachedGB = if (!$LatestRamCachedGBEntry) {"0"} else {$LatestRamCachedGBEntry.ToString() + 'GB'}
                    $FinalRamPagedPoolMB = if (!$LatestRamPagedPoolMBEntry) {"0"} else {$LatestRamPagedPoolMBEntry.ToString() + 'MB'}
                    $FinalRamNonPagedPoolMB = if (!$LatestRamNonPagedPoolMBEntry) {"0"} else {$LatestRamNonPagedPoolMBEntry.ToString() + 'MB'}
                    
                    [pscustomobject]@{
                        RAM_Utilization     = $FinalRamPct
                        Total               = $FinalRamTotalGB
                        InUse               = $FinalRamInUseGB
                        Available           = $FinalRamFreeGB
                        Committed           = $FinalRamCommittedGB
                        Cached              = $FinalRamCachedGB
                        #PagedPool = $FinalRamPagedPoolMB
                        #NonPagedPool = $FinalRamNonPagedPoolMB
                    } | Out-UDTableData -Property $RamTableProperties
                }

                $RamMonitorEndpoint = {
                    $PUDRSSyncHT = $global:PUDRSSyncHT

                    $RamLiveOutputCount = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count
                    if ($RamLiveOutputCount -gt 0) {
                        # Clone the LiveOutput ArrayList Object because if we try to Enumerate (using Where-Object or other method) while elements are
                        # being added/removed from the ArrayList, things break
                        #$RamLiveOutputClone = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Clone()
                        
                        $ArrayOfRamPctEntries = @(
                            $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.RamPct
                        ) | Where-Object {$_ -ne $null}
                        if ($ArrayOfRamPctEntries.Count -gt 0) {
                            $LatestRamPctEntry = $ArrayOfRamPctEntries[-1]
                        }
                    }

                    $FinalRamPct = if (!$LatestRamPctEntry) {"0"} else {$LatestRamPctEntry}

                    $FinalRamPct | Out-UDMonitorData
                }

                $RAMMonitorSplatParams = @{
                    Title                   = "Memory (RAM) Utilization %"
                    Type                    = "Line"
                    DataPointHistory        = 20
                    ChartBackgroundColor    = "#80FF6B63"
                    ChartBorderColor        = "#FFFF6B63"
                    AutoRefresh             = $True
                    RefreshInterval         = 5
                    Endpoint                = $RamMonitorEndpoint
                }
                New-UdMonitor @RAMMonitorSplatParams
            }
        }

        # Network Statistics

        if (@($PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces).Count -eq 1) {
            New-UDRow -Columns {
                New-UDHeading -Text "Network Interface Info" -Size 4
                New-UDColumn -Size 6 -Endpoint {
                    $NetworkTableProperties = @("Name","Description","Sent","Received","DeltaSent","DeltaReceived")
                    New-UDTable -Headers $NetworkTableProperties -AutoRefresh -RefreshInterval 5 -Endpoint {
                        $PUDRSSyncHT = $global:PUDRSSyncHT
                        #$ThisNetworkInterfaceStaticInfo = $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces

                        #$NetworkLiveOutputCount = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count
                        if ($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count -gt 0) {
                            # Clone the LiveOutput ArrayList Object because if we try to Enumerate (using Where-Object or other method) while elements are
                            # being added/removed from the ArrayList, things break
                            #$NetworkLiveOutputClone = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Clone()
                            
                            # NOTE: Each element in the below $ArrayOfNetworkEntries is an ArrayList of PSCustomObjects.
                            # Each PSCustomObject contains:
                            
                            #[pscustomobject]@{
                            # Name = $NetInt.Name
                            # Description = $NetInt.Description
                            # TotalSentBytes = $IPv4Stats.BytesSent
                            # TotalReceivedBytes = $IPv4Stats.BytesReceived
                            #}
                            
                            $ArrayOfNetworkEntriesA = @(
                                $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.NetStats
                            ) | Where-Object {$_ -ne $null}
                            if ($ArrayOfNetworkEntriesA.Count -gt 0) {
                                $PreviousNetworkEntryA = $ArrayOfNetworkEntriesA[-2]
                                $LatestNetworkEntryA = $ArrayOfNetworkEntriesA[-1]
                            }
                        }

                        #$PreviousSentBytesTotalA = @($PUDRSSyncHT."$RemoteHost`Info".NetworkSendReceiveInfo."$($ThisNetworkInterfaceStaticInfo.Name)")[-1].TotalSentBytes
                        $PreviousSentBytesTotalA = $PreviousNetworkEntryA.TotalSentBytes
                        $NewSentBytesTotalA = $LatestNetworkEntryA.TotalSentBytes
                        $DifferenceSentBytesA = $NewSentBytesTotalA - $PreviousSentBytesTotalA
                        if ($DifferenceSentBytesA -le 0) {
                            $FinalKBSentA = 0
                        }
                        else {
                            $FinalKBSentA = [Math]::Round($($DifferenceSentBytesA / 1KB),2).ToString() + 'KB'
                        }
                        #$FinalKBSentA = [Math]::Round($($DifferenceSentBytesA / 1KB),2).ToString() + 'KB'

                        #$PreviousReceivedBytesTotalA = @($PUDRSSyncHT."$RemoteHost`Info".NetworkSendReceiveInfo."$($ThisNetworkInterfaceStaticInfo.Name)")[-1].TotalReceivedBytes
                        $PreviousReceivedBytesTotalA = $PreviousNetworkEntryA.TotalReceivedBytes
                        $NewReceivedBytesTotalA = $LatestNetworkEntryA.TotalReceivedBytes
                        $DifferenceReceivedBytesA = $NewReceivedBytesTotalA - $PreviousReceivedBytesTotalA
                        if ($DifferenceReceivedBytesA -le 0) {
                            $FinalKBReceivedA = 0
                        }
                        else {
                            $FinalKBReceivedA = [Math]::Round($($DifferenceReceivedBytesA / 1KB),2).ToString() + 'KB'
                        }
                        #$FinalKBReceivedA = [Math]::Round($($DifferenceReceivedBytesA / 1KB),2).ToString() + 'KB'

                        [pscustomobject]@{
                            Name                        = $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces.Name
                            Description                 = $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces.Description
                            Sent                        = [Math]::Round($($NewSentBytesTotalA / 1GB),2).ToString() + 'GB'
                            Received                    = [Math]::Round($($NewReceivedBytesTotalA / 1GB),2).ToString() + 'GB'
                            DeltaSent                   = $FinalKBSentA
                            DeltaReceived               = $FinalKBReceivedA

                        } | Out-UDTableData -Property $NetworkTableProperties
                    }
                    New-Variable -Name "NetworkMonitorEndpoint" -Force -Value $({
                        $PUDRSSyncHT = $global:PUDRSSyncHT
                        #$ThisNetworkInterfaceStaticInfo = $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces

                        #$NetworkLiveOutputCount = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count
                        if ($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count -gt 0) {
                            # Clone the LiveOutput ArrayList Object because if we try to Enumerate (using Where-Object or other method) while elements are
                            # being added/removed from the ArrayList, things break
                            #$NetworkLiveOutputClone = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Clone()
                            
                            # NOTE: Each element in the below $ArrayOfNetworkEntries is an ArrayList of PSCustomObjects.
                            # Each PSCustomObject contains:
                            <#
                                [pscustomobject]@{
                                    Name = $NetInt.Name
                                    Description = $NetInt.Description
                                    TotalSentBytes = $IPv4Stats.BytesSent
                                    TotalReceivedBytes = $IPv4Stats.BytesReceived
                                }
                            #>

                            $ArrayOfNetworkEntries = @(
                                $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.NetStats
                            ) | Where-Object {$_ -ne $null}
                            if ($ArrayOfNetworkEntries.Count -gt 0) {
                                $PreviousNetworkEntry = $ArrayOfNetworkEntries[-2]
                                $LatestNetworkEntry = $ArrayOfNetworkEntries[-1]
                            }
                        }

                        #$PreviousSentBytesTotal = @($PUDRSSyncHT."$RemoteHost`Info".NetworkSendReceiveInfo."$($ThisNetworkInterfaceStaticInfo.Name)")[-1].TotalSentBytes
                        $PreviousSentBytesTotal = $PreviousNetworkEntry.TotalSentBytes
                        $NewSentBytesTotal = $LatestNetworkEntry.TotalSentBytes
                        $DifferenceSentBytes = $NewSentBytesTotal - $PreviousSentBytesTotal
                        if ($DifferenceSentBytes -le 0) {
                            $FinalKBSent = 0
                        }
                        else {
                            $FinalKBSent = [Math]::Round($($DifferenceSentBytes / 1KB),2)
                        }
                        #$FinalKBSent = [Math]::Round($($DifferenceSentBytes / 1KB)).ToString() + 'KB'

                        #$PreviousReceivedBytesTotal = @($PUDRSSyncHT."$RemoteHost`Info".NetworkSendReceiveInfo."$($ThisNetworkInterfaceStaticInfo.Name)")[-1].TotalReceivedBytes
                        $PreviousReceivedBytesTotal = $PreviousNetworkEntry.TotalReceivedBytes
                        $NewReceivedBytesTotal = $LatestNetworkEntry.TotalReceivedBytes
                        $DifferenceReceivedBytes = $NewReceivedBytesTotal - $PreviousReceivedBytesTotal
                        if ($DifferenceReceivedBytes -le 0) {
                            $FinalKBReceived = 0
                        }
                        else {
                            $FinalKBReceived = [Math]::Round($($DifferenceReceivedBytes / 1KB),2)
                        }
                        #$FinalKBReceived = [Math]::Round($($DifferenceReceivedBytes / 1KB)).ToString() + 'KB'

                        # Update the SyncHash so we have a record of the previous total
                        #$PUDRSSyncHT."$RemoteHost`Info".NetworkSendReceiveInfo."$($ThisNetworkInterfaceStaticInfo.Name)" = $LatestNetworkEntry

                        $FinalKBSent | Out-UDMonitorData
                    })

                    $NetworkMonitorSplatParams = @{
                        Title                   = '"' + $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces.Name + '"' + ' Interface' + " Delta Sent KB"
                        Type                    = "Line"
                        DataPointHistory        = 20
                        ChartBackgroundColor    = "#80FF6B63"
                        ChartBorderColor        = "#FFFF6B63"
                        AutoRefresh             = $True
                        RefreshInterval         = 5
                        Endpoint                = $(Get-Variable -Name "NetworkMonitorEndpoint" -ValueOnly)
                    }
                    New-UdMonitor @NetworkMonitorSplatParams
                }
                New-UDColumn -Endpoint {
                    $null = $Session:OverviewPageLoadingTracker.Add("FinishedLoading")
                }
            }
        }
        else {
            New-UDRow -EndPoint {
                New-UDHeading -Text "Network Interface Info" -Size 4
            }
            for ($i=0; $i -lt @($PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces).Count; $i = $i+2) {
                New-UDRow -Columns {
                    New-UDColumn -Size 6 -Endpoint {
                        $NetworkTableProperties = @("Name","Description","Sent","Received","DeltaSent","DeltaReceived")
                        New-UDTable -Headers $NetworkTableProperties -AutoRefresh -RefreshInterval 5 -Endpoint {
                            $PUDRSSyncHT = $global:PUDRSSyncHT
                            #$ThisNetworkInterfaceStaticInfo = $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces[$i]

                            #$NetworkLiveOutputCount = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count
                            if ($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count -gt 0) {
                                # Clone the LiveOutput ArrayList Object because if we try to Enumerate (using Where-Object or other method) while elements are
                                # being added/removed from the ArrayList, things break
                                #$NetworkLiveOutputClone = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Clone()
                                
                                # NOTE: Each element in the below $ArrayOfNetworkEntries is an ArrayList of PSCustomObjects.
                                # Each PSCustomObject contains:
                                <#
                                    [pscustomobject]@{
                                        Name = $NetInt.Name
                                        Description = $NetInt.Description
                                        TotalSentBytes = $IPv4Stats.BytesSent
                                        TotalReceivedBytes = $IPv4Stats.BytesReceived
                                    }
                                #>

                                $ArrayOfNetworkEntries = @(
                                    $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.NetStats | Where-Object {
                                        $_.Name -eq $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces[$i].Name
                                    }
                                ) | Where-Object {$_ -ne $null}
                                if ($ArrayOfNetworkEntries.Count -gt 0) {
                                    $PreviousNetworkEntry = $ArrayOfNetworkEntries[-2]
                                    $LatestNetworkEntry = $ArrayOfNetworkEntries[-1]
                                }
                            }
        
                            #$PreviousSentBytesTotal = @($PUDRSSyncHT."$RemoteHost`Info".NetworkSendReceiveInfo."$($ThisNetworkInterfaceStaticInfo.Name)")[-1].TotalSentBytes
                            $PreviousSentBytesTotal = $PreviousNetworkEntry.TotalSentBytes
                            $NewSentBytesTotal = $LatestNetworkEntry.TotalSentBytes
                            $DifferenceSentBytes = $NewSentBytesTotal - $PreviousSentBytesTotal
                            if ($DifferenceSentBytes -le 0) {
                                $FinalKBSent = 0
                            }
                            else {
                                $FinalKBSent = [Math]::Round($($DifferenceSentBytes / 1KB),2).ToString() + 'KB'
                            }
                            #$FinalKBSent = [Math]::Round($($DifferenceSentBytes / 1KB),2).ToString() + 'KB'

                            #$PreviousReceivedBytesTotal = @($PUDRSSyncHT."$RemoteHost`Info".NetworkSendReceiveInfo."$($ThisNetworkInterfaceStaticInfo.Name)")[-1].TotalReceivedBytes
                            $PreviousReceivedBytesTotal = $PreviousNetworkEntry.TotalReceivedBytes
                            $NewReceivedBytesTotal = $LatestNetworkEntry.TotalReceivedBytes
                            $DifferenceReceivedBytes = $NewReceivedBytesTotal - $PreviousReceivedBytesTotal
                            if ($DifferenceReceivedBytes -le 0) {
                                $FinalKBReceived = 0
                            }
                            else {
                                $FinalKBReceived = [Math]::Round($($DifferenceReceivedBytes / 1KB),2).ToString() + 'KB'
                            }
                            #$FinalKBReceived = [Math]::Round($($DifferenceReceivedBytes / 1KB),2).ToString() + 'KB'

                            [pscustomobject]@{
                                Name                        = $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces[$i].Name
                                Description                 = $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces[$i].Description
                                Sent                        = [Math]::Round($($NewSentBytesTotal / 1GB),2).ToString() + 'GB'
                                Received                    = [Math]::Round($($NewReceivedBytesTotal / 1GB),2).ToString() + 'GB'
                                DeltaSent                   = $FinalKBSent
                                DeltaReceived               = $FinalKBReceived
                            } | Out-UDTableData -Property $NetworkTableProperties
                        }

                        New-Variable -Name "NetworkMonitorEndpoint$i" -Force -Value $({
                            $PUDRSSyncHT = $global:PUDRSSyncHT
                            #$ThisNetworkInterfaceStaticInfo = $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces[$i]
        
                            #$NetworkLiveOutputCount = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count
                            if ($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count -gt 0) {
                                # Clone the LiveOutput ArrayList Object because if we try to Enumerate (using Where-Object or other method) while elements are
                                # being added/removed from the ArrayList, things break
                                #$NetworkLiveOutputClone = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Clone()
                                
                                # NOTE: Each element in the below $ArrayOfNetworkEntries is an ArrayList of PSCustomObjects.
                                # Each PSCustomObject contains:
                                <#
                                    [pscustomobject]@{
                                        Name = $NetInt.Name
                                        Description = $NetInt.Description
                                        TotalSentBytes = $IPv4Stats.BytesSent
                                        TotalReceivedBytes = $IPv4Stats.BytesReceived
                                    }
                                #>

                                $ArrayOfNetworkEntriesA = @(
                                    $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.NetStats | Where-Object {
                                        $_.Name -eq $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces[$i].Name
                                    }
                                ) | Where-Object {$_ -ne $null}
                                if ($ArrayOfNetworkEntriesA.Count -gt 0) {
                                    $PreviousNetworkEntryA = $ArrayOfNetworkEntriesA[-2]
                                    $LatestNetworkEntryA = $ArrayOfNetworkEntriesA[-1]
                                }
                            }
        
                            #$PreviousSentBytesTotal = @($PUDRSSyncHT."$RemoteHost`Info".NetworkSendReceiveInfo."$($ThisNetworkInterfaceStaticInfo.Name)")[-1].TotalSentBytes
                            $PreviousSentBytesTotalA = $PreviousNetworkEntryA.TotalSentBytes
                            $NewSentBytesTotalA = $LatestNetworkEntryA.TotalSentBytes
                            $DifferenceSentBytesA = $NewSentBytesTotalA - $PreviousSentBytesTotalA
                            if ($DifferenceSentBytesA -le 0) {
                                $FinalKBSentA = 0
                            }
                            else {
                                $FinalKBSentA = [Math]::Round($($DifferenceSentBytesA / 1KB),2)
                            }
                            #$FinalKBSent = [Math]::Round($($DifferenceSentBytes / 1KB),2).ToString() + 'KB'

                            #$PreviousReceivedBytesTotal = @($PUDRSSyncHT."$RemoteHost`Info".NetworkSendReceiveInfo."$($ThisNetworkInterfaceStaticInfo.Name)")[-1].TotalReceivedBytes
                            $PreviousReceivedBytesTotalA = $PreviousNetworkEntryA.TotalReceivedBytes
                            $NewReceivedBytesTotalA = $LatestNetworkEntryA.TotalReceivedBytes
                            $DifferenceReceivedBytesA = $NewReceivedBytesTotalA - $PreviousReceivedBytesTotalA
                            if ($DifferenceReceivedBytesA -le 0) {
                                $FinalKBReceivedA = 0
                            }
                            else {
                                $FinalKBReceivedA = [Math]::Round($($DifferenceReceivedBytesA / 1KB),2)
                            }
                            #$FinalKBReceived = [Math]::Round($($DifferenceReceivedBytes / 1KB),2).ToString() + 'KB'

                            # Update the SyncHash so we have a record of the previous total
                            #$PUDRSSyncHT."$RemoteHost`Info".NetworkSendReceiveInfo."$($ThisNetworkInterfaceStaticInfo.Name)" = $LatestNetworkEntry
        
                            $FinalKBSentA | Out-UDMonitorData
                        })
        
                        $NetworkMonitorSplatParamsA = @{
                            Title                   = '"' + $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces[$i].Name + '"' + ' Interface' + " Delta Sent KB"
                            Type                    = "Line"
                            DataPointHistory        = 20
                            ChartBackgroundColor    = "#80FF6B63"
                            ChartBorderColor        = "#FFFF6B63"
                            AutoRefresh             = $True
                            RefreshInterval         = 5
                            Endpoint                = $(Get-Variable -Name "NetworkMonitorEndpoint$i" -ValueOnly)
                        }
                        New-UdMonitor @NetworkMonitorSplatParamsA
                    }
                    New-UDColumn -Size 6 -Endpoint {
                        $NetworkTableProperties = @("Name","Description","Sent","Received","DeltaSent","DeltaReceived")
                        New-UDTable -Headers $NetworkTableProperties -AutoRefresh -RefreshInterval 5 -Endpoint {
                            $PUDRSSyncHT = $global:PUDRSSyncHT
                            #$ThisNetworkInterfaceStaticInfo = $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces[$($i+1)]

                            #$NetworkLiveOutputCount = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count
                            if ($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count -gt 0) {
                                # Clone the LiveOutput ArrayList Object because if we try to Enumerate (using Where-Object or other method) while elements are
                                # being added/removed from the ArrayList, things break
                                #$NetworkLiveOutputClone = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Clone()
                                
                                # NOTE: Each element in the below $ArrayOfNetworkEntries is an ArrayList of PSCustomObjects.
                                # Each PSCustomObject contains:
                                <#
                                    [pscustomobject]@{
                                        Name = $NetInt.Name
                                        Description = $NetInt.Description
                                        TotalSentBytes = $IPv4Stats.BytesSent
                                        TotalReceivedBytes = $IPv4Stats.BytesReceived
                                    }
                                #>

                                $ArrayOfNetworkEntriesB = @(
                                    $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.NetStats | Where-Object {
                                        $_.Name -eq $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces[$($i+1)].Name
                                    }
                                ) | Where-Object {$_ -ne $null}
                                if ($ArrayOfNetworkEntriesB.Count -gt 0) {
                                    $PreviousNetworkEntryB = $ArrayOfNetworkEntriesB[-2]
                                    $LatestNetworkEntryB = $ArrayOfNetworkEntriesB[-1]
                                }
                            }
        
                            #$PreviousSentBytesTotal = @($PUDRSSyncHT."$RemoteHost`Info".NetworkSendReceiveInfo."$($ThisNetworkInterfaceStaticInfo.Name)")[-1].TotalSentBytes
                            $PreviousSentBytesTotalB = $PreviousNetworkEntryB.TotalSentBytes
                            $NewSentBytesTotalB = $LatestNetworkEntryB.TotalSentBytes
                            $DifferenceSentBytesB = $NewSentBytesTotalB - $PreviousSentBytesTotalB
                            if ($DifferenceSentBytesB -le 0) {
                                $FinalKBSentB = 0
                            }
                            else {
                                $FinalKBSentB = [Math]::Round($($DifferenceSentBytesB / 1KB),2).ToString() + 'KB'
                            }
                            #$FinalKBSent = [Math]::Round($($DifferenceSentBytes / 1KB),2).ToString() + 'KB'

                            #$PreviousReceivedBytesTotal = @($PUDRSSyncHT."$RemoteHost`Info".NetworkSendReceiveInfo."$($ThisNetworkInterfaceStaticInfo.Name)")[-1].TotalReceivedBytes
                            $PreviousReceivedBytesTotalB = $PreviousNetworkEntryB.TotalReceivedBytes
                            $NewReceivedBytesTotalB = $LatestNetworkEntryB.TotalReceivedBytes
                            $DifferenceReceivedBytesB = $NewReceivedBytesTotalB - $PreviousReceivedBytesTotalB
                            if ($DifferenceReceivedBytesB -le 0) {
                                $FinalKBReceivedB = 0
                            }
                            else {
                                $FinalKBReceivedB = [Math]::Round($($DifferenceReceivedBytesB / 1KB),2).ToString() + 'KB'
                            }
                            #$FinalKBReceived = [Math]::Round($($DifferenceReceivedBytes / 1KB),2).ToString() + 'KB'

                            [pscustomobject]@{
                                Name                        = $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces[$($i+1)].Name
                                Description                 = $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces[$($i+1)].Description
                                Sent                        = [Math]::Round($($NewSentBytesTotalB / 1GB),2).ToString() + 'GB'
                                Received                    = [Math]::Round($($NewReceivedBytesTotalB / 1GB),2).ToString() + 'GB'
                                DeltaSent                   = $FinalKBSentB
                                DeltaReceived               = $FinalKBReceivedB
                            } | Out-UDTableData -Property $NetworkTableProperties
                        }

                        New-Variable -Name "NetworkMonitorEndpoint$($i+1)" -Force -Value $({
                            $PUDRSSyncHT = $global:PUDRSSyncHT
                            #$ThisNetworkInterfaceStaticInfo = $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces[$($i+1)]
        
                            #$NetworkLiveOutputCount = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count
                            if ($PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Count -gt 0) {
                                # Clone the LiveOutput ArrayList Object because if we try to Enumerate (using Where-Object or other method) while elements are
                                # being added/removed from the ArrayList, things break
                                #$NetworkLiveOutputClone = $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataRSInfo.LiveOutput.Clone()
                                
                                # NOTE: Each element in the below $ArrayOfNetworkEntries is an ArrayList of PSCustomObjects.
                                # Each PSCustomObject contains:
                                <#
                                    [pscustomobject]@{
                                        Name = $NetInt.Name
                                        Description = $NetInt.Description
                                        TotalSentBytes = $IPv4Stats.BytesSent
                                        TotalReceivedBytes = $IPv4Stats.BytesReceived
                                    }
                                #>

                                $ArrayOfNetworkEntriesC = @(
                                    $PUDRSSyncHT."$RemoteHost`Info".Overview.LiveDataTracker.Previous.NetStats | Where-Object {
                                        $_.Name -eq $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces[$($i+1)].Name
                                    }
                                ) | Where-Object {$_ -ne $null}
                                if ($ArrayOfNetworkEntriesC.Count -gt 0) {
                                    $PreviousNetworkEntryC = $ArrayOfNetworkEntriesC[-2]
                                    $LatestNetworkEntryC = $ArrayOfNetworkEntriesC[-1]
                                }
                            }
        
                            #$PreviousSentBytesTotal = @($PUDRSSyncHT."$RemoteHost`Info".NetworkSendReceiveInfo."$($ThisNetworkInterfaceStaticInfo.Name)")[-1].TotalSentBytes
                            $PreviousSentBytesTotalC = $PreviousNetworkEntryC.TotalSentBytes
                            $NewSentBytesTotalC = $LatestNetworkEntryC.TotalSentBytes
                            $DifferenceSentBytesC = $NewSentBytesTotalC - $PreviousSentBytesTotalC
                            if ($DifferenceSentBytesC -le 0) {
                                $FinalKBSentC = 0
                            }
                            else {
                                $FinalKBSentC = [Math]::Round($($DifferenceSentBytesC / 1KB),2)
                            }
                            #$FinalKBSent = [Math]::Round($($DifferenceSentBytes / 1KB),2).ToString() + 'KB'

                            #$PreviousReceivedBytesTotal = @($PUDRSSyncHT."$RemoteHost`Info".NetworkSendReceiveInfo."$($ThisNetworkInterfaceStaticInfo.Name)")[-1].TotalReceivedBytes
                            $PreviousReceivedBytesTotalC = $PreviousNetworkEntryC.TotalReceivedBytes
                            $NewReceivedBytesTotalC = $LatestNetworkEntryC.TotalReceivedBytes
                            $DifferenceReceivedBytesC = $NewReceivedBytesTotalC - $PreviousReceivedBytesTotalC
                            if ($DifferenceReceivedBytesC -le 0) {
                                $FinalKBReceivedC = 0
                            }
                            else {
                                $FinalKBReceivedC = [Math]::Round($($DifferenceReceivedBytesC / 1KB),2)
                            }
                            #$FinalKBReceived = [Math]::Round($($DifferenceReceivedBytes / 1KB),2).ToString() + 'KB'

                            # Update the SyncHash so we have a record of the previous total
                            #$PUDRSSyncHT."$RemoteHost`Info".NetworkSendReceiveInfo."$($ThisNetworkInterfaceStaticInfo.Name)" = $LatestNetworkEntry
        
                            $FinalKBSentC | Out-UDMonitorData
                        })
        
                        $NetworkMonitorSplatParamsC = @{
                            Title                   = '"' + $PUDRSSyncHT."$RemoteHost`Info".Overview.RelevantNetworkInterfaces[$($i+1)].Name + '"' + ' Interface' + " Delta Sent KB"
                            Type                    = "Line"
                            DataPointHistory        = 20
                            ChartBackgroundColor    = "#80FF6B63"
                            ChartBorderColor        = "#FFFF6B63"
                            AutoRefresh             = $True
                            RefreshInterval         = 5
                            Endpoint                = $(Get-Variable -Name "NetworkMonitorEndpoint$($i+1)" -ValueOnly)
                        }
                        New-UdMonitor @NetworkMonitorSplatParamsC
                    }
                }
            }
            New-UDColumn -Endpoint {
                $null = $Session:OverviewPageLoadingTracker.Add("FinishedLoading")
            }
        }

        #endregion >> Monitors
    }
}
$Page = New-UDPage -Url "/Overview/:RemoteHost" -Endpoint $OverviewPageContent
$null = $Pages.Add($Page)

#endregion >> Overview Page