The 2013 Scripting Games, Beginner Event #3


Dr. Scripto has been fielding a lot of calls from the Help Desk lately. They’ve been asking him to look up information about the local hard drives in various servers—mainly size and free space information. He doesn’t mind helping, but all the requests have been getting in the way of his naps. He’s asked you to write a one-liner command that can get the information for him, and he wants the output in an HTML file. The HTML file should look something like this:



The Doctor says you don’t need to parameterize your command. It’s okay to write it to run against LocalHost, and he can just change that computer name as needed in the future. The resulting HTML does need to go into an HTML file on disk someplace, and he wants you to pay special attention to the following:

  • The browser displays “Disk Free Space Report” in the page tab when viewing the report.
  • “Local Fixed Disk Report” is in the Heading 2 (H2) HTML style.
  • The report ends with an HTML horizontal rule, and the date and time that the report was generated.
  • The size and free space values are shown as gigabytes (GB) and megabytes (MB) respectively, each to two decimal places.

The command you write can assume that both WMI and CIM are available on the remote computers, and that all the necessary firewall rules and authentication have already been taken care of.


Actual Entry (forgot to save the HTML)

Get-WmiObject -class Win32_Logicaldisk -computername "Localhost" -Filter "DriveType=3" | Select @{label="Drive";Expression={$_.DeviceID}},@{label="Size(GB)";Expression={"{0:N2}" -f($_.Size / 1GB)}},@{label="Size(MB)";Expression={"{0:N2}" -f($_.FreeSpace / 1MB)}} | ConvertTo-Html -head "

Local Fixed Disk Report

" -PostContent ("

" + (get-Date))

Should have been (used body to hold title and output the file)

Get-WmiObject -class Win32_Logicaldisk -computername "Localhost" -Filter "DriveType=3" | Select @{label="Drive";Expression={$_.DeviceID}},@{label="Size(GB)";Expression={"{0:N2}" -f($_.Size / 1GB)}},@{label="Size(MB)";Expression={"{0:N2}" -f($_.FreeSpace / 1MB)}} | ConvertTo-Html -body "

Local Fixed Disk Report

" -PostContent ("

" + (get-Date))| Out-File -FilePath $PWD\DiskReport.html


Learning Points

Hard Coded Paths (Boe Prox)

Hard path’s like C:\test\ won’t work for everyone, a better solution would be to use one of the built in PowerShell path variables like:

  • $pwd (present working directory)
  • $Env:TEMP  (OS temp directory)
  • $Env:USERPROFILE. (Current user root profile)
  • Among others

ConvertTo-Html Tricks (Bartek Bielawski)

The -preContent and -PostContent parameters can take string arrays, e.g.:

  • ConvertTo-Html (...) -PostContent '

    ', (Get-Date)

You can also submit a hashtable for the -Property parameter, thus bypassing the need to use Select-Object if needed, e.g. :

Get-Process | ConvertTo-Html -Property @{                Label = 'Process Name'                Expression = { $_.Name }            }, @{                Label = 'Process Id'                Expression = { $_.Id }            }, @{                Label = 'Path to executable'                Expression = { $_.Path }            } | Out-File Processes.html

CIM vs WMI (Jan Egil Ring and Ann Hershel)

  • While we should be moving towards CIM due to its use of both DCOM and WinRM. Granted they both can’t be used in the same statement and need to specified separately since CIM uses WinRM by default
  • if any W2K systems were present they would only work with DCOM, and most modern systems that are set up securely would block DCOM access

Advanced Notes (Bartek Bielawski)

  • I know this particualr notion appeard with a different blogger but it’s good enough to mention twice
  • Use splatting if you plan to use the same info over and over again in a script, in fact it’s not a bad idea to do it all the time
    • Instead of 

Send-MailMessage -To -From -Subject Test -SMTPServer -Body “This is a test”

    • Do
$email = @{ To = '' From = '' Subject = 'Test' SMTPServer = '' Send-MailMessage @email
  • Uses aliases for parameter that might have multiple input names. E.g. -ComputerName could also have __Server or Name to compensate for different inputs on different PS versions

Advanced Notes (Ann Hershel)

  • You can created parameters sets such that when a parameter that is not required can become required when another parameter is specified
  • This next portion appeared in a previous blog entry as well but once again it’s good info and this had a more fleshed out example
  • When you declare a parameter as ValueFromPipeline you need to use a process block in order for the script/function to work with each pipelined in object.
function Get-DiskInfo { param( [Parameter(ValueFromPipeline=$true)] [String[]] $ComputerName ) process { "Processing $ComputerName" } }
  • So this would work
'server1', 'server2' | Get-DiskInfo
  • But a string array won’t, as it will process the both names at the same time
Get-DiskInfo -ComputerName 'server1', 'server2'
  • In order to get this to work you need to have the process block unroll the content of $ComputerName and process each element separately.
function Get-DiskInfo { param( [Parameter(ValueFromPipeline=$true)] [String[]] $ComputerName ) process { $ComputerName | Foreach-Object { "Processing $_" } } }

About mell9185

IT proffesional. Tech, video game, anime, and punk aficionado.
This entry was posted in PowerShell, Scripting Games. Bookmark the permalink.

Leave a Reply