Common/ServerRake.Common.Read.ps1

################################
### COMMON FUNCTIONS: READ ###
################################

function Get-MaintenanceWindow {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName,

        [Parameter(Mandatory = $true)]
        [string[]] $MaintenanceWindows

    )

    $remoteScript = {
        
        param ($MaintenanceWindows)

        $window = Get-ItemProperty -Path 'HKLM:\SOFTWARE\WOW6432Node\Tanium\Tanium Client\Sensor Data\Tags'
        $window = ($window | Get-Member) | Where-Object { $_.Name -like "SRV*" -or $_.Name -like "WRK*" } | 
        Select-Object -Property Name

        $response = [PSCustomObject]@{
            Server                     = $ENV:COMPUTERNAME
            'Tanium Maintenance Tag'   = $window.Name
            'Tainum Maintenance Day'   = $MaintenanceWindows[$window.Name].Day
            'Tanium Maintenance Start' = $MaintenanceWindows[$window.Name].Start
            'Tanium Maintenance End'   = $MaintenanceWindows[$window.Name].End
        }

        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript -ArgumentList $MaintenanceWindows

}

function Get-AvailableUpdates {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {
            
        $updates = Get-WindowsUpdate

        $response = @()
        
        foreach ($update in $updates) { 
            $response += [PSCustomObject]@{
                Server                  =   $ENV:COMPUTERNAME
                'Update Size'           =   $update.Size
                'Update KB'             =   $update.KB
                'Update Title'          =   $update.Title
                'Update URL'            =   $update.MoreInfoUrls
                'Update Description'    =   $update.Description
            }
        }

        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript

}

function Get-InstalledUpdates {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {

        $patches = Get-HotFix

        $response = @()

        foreach ($patch in $patches) {
            $response += [PSCustomObject]@{
                Server               = $ENV:COMPUTERNAME
                'Patch Description'  = $patch.Description
                'Patch Hotfix ID'    = $patch.HotFixID
                'Patch Install Date' = $patch.InstalledOn
            }
        }

        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript

}

function Get-SystemLogs {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = { 

        $events = Get-WinEvent -FilterHashtable @{
            LogName = 'System'
            Level   = 2
        } -MaxEvents 50

        $response = @()
        
        foreach ($e in $events) {
            $response += [PSCustomObject]@{
                Server                 = $ENV:COMPUTERNAME
                'System Error Time'    = $e.TimeCreated
                'System Error Source'  = $e.ProviderName
                'System Error ID'      = $e.Id
                'System Error Message' = $e.Message
            }
        }

        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript
    
}

function Get-ApplicationLogs {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {

        $events = Get-WinEvent -FilterHashtable @{
            LogName = 'Application'
            Level   = 2
        } -MaxEvents 50

        $response = @()

        foreach ($e in $events) {
            $response += [PSCustomObject]@{
                Server                      = $ENV:COMPUTERNAME
                'Application Error Time'    = $e.TimeCreated
                'Application Error Source'  = $e.ProviderName
                'Application Error ID'      = $e.Id
                'Application Error Message' = $e.Message
            }
        }

        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript

}

function Get-NetworkingLogs {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {
        
        $events = Get-WinEvent -FilterHashtable @{
            LogName   = 'Microsoft-Windows-NetworkProfile/Operational'
            StartTime = (Get-Date).AddDays(-1)
        } -ErrorAction SilentlyContinue

        $response = @()
        
        foreach ($e in $events) {
            $response += [PSCustomObject]@{
                Server                     = $ENV:COMPUTERNAME
                'Networking Error Time'    = $e.TimeCreated
                'Networking Error Source'  = $e.ProviderName
                'Networking Error ID'      = $e.Id
                'Networking Error Message' = $e.Message
            }
        }

        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript
    
}

function Get-SQLLogs {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {

        $events = Get-WinEvent -FilterHashtable @{
            LogName      = 'Application'
            ProviderName = 'MSSQLSERVER'
            Level        = 2
        } -MaxEvents 50 

        $response = @()

        foreach ($e in $events) {
            $response += [PSCustomObject]@{
                Server                 = $ENV:COMPUTERNAME
                'Backup Error Time'    = $e.TimeCreated
                'Backup Error Source'  = $e.ProviderName
                'Backup Error ID'      = $e.Id
                'Backup Error Message' = $e.Message
            }
        }

        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript

}

function Get-SystemDrives {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {

        $disks = Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3"

        $response = @()
        foreach ($disk in $disks) { 

            $response += [PSCustomObject]@{
                Server              = $ENV:COMPUTERNAME
                'Disk Letter'       = $disk.DeviceID
                'Disk Label'        = $disk.VolumeName 
                'Disk Size (GB)'    = [Math]::Round($disk.Size / 1GB, 2)  
                'Disk Free (GB)'    = [Math]::Round($disk.FreeSpace / 1GB, 2) 
            }

        }
        
        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript

}

function Get-SystemRam {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {

        $ram = [math]::round((Get-CimInstance win32_ComputerSystem -OperationTimeoutSec 10 -ErrorAction SilentlyContinue).TotalPhysicalMemory / 1GB)

        $response = [PSCustomObject]@{
            Server        = $ENV:COMPUTERNAME
            'Memory (GB)' = $ram
        }

        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript

}

function Get-SystemCpuCores {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {

        $cores = (Get-CimInstance -ClassName Win32_Processor).NumberOfCores

        $response = [PSCustomObject]@{
            Server      = $ENV:COMPUTERNAME
            'CPU Cores' = $cores
        }

        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript

}

function Get-OpenNetworkingPorts {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {

        $openPorts = Get-NetTCPConnection -State Listen, Established | Sort-Object LocalPort -Unique
        
        $response = @()

        foreach ($port in $openPorts) {

            $procId = $port.OwningProcess
            $process = Get-Process -Id $procId -ErrorAction SilentlyContinue
            $service = Get-CimInstance -ClassName Win32_Service -Filter "ProcessId = $procId" -ErrorAction SilentlyContinue
            
            $response += [PSCustomObject]@{
                Server                      = $ENV:COMPUTERNAME
                'Open Port Local'           = $port.LocalPort
                'Open Port Remote'          = $port.RemotePort
                'Open Port Applied Setting' = $port.AppliedSetting
                'Open Port Process'         = $process.ProcessName
                'Open Port Process Name'    = if ($service) { $service.DisplayName } else { $process.Description }
            }

        }

        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript

}

function Get-SystemServices {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {

        $services = Get-CimInstance -ClassName Win32_Service | Select-Object Name, DisplayName, State, StartMode, StartName

        $response = @()

        foreach ($service in $services) {
            $response += [PSCustomObject]@{
                Server                  =   $ENV:COMPUTERNAME
                'Service Name'          =   $service.DisplayName
                'Service Status'        =   $service.State
                'Service Start Mode'    =   $service.StartMode
                'Service Account'       =   $service.StartName
            }
        }

        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript
    
}

function Get-AdminUsers {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {

        $adminMembers = Get-LocalGroupMember -Name "Administrators" | ? ObjectClass -EQ "User" 

        $response = @()

        foreach ($member in $adminMembers) {
            $response += [PSCustomObject]@{
                Server         = $ENV:COMPUTERNAME
                'Admin Name'   = $member.Name
                'Admin Source' = $member.PrincipalSource
            }
        }

        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript

}

function Get-AdminGroups {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {

        $adminGroups = Get-LocalGroupMember -Name "Administrators" | ? ObjectClass -EQ "Group"

        $response = @()

        foreach ($group in $adminGroups) {
            $response += [PSCustomObject]@{
                Server         = $ENV:COMPUTERNAME
                'Group Name'   = $group.Name
                'Group Source' = $group.PrincipalSource
            }
        }

        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript
    
}

function Get-SQLClusterPrimary {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {

        Import-Module FailoverClusters; 
        
        $sqlCluster = Get-ClusterGroup | Where-Object { $_.Name -ne "Available Storage" -and $_.Name -ne "Cluster Group" }

        $response = [PSCustomObject]@{
            Server             = $ENV:COMPUTERNAME
            'SQL Owner Node'   = $sqlCluster.OwnerNode
            'SQL Node State'   = $sqlCluster.State
            'SQL Cluster Name' = $sqlCluster.Name
        }

        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript
    
}

function Get-ServerCertificates {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {

        $stores = @("Cert:\LocalMachine\My", "Cert:\LocalMachine\WebHosting")
        $certificates = Get-ChildItem -Path $stores -Recurse | Where-Object { !$_.IsContainer }

        if ($certificates) {

            $response = @()

            foreach ($cert in $certificates) {
                $response += [PSCustomObject]@{
                    Server                              =   $ENV:COMPUTERNAME
                    'Certificate Name'                  =   $cert.Subject
                  # 'Certificate Thumbprint' = $cert.Thumbprint
                    'Certificate Expiration Date'       =   $cert.NotAfter
                    'Certificate Expiration (Days)'     =   ($cert.NotAfter - (Get-Date)).Days
                }
            }

            return $response

        } else {

            Write-Host "No certs found for [$ENV:COMPUTERNAME]."

        }

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript
    
}

function Get-SystemRebootStatus {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {

        $rebootNeeded = $False
        $paths = @()

        if (Test-Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending") {
            $rebootNeeded = $True
            $paths += "Component"
        }
        
        if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired") {
            $rebootNeeded = $True
            $paths += "Windows Update"
        } 

        if ([bool](Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" -Name PendingFileRenameOperations -EA 0).PendingFileRenameOperations) {
            $rebootNeeded = $True
            $paths += "File Rename"
        }

        if (Test-Path "HKLM:\SOFTWARE\Microsoft\SMS\Mobile Client\Reboot Management\RebootData") {
            $rebootNeeded = $True
            $paths += "Configuration Manager"
        }

        $response = [PSCustomObject]@{
            Server              = $ENV:COMPUTERNAME
            'Reboot Pending'    = $rebootNeeded
            'Reboot Cause'      = $paths -join ', '
        }

        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript 

}

function Get-InstalledPrograms {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {

        $programs = @()
        $programs += Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
        $programs += Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*"
        $programs = $programs | Where-Object { $null -ne $_.DisplayName }
        
        $response = @()

        foreach ($program in $programs) {
            foreach ($entry in $program) {
                if ($entry.DisplayName) {
                    $response += [PSCustomObject]@{
                        Server                 = $ENV:COMPUTERNAME
                        'Program Name'         = $entry.DisplayName
                        'Program Version'      = $entry.DisplayVersion
                        'Program Publisher'    = $entry.Publisher
                        'Program Install Date' = $entry.InstallDate
                    }
                }
            }
        }

        return $response
        
    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript
    
}

function Get-SystemTopProcesses {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string[]] $ComputerName
    )

    $remoteScript = {

        $ramProcesses = Get-Process | 
        Sort-Object -Property WS -Descending | 
        Select-Object -First 10 -Property ProcessName, WS

        $response = @()
        
        foreach ($process in $ramProcesses) {

            $response += [PSCustomObject]@{
                Server              = $ENV:COMPUTERNAME
                'Process Name'      = $process.ProcessName
                'Memory Used (MB)'  = ($process.WS / 1MB)
            }

        }

        return $response

    }

    return Send-RemoteScript -ComputerName $ComputerName -RemoteScript $remoteScript 

}