I think you'll like this. Normally, I prefer my PowerShell commands to write objects to the pipeline. But there's nothing wrong with sending output directly to the console, as long as you know that the output is intended only for the screen. What I find frustrating is the use of Write-Host when really, pipelined objects would be better. But for today, I'm going to revel in the beauty of the console and create a colorized drive utilization graph.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
The color will come from the BackgroundColor or ForegroundColor properties of Write-Host. For example, try this command in your PowerShell session:
[cc lang="PowerShell"]
PS C:\> write-host (" "*30) -BackgroundColor Yellow
[/cc]
The command is creating a "string" of 30 spaces. See where I'm going with this? Using WMI I can get drive usage information and turn it into values that I can "graph" using Write-Host. Here's the code I'm working with:
[cc lang="PowerShell"]
#requires -version 2.0
Param (
[string[]]$computers=@("computera","computerb","computerc")
)
#get the current window width so that our lines will be proportional
$Width = $Host.UI.RawUI.BufferSize.Width/2
$data=get-wmiobject -Class Win32_logicaldisk -filter "drivetype=3" -computer $computers
#get length of longest computername so we can pad
$longest=$data | select -ExpandProperty SystemName | sort Length | select -last 1
#group data by computername
$groups=$Data | Group-Object -Property SystemName
Clear-Host
Write-Host ("`n{0} {1}`n" -f "Disk Drive Report",(Get-Date)) -ForegroundColor Yellow
#iterate through each group object
ForEach ($computer in $groups) {
#define a collection of drives from the group object
$Drives=$computer.group
#iterate through each drive on each computer
Foreach ($drive in $drives) {
$FreeDividedSize=$drive.FreeSpace/$drive.Size
[string]$PerFree="{0:P}" -f $FreeDividedSize
[int]$FreePad=$Width*$FreeDividedSize
$Used=$drive.Size - $drive.Freespace
$UsedDividedSize=$used/$drive.Size
[string]$perUsed="{0:P}" -f $UsedDividedSize
[int]$UsedPad=$Width*$UsedDividedSize
#not currently used
[string]$UsedGB="{0:N2}GB " -f ($Used/1GB)
[string]$FreeGB="{0:N2}GB " -f ($drive.FreeSpace/1GB)
#this is the graph character
[string]$g=[char]9608
[string]$freeGraph=$g*($FreePad)
[string]$UsedGraph=$g*($UsedPad)
write-host ("[{0}] {1} " -f $drive.systemname.PadRight($longest.length),$drive.DeviceID) -NoNewline
write-host $freeGraph -ForegroundColor darkgreen -NoNewline
write-host $UsedGraph -ForegroundColor red -NoNewline
write-host (" {0} free " -f $PerFree)
#insert a return between each drive
write-host "`r"
} #foreach drive
#insert a blank line between computers if you want
#Write-host "`n"
} #foreach computer
[/cc]
Because I will need to adjust my graph to accommodate the width of the PowerShell window, I'm going to retrieve the console width and divide by 2. This will give me plenty of room to fit in the other output and still make a nice looking graph.
[cc lang="PowerShell"]
#get the current window width so that our lines will be proportional
$Width = $Host.UI.RawUI.BufferSize.Width/2
[/cc]
The script takes a collection of computer names and retrieves fixed logical disk information via WMI.
[cc lang="PowerShell"]
$data=get-wmiobject -Class Win32_logicaldisk -filter "drivetype=3" -computer $computers
[/cc]
Because I'm most likely going to be reporting on a group of computers, I want to include the computer name in the output. And because I want to keep everything proportional, I need to find the longest computer name. For all other names, I'll pad their names to equal the longest name. You'll see.
[cc lang="PowerShell"]
#get length of longest computername so we can pad
$longest=$data | select -ExpandProperty SystemName | sort Length | select -last 1
[/cc]
After a bit of experimentation, I decided the best way to process the data was to group it based on computer name, so I pipe it to Group-Object, grouping on the computername (systemname) property.
[cc lang="PowerShell"]
#group data by computername
$groups=$Data | Group-Object -Property SystemName
[/cc]
Now for the report. For every computer in the group, I'm going to enumerate every logical drive, get some stats and graph them. I didn't have to group them, but for a number of reasons, as well as showing you how to use the cmdlet, I decided to. When I piped the WMI results to Group-Object, I got a new object type. The object has a Group property which will be the collection of objects that have been grouped based on the property name, in my case, SystemName. Thus the Group property is a collection of Win32_LogicalDisk objects.
[cc lang="PowerShell"]
#iterate through each group object
ForEach ($computer in $groups) {
#define a collection of drives from the group object
$Drives=$computer.group
[/cc]
Now I can run some calculations and format the size and freespace properties. I'll be using these values with Write-Host.
[cc lang="PowerShell"]
#iterate through each drive on each computer
Foreach ($drive in $drives) {
$FreeDividedSize=$drive.FreeSpace/$drive.Size
[string]$PerFree="{0:P}" -f $FreeDividedSize
[int]$FreePad=$Width*$FreeDividedSize
$Used=$drive.Size - $drive.Freespace
$UsedDividedSize=$used/$drive.Size
[string]$perUsed="{0:P}" -f $UsedDividedSize
[int]$UsedPad=$Width*$UsedDividedSize
#not currently used
[string]$UsedGB="{0:N2}GB " -f ($Used/1GB)
[string]$FreeGB="{0:N2}GB " -f ($drive.FreeSpace/1GB)
[/cc]
Notice I'm using the -f operator to construct new strings, and format data. The qualifiers P and N will format the value as percent and a number, respectively. I originally planned in including the usage values directly in the bar chart, but it skewed the proportions. Instead, I decided to use a character and repeat it X number of times as necessary to reflect the amount of free space and amount used. I picked a block character, although I could have just used a space.
[cc lang="PowerShell"]
#this is the graph character
[string]$g=[char]9608
[string]$freeGraph=$g*($FreePad)
[string]$UsedGraph=$g*($UsedPad)
[/cc]
Armed with these values, I can now use Write-Host to create the graph. Because I want to graph system information, free space and usage on the same line, I tell Write-Host to not create a new line. The first part writes the computer name in square brackets. I'm also padding the computer name with empty spaces at the end so that the brackets all line up. After the computer name is the drive letter, or device ID.
[cc lang="PowerShell"]
write-host ("[{0}] {1} " -f $drive.systemname.PadRight($longest.length),$drive.DeviceID) -NoNewline
[/cc]
Remember, this is all on the same line. So next I "graph" usage using the -Foregroundcolor parameter.
[cc lang="PowerShell"]
write-host $freeGraph -ForegroundColor darkgreen -NoNewline
write-host $UsedGraph -ForegroundColor red -NoNewline
[/cc]
The last part writes the percent free value. At this point I have nothing else to write on the line so I'll let Write-Host insert a return.
[cc lang="PowerShell"]
write-host (" {0} free " -f $PerFree)
[/cc]
I toyed with a number of spacing options but ended up inserting a return after every result.
[cc lang="PowerShell"]
#insert a return between each drive
write-host "`r"
[/cc]
The final script can be run like this:
[cc lang="DOS"]
PS C:\> S:\demo-colorgraph.ps1 "client2","coredc01","server01"
[/cc]
Here's the end result:
If you need a quick visual check, this works just fine. However, because nothing is written to the pipeline all you can do is look; but sometimes that is enough. If nothing else, maybe you picked up a few PowerShell tidbits that might help in your own work.
You can download demo-colorgraph.ps1 to kick around. As with all my Friday Fun posts, this is not intended as a production ready, or even production worthy script, but rather something to have a little fun with and learn something new along the way. Enjoy.
Awesome! Looking forward to messin’ with it.
This is awesome Jeff! Very cool! I can’t wait to play with it myself!
If you try this in the ISE, you’ll want to pick a different color than Yellow for the title text.
This is pretty slick and came just in time for something that I was getting ready to work on. Thanks.
That’s just awesome. I am putting this in production straight away..totally ignoring your warnings.
BTW Jeffrey, on a different note : I use ISE and keep having these weird color issues. I have a black background and yellow prompt. But every now and then the colors get messed up, for instance after an error in red is triggered. Then my prompt is cyan all of a sudden, or any other color, and the ISE maintains this until I restart it. I have no idea how to troubleshoot this.
The first step in your problem is to document steps to reproduce it, both for yourself and others. Are you resetting the output pane using $psise.options?
Check out his format ps1xml file that goes along with with: http://poshcode.org/3090
Jeffrey, this is awesome!!
Very nice! Absolutely going in my function library!