Skip to content

Instantly share code, notes, and snippets.

@jdhitsolutions
Last active April 18, 2026 17:52
Show Gist options
  • Select an option

  • Save jdhitsolutions/c05afd479f766b279f4fc18135fc9eb8 to your computer and use it in GitHub Desktop.

Select an option

Save jdhitsolutions/c05afd479f766b279f4fc18135fc9eb8 to your computer and use it in GitHub Desktop.
PowerShell Water Tools

WaterTools

This is a set of PowerShell functions I wrote to help me manage and keep track of my water consumption. You will need to install the pwshSpectreConsole module for the graphing function to work.

I demonstrated this during the Lightning Demos during the 2026 PowerShell Summit.

<!--
Format type data generated 03/30/2026 12:47:58 by PROSPERO\Jeff
This file was created using the New-PSFormatXML command that is part
of the PSScriptTools module.
https://github.com/jdhitsolutions/PSScriptTools
-->
<Configuration>
<ViewDefinitions>
<View>
<!--Created 03/30/2026 12:47:58 by PROSPERO\Jeff-->
<Name>default</Name>
<ViewSelectedBy>
<TypeName>WaterReport</TypeName>
</ViewSelectedBy>
<TableControl>
<!--Delete the AutoSize node if you want to use the defined widths.-->
<AutoSize />
<TableHeaders>
<TableColumnHeader>
<Label>Date</Label>
<Width>24</Width>
<Alignment>left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Count</Label>
<Width>8</Width>
<Alignment>center</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Average</Label>
<Width>10</Width>
<Alignment>left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>TotalOz</Label>
<Width>15</Width>
<Alignment>right</Alignment>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Date</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Count</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Average</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Amount</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
<View>
<!--Created 03/30/2026 12:49:43 by PROSPERO\Jeff-->
<Name>text</Name>
<ViewSelectedBy>
<TypeName>WaterReport</TypeName>
</ViewSelectedBy>
<TableControl>
<!--Delete the AutoSize node if you want to use the defined widths.
<AutoSize />-->
<TableHeaders>
<TableColumnHeader>
<Label>Date</Label>
<Width>24</Width>
<Alignment>left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Count</Label>
<Width>8</Width>
<Alignment>center</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>TotalAmount</Label>
<!--let the width autofill-->
<!--<Width>15</Width>-->
<Alignment>left</Alignment>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Date</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Count</PropertyName>
</TableColumnItem>
<TableColumnItem>
<ScriptBlock>Convert-Water $_.Amount</ScriptBlock>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
<View>
<!--Created 04/18/2026 13:20:33 by PROSPERO\Jeff-->
<Name>default</Name>
<ViewSelectedBy>
<TypeName>WaterInfo</TypeName>
</ViewSelectedBy>
<GroupBy>
<PropertyName>Data</PropertyName>
<Label>Data</Label>
</GroupBy>
<TableControl>
<!--Delete the AutoSize node if you want to use the defined widths.-->
<AutoSize />
<TableHeaders>
<TableColumnHeader>
<Label>Date</Label>
<Width>24</Width>
<Alignment>left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Amount</Label>
<Width>9</Width>
<Alignment>right</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Comment</Label>
<Width>10</Width>
<Alignment>left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Description</Label>
<Width>14</Width>
<Alignment>left</Alignment>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Date</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Amount</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Comment</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Description</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
</ViewDefinitions>
</Configuration>
#requires -version 7.5
#requires -module pwshSpectreConsole
#TODO: Create a module
<#
The PSFunctionInfo comment blocks are used by the PSFunctionInfo
module [https://github.com/jdhitsolutions/PSFunctionInfo]
which is designed to help manage standalone functions. They can be
deleted.
#>
<#
Prototype
amount in ounces
[PSCustomObject]@{
PSTypeName = 'WaterInfo'
Date = Get-Date
Amount = 12
Comment = 'Workout'
}
#>
Class WaterInfo {
#the property defaults to the current date and time
[datetime]$Date = (Get-Date)
#amount in ounces
[int32]$Amount
#allow for a description, note, or comment
[string]$Comment
#a method to convert value to descriptive text
[string]GetAmountDescription() {
$r = Convert-Water $this.Amount
return $r
}
#the constructor requires an amount
WaterInfo([int32]$Amount) {
$this.Amount = $Amount
}
}
#CSV is an option but limited to flat data
#define the path to the JSON file
$waterInfoPath = "$env:OneDrive\Personal\waterInfo.json"
Function Add-Water {
<# PSFunctionInfo
Version 1.4.0
Author Jeffery Hicks
CompanyName JDH IT Solutions, Inc.
Copyright (c) JDH IT Solutions, Inc.
Description Log water consumption to a JSON file
Guid e25530d7-058a-45a0-a794-73c7d20c920d
Tags profile,personal,profile
LastUpdate 4/18/2026 1:08 PM
Source C:\scripts\water.ps1
#>
[cmdletbinding(SupportsShouldProcess)]
[OutputType('WaterInfo')]
[alias('aw')]
Param(
[Parameter(
Position = 0,
Mandatory,
HelpMessage = "The number of ounces of water consumed"
)]
[ValidateNotNullOrEmpty()]
[ValidateRange(1,64)]
[int32]$Amount,
[Parameter(
Position = 1,
HelpMessage = "Enter the consumption date."
)]
[ValidateNotNullOrEmpty()]
[DateTime]$Date = (Get-Date),
[Parameter(
Position = 2,
HelpMessage = "Enter an optional comment"
)]
[string]$Comment,
[Parameter(HelpMessage = "The Json file to store water data.")]
[ValidateNotNullOrEmpty()]
[ValidateScript({Test-Path $_},ErrorMessage = "Failed to find or validate {0}.")]
[string]$Path = $waterInfoPath
)
Begin {
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)"
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)"
if (Test-Path $Path) {
[object[]]$data = Get-Content $Path | ConvertFrom-Json
#Get previous entries for today
[int32]$inToday = ($data | Where-Object {$_.Date.date -eq (Get-Date).Date} | Measure-Object amount -sum).Sum
}
else {
#This will only be used on the very first execution, before a JSON file has
#been created.
$data=@()
[int32]$inToday = 0
}
} #begin
Process {
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Adding $Amount ounces of water"
#update today's intake
$inToday+=$Amount
$item = [WaterInfo]::New($Amount)
$item.Date = $Date
if ($Comment) {
$item.Comment = $comment
}
$item
$data += $item
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Appending data to $Path"
#18 April 2026 - write to a compressed JSON file to save a little disk space
$data | ConvertTo-Json -Compress | Out-File $Path -Encoding utf8
} #process
End {
#motivation
Switch ($inToday) {
{$_ -ge 64} {
$color = "Green3 blink"
$msg = "You crushed it! Job well done."
Break
}
{$_ -ge 56} {
$color = "Cyan3"
$msg = "So close to the magic number. Keep sipping."
Break
}
{$_ -ge 48} {
$color = "Yellow3"
$msg = "Now we're talking!!"
Break
}
{$_ -ge 32} {
$color = "LightGoldenrod2_1"
$msg = "Outstanding work. Don't stop now."
Break
}
{$_ -ge 16} {
$color = "orange1"
$msg = "You're making progress."
Break
}
{$_ -ge 8} {
$color = "Magenta1"
$msg = "Keep at it, one glass at a time."
Break
}
Default {
$color = "red3"
$msg = "You have to start somewhere."
}
}
Write-SpectreHost "[$color]Your current daily total is $inToday oz. $msg[/]"
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)"
} #end
} #close Add-Water
Function Get-Water {
<# PSFunctionInfo
Version 1.2.
Author Jeffery Hicks
CompanyName JDH IT Solutions, Inc.
Copyright (c) JDH IT Solutions, Inc.
Description Get water consumption
Guid 8bc70c8a-9a20-4cd1-a589-7651d87f630d
Tags profile,personal,profile
LastUpdate 3/18/2026 1:46 PM
Source C:\scripts\water.ps1
#>
<#
.SYNOPSIS
Get raw water consumption data
.DESCRIPTION
Use this command to display raw water consumption data. The default is the last 7 days. Use 0 for today's water intake.
.Parameter Days
Limit results to the last X number of days. Use a value of 0 for today.
.Parameter Path
The path to the Json data file"
.INPUTS
None
.LINK
Measure-Water
.LINK
Show-Water
#>
[cmdletbinding()]
[OutputType('waterInfo')]
[alias('gw')]
Param(
[Parameter(
Position = 0,
HelpMessage = "Limit results to the last X number of days. Use a value of 0 for today."
)]
[ValidateRange(0,365)]
[int32]$Days = 7,
[Parameter(HelpMessage = "The path to the Json data file.")]
[ValidateNotNullOrEmpty()]
[ValidateScript({Test-Path $_},ErrorMessage = "Failed to find or validate {0}.")]
[string]$Path = $waterInfoPath
)
Begin {
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)"
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)"
If ($Days -eq 0) {
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Getting water data for today"
}
elseif ($Days -eq 1) {
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Getting water data from yesterday"
}
else {
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Getting water data for the last $Days days"
}
$cutOff = (Get-Date).AddDays(-$Days).Date
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Cutoff date is $cutOff"
$today = (Get-Date).Date
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Today is $today"
} #begin
Process {
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Importing water data from $Path"
if ($Days -eq 0) {
$filter = {$_.date -ge $cutoff }
}
elseif ($Days -eq 1) {
$filter = {$_.date.date -eq $cutoff}
}
else {
$filter = {$_.date.date -ge $cutoff -AND $_.Date -lt $Today}
}
#14 Feb 2026 - Sort by date in ascending order
Get-Content $Path | ConvertFrom-Json | Where-Object $Filter |
Sort-Object -property Date | Foreach-Object {
#this could be turned into a private helper function
#which is recommended for Pester testing
$item = [WaterInfo]::New($_.Amount)
$item.Date = $_.Date
$item.Comment = $_.Comment
$item
}
} #process
End {
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)"
} #end
} #close Get-Water
Function Measure-Water {
<# PSFunctionInfo
Version 2.0.0
Author Jeffery Hicks
CompanyName JDH IT Solutions, Inc.
Copyright (c) JDH IT Solutions, Inc.
Description Get daily water consumption totals
Guid 938fb522-b33d-4068-b2ea-cc25da44a83a
Tags profile,personal,profile
LastUpdate 3/18/2026 1:46 PM
Source C:\scripts\water.ps1
#>
[cmdletbinding()]
[OutputType('WaterReport')]
[alias('mw')]
Param(
[Parameter(
Position = 0,
HelpMessage = "Limit results to the last X number of days"
)]
[ValidateRange(0,365)]
[int32]$Days = 7,
[Parameter(HelpMessage = "The path to the Json data file")]
[ValidateNotNullOrEmpty()]
[ValidateScript({Test-Path $_},ErrorMessage = "Failed to find or validate {0}.")]
[string]$Path = $waterInfoPath
)
Begin {
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)"
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)"
} #begin
Process {
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Measuring water consumption for the last $Days day(s)"
#get the water data for the specified number of days and group on the short date string,
# i.e 4/15/2026 12:00
$get = Get-Water -Path $Path -Days $Days | Group-Object {$_.Date.ToShortDateString()} |
Sort-Object {$_.Name -as [datetime]}
foreach ($item in $get) {
$measure = $item.Group | Measure-Object -Property Amount -Sum -Average
[PSCustomObject]@{
PSTypeName = 'WaterReport'
Date = $item.Name -as [DateTime]
Count = $item.Count
Average = $measure.Average
Amount = $measure.Sum -as [int]
}
}
} #process
End {
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)"
} #end
} #close Measure-Water
Function Show-WaterReport {
<# PSFunctionInfo
Version 1.6.1
Author Jeffery Hicks
CompanyName JDH IT Solutions, Inc.
Copyright (c) JDH IT Solutions, Inc.
Description Display a Spectre bar chart of daily water consumption.
Guid 13aba3be-403c-4b30-a845-86b6238db537
Tags profile,personal,profile
LastUpdate 4/7/2026 8:54 AM
Source C:\scripts\water.ps1
#>
[cmdletbinding()]
[OutputType('Spectre.Console.Panel')]
[alias('sw')]
Param(
[Parameter(
Position = 0,
ValueFromPipeline,
HelpMessage = "The path to the Json data file"
)]
[ValidateNotNullOrEmpty()]
[ValidateScript({Test-Path $_},ErrorMessage = "Failed to find or validate {0}.")]
[string]$Path = $waterInfoPath,
[Parameter(HelpMessage = "Limit results to the last X number of days")]
[ValidateRange(1,365)]
[int32]$Days = 7,
[Parameter(HelpMessage = "Convert amount to descriptive text")]
[switch]$Convert
)
Begin {
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)"
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)"
#filter out colors that don't show well in my terminal and the R G B properties
$colors = [Spectre.Console.Color].GetProperties().Name |
Where-Object {$_.length -gt 1 -And $_ -notMatch 'Black|Gr[ae]y|Olive|DeepSkyBlue4|Blue(Violet)?|DarkGreen|(Dark|Navy)Blue|Blue\d+'}
} #begin
Process {
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Preparing water consumption report for the last $Days day(s)"
$get = Measure-Water -Path $Path -Days $days -OutVariable g |
Group-Object {$_.Date.ToShortDateString()} | Sort-Object {$_.Name -as[datetime]}
Write-Information $g
$data = @()
$grandTotal = 0
foreach ($item in $get) {
#add each day's totals to the grand total
$grandTotal += $item.Group.Amount
# Get a random color
$color = $colors | Get-Random
$data+= New-SpectreChartItem -label $item.Name -value $item.Group.Amount -color $color
}
[int]$dailyAvg = $grandTotal/$data.count
Write-Information "GrandTotal = $grandTotal"
Write-Information "Average = $dailyAvg"
if ($Convert) {
$avg = Convert-Water $dailyAvg
#adjust the panel width
$width = 60
}
else {
$avg = "$dailyAvg oz"
$width = 50
}
$data | Format-SpectreBarChart -Width 50 | Format-SpectrePadded -Padding 1 |
Format-SpectrePanel -width $width -Color "Aqua" -Header "[italic Aqua]Water Report: Daily Average $avg[/]"
} #process
End {
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)"
} #end
} #close Show-WaterReport
Function Export-WaterReport {
<# PSFunctionInfo
Version 1.1.0
Author Jeffery Hicks
CompanyName JDH IT Solutions, Inc.
Copyright (c) JDH IT Solutions, Inc.
Description Export water consumption report to PNG file
Guid a3c8f7d2-9e4a-4b5c-8d9a-2f6e1b3c4d5a
Tags profile,personal,profile
LastUpdate 3/17/2026 2:15 PM
Source C:\scripts\water.ps1
#>
[cmdletbinding(SupportsShouldProcess)]
[OutputType([string])]
[alias('ewp')]
Param(
[Parameter(
Position = 0,
HelpMessage = "The path to the Json data file"
)]
[ValidateNotNullOrEmpty()]
[ValidateScript({Test-Path $_},ErrorMessage = "Failed to find or validate {0}.")]
[string]$Path = $waterInfoPath,
[Parameter(HelpMessage = "Limit results to the last X number of days")]
[ValidateRange(1,365)]
[int32]$Days = 30,
[Parameter(HelpMessage = "Specify a report title.")]
[ValidateNotNullOrEmpty()]
[string]$Title = "Jeff's Water Consumption Report",
[ValidateNotNullOrEmpty()]
[string]$FontName = "Consolas",
[ValidateRange(10,48)]
[int]$TitleSize = 14,
[Parameter(
Position = 1,
HelpMessage = "The output PNG file path"
)]
[string]$OutPath = "C:\Temp\WaterReport.png",
[Parameter(HelpMessage = "Preview the image")]
[switch]$Preview
)
Begin {
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)"
# Check if System.Drawing is available
try {
Add-Type -AssemblyName System.Drawing -ErrorAction Stop
}
catch {
Write-Error "System.Drawing assembly could not be loaded. This function requires .NET Framework."
return
}
} #begin
Process {
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Generating water report and converting to PNG"
try {
# Capture the Spectre output to SVG first (Spectre can export to SVG)
$report = Show-WaterReport -Path $Path -Days $Days
$sz = $report | Get-SpectreRenderableSize
Write-Information $report
Write-Information $sz
# Create a bitmap to render the console output
$width = ($sz.width * 10) #+ 10
$height = ($sz.height * 25)# + 10
$bitmap = New-Object System.Drawing.Bitmap($width, $height)
$graphics = [System.Drawing.Graphics]::FromImage($bitmap)
# Set background to white
$graphics.Clear([System.Drawing.Color]::White)
# Define font and colors
$font = New-Object System.Drawing.Font($FontName, 10)
$brush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::Black)
$y = 10
# Get the water data and render it
$measureData = Measure-Water -Path $Path -Days $Days | Sort-Object Date -Descending
$grandTotal = ($measureData | Measure-Object -Property Amount -Sum).Sum
[int]$dailyAvg = $grandTotal / @($measureData).Count
# Draw title
$titleFont = New-Object System.Drawing.Font($FontName, $TitleSize, [System.Drawing.FontStyle]::Bold)
$graphics.DrawString($title, $Font, $brush, 10, $y)
$y += 30
# Draw summary
$graphics.DrawString("Daily Average: $dailyAvg oz. | Total Days: $(@($measureData).Count) | Grand Total: $grandTotal oz.", $font, $brush, 10, $y)
$y += 25
# Draw chart data
$graphics.DrawString("Daily Breakdown:", $font, $brush, 10, $y)
$y += 20
foreach ($item in $measureData) {
$barWidth = [int]($item.Amount * 3) # Scale the bar
$barHeight = 15
# Draw date and amount
$dateText = $item.Date.ToString("MM/dd/yyyy")
$graphics.DrawString("$($dateText): $($item.Amount) oz", $font, $brush, 10, $y)
# Draw visual bar
$barRect = New-Object System.Drawing.Rectangle(150, $y, $barWidth, $barHeight)
$graphics.FillRectangle([System.Drawing.Brushes]::LightBlue, $barRect)
$graphics.DrawRectangle([System.Drawing.Pens]::Blue, $barRect)
$y += 20
if ($y -gt ($height - 50)) {
Write-Warning "Image has run out space"
break # Stop if we run out of space
}
}
# Save the bitmap to PNG
#convert the paths elements to FileSystem elements
$fileName = Split-Path $OutPath -Leaf
$parent = Split-Path $OutPath -Parent
$fullPath = Join-Path (Convert-Path $parent) -ChildPath $fileName
if (Test-Path $fullPath) {
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Removing previous version of $fullPath"
Remove-Item $fullPath -ErrorAction stop
}
$bitmap.Save($fullPath, [System.Drawing.Imaging.ImageFormat]::Png)
Write-Information $bitmap
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] PNG file saved to $fullPath"
if ($Preview) {
Write-SpectreHost "[Italic Aquamarine1_1]Water report exported to: $fullPath[/]"
Get-SpectreImage -ImagePath $fullPath -MaxWidth 40
}
else {
Get-Item $fullPath
}
}
catch {
Write-Error "Failed to create PNG file: $_"
}
finally {
# Clean up resources
if ($graphics) { $graphics.Dispose() }
if ($bitmap) { $bitmap.Dispose() }
if ($font) { $font.Dispose() }
if ($titleFont) { $titleFont.Dispose() }
if ($brush) { $brush.Dispose() }
}
} #process
End {
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)"
} #end
} #close Export-WaterReportToPng
function Convert-Water {
<# PSFunctionInfo
Version 1.1.0
Author Jeffery Hicks
CompanyName JDH IT Solutions, Inc.
Copyright (c) JDH IT Solutions, Inc.
Description Convert ounces to text description
Guid 5e461978-a05c-464c-b8ff-f3c64c41df95
Tags stand-alone,personal,profile
LastUpdate 4/18/2026 1:28 PM
Source C:\scripts\Water.ps1
#>
[CmdletBinding()]
[alias("cw")]
param(
[Parameter(
Position = 0,
Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName,
HelpMessage = "Specify the number of ounces"
)]
[ValidateScript({$_ -ge 1},ErrorMessage = "The value {0} must be >= 1")]
[alias("Ounces","Sum")]
[int]$Amount
)
begin {
<#
16 oz = 1 pint
32 oz = 1 qt
64 oz = 1/2 gal
128 oz = 1 gal
33.8 oz = 1 liter
#>
#define script blocks to calculate text-based usage
#these script blocks could be re-factored into a single command
#but clarity might be lost
$pt = {
param ($amount)
[int]$pints = [Math]::Truncate(($amount / 16))
[int]$oz = $amount % 16
($oz -gt 0) ? "$pints pint $oz ounces" : "$pints pint"
}
$qt = {
param ($amount)
[int]$qts = [Math]::Truncate(($amount / 32))
[int]$pints = $amount % 32
#convert pint value to pints and ounces
$out = ($pints -gt 0) ? "$qts quart $(&$pt $pints)" : "$qts quart"
$out
}
$hg = {
param ($amount)
[int]$half = [Math]::Truncate(($amount / 64))
[int]$qts = $amount % 64
$out = ($qts -gt 0) ? "$half half-gallon $(&$qt $qts)" : "$half half-gallon"
$out
}
$gal = {
param ($amount)
[int]$gals = [Math]::Truncate(($amount / 128))
[int]$qts = $amount % 128
$out = ($qts -gt 0) ? "$gals gallon $(&$qt $qts)" : "$gals gallon(s)"
$out
}
} #begin
process {
Write-Verbose "Processing $Amount ounces"
switch ($Amount) {
{ $_ -ge 128 } {
&$gal $_
Break
}
{ $_ -ge 64 } {
&$hg $_
Break
}
{ $_ -ge 32 } {
&$qt $_
Break
}
{ $_ -ge 16 } {
&$pt $_
Break
}
default {
"$_ ounces"
}
}
} #Process
end {
#not used
} #end
}
#load formatting
Update-FormatData $PSScriptRoot\water.format.ps1xml
# add script properties
Update-TypeData -TypeName WaterReport -MemberType ScriptProperty -MemberName Description -Value {Convert-Water $this.Amount} -Force
Update-TypeData -TypeName WaterInfo -MemberType ScriptProperty -MemberName Description -value {$this.GetAmountDescription()} -Force
#18 April 2026 Add a note property for the JSON file path to be used in custom formatting
Update-TypeData -TypeName WaterInfo -MemberType NoteProperty -MemberName Data -value $waterInfoPath -Force
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment