PowerShell is very adept at retrieving all sorts of information from computer systems in your network. Often the data is in a format that is hard to digest at a glance. For example, when you see a value like 1202716672 is that something in MB or GB? What if you need to view that value as KB? I don't know about you but I'm not good at making those conversions in my head and on-the-fly. Instead, we often resort to commands like this.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
PS C:\> get-ciminstance win32_computersystem | select Name,Number*,@{Name="MemGB";Expression={$_.totalphysicalmemory/1gb -as [int]}},Manufacturer Name : WIN81-ENT-01 NumberOfLogicalProcessors : 4 NumberOfProcessors : 1 MemGB : 8 Manufacturer : LENOVO
That is much easier than seeing a value of 8589934592. The same thing applies when it comes to calculating percentages. Again, we're back to using custom hashtables with Select-Object. Of course, you can go the extra mile and create custom format and type extensions. But sometimes, at least speaking for myself, you want something in between. So I created two functions, Format-Value and Format-Percent and packaged them as a module.
Function Format-Percent { <# .Synopsis Calculate a percent .Description This command calculates a percentage of a value from a total, with the formula (value/total)*100. The default is to return a value to 2 decimal places but you can configure that with -Decimal. There is also an option to format the percentage as a string which will include the % symbol. .Parameter Value The numerator value. The parameter has aliases of X and Numerator. .Parameter Total The denominator value. The parameter has aliases of Y and Denominator. .Parameter Decimal The number of decimal places to return between 0 and 15. .Parameter String Format the percentage as a string which will include the % symbol. This is done using the -f operator. .Example PS C:\> Format-Percent 1234 5000 24.68 .Example PS C:\> get-ciminstance win32_operatingsystem -computer chi-dc04 | select PSComputername,TotalVisibleMemorySize,@{Name="PctFreeMem";Expression={ Format-Percent $_.FreePhysicalMemory $_.TotalVisibleMemorySize }} PSComputerName TotalVisibleMemorySize PctFreeMem -------------- ---------------------- ---------- chi-dc04 1738292 23.92 .Example PS C:\> get-ciminstance win32_operatingsystem -computer chi-dc04 | select PSComputername,TotalVisibleMemorySize,@{Name="PctFreeMem";Expression={ Format-Percent $_.FreePhysicalMemory $_.TotalVisibleMemorySize -asString }} PSComputerName TotalVisibleMemorySize PctFreeMem -------------- ---------------------- ---------- chi-dc04 1738292 23.92% .Notes Last Updated: May 30, 2014 Version : 1.0 #> [cmdletbinding(DefaultParameterSetName="None")] Param( [Parameter(Position=0,Mandatory,HelpMessage="What is the value?")] [ValidateNotNullorEmpty()] [Alias("X","Numerator")] $Value, [Parameter(Position=1,Mandatory,HelpMessage="What is the total value?")] [ValidateNotNullorEmpty()] [Alias("Y","Denominator")] $Total, [ValidateNotNullorEmpty()] [ValidateRange(0,15)] [int]$Decimal=2, [Parameter(ParameterSetName="String")] [Switch]$AsString ) Write-Verbose "Calculating percentage from $Value/$Total to $decimal places" $result = $Value/$Total if ($AsString) { Write-Verbose "Writing string result" $pctstring = "{0:p$Decimal}" -f $result #remove the space before the % symbol $pctstring.Replace(" ","") } else { Write-Verbose "Writing numeric result" [math]::Round( ($result*100),$Decimal) } } #end function Function Format-Value { <# .Synopsis Format a numeric value .Description This command will format a given numeric value. By default it will treat the number as an integer. Or you can specify a certain number of decimal places. The command will also allow you to format the value in KB, MB, etc. Or you can let the command autodetect the value and divide by an appropriate value. .Parameter Unit The unit of measurement for your value. Valid choices are "KB","MB","GB","TB", and "PB". If you don't specify a unit, the value will remain as is, although you can still specify the number of decimal places. .Parameter Decimal The number of decimal places to return between 0 and 15. .Example PS C:\> Get-CimInstance -class win32_logicaldisk -filter "DriveType=3" | Select DeviceID,@{Name="SizeGB";Expression={$_.size | format-value -unit GB}},@{Name="FreeGB";Expression={$_.freespace | format-value -unit GB -decimal 2}} DeviceID SizeGB FreeGB -------- ------ ------ C: 200 124.97 D: 437 29.01 E: 25 9.67 .Example PS C:\> (get-process chrome | measure ws -sum ).sum | format-value -Autodetect -verbose -Decimal 4 VERBOSE: Formatting 1180504064 VERBOSE: Using Autodetect VERBOSE: ..as GB VERBOSE: Reformatting 1.09943008422852 VERBOSE: ..to 4 decimal places 1.0994 .Notes Last Updated: 5/29/2014 Version : 1.0 #> [cmdletbinding(DefaultParameterSetName="Default")] Param( [Parameter(Position=1,Mandatory,ValueFromPipeline)] [ValidateNotNullorEmpty()] $InputObject, [Parameter(Position=0,ParameterSetName="Default")] [ValidateSet("KB","MB","GB","TB","PB")] [string]$Unit, [ValidateRange(0,15)] [int]$Decimal, [Parameter(ParameterSetName="Auto")] [switch]$Autodetect ) Process { Write-Verbose "Formatting $Inputobject" if ($PSCmdlet.ParameterSetName -EQ "Default") { Write-Verbose "..as $Unit" Switch ($Unit) { "KB" { $value = $Inputobject / 1KB ; break } "MB" { $value = $Inputobject / 1MB ; break } "GB" { $value = $Inputobject / 1GB ; break } "TB" { $value = $Inputobject / 1TB ; break } "PB" { $value = $Inputobject / 1PB ; break } default { #just use the raw value $value = $Inputobject } } #switch } else { Write-Verbose "Using Autodetect" if ($InputObject -ge 1PB) { Write-Verbose "..as PB" $value = $Inputobject / 1PB } elseif ($InputObject -ge 1TB) { Write-Verbose "..as TB" $value = $Inputobject / 1TB } elseif ($InputObject -ge 1GB) { Write-Verbose "..as GB" $value = $Inputobject / 1GB } elseif ($InputObject -ge 1MB) { Write-Verbose "..as MB" $value = $Inputobject / 1MB } elseif ($InputObject -ge 1KB) { Write-Verbose "..as KB" $value = $Inputobject / 1KB } else { Write-Verbose "..as bytes" $value = $InputObject } } Write-Verbose "Reformatting $value" if ($decimal) { Write-Verbose "..to $decimal decimal places" [math]::Round($value,$decimal) } else { Write-verbose "..as [int]" $value -as [int] } } #process } Set-Alias -Name fv -Value Format-Value Set-Alias -Name fp -value Format-Percent Export-ModuleMember -Function * -Alias *
Format-Value will take any value and by default round it to an integer. Or you can specify to format the value as a certain unit of measurement such as GB or MB. You can even specify the number of decimal places. Or, you can use the -Autodetect parameter and the function will make the best guess about the 'size' of your value. Use -Verbose if you want to know what unit it detects.
I did a similar thing with percentages. All you have to do is specify a value and a total and the function does the rest. Again, you can specify the number of decimal places. By default, the function writes a numeric value to the pipeline which I find makes it easier if you want to sort. But you can also specify to get a percentage as a string which will use the -f operator. The string will include the % symbol. I take an extra step to remove the space between the value and symbol.
With the function, my PowerShell expressions become a little easier to write.
Get-CimInstance -class win32_logicaldisk -filter "DriveType=3" | Select DeviceID, @{Name="SizeGB";Expression={$_.size | fv -unit GB}}, @{Name="FreeGB";Expression={$_.freespace | fv -unit GB -decimal 2}}, @{Name="PctFree";Expression={fp -x $_.freespace -y $_.size}}
In the code sample I'm using the function and parameter aliases. But I like the result.
Download FormatFunctions.zip extract it to your modules directory and you should be good to go. I've set the minimum PowerShell version to 3.0 although there's nothing I can think of that would prevent these commands from working on v2. But I'd like to drive you to at least 3 anyway.
I hope you'll let me know what you think and what other types of data formatting you'd like to see added to the module.
NOTE: An update has been posted at http://bit.ly/1PzSnJa
1 thought on “Friday Fun with Formatting”
Comments are closed.