Generating a single table using Powershell

ndalmolin_13
ndalmolin_13 used Ask the Experts™
on
Hello Powershell Experts,

I need some help generating a table to display results of a Powershell script.  The script basically checks our servers for drive space.  The code of the script is as follows:

Get-ADComputer -Filter {OperatingSystem -like '*Windows Server*'} | Select name | sort name | ForEach-Object {
    $PingTest =Test-Connection -ComputerName $_.name -Count 1 -Quiet 
        if ($PingTest -eq "True") {
            Get-WmiObject win32_logicaldisk -ComputerName $_.name -Filter "DriveType=3" -ErrorAction SilentlyContinue | `
                Select-Object `
                    @{n="Server";e={$_.SystemName}},`
                    @{n="Drive Letter";e={$_.DeviceID}},`
                    @{n="Volume Name";e={$_.VolumeName}},`
                    @{n="Total Size (GB)";e={"{0:n2}" -f($_.size/1GB)}},`
                    @{n="Free Space (GB)";e={"{0:n2}" -f($_.FreeSpace/1GB)}},`
                    @{n="Used Space (GB)";e={"{0:n2}" -f(([Int64]$_.size/1gb) - ([Int64]$_.FreeSpace/1gb))}},`
                    @{n="Percentage Used";e={"{0:P2}" -f((1-[Int64]$_.FreeSpace/[Int64]$_.Size))}} 

        }

}

Open in new window


This returns the desired information in a list format.  If I add the format-table commandlet at the end, it almost gives me what I want.  Below is the code and the results:

Get-ADComputer -Filter {OperatingSystem -like '*Windows Server*'} | Select name | sort name | ForEach-Object {
    $PingTest =Test-Connection -ComputerName $_.name -Count 1 -Quiet 
        if ($PingTest -eq "True") {
            Get-WmiObject win32_logicaldisk -ComputerName $_.name -Filter "DriveType=3" -ErrorAction SilentlyContinue | `
                Select-Object `
                    @{n="Server";e={$_.SystemName}},`
                    @{n="Drive Letter";e={$_.DeviceID}},`
                    @{n="Volume Name";e={$_.VolumeName}},`
                    @{n="Total Size (GB)";e={"{0:n2}" -f($_.size/1GB)}},`
                    @{n="Free Space (GB)";e={"{0:n2}" -f($_.FreeSpace/1GB)}},`
                    @{n="Used Space (GB)";e={"{0:n2}" -f(([Int64]$_.size/1gb) - ([Int64]$_.FreeSpace/1gb))}},`
                    @{n="Percentage Used";e={"{0:P2}" -f((1-[Int64]$_.FreeSpace/[Int64]$_.Size))}} | Format-Table

        }

}

Open in new window


Results:
Server    Drive Letter Volume Name Total Size (GB) Free Space (GB) Used Space (GB) Percentage Used
------    ------------ ----------- --------------- --------------- --------------- ---------------
Server1   C:                       59.90           14.44           45.46           75.90 %        

Server    Drive Letter Volume Name Total Size (GB) Free Space (GB) Used Space (GB) Percentage Used
------    ------------ ----------- --------------- --------------- --------------- ---------------
WEBSERVER C:           OS          120.00          29.86           90.14           75.11 %        
WEBSERVER E:           DATA        713.58          598.74          114.85          16.09 %        


I would like the results to only have one set of column headers.  How would I do this?

Server          Drive Letter    Volume Name Total Size (GB) Free Space (GB) Used Space (GB) Percentage Used
------              ------------          ----------- --------------- --------------- --------------- ---------------
Server1         C:                                    59.90           14.44           45.46           75.90 %        
WEBSERVER C:                    OS          120.00          29.86           90.14           75.11 %        
WEBSERVER E:                     ATA        713.58          598.74        114.85          16.09 %        


Any help would be greatly appreciated.

Thanks,
Nick
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Most Valuable Expert 2018
Distinguished Expert 2018
Commented:
Just add it at the end of the script.
Get-ADComputer -Filter {OperatingSystem -like '*Windows Server*'} | Select-Object -Property Name | Sort-Object -Property Name | ForEach-Object {
    If (Test-Connection -ComputerName $_.name -Count 1 -Quiet) {
		Get-WmiObject Win32_LogicalDisk -ComputerName $_.name -Filter "DriveType=3" -ErrorAction SilentlyContinue |
			Select-Object -Property `
				@{n="Server"; e={$_.SystemName}},
				@{n="Drive Letter"; e={$_.DeviceID}},
				@{n="Volume Name"; e={$_.VolumeName}},
				@{n="Total Size (GB)"; e={"{0:n2}" -f($_.size/1GB)}},
				@{n="Free Space (GB)"; e={"{0:n2}" -f($_.FreeSpace/1GB)}},
				@{n="Used Space (GB)"; e={"{0:n2}" -f(([Int64]$_.size/1gb) - ([Int64]$_.FreeSpace/1gb))}},
				@{n="Percentage Used"; e={"{0:P2}" -f((1-[Int64]$_.FreeSpace/[Int64]$_.Size))}} 
	}
} | Format-Table -AutoSize

Open in new window

Or, more flexible, just pipe the output of the original script to Format-Table
.\SomeScript.ps1 | Format-Table -AutoSize

Open in new window

Author

Commented:
I changed up the code as suggested and added an email function.  I almost got what I need.  Here is the code:
$Date = Get-Date
$Body = get-ADComputer -Filter {OperatingSystem -like '*Windows Server*'} | where {$_.name -ne "Edge"} | select name | sort name | ForEach-Object {
    $PingTest =Test-Connection -ComputerName $_.name -Count 1 -Quiet 
        if ($PingTest -eq "True") {
            Get-WmiObject win32_logicaldisk -ComputerName $_.name -Filter "DriveType=3" -ErrorAction SilentlyContinue | `
                Select-Object `
                    @{n="Server";e={$_.SystemName}},`
                    @{n="Drive Letter";e={$_.DeviceID}},`
                    @{n="Volume Name";e={$_.VolumeName}},`
                    @{n="Total Size (GB)";e={"{0:n2}" -f($_.size/1GB)}},`
                    @{n="Free Space (GB)";e={"{0:n2}" -f($_.FreeSpace/1GB)}},`
                    @{n="Used Space (GB)";e={"{0:n2}" -f(([Int64]$_.size/1gb) - ([Int64]$_.FreeSpace/1gb))}},`
                    @{n="Percentage Used";e={"{0:P2}" -f((1-[Int64]$_.FreeSpace/[Int64]$_.Size))}} 

        }

} | Format-Table -AutoSize 

$SendMailArguments = @{
    SmtpServer = "SMTP1.server.com"
    Port = 25
    To = "serveradmin@mydomain.com"
    From = "ServerAdmin@mydomain.gov"
    Subject = "$($Date) Drive Space report"
    Body = $Body | Out-String
}

Open in new window


Here is the report:

Emailed Output
My question now is how can I get the table in the body of the email to be nice and clean (properly lined up)?
Most Valuable Expert 2018
Distinguished Expert 2018

Commented:
Then you need to create HTML and send the email as such.
$Date = Get-Date
$diskReport = Get-ADComputer -Filter {OperatingSystem -like '*Windows Server*'} | Where-Object {$_.name -ne "Edge"} | Select-Object -Property Name | Sort-Object -Property Name | ForEach-Object {
	If (Test-Connection -ComputerName $_.name -Count 1 -Quiet) {
		Get-WmiObject Win32_LogicalDisk -ComputerName $_.Name -Filter "DriveType=3" -ErrorAction SilentlyContinue |
			Select-Object -Property `
				@{n="Server";e={$_.SystemName}},
				@{n="Drive Letter"; e={$_.DeviceID}},
				@{n="Volume Name"; e={$_.VolumeName}},
				@{n="Total Size (GB)"; e={"{0:n2}" -f($_.size/1GB)}},
				@{n="Free Space (GB)"; e={"{0:n2}" -f($_.FreeSpace/1GB)}},
				@{n="Used Space (GB)"; e={"{0:n2}" -f(([Int64]$_.size/1gb) - ([Int64]$_.FreeSpace/1gb))}},
				@{n="Percentage Used"; e={"{0:P2}" -f((1-[Int64]$_.FreeSpace/[Int64]$_.Size))}} 
	}
}

$SendMailArguments = @{
	SmtpServer = "SMTP1.server.com"
	Port = 25
	To = "serveradmin@mydomain.com"
	From = "ServerAdmin@mydomain.gov"
	Subject = "$($Date) Drive Space report"
	BodyAsHtml = $true
	Body = -join ($diskReport | ConvertTo-Html)
}

Open in new window

Commented:
A couple of suggestions:
1. If you ever want to just see the results rather than emailing them, pipe the results to Out-GridView which will also give you the advantage of being able to sort and search the results.

2. A way to make the ConvertTo-Html much nicer to read is to add:
 '<style>
            th {
                  VERTICAL-ALIGN:  TOP; 
                  COLOR:  #018AC0; 
                  TEXT-ALIGN:  left;
                  background-color:LightSteelBlue;
                  color:Black;
                  BORDER: 1px  solid black;
                  }
            table, td 
            {
                border: 1px solid black;
            }
            td 
            {
                padding: 5px;
            }
            tr:nth-child(even) {background-color:White;}
            tr:nth-child(odd) {background-color:AliceBlue;}
            </style>'

Open in new window


to the -Head Parameter.  It will put borders around the cells, a dark header row background and alternating coloured background row colours.

I have made my own version of ConvertTo-Html by creating a Proxy or wrapper command that I include in one of my modules:

function ConvertTo-CCHTML
{
	[CmdletBinding(DefaultParameterSetName = 'Page', HelpUri = 'http://go.microsoft.com/fwlink/?LinkID=113290', RemotingCapability = 'None')]
	param
	(
		[Parameter(ValueFromPipeline = $true)]
		[psobject]${InputObject},
		[Parameter(Position = 0)]
		[System.Object[]]${Property},
		[Parameter(ParameterSetName = 'Page', Position = 3)]
		[string[]]${Body},
		[Parameter(ParameterSetName = 'Page', Position = 1)]
		[string[]]${Head},
		[Parameter(ParameterSetName = 'Page', Position = 2)]
		[ValidateNotNullOrEmpty()]
		[string]${Title},
		[ValidateSet('Table', 'List')]
		[ValidateNotNullOrEmpty()]
		[string]${As},
		[Parameter(ParameterSetName = 'Page')]
		[Alias('cu', 'uri')]
		[ValidateNotNullOrEmpty()]
		[uri]${CssUri},
		[Parameter(ParameterSetName = 'Fragment')]
		[ValidateNotNullOrEmpty()]
		[switch]${Fragment},
		[ValidateNotNullOrEmpty()]
		[string[]]${PostContent},
		[ValidateNotNullOrEmpty()]
		[string[]]${PreContent}
	)
	
	begin
	{
		try
		{
			$defaultTableStyle = '<style>
            th {
                  VERTICAL-ALIGN:  TOP; 
                  COLOR:  #018AC0; 
                  TEXT-ALIGN:  left;
                  background-color:LightSteelBlue;
                  color:Black;
                  BORDER: 1px  solid black;
                  }
            table, td 
            {
                border: 1px solid black;
            }
            td 
            {
                padding: 5px;
            }
            tr:nth-child(even) {background-color:White;}
            tr:nth-child(odd) {background-color:AliceBlue;}
            </style>'
			if ([String]::IsNullOrWhiteSpace($Head))
			{
				$PSBoundParameters['Head'] = $defaultTableStyle
			}
			$outBuffer = $null
			if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
			{
				$PSBoundParameters['OutBuffer'] = 1
			}
			$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Utility\ConvertTo-Html', [System.Management.Automation.CommandTypes]::Cmdlet)
			$scriptCmd = { & $wrappedCmd @PSBoundParameters }
			$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
			$steppablePipeline.Begin($PSCmdlet)
		}
		catch
		{
			throw
		}
	}
	
	process
	{
		try
		{
			$steppablePipeline.Process($_)
		}
		catch
		{
			throw
		}
	}
	
	end
	{
		try
		{
			$steppablePipeline.End()
		}
		catch
		{
			throw
		}
	}
}

Open in new window

Author

Commented:
Thanks for all of your help.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial