Public/Get-ServerStatus.ps1

<#
.SYNOPSIS
    Get-ServerStatus.ps1 - Test network, RPC, and RDP connections, as well as gathering uptime and
    pending reboot status against one or more computers.
.DESCRIPTION
    Get-ServerStatus.ps1 - Test an RPC connection (WMI request) against one or more computer(s)
    with test-connection before to see if the computer is reachable or not first
.PARAMETER ComputerList
    Defines the path to the file containing a list of servers to test against, either by hostname or IP address.
.PARAMETER ComputerName
    Defines the computer name or IP address to test against. Could be an array of server names.
.PARAMETER User
    Username
.PARAMETER Pass
    Password
.NOTES
    File Name : Get-ServerStatus.ps1
    Author : Marcus Daniels - danielm1@mskcc.org
    Adapted From : RPC-Ping.ps1 by Fabrice ZERROUKI - fabricezerrouki@hotmail.com
.EXAMPLE
    PS D:\> Get-ServerStatus.ps1 -ComputerList C:\servers.txt -ExportPath C:\Reports\
    Get server status from a list of servers and export to a CSV at the defined path.
.EXAMPLE
    PS D:\> Get-ServerStatus.ps1 -ComputerName SERVER1
    Get server status for SERVER1 as current user
.EXAMPLE
    PS D:\> Get-ServerStatus.ps1 -ComputerName SERVER1,192.168.0.23 -Credential JSMith
    Get server status for SERVER1 and 192.168.0.23 as a supplied user. Can also pass "-Credential (Get-Credential)" for a Windows security prompt.
#>


function Get-ServerStatus {

[CmdletBinding(DefaultParameterSetName='ByComputerName')]

Param(

    [Parameter(
    Mandatory = $true, 
    ParameterSetName = 'ByComputerList')]
    [array]$ComputerList,
    
    [Parameter(
    Position=0,
    ValueFromPipeline=$true,
    ValueFromPipelineByPropertyName=$true,
    ParameterSetName = 'ByComputerName')]
    [array]$ComputerName="$env:COMPUTERNAME",


    [Parameter()]
    [string[]]$User,

    [Parameter()]
    $Pass,

    [Parameter()]
    [System.Management.Automation.PSCredential]
    [System.Management.Automation.Credential()]
    $Credential = [System.Management.Automation.PSCredential]::Empty,

    [Parameter()]
    [string]$ExportPath=$(Get-Location).Path,

    #[switch]$ErrorLog,

    [switch]$ExportCSV,
    
    [switch]$ExportXLSX

    )

$WriteReport = $false

if ($ExportXLSX) {
    try {
        Import-Module ImportExcel -ErrorAction Stop | Out-Nulll
        }
    catch {
        Write-Host "`nYou must install the ImportExcel module first to export to XLSX" -BackgroundColor DarkRed -ForegroundColor White
        if ($PSVersionTable.PSVersion.Major -ge 5) {
            Write-Host "Choose " -NoNewline 
            Write-Host "-ExportCSV " -BackgroundColor Yellow -ForegroundColor Black -NoNewline        
            Write-Host "or run "  -NoNewline 
            Write-Host "Install-Module ImportExcel -scope CurrentUser"  -BackgroundColor Yellow -ForegroundColor Black -NoNewline
            Write-Host " to install`n" 
        }
        else {
            Write-Host "Choose " -NoNewline 
            Write-Host "-ExportCSV " -BackgroundColor Yellow -ForegroundColor Black -NoNewline        
            Write-Host "or visit "  -NoNewline 
            Write-Host "https://github.com/dfinke/ImportExcel "  -BackgroundColor Yellow -ForegroundColor Black -NoNewline
            Write-Host "for install instructions" 
        }
        break
        }
}

if ($ExportCSV -or $ExportXLSX) {
$WriteReport = $true
}

if ($ExportCSV -and $ExportXLSX) {
$ExportXLSX = $null
Write-Host "Multiple export options set; disabling ExportXLSX, only one is allowed"
}

$time = (Get-Date -UFormat %H.%M.%S)

$ExtensionCheck = $null

#if ($ExportPath) {
# write-host "export path specified"
# $WriteReport = $true
    $ExtensionCheck = (Get-Extension -ExportPath $ExportPath)
    Switch ($ExtensionCheck) {
    "True" {
            do { 
                $ExportPath = Read-Host "Invalid path or directory. Filenames are not allowed"
                $ExtensionCheck = (Get-Extension -ExportPath $ExportPath)
                }
            while ($ExtensionCheck -eq "True")
            }
    "False" {
            }
        }
#}
<#
else {
#$WriteReport = $false
$WriteReport = $true
$ExportPath = (Get-Location).Path
write-host "$exportpath should be the current working dir"
}#>



if ($WriteReport -eq $true -and $ExportPath[-1] -eq "\") {
    $ExportPath = $ExportPath.Substring(0,$ExportPath.Length-1)
    write-host "debug write report file ext check, exportpath is $ExportPath"
    }  


$ErrorLog = $true

if ($ErrorLog) {

try {
    #Import-Module PSLogging -ErrorAction Stop
    #$LogPath = ".\"
    $LogPath = $ExportPath
    $LogName = “ServerStatus_ErrorLog_" + (Get-Date -Format MM.dd.yyyy) + "_$time.log”
    Start-Log -LogPath $LogPath -LogName $LogName -ScriptVersion “1.0” | Out-Null
    $Log = "$LogPath\$LogName"
    }
catch {
    Write-Host $_
    }
}


if ($WriteReport -eq $true -and (!(Test-Path $ExportPath)) ) {
    New-Item -Path $ExportPath -ItemType Directory | Out-Null 
    }

if ($PSCmdlet.ParameterSetName -eq 'ByComputerList') {
$ComputerName = (Get-Content $ComputerList) 
}

# Reset the user just in case

$RunAsUser = $null

# Authentication logic

if ($User -and $Pass) {
$SecPass = ConvertTo-SecureString -String $Pass -AsPlainText -Force
$Mycreds = New-Object System.Management.Automation.PSCredential ($User, $SecPass)
}

elseif ($User -ne $null -and $Pass -eq $null) {
$SecPass = Read-Host "Enter Password" -AsSecureString
$Mycreds = New-Object System.Management.Automation.PSCredential ($User, $SecPass)
}

#elseif ($User -eq $null -and $Pass -eq $null) {
else { 
$RunAsUser = $True
$mycreds = [System.Management.Automation.PSCredential]::Empty
}

# Create an empty array for our end results #
$Results = @()

# Set the report filename #
$Reportname = "ServerStatusReport_" + (Get-Date -Format MM.dd.yyyy) + "_$time.xlsx"

# Begin main for loop on the computer array

ForEach ($Computer in $ComputerName) {

    # Start progress bar
    $i++
    $progress = [math]::truncate(($i / $computername.length)  * 100) 
    Write-Progress -activity "Checking $computer" -status "$Progress percent complete: " -PercentComplete (($i / $computername.length)  * 100)
    
    # Create an object to hold each machine's results #
    $Result = New-Object System.Object    
    
    # Write the hostname to the array #
    $Result | Add-Member -MemberType NoteProperty -Name "Hostname" -Value $Computer -Verbose

    # Starting main if/else statement: pass/fail ping test #
    if (Test-Connection -ComputerName $Computer -Quiet -Count 1) {
        $Result | Add-Member -MemberType NoteProperty -Name "Ping Result" -Value "Online"
    # RDP Try/Catch
                
    try {
    $RDPOnline = (Test-Port $Computer -Port 3389 -ErrorAction Stop)
    Switch ($RDPOnline) {
    "False" {
         $Result | Add-Member -MemberType NoteProperty -Name "RDP" -Value "Down"
         }
    "True" {
         $Result | Add-Member -MemberType NoteProperty -Name "RDP" -Value "Online"
         }
       }
     }
    catch {
    $Result | Add-Member -MemberType NoteProperty -Name "RDP" -Value "Unknown"
     }        

  # First an RPC port test

  $RPCOnline = (Test-Port $Computer -Port 135 -ErrorAction Stop)

    Switch ($RPCOnline) {
        "False" {
            $Result | Add-Member -MemberType NoteProperty -Name "RPC" -Value "Down"
        }
        "True" {
        # RPC Try/Catch via WMI call
        
                   try {
                       (Get-WmiObject win32_computersystem -ComputerName $Computer -Credential $Mycreds -ErrorAction Stop | Out-Null)
                       $Result | Add-Member -MemberType NoteProperty -Name "RPC" -Value "Online"
                       }
                   catch {
                       $Result | Add-Member -MemberType NoteProperty -Name "RPC" -Value "Error"
                       Write-LogError -LogPath $Log -Message “$Computer : Error: $_ ” -ErrorAction SilentlyContinue -TimeStamp | Out-Null
                       }
                   
      # Uptime Try/Catch
                   try {
                    $uptime = (Get-Uptime -ComputerName $Computer -Credential $mycreds)
                    $Result | Add-Member -MemberType NoteProperty -Name "Uptime (DD:HH:MM)" -Value $uptime
                    }
                   catch{
                    $Result | Add-Member -MemberType NoteProperty -Name "Uptime (DD:HH:MM)" -Value "Unknown"
                    Write-LogError -LogPath $Log -Message “$Computer : Error: $_ ” -ErrorAction SilentlyContinue -TimeStamp | Out-Null
                   }


      # Pending Reboot Try/Catch - clear pending reboot to avoid false positives

                    $PendingReboot = $null

                    try {
                        $PendingReboot = (Get-PendingReboot -ComputerName $Computer -Credential $mycreds -ErrorAction Stop)
                        }                        
                    catch {
                        $Result | Add-Member -MemberType NoteProperty -Name "Pending Reboot" -Value "Error"
                        Write-LogError -LogPath $Log -Message “$Computer : Error: $_ ” -ErrorAction SilentlyContinue -TimeStamp | Out-Null
                        }

                        if ($PendingReboot -eq "" -or $PendingReboot -eq "Unknown" -or $PendingReboot -eq "Pending Reboot") {
                        $Result | Add-Member -MemberType NoteProperty -Name "Pending Reboot" -Value $pendingreboot
                        }
                        elseif ($PendingReboot -eq "False") {
                        $Result | Add-Member -MemberType NoteProperty -Name "Pending Reboot" -Value ""
                        }
                        elseif ($PedingReboot -notmatch "^\d{2}.\d{2}.\d{2}") {
                        $Result | Add-Member -MemberType NoteProperty -Name "Pending Reboot" -Value "Error"
                        Write-LogError -LogPath $Log -Message “$Computer : Pending Reboot Error from catch: $_ ” -ErrorAction SilentlyContinue -TimeStamp | Out-Null
                        }
                        
                    
}

         
}           
                

    }
       
    else {
            # Computer doesn't even respond to ping...
            $Result | Add-Member -MemberType NoteProperty -Name "Ping Result" -Value "Failed"
            Write-LogError -LogPath $Log -Message “$Computer Error: Ping Failed ” -ErrorAction SilentlyContinue -TimeStamp | Out-Null
        }

# Write this machine's results to the array
 
$Results += $Result

}

# End for loop on the computer array

# Export the array to the CSV report

if ($WriteReport -eq $true) {
#$Results | Export-Csv -NoTypeInformation -Path "$ExportPath\$Reportname"
$Results | Export-Excel $ExportPath\$Reportname 
Write-Host "Report exported to $ExportPath\$Reportname" -BackgroundColor DarkGreen
}
elseif ($ExportCSV) {
$ReportName =  ($Reportname).Replace("xlsx","csv")
$Results | ConvertTo-CSV -NoTypeInformation | Out-File  "$ExportPath\$Reportname"
}

else {
$Results | fl *
}

if ($ErrorLog) {
Stop-Log -LogPath $Log -NoExit
Write-Host "Error log written to $Log" -BackgroundColor DarkGreen
}

}