diff --git a/Get-SystemStatus.ps1 b/Get-SystemStatus.ps1 new file mode 100644 index 0000000..0529500 --- /dev/null +++ b/Get-SystemStatus.ps1 @@ -0,0 +1,416 @@ +<# + +.SYNOPSIS +Gets various information related to a running system's status for reporting. + +.DESCRIPTION +Gathers the follow information from a provided list of computers. +The collected data is then returned as a DataTable or can be exported to a variety of file formats. +Optional Metadata can be included to be included in the returned results/reports to assist in machine identification. + +Collected Data: Computer Name, Operating System, Operating System Build, Uptime, Recent Updates, Disk Space Utilization, Date Gathered +Optional Metadata: Organization, Role, UpdateWindow + +.PARAMETER ComputerName +Specifies a computer or set of computers that should be queried for their status. + +.PARAMETER CsvPath +Path to a CSV that contains the list computers that should be collected. +Optional metadata can be included that will be included in returned data. + +Columns: +Name* +Organization +Role +UpdateWindow + +*: Required + +.PARAMETER Credential +Credentials used for connecting to the specified computers to gather the machine's status information. + +.PARAMETER CredentialPath +Path to stored credentials that will be imported using Import-Clixml to allow for storing credentials using a secure method. + +.PARAMETER OutputType +Style of report that should be output. Defaults to JSON output but can be exported as a CSV or JSON. + +.PARAMETER OutputPath +Path to where the report should be saved. + +.PARAMETER Organization +Optional metadata that can be included in the returned results. + +.PARAMETER Role +Optional metadata that can be included in the returned results. + +.PARAMETER UpdateWindow +Optional metadata that can be included in the returned results. + +.NOTES + Version: 1.0 + Author: Tyler Hale + Creation Date: 2021.09.14 + +#> + +[CmdletBinding(DefaultParameterSetName = 'Local')] +param ( + [Parameter(Mandatory = $true, ParameterSetName = "CnDefaultCred")] + [Parameter(Mandatory = $true, ParameterSetName = "CnDefaultCredReport")] + [Parameter(Mandatory = $true, ParameterSetName = "CnCred")] + [Parameter(Mandatory = $true, ParameterSetName = "CnCredReport")] + [Parameter(Mandatory = $true, ParameterSetName = "CnStoredCred")] + [Parameter(Mandatory = $true, ParameterSetName = "CnStoredCredReport")] + [ValidateScript( { Test-Connection $_ -Count 2 } )] + [alias('Cn')] + [string[]] + $ComputerName, + + [Parameter(Mandatory = $true, ParameterSetName = "CsvDefaultCred")] + [Parameter(Mandatory = $true, ParameterSetName = "CsvDefaultCredReport")] + [Parameter(Mandatory = $true, ParameterSetName = "CsvCred")] + [Parameter(Mandatory = $true, ParameterSetName = "CsvCredReport")] + [Parameter(Mandatory = $true, ParameterSetName = "CsvStoredCred")] + [Parameter(Mandatory = $true, ParameterSetName = "CsvStoredCredReport")] + [ValidateNotNullOrEmpty()] + [ValidateScript( { Test-Path -Path $_ } )] + [string] + $CsvPath, + + [Parameter(Mandatory = $true, ParameterSetName = "CnCred")] + [Parameter(Mandatory = $true, ParameterSetName = "CnCredReport")] + [Parameter(Mandatory = $true, ParameterSetName = "CsvCred")] + [Parameter(Mandatory = $true, ParameterSetName = "CsvCredReport")] + [ValidateNotNull()] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty, + + [Parameter(Mandatory = $true, ParameterSetName = "CnStoredCred")] + [Parameter(Mandatory = $true, ParameterSetName = "CnStoredCredReport")] + [Parameter(Mandatory = $true, ParameterSetName = "CsvStoredCred")] + [Parameter(Mandatory = $true, ParameterSetName = "CsvStoredCredReport")] + [ValidateNotNullOrEmpty()] + [ValidateScript( { Test-Path -Path $_ })] + [string] + $CredentialPath, + + [Parameter(Mandatory = $false, ParameterSetName = "LocalReport")] + [Parameter(Mandatory = $false, ParameterSetName = "CnDefaultCredReport")] + [Parameter(Mandatory = $false, ParameterSetName = "CnCredReport")] + [Parameter(Mandatory = $false, ParameterSetName = "CnStoredCredReport")] + [Parameter(Mandatory = $false, ParameterSetName = "CsvDefaultCredReport")] + [Parameter(Mandatory = $false, ParameterSetName = "CsvCredReport")] + [Parameter(Mandatory = $false, ParameterSetName = "CsvStoredCredReport")] + [ValidateSet("CSV", "JSON", "HTML")] + [string] + $OutputType = "JSON", + + [Parameter(Mandatory = $true, ParameterSetName = "LocalReport")] + [Parameter(Mandatory = $true, ParameterSetName = "CnDefaultCredReport")] + [Parameter(Mandatory = $true, ParameterSetName = "CnCredReport")] + [Parameter(Mandatory = $true, ParameterSetName = "CnStoredCredReport")] + [Parameter(Mandatory = $true, ParameterSetName = "CsvDefaultCredReport")] + [Parameter(Mandatory = $true, ParameterSetName = "CsvCredReport")] + [Parameter(Mandatory = $true, ParameterSetName = "CsvStoredCredReport")] + [string] + $OutputPath, + + [Parameter(Mandatory = $false)] + [ValidateNotNullOrEmpty()] + [string] + $Organization, + + [Parameter(Mandatory = $false)] + [ValidateNotNullOrEmpty()] + [string] + $Role, + + [Parameter(Mandatory = $false)] + [ValidateNotNullOrEmpty()] + [string] + $UpdateWindow +) + +############################################### [Script Settings] ################################################ + +# Define Default Columns +[System.Collections.ArrayList]$Columns = @( + "Computer Name", + "Operating System", + "Operating System Build", + "Uptime", + "Recent Updates", + "Disk Space Utilization", + "Date Gathered" +) + +# Define optional columns that will be removed if not provided +[System.Collections.ArrayList]$OptionalColumns = @( + "Role" + "Organization" + "UpdateWindow" +) + +# HTML Header for table formatting +$Head = @" + + + +"@ + +################################################## [Functions] ################################################### + +function Format-DataSizes ($Size) { + switch ($Size) { + { $_ -ge 1PB } { "{0:#.#'P'}" -f ($Size / 1PB); break } + { $_ -ge 1TB } { "{0:#.#'T'}" -f ($Size / 1TB); break } + { $_ -ge 1GB } { "{0:#.#'G'}" -f ($Size / 1GB); break } + { $_ -ge 1MB } { "{0:#.#'M'}" -f ($Size / 1MB); break } + { $_ -ge 1KB } { "{0:#'K'}" -f ($Size / 1KB); break } + default { "{0}" -f ($Size) + "B" } + } +} + +function Format-TimeSpan { + process { + "{0:00} Day(s) {1:00}:{2:00}:{3:00}" -f $_.Days, $_.Hours, $_.Minutes, $_.Seconds + } +} + +function Add-RowEntry { + [CmdletBinding()] + param ( + $Table, + $Name = $OperatingSystem.CSName, + $Role, + $Organization = $OperatingSystem.Organization, + $OperatingSystem, + $LogicalDisk, + $Updates, + $UpdateWindow, + $DateGathered, + $OptionalColumns + ) + + # Create a row + $Row = $Table.NewRow() + + # Define the computer name + $Row."Computer Name" = $Name + $Row."Date Gathered" = $DateGathered + + # OS + if ($null -ne ($OperatingSystem)) { + $Row."Operating System" = "$($OperatingSystem.Caption)" + $Row."Operating System Build" = "$($OperatingSystem.Version)" + $Row."Uptime" = "$((New-TimeSpan -Start ($OperatingSystem.LastBootUpTime) -End $DataGatheredDate) | Format-TimeSpan)" + } + + # Disk + if ($null -ne ($LogicalDisk)) { + [string]$DiskUsage = "" + $LogicalDisk | ForEach-Object { + if ($null -ne $_.Size) { + $FreeSpace = Format-DataSizes -Size $_.FreeSpace + $TotalSize = Format-DataSizes -Size $_.Size + $DiskUsage += "$($_.DeviceID) $($TotalSize) Total \ $($FreeSpace) Free - {0:P0}`n" -f ($_.FreeSpace / $_.Size) + } + } + $Row."Disk Space Utilization" = $DiskUsage.TrimEnd() + } + + # Updates + if ($null -ne ($Updates)) { + $Row."Recent Updates" = "" + $RecentUpdates = ($Updates | Sort-Object InstalledOn -Descending) | Select-Object -First 3 + foreach ($Update in $RecentUpdates) { + $Row."Recent Updates" += "$(($Update.InstalledOn | Select-String -Pattern "(.*)(?= 00:00:00)").Matches.Value) - $($Update.HotFixID)`n" + } + } + + # Optional Columns + foreach ($OptionalColumn in $OptionalColumns) { + if ($Table.Columns -match "$OptionalColumn") { + $Row."$OptionalColumn" = (Get-Variable -Name "$OptionalColumn").Value + } + } + + # Add the row to the table + $Table.Rows.Add($Row) +} + +############################################# [Internal Processing] ############################################## + +# Change to the script's current directory to include support for relative paths +Set-Location $PSScriptRoot + +# Determine execution scope based on parameter set +Write-Verbose "ParameterSetName: $($PSCmdlet.ParameterSetName)" +switch -Wildcard ($PSCmdlet.ParameterSetName) { + "Local*" { + $Computers = [PSCustomObject]@{ + Name = $env:COMPUTERNAME + Role = $Role + Organization = $Organization + UpdateWindow = $UpdateWindow + } + } + "Cn*" { + # If the only computer name provided is the current machine, + # Switch back to using the Local parameter set and drop the + # ComputerName variable to avoid needing additional permissions + if ($ComputerName -ne $env:COMPUTERNAME) { + $Computers = foreach ($Computer in $ComputerName) { + [PSCustomObject]@{ + Name = $Computer + Role = $Role + Organization = $Organization + UpdateWindow = $UpdateWindow + } + } + } + else { + $Computers = [PSCustomObject]@{ + Name = $env:COMPUTERNAME + Role = $Role + Organization = $Organization + UpdateWindow = $UpdateWindow + } + Remove-Variable ComputerName + } + } + "Csv*" { + $Computers = Import-Csv -Path $CsvPath + [string[]]$ComputerName = $Computers.Name + } +} + +# Add Optional Columns if they exist +foreach ($OptionalColumn in $OptionalColumns) { + switch ($OptionalColumn) { + "Organization" { [int]$ColumnPosition = 1 } + "Role" { [int]$ColumnPosition = 1 } + Default { [int]$ColumnPosition = $Columns.Count } + } + + if ($null -ne $Computers."$($OptionalColumn)") { + if ('' -ne ($Computers."$($OptionalColumn)" | Out-String).Trim()) { + $Columns.Insert($ColumnPosition, "$OptionalColumn") + } + } +} + +# If using stored credentials, import the credentials for future use +if ($PSCmdlet.ParameterSetName -like "*StoredCred*") { + $Credential = Import-Clixml -Path $CredentialPath +} + +# Build Remote Parameters splat variable +$RemoteParameters = @{} + +if ($null -ne $ComputerName) { + Write-Verbose "Adding $ComputerName to Remote Parameters splat variable" + $RemoteParameters['ComputerName'] = $ComputerName + $RemoteParameters['Authentication'] = "Kerberos" +} + +if ($Credential -ne [System.Management.Automation.PSCredential]::Empty) { + Write-Verbose "Adding provided credentials to Remote Parameters splat variable" + $RemoteParameters['Credential'] = $Credential + $RemoteParameters['Authentication'] = "Kerberos" +} + +# Create Table object +$Table = New-Object system.Data.DataTable "Report" +foreach ($Column in $Columns) { + $Table.Columns.Add((New-Object system.Data.DataColumn $Column, ([string]))) + $Table.Columns[$Column].DefaultValue = "Unknown" +} + +################################################## [Execution] ################################################### + +# Gather Cim Data + +Write-Verbose "Started Data gathering: $(Get-Date -Format o)" +$CimMasterSession = New-CimSession @RemoteParameters + +$CimMasterData = @{} +$CimMasterData["OS"] = Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $CimMasterSession +$CimMasterData["Drives"] = Get-CimInstance -ClassName "Win32_LogicalDisk" -Namespace "root\CIMV2" -CimSession $CimMasterSession +$CimMasterData["Updates"] = Get-CimInstance -ClassName "Win32_QuickfixEngineering" -CimSession $CimMasterSession + +$DataGatheredDate = Get-Date -Format o + +Write-Verbose "Finished Data gathering: $DataGatheredDate" +Remove-CimSession -CimSession $CimMasterSession + +foreach ($Computer in ($Computers | Sort-Object Name)) { + Write-Verbose "Processing $($Computer.Name) - $(Get-Date -Format o)" + + # Add Optional Parameters to the row as needed + $OptionalParameters = @{"OptionalColumns" = $OptionalColumns } + foreach ($OptionalColumn in $OptionalColumns) { + if ($null, '' -ne $Computer."$($OptionalColumn)") { + $OptionalParameters["$($OptionalColumn)"] = $Computer."$($OptionalColumn)" + } + } + + # Created the row based on the provided data + # Local execution sets the PSComputerName as null + if ($null -ne $ComputerName) { + Add-RowEntry -Table $Table ` + -Name $Computer.Name ` + -OperatingSystem ($CimMasterData.OS | Where-Object { $_.PSComputerName -eq "$($Computer.Name)" }) ` + -LogicalDisk ($CimMasterData.Drives | Where-Object { $_.PSComputerName -eq "$($Computer.Name)" }) ` + -Updates ($CimMasterData.Updates | Where-Object { $_.PSComputerName -eq "$($Computer.Name)" }) ` + -DateGathered $DataGatheredDate ` + @OptionalParameters + } + else { + Add-RowEntry -Table $Table ` + -Name $Computer.Name ` + -OperatingSystem ($CimMasterData.OS | Where-Object { $null -eq $_.PSComputerName }) ` + -LogicalDisk ($CimMasterData.Drives | Where-Object { $null -eq $_.PSComputerName }) ` + -Updates ($CimMasterData.Updates | Where-Object { $null -eq $_.PSComputerName }) ` + -DateGathered $DataGatheredDate ` + @OptionalParameters + } +} + +if ($PSCmdlet.ParameterSetName -like "*Report*") { + switch ($OutputType) { + "CSV" { $Table | Export-Csv -Path $OutputPath -NoTypeInformation } + "JSON" { $Table | Select-Object * -ExcludeProperty ItemArray, Table, RowError, RowState, HasErrors | ConvertTo-Json | Out-File -FilePath $OutputPath } + "HTML" { $Table | Select-Object -Property $Columns | ConvertTo-HTML -Head $Head -Body "

System Status Update

Date Gathered: $DataGatheredDate

" | Set-Content $OutputPath } + } +} +else { + $Table +} + diff --git a/Images/Example-Default.png b/Images/Example-Default.png new file mode 100644 index 0000000..634e500 Binary files /dev/null and b/Images/Example-Default.png differ diff --git a/Images/Example-HTML.png b/Images/Example-HTML.png new file mode 100644 index 0000000..7967524 Binary files /dev/null and b/Images/Example-HTML.png differ diff --git a/README.md b/README.md index 1a9a1b4..34ce141 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,110 @@ # Get-SystemStatus -Gets various information related to a running system's status for reporting. +Gathers the follow information from a provided list of computers. +The collected data is then returned as a DataTable or can be exported to a variety of file formats. +Optional Metadata can be included to be included in the returned results/reports to assist in machine identification. -## Requirements +Collected Data: Computer Name, Operating System, Operating System Build, Uptime, Recent Updates, Disk Space Utilization, Date Gathered +Optional Metadata: Organization, Role, UpdateWindow ## Variables -| Variable | Required | Default | Choices | Description | -| -------- | -------- | ------- | ------- | ----------- | -| | | | | | +### ComputerName Set + +| Variable | Required | Default | Choices | Description | +| -------------- | -------- | ------- | --------------- | --------------------------------------------------------------------------------------------------------------------------- | +| ComputerName | Yes | | | Specifies a computer or set of computers that should be queried for their status | + +### CsvPath Set + +| Variable | Required | Default | Choices | Description | +| -------------- | -------- | ------- | --------------- | --------------------------------------------------------------------------------------------------------------------------- | +| CsvPath | Yes | | | Specifies a computer or set of computers that should be queried for their status | + +### Credential Set + +| Variable | Required | Default | Choices | Description | +| ---------- | -------- | ------- | ------- | ----------------------------------------------------------------------------------------------------- | +| Credential | Yes | | | Credentials used for connecting to the specified computers to gather the machine's status information | + +### CredentialPath Set + +| Variable | Required | Default | Choices | Description | +| -------------- | -------- | ------- | ------- | --------------------------------------------------------------------------------------------------------------------------- | +| CredentialPath | Yes | | | Path to stored credentials that will be imported using Import-Clixml to allow for storing credentials using a secure method | + +### Report Set + +| Variable | Required | Default | Choices | Description | +| -------------- | -------- | ------- | --------------- | --------------------------------------------------------------------------------------------------------------------------- | +| OutputType | No | JSON | CSV, JSON, HTML | Style of report that should be output | +| OutputPath | Yes | | | Path to where the report should be saved | + +### Common Variables + +| Variable | Required | Default | Choices | Description | +| -------------- | -------- | ------- | --------------- | --------------------------------------------------------------------------------------------------------------------------- | +| Organization | No | | | Optional metadata that can be included in the returned results | +| Role | No | | | Optional metadata that can be included in the returned results | +| UpdateWindow | No | | | Optional metadata that can be included in the returned results | + +## Syntax + +```powershell +Get-SystemStatus.ps1 [-Organization ] [-Role ] [-UpdateWindow ] [] +``` + +```powershell +Get-SystemStatus.ps1 -ComputerName -CredentialPath [-OutputType ] -OutputPath [-Organization ] [-Role ] [-UpdateWindow ] [] +``` + +```powershell +Get-SystemStatus.ps1 -ComputerName -CredentialPath [-Organization ] [-Role ] [-UpdateWindow ] [] +``` + +```powershell +Get-SystemStatus.ps1 -ComputerName -Credential [-OutputType ] -OutputPath [-Organization ] [-Role ] [-UpdateWindow ] [] +``` + +```powershell +Get-SystemStatus.ps1 -ComputerName -Credential [-Organization ] [-Role ] [-UpdateWindow ] [] +``` + +```powershell +Get-SystemStatus.ps1 -ComputerName [-OutputType ] -OutputPath [-Organization ] [-Role ] [-UpdateWindow ] [] +``` + +```powershell +Get-SystemStatus.ps1 -ComputerName [-Organization ] [-Role ] [-UpdateWindow ] [] +``` + +```powershell +Get-SystemStatus.ps1 -CsvPath -CredentialPath [-OutputType ] -OutputPath [-Organization ] [-Role ] [-UpdateWindow ] [] +``` + +```powershell +Get-SystemStatus.ps1 -CsvPath -CredentialPath [-Organization ] [-Role ] [-UpdateWindow ] [] +``` + +```powershell +Get-SystemStatus.ps1 -CsvPath -Credential [-OutputType ] -OutputPath [-Organization ] [-Role ] [-UpdateWindow ] [] +``` + +```powershell +Get-SystemStatus.ps1 -CsvPath -Credential [-Organization ] [-Role ] [-UpdateWindow ] [] +``` + +```powershell +Get-SystemStatus.ps1 -CsvPath [-OutputType ] -OutputPath [-Organization ] [-Role ] [-UpdateWindow ] [] +``` + +```powershell +Get-SystemStatus.ps1 -CsvPath [-Organization ] [-Role ] [-UpdateWindow ] [] +``` + +```powershell +Get-SystemStatus.ps1 [-OutputType ] -OutputPath [-Organization ] [-Role ] [-UpdateWindow ] [] +``` ## Example @@ -17,3 +113,7 @@ Gets various information related to a running system's status for reporting. See LICENSE file for full license information. ## Screenshots + +![Example Default Execution](Images/Example-Default.png?raw=true) + +![Example Default Execution](Images/Example-HTML.png?raw=true)