# HRZones.ps1 # PowerShell script to calculate training heart rate zones using the Karvonen method. # ---------------------------------------------------------------------- # Copyright (c) 2016-2022 Richard L. Mueller # Hilltop Lab web site - http://www.rlmueller.net # Version 1.0 - October 4, 2016 # Version 1.1 - October 8, 2016 - Made $Formula Script scope to support PowerShell V5. # Version 1.2 - November 27, 2016 - Improve help for unrecognized parameters. # Version 2.0 - January 21, 2022 - Added help feature to the textboxes on the form, # removed Sex as a parameter, revised formulas for maximum heart rate. # Version 2.1 - January 29, 2022 - Added form that compares the formulas for maximum HR. # # You have a royalty-free right to use, modify, reproduce, and # distribute this script file in any way you find useful, provided that # you agree that the copyright owner above has no warranty, obligations, # or liability for such use. # Specify the supported parameters. The first one (or several) letters of each parameter can # be used as an alias. They can also be specified in order without names. The [CmdletBinding] # attribute is not supported in PowerShell V1. We also cannot specify any parameters as # mandatory in PowerShell V1. The Param statement must come before any executable statements. Param( [Int16]$RestingHR, [Int16]$MaxHR, [Int16]$Age, [String]$Formula, [Switch]$Estimate, [Switch]$Help, [Switch]$NoGUI, [Switch]$Black ) # Script version and date. $Version = "Version 2.1 - January 29, 2022" $Today = Get-Date # Flag any parameters not recognized and abort the script. Any parameters that do not match # the supported parameters (specified by the Param statement above) will populate the $Args # collection, an automatic variable. If all of the parameters supplied are recognized, then # $Args will be empty. $Abort = $False ForEach ($Arg In $Args) { If ($Arg -Like "-*") { Write-Host "Argument not recognized: $Arg" -ForegroundColor Red -BackgroundColor Black } Else { Write-Host "Value not recognized: $Arg" -ForegroundColor Red -BackgroundColor Black } $Abort = $True } # Breaking out of the above ForEach would not break out of the script. Breaking out # of the If statment will. If ($Abort -eq $True) { # Display a brief help listing the supported parameters and their data types. Write-Host "Syntax: HRZones.ps1 [[-RestingHR] ] [[-MaxHR] ] [[-Age] ]`r`n" ` " [[-Formula] ] [-Estimate] [-Help] [-NoGUI] [-Black]" ` -ForegroundColor Yellow -BackgroundColor Black Write-Host "For help use HRZones.ps1 -Help" -ForegroundColor yellow -BackgroundColor Black Break } # Constants, to validate parameters. # Allowed range for resting heart rate, in bpm. $RestingL = 28 $RestingU = 115 # Allowed range for maximum heart rate, in bpm. $MaxL = 135 $MaxU = 230 # Allowed range for age, in years. $AgeL = 5 $AgeU = 105 # Allowed values for the formula to use to estimate maximum heart rate. # The allowed values are case insensitive, but this array should be all lower case so the # value provided by the user can be easily compared. $Formulas = @("oakland1", "oakland2", "haskell", "cooper", "tanaka", ` "gellish", "robergs", "nes") # Maximum heart rate less resting heart rate is called the heart rate reserve. # Heart rate reserve must be at least this amount (in bpm). $MaxRestingDiff = 30 Function Estimate-MaxHR ($UserAge, $FormulaSelected) { # Function to estimate the maximum heart rate from age. # Returns an integer. # Reference: https://en.wikipedia.org/wiki/Heart-rate Switch ($FormulaSelected) { "Oakland1" { # Per Oakland University, 2007. Return [int16](206.9 - (0.67 * $UserAge)) } "Oakland2" { # Per Oakland University, 2007. Return [int16](192 - (0.007 * $UserAge * $UserAge)) } "Haskell" { # Per Haskell and Fox (ca. 1970). Return [int16](220 - $UserAge) } "Cooper" { # Per Kenneth Cooper, 1988. Return [int16](205 - (0.5 * $UserAge)) } "Tanaka" { # Per Tanaka, Monaham, and Seals (2001). Return [int16](208 - (0.7 * $UserAge)) } "Gellish" { # Per Wohlfart and Farazdaghi (2003). Return [int16](203.7 /( 1 + [Math]::Exp(0.033 * ($UserAge - 104.3)))) } "Robergs" { # Per Robergs and Landwehr (2002). Return [int16](205.8 - (0.685 * $UserAge)) } "Nes" { # Nes, et al. (2013). Return [int16](211 - (0.64 * $UserAge)) } } } # End of Function Calculate-MaxHR. Function Calculate-Zones ($UserResting, $UserMax) { # Function to calculate training heart rate zones - Karvonen method. # Per Karvonen, Vuorimaa (1988). # Returns an array of 12 integers. # $AdjHR is called the heart rate reserve. $AdjHR = $UserMax - $UserResting $Level = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 $Level[0] = [Int16](0.50 * $AdjHR) + $UserResting $Level[1] = [Int16](0.60 * $AdjHR) + $UserResting $Level[2] = $Level[1] + 1 $Level[3] = [Int16](0.70 * $AdjHR) + $UserResting $Level[4] = $Level[3] + 1 $Level[5] = [Int16](0.75 * $AdjHR) + $UserResting $Level[6] = $Level[5] + 1 $Level[7] = [Int16](0.80 * $AdjHR) + $UserResting $Level[8] = $Level[7] + 1 $Level[9] = [Int16](0.90 * $AdjHR) + $UserResting $Level[10] = $Level[9] + 1 $Level[11] = $UserMax Return $Level } # End of Function Calculate-Zones. Function Get-Help ($Topic) { # Function to display a help form for the requested topic. # Specify the form. $Font1 = New-Object System.Drawing.Font("Times New Roman", 12, ` [System.Drawing.FontStyle]::Regular) $Font2 = New-Object System.Drawing.Font("Courier New", 10, ` [System.Drawing.FontStyle]::Regular) $HRZHelp = New-Object System.Windows.Forms.Form $HRZHelp.Text = "Help for $Topic" $HRZHelp.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen $HRZHelp.Width = 650 $HRZHelp.Height = 600 # $HRZHelp.Font = $Font1 $HRZHelp.KeyPreview = $True $HRZHelp.Add_KeyDown({ If ($_.KeyCode -eq "Enter") { # User pressed the Enter key (same as Return). $HRZHelp.Close() } If ($_.KeyCode -eq "Escape") { # User pressed the Esc key (same as Cancel). $HRZHelp.Close() } }) # Specify the controls on the form. $HelpLabel = New-Object Windows.Forms.Label $HelpLabel.Top = 20 $HelpLabel.Left = 20 $HelpLabel.Width = 600 $HelpLabel.Height = 190 $HelpLabel.Font = $Font1 $FormulaLabel = New-Object Windows.Forms.Label $FormulaLabel.Top = 210 $FormulaLabel.Left = 10 $FormulaLabel.Width = 660 $FormulaLabel.Height = 290 $FormulaLabel.Font = $Font2 $FooterLabel = New-Object Windows.Forms.Label $FooterLabel.Top = 500 $FooterLabel.Left = 20 $FooterLabel.Width = 600 $FooterLabel.Height = 40 $FooterLabel.Font = $Font1 Switch ($Topic) { "Resting Heart Rate" { $HelpLabel.Text = "Your resting heart rate should be entered in beats per minute (bpm). " ` + "The value should be an integer between $RestingL and $RestingU bpm. If you have a heart rate " ` + "monitor, you can measure your resting heart rate first thing in the morning, " ` + "before you get out of bed. You can average readings over several days. " ` + "Resting heart rate can be lowered, temporarily, after aerobic training at altitude. " ` + "Also, as aerobic fitness improves, resting heart rate generally declines. This increases " ` + "the heart rate reserve, which is maximum heart rate less resting heart rate. " ` + "Resting heart rate is increased by illness and some drugs. " ` + "The table of normal resting heart rates below is based on the Wikipedia article: " ` + "https://en.wikipedia.org/wiki/Heart_rate#Resting_heart_rate" $FormulaLabel.Text = "Age (years) Range for Resting Heart Rate (bpm)`r`n" ` + "------------------------ ----------------------------------`r`n" ` + " 5-6 75-115`r`n" ` + " 7-9 70-110`r`n" ` + " > 10 60-100`r`n" ` + "trained adult athletes 40- 60`r`n" ` + "endurance athletes 33- 50" $FooterLabel.Text = "To return to the main screen, press the ""Enter"" or ""Esc"" keys, " ` + "or click the ""X"" in the upper right to close this Help." } "Maximum Heart Rate" { $HelpLabel.Text = "If you know your maximum heart rate, enter the value in beats per minute (bpm). " ` + "It should be an integer between $MaxL and $MaxU bpm. The best way to measure your maximum " ` + "heart rate is to take a cardic stress test on a treadmill (under medical supervision). " ` + "Otherwise, if you wear a heart rate monitor during workouts, and you are in excellent health, " ` + "you may base you maximum rate on the reading after a run of about 2 miles (or a similar aerobic " ` + "activity) where you sprint at the end. An average of several such runs is best. " ` + "If you do not know your maximum heart rate, this program can estimate a maximum " ` + "based on your age. Simply check the box to estimate maximum heart rate from age on the form. " ` + "You then can enter your age. In addition, select one of the 8 formulas to be used to " ` + "estimate your maximum heart rate." $FooterLabel.Text = "To return to the main screen, press the ""Enter"" or ""Esc"" keys, " ` + "or click the ""X"" in the upper right to close this Help." } "Age" { $HelpLabel.Text = "Enter your age in whole years. The value should be an integer between $AgeL and " ` + "$AgeU years." $FooterLabel.Text = "To return to the main screen, press the ""Enter"" or ""Esc"" keys, " ` + "or click the ""X"" in the upper right to close this Help." } "Oakland1" { $HelpLabel.Text = "Oakland University researchers in 2007 developed two formulas to estimate maximum " ` + "heart rate. They studied 132 individuals over 25 years. Their first formula, similar to " ` + "the Tanaka formula, has a confidence interval of plus or minus 5-8 bpm. " ` + "In the formula below, the expression ""[int16]"" means that the result is rounded to the " ` + "nearest whole 16-bit integer. The formula is:" $FormulaLabel.Text = "HR_max = [int16](206.9 - (0.67 * Age))" $FooterLabel.Text = "To return to the main screen, press the ""Enter"" or ""Esc"" keys, " ` + "or click the ""X"" in the upper right to close this Help." } "Oakland2" { $HelpLabel.Text = "Oakland University researchers developed two formulas to estimate maximum " ` + "heart rate in 2007. They studied 132 individuals over 25 years. Their second formula " ` + "has a confidence interval of plus or minus 2-5 bpm. In the formula below, the ""^"" " ` + "character is the symbol to raise to a power. So ""Age^2"" is the square of the Age. " ` + "The expression ""[int16]"" means that the result is rounded to the " ` + "nearest whole 16-bit integer. The resulting nonlinear formula is:" $FormulaLabel.Text = "HR_max = [int16](192 - (0.007 * Age^2))" $FooterLabel.Text = "To return to the main screen, press the ""Enter"" or ""Esc"" keys, " ` + "or click the ""X"" in the upper right to close this Help." } "Haskell" { $HelpLabel.Text = "Dr. William Haskell and Dr. Samual Fox are believed to have developed their " ` + "formula in 1970. It seems to have been based on several scientific papers, rather than " ` + "original research. It is the most commonly known formula, and the easiest to remember and " ` + "calculate. However much research reveals it has large errors. It is not considered as " ` + "accurate as the alternatives. " ` + "In the formula below, the expression ""[int16]"" means that the result is rounded to the " ` + "nearest whole 16-bit integer. The formula is:" $FormulaLabel.Text = "HR_max = [int16](220 - Age)" $FooterLabel.Text = "To return to the main screen, press the ""Enter"" or ""Esc"" keys, " ` + "or click the ""X"" in the upper right to close this Help." } "Cooper" { $HelpLabel.Text = "Dr. Kenneth Cooper published his formula on page 253 of his book " ` + """Controlling Cholesterol"", copyright 1988. I personally find it most closely matches " ` + "my own experience. " ` + "In the formula below, the expression ""[int16]"" means that the result is rounded to the " ` + "nearest whole 16-bit integer. The formula is:" $FormulaLabel.Text = "HR_max = [int16](205 - (0.5 * Age))" $FooterLabel.Text = "To return to the main screen, press the ""Enter"" or ""Esc"" keys, " ` + "or click the ""X"" in the upper right to close this Help." } "Tanaka" { $HelpLabel.Text = "Tanaka, Monahan, and Seals in 2001 studied some 19,000 subjects to come up with " ` + "their formula. They reported the formula correlated with age, regardless of gender, with a " ` + "standard deviation of 10 bpm. " ` + "In the formula below, the expression ""[int16]"" means that the result is rounded to the " ` + "nearest whole 16-bit integer. The formula is:" $FormulaLabel.Text = "HR_max = [int16](208 - (0.7 * Age))" $FooterLabel.Text = "To return to the main screen, press the ""Enter"" or ""Esc"" keys, " ` + "or click the ""X"" in the upper right to close this Help." } "Gellish" { $HelpLabel.Text = "The Gellish formula is attributed to B. Wohlfart and G. R. Farazdaghi. " ` + "It is based on a 2003 study of bicycle ergometry in Lund, Sweden. In the formula " ` + "below, e = 2.71828 (Euler's number, the base of natural logarithms). The ""^"" symbol means " ` + "to raise to the power. In this case, ""e"" is raised to the power of the " ` + "expression ""(0.033 * (Age - 104.3))"". " ` + "The expression ""[int16]"" means that the result is rounded to the " ` + "nearest whole 16-bit integer. The formula is:" $FormulaLabel.Text = "HR_max = [int16](203.7 / (1 + e^(0.033 * (Age - 104.3))))" $FooterLabel.Text = "To return to the main screen, press the ""Enter"" or ""Esc"" keys, " ` + "or click the ""X"" in the upper right to close this Help." } "Robergs" { $HelpLabel.Text = "Robergs and Landwehr studied 43 formulas in 2002 and concluded that the best " ` + "formula has a standard deviation of 6.4 bpm. " ` + "In the formula below, the expression ""[int16]"" means that the result is rounded to the " ` + "nearest whole 16-bit integer. The formula is:" $FormulaLabel.Text = "HR_max = [int16](205.8 - (0.685 * Age))" $FooterLabel.Text = "To return to the main screen, press the ""Enter"" or ""Esc"" keys, " ` + "or click the ""X"" in the upper right to close this Help." } "Nes" { $HelpLabel.Text = "Nes et al. studied 3,320 healthy men and women between 19 and 89 years of " ` + "age. They determined their formula held regardless of gender, body mass index, or activity level. " ` + "They reported a standard deviation of 10.8 bpm. " ` + "In the formula below, the expression ""[int16]"" means that the result is rounded to the " ` + "nearest whole 16-bit integer. The formula is:" $FormulaLabel.Text = "HR_max = [int16](211 - (0.64 * Age))" $FooterLabel.Text = "To return to the main screen, press the ""Enter"" or ""Esc"" keys, " ` + "or click the ""X"" in the upper right to close this Help." } "Karvonen" { $HelpLabel.Text = "The Karvonen method is used to calculate training heart rate zones. " ` + "The method is described on pages 58-69 of the book ""Serious Training for Serious " ` + "Athletes"", copyright 1989, by Rob Sleamaker. The method requires knowing the resting " ` + "and maximum heart rates. The difference between these values is called the heart rate reserve.`r`n" ` + "HR_Reserve = HR_Max - HR_Resting`r`n" ` + "Percentages of heart rate reserve correspond to percentages of VO2Max, maximal oxygen uptake " ` + "capacity. The suggested training heart rate zones are defined by the following table (from " ` + "table 5.1 on page 60 of Rob Sleamaker's book):" $FormulaLabel.Text = " Intensity`r`n" ` + "Level % VO2Max (% HR_Max) Description`r`n" ` + "----- -------- --------- ----------------`r`n" ` + " 50-60 Warmup`r`n" ` + " 1 55-65 61-70 Over Distance`r`n" ` + " 2 66-75 71-75 Endurance / Easy Speed`r`n" ` + " 3 76-80 76-80 Endurance / Long Races`r`n" ` + " 4 81-90 81-90 Anaerobic Threshold / Intervals`r`n" ` + " 5 91-100 91-100 Peaking / Racing" $FooterLabel.Text = "To return to the main screen, press the ""Enter"" or ""Esc"" keys, " ` + "or click the ""X"" in the upper right to close this Help." } "All Formulas" { $HelpLabel.Text = "Results from all of the formulas are shown in the table below. This may help " ` + "you decide which formula is best for your situation.`r`n" ` + "Notice that the Haskell formula results in the estimated maximum heart rate dropping off " ` + "the fastest with age. The Cooper formula drops off more slowly with age, so the maximum is higher " ` + "for older people. The differences between all of the formulas is less for middle ages, " ` + "between 25 and 45 years of age." $FormulaLabel.Text = "Age Oakland1 Oakland2 Haskell Cooper Tanaka Gellish Roberg Nes`r`n" ` + "--- -------- -------- -------- -------- -------- -------- -------- -------`r`n" ` + " 5 204 192 215 202 204 196 202 208`r`n" ` + " 10 200 191 210 200 201 195 199 205`r`n" ` + " 15 197 190 205 198 198 194 196 201`r`n" ` + " 20 194 189 200 195 194 192 192 198`r`n" ` + " 25 190 188 195 192 190 190 189 195`r`n" ` + " 30 187 186 190 190 187 188 185 192`r`n" ` + " 35 183 183 185 188 184 185 182 189`r`n" ` + " 40 180 181 180 185 180 182 178 185`r`n" ` + " 45 177 178 175 182 176 178 175 182`r`n" ` + " 50 173 174 170 180 173 175 172 179`r`n" ` + " 55 170 171 165 178 170 170 168 176`r`n" ` + " 60 167 167 160 175 166 165 165 173`r`n" ` + " 65 163 162 155 172 162 160 161 169`r`n" ` + " 70 160 158 150 170 159 154 158 166`r`n" ` + " 75 157 153 145 168 156 148 154 163`r`n" ` + " 80 153 147 140 165 152 141 151 160`r`n" ` + " 85 150 141 135 162 148 133 148 157" $FooterLabel.Text = "To return to the main screen, press the ""Enter"" or ""Esc"" keys, " ` + "or click the ""X"" in the upper right to close this Help." } } $HRZHelp.Controls.Add($HelpLabel) $HRZHelp.Controls.Add($FormulaLabel) $HRZHelp.Controls.Add($FooterLabel) $HRZHelp.Add_Load({ $HRZHelp.Activate() }) # Display the form to the user. $HRZHelp.ShowDialog() } # End of Function Get-Help Function Validate-Form() { # Function to validate values on the form. # Returns $True if all values are valid, otherwise returns $False. # Check for request for help. $Continue = $True If ($Resting.Text -eq "?") { Get-Help "Resting Heart Rate" $Resting.Text = "" $Continue = $False } If ($Max.Text -eq "?") { Get-Help "Maximum Heart Rate" $Max.Text = "" $Continue = $False } If ($AgeBox.Text -eq "?") { Get-Help "Age" $AgeBox.Text = "" $Continue = $False } If ($Continue -eq $True) { # Retrieve values from the form. $RestingHR = [Int16]$Resting.Text $MaxHR = [Int16]$Max.Text $Age = [Int16]$AgeBox.Text If ($EstimateChk.CheckState -eq "Checked") {$Estimate = $True} Else {$Estimate = $False} # Initialize controls on the form. $RestingFlag.Visible = $False $MaxFlag.Visible = $False $AgeFlag.Visible = $False $Warning.Visible = $False $FormulaLabel.Visible = $False $Formula1.Visible = $False $Formula2.Visible = $False $Formula3.Visible = $False $Formula4.Visible = $False $Formula5.Visible = $False $Formula6.Visible = $False $Formula7.Visible = $False $Formula8.Visible = $False $FHelpLabel.Visible = $False $FHelp.Visible = $False $AllHelp.Visible = $False $RestingLabel.ForeColor = "Black" $MaxLabel.ForeColor = "Black" $AgeLabel.ForeColor = "Black" $ReportLabel.Visible = $False $ZonesHelp.Visible = $False $L0Label.Visible = $False $L1Label.Visible = $False $L2Label.Visible = $False $L3Label.Visible = $False $L4Label.Visible = $False $L5Label.Visible = $False $L0BPM.Text = "" $L1BPM.Text = "" $L2BPM.Text = "" $L3BPM.Text = "" $L4BPM.Text = "" $L5BPM.Text = "" # If variable $Go is $True, the function will return with the value $True. # Otherwise the function will return with the value $False. $Go = $True # Validate resting heart rate. If (($RestingHR) -And (($RestingHR -lt $RestingL) -Or ($RestingHR -gt $RestingU))) { $RestingLabel.ForeColor = "Red" $RestingFlag.Visible = $True $Go = $False } # Validate maximum heart rate, if needed. If ((-Not $Estimate) -And ($MaxHR) -And (($MaxHR -lt $MaxL) -Or ($MaxHR -gt $MaxU))) { $MaxLabel.ForeColor = "Red" $MaxFlag.Visible = $True $Go = $False } # Validate age, if needed. If (($Age) -And ($Estimate) -And (($Age -lt $AgeL) -Or ($Age -gt $AgeU))) { $AgeLabel.ForeColor = "Red" $AgeFlag.Visible = $True $Go = $False } If ($Estimate -eq $True) { $MaxLabel.Visible = $False $Max.Visible = $False $AgeLabel.Visible = $True $AgeBox.Visible = $True $EstimateMaxLabel.Visible = $False $EstimateMax.Visible = $False $FormulaLabel.Visible = $True $Formula1.Visible = $True $Formula2.Visible = $True $Formula3.Visible = $True $Formula4.Visible = $True $Formula5.Visible = $True $Formula6.Visible = $True $Formula7.Visible = $True $Formula8.Visible = $True $FHelpLabel.Visible = $True $FHelp.Visible = $True $AllHelp.Visible = $True If ($Go -eq $True) { If ($AgeFlag.Visible -eq $False) { If ($Age) { # $Formula must have Script scope in PowerShell Version 5, so the value # can be assigned by the RadioButtons. $EstimateMax.Text = Estimate-MaxHR $Age $Script:Formula $EstimateMaxLabel.Visible = $True $EstimateMax.Visible = $True If (-Not $RestingHR) {$Go = $False} } } If (-Not $Age) { $EstimateMax.Text = "" $EstimateMaxLabel.Visible = $False $EstimateMax.Visible = $False $Report.Visible = $False $Go = $False } } } If (-Not $Estimate) { $MaxLabel.Visible = $True $Max.Visible = $True $AgeLabel.Visible = $False $AgeBox.Visible = $False $EstimateMaxLabel.Visible = $False $EstimateMax.Visible = $False $FormulaLabel.Visible = $False $Formula1.Visible = $False $Formula2.Visible = $False $Formula3.Visible = $False $Formula4.Visible = $False $Formula5.Visible = $False $Formula6.Visible = $False $Formula7.Visible = $False $Formula8.Visible = $False $FHelpLabel.Visible = $False $FHelp.Visible = $False $AllHelp.Visible = $False If ((-Not $RestingHR) -Or (-Not $MaxHR)) {$Go = $False} } If (($Go -eq $True) -And ($Estimate)) { # $Formula must have Script scope in PowerShell Version 5, so the value # can be assigned by the RadioButtons. $MaxHR = Estimate-MaxHR $Age $Script:Formula } If (($Go -eq $True) -And (($RestingHR + $MaxRestingDiff) -gt $MaxHR)) { $Warning.Visible = $True $RestingFlag.Visible = $True $RestingLabel.ForeColor = "Red" $MaxFlag.Visible = $True $MaxLabel.ForeColor = "Red" $Go = $False } If ($Go -eq $True) { $ReportLabel.Visible = $True $ZonesHelp.Visible = $True $L0Label.Visible = $True $L1Label.Visible = $True $L2Label.Visible = $True $L3Label.Visible = $True $L4Label.Visible = $True $L5Label.Visible = $True $L0BPM.Visible = $True $L1BPM.Visible = $True $L2BPM.Visible = $True $L3BPM.Visible = $True $L4BPM.Visible = $True $L5BPM.Visible = $True # $L is an array of 12 integers returned by Function Calculate-Zones. $L = Calculate-Zones $RestingHR $MaxHR $L0BPM.Text = $L[0].ToString() + " - " + $L[1].ToString() + " bpm" $L1BPM.Text = $L[2].ToString() + " - " + $L[3].ToString() + " bpm" $L2BPM.Text = $L[4].ToString() + " - " + $L[5].ToString() + " bpm" $L3BPM.Text = $L[6].ToString() + " - " + $L[7].ToString() + " bpm" $L4BPM.Text = $L[8].ToString() + " - " + $L[9].ToString() + " bpm" $L5BPM.Text = $L[10].ToString() + " - " + $L[11].ToString() + " bpm" $Report.Visible = $True } Else {$Report.Visible = $False} } # End If ($Continue -eq $True). Else {$Go = $False} Return $Go } # End of Function Validate-Form. If ($Help) { # User has requested help information. "HRZones.ps1" "$Version" "PowerShell script to calculate training heart rate zones using the Karvonen method." "Parameters" " -RestingHR: Resting heart rate in beats per minute. An integer between $RestingL" " and $RestingU. If no value is provided you will be prompted for a value." " -MaxHR: Maximum heart rate in beats per minute. An integer between $MaxL and $MaxU." " If no value is provided, an estimate can be calculated from your age." " -Age: Your age in years. An integer between $AgeL and $AgeU. Only needed if you" " do not provide a maximum heart rate, or you use the -Estimate parameter." " -Formula: The formula to use to estimate the maximum heart rate (if needed)." " Options: Oakland1 (default), Oakland2, Haskell, Cooper, Tanaka, Gellish," " Robergs, or Nes." " -Estimate: A switch indicating that you want the script to calculate an estimated" " maximum heart rate. You are prompted for your age (if you did not provide" " the -Age parameter)." " -NoGUI: A switch that requests that the GUI form not be used. Data input is accepted" " and all results are displayed at the command line." " -Black: A switch to output results without using the Write-Host cmdlet. The output" " will not have colors, but it can be redirected to a text file." " -Help: A switch that outputs this help." "Note: The first one (or several) letters of each parameter can be used as aliases." " In addition, the parameters -RestingHR, -MaxHR, -Age, and -Formula can be" " listed in order without the parameter names. See the first example below." "Some usage examples:" ".\HRZones.ps1 52 180" " Calculate heart rate zones based on a resting HR of 52 and a maximum HR of 180." ".\HRZones.ps1 -MaxHR 180 -RestingHR 52" " Same as the previous." ".\HRZones.ps1 52 180 40 Cooper -est" " Calculate zones based on a resting HR of 52 and estimated maximum using the Cooper" " formula and a 40 year old. The 180 maximum HR will not be used." ".\HRZone.ps1 -Estimate -Age 39 -RestingHR 52" " Calculate heart rate zones based on a resting HR of 52 and an estimated" " maximum. The maximum heart rate will be calculated base on a 39 year old." " The default formula, Oakland1, is used to estimate the maximum heart rate." ".\HRZones.ps1 -r 52 -a 39 -e -n -b > Report.txt" " Same as the previous, but no GUI is selected and black is selected. The output is" " redirected to the text file Report.txt in the current directory." ".\HRZones.ps1 -R 52" " You are prompted for either your maximum heart rate or your age." ".\HRZones.ps1" " You are prompted for resting heart rate and either maximum heart rate or age." "Example output:" "-----" "HRZones.ps1" "Version 2.1 - January 29, 2022" "Age: 39" "Resting heart rate: 52 bpm" "Maximum heart rate: 181 bpm (estimate, Oakland1)" "Calculated training heart rate zones (1/31/2022 13:32:17):" "Level Description Intensity bpm" "----- ---------------------- --------- ---------" " warmup 50-60% 116 - 129" " 1 over distance 61-70% 130 - 142" " 2 endurance / easy speed 71-75% 143 - 149" " 3 endurance / long races 76-80% 150 - 155" " 4 anaerobic threshold 81-90% 156 - 168" " 5 peaking / racing 91-100% 169 - 181" Break } If (($ExecutionContext.SessionState.LanguageMode -eq "ConstrainedLanguage") -Or ($NoGUI)) { # PowerShell is constrained. Possibly Windows 8.1 RT, or the user has requested no GUI. # Cannot use Windows forms. If ($ExecutionContext.SessionState.LanguageMode -eq "ConstrainedLanguage") { Write-Host "PowerShell constrained on this computer. Windows forms not used." ` -ForegroundColor yellow -BackgroundColor Black } # Validate the input parameters # Default formula for estimated maximum heart rate. # $Formula must have Script scope in PowerShell Version 5, so the value # can be assigned by the RadioButtons. If (-Not $Script:Formula) {$Script:Formula = "Oakland1"} # Check for a valid formula. If ($Formulas -NotContains $Script:Formula.ToLower()) { # Formula to calculate estimated maximum heart rate not recognized. Do { # PowerShell V1 does not support the -Join PowerShell operator. # Use the .NET Framework function instead. $ValidValues = [String]::Join(", ", $Formulas) Write-Host "Formula to estimate maximum heart rate ($Script:Formula) not" ` "recognized.`r`n" ` "Valid values: $ValidValues" -ForegroundColor Red -BackgroundColor Black $Script:Formula = Read-Host "Enter formula to estimate maximum heart rate" } Until ($Formulas -Contains $Script:Formula.ToLower()) } # If no maximum HR specfied, but Age is, calculate an estimated maximum. If ((-Not $MaxHR) -And $Age) {$Estimate = $True} If (-Not $RestingHR) { # Resting heart rate not provided. $RestingHR = Read-Host "Enter your resting heart rate (in beats per minute)" } If (($RestingHR -lt $RestingL) -Or ($RestingHR -gt $RestingU)) { # Resting heart rate is out of range. Do { Write-Host "Resting heart rate ($RestingHR) must be between $RestingL and" ` "$RestingU" -ForegroundColor Red -BackgroundColor Black $RestingHR = Read-Host "Enter your resting heart rate (in beats per minute)" } Until (($RestingHR -ge $RestingL) -And ($RestingHR -le $RestingU)) } If ((-Not $MaxHR) -And (-Not $Estimate) -And (-Not $Age)) { # User did not specify a maximum HR or an estimated maximum or Age. $Ans = Read-Host "Enter your maximum heart rate (in beats per minute)`r`n" ` "Or enter ""0"" to have it estimated from your age" If ($Ans -eq 0) {$Estimate = $True} Else {$MaxHr = $Ans} } If (($MaxHR) -And (-Not $Estimate) -And (($MaxHR -lt $MaxL) -Or ($MaxHR -gt $MaxU))) { # Specified maximum heart rate is out of range. Do { Write-Host "Maximum heart rate ($MaxHR) must be between $MaxL and $MaxU" ` -ForegroundColor Red -BackgroundColor Black $MaxHR = Read-Host "Enter your maximum heart rate (in beats per minute)" } Until (($MaxHR -ge $MaxL) -And ($MaxHR -le $MaxU)) } # If maximum heart rate not provided, estimate based on age. If ((-Not $MaxHR) -Or ($Estimate)) { If ($MaxHR) { # User specified $MaxHR but also selected to estimate maximum heart rate. Do { Write-Host "Estimated maximum heart rate requested, but maximum of`r`n" ` "$MaxHR specified." -ForegroundColor Red -BackgroundColor Black $Ans = Read-Host "Enter 0 to use specified maximum ($MaxHR), 1 to`r`n" ` "estimate based on age." If ($Ans -eq 0) { # Estimate changed from $True to $False. Check if $MaxHR in range. $Estimate = $False If (($MaxHR -lt $MaxL) -Or ($MaxHR -gt $MaxU)) { # Specified maximum heart rate is out of range. Do { Write-Host "Maximum heart rate ($MaxHR) must be between" ` "$MaxL and $MaxU" -ForegroundColor Red -BackgroundColor Black $MaxHR = Read-Host "Enter your maximum heart rate" ` "(in beats per minute)" } Until (($MaxHR -ge $MaxL) -And ($MaxHR -le $MaxU)) } } } Until (($Ans -eq 0) -Or ($Ans -eq 1)) } If ($Estimate) { If ((-Not $Age) -Or ($Age -lt $AgeL) -Or ($Age -gt $AgeU)) { # Valid age not provided. If (($Age -lt $AgeL) -Or ($Age -gt $AgeU)) { Write-Host "Age ($Age) must be in years, between $AgeL and $AgeU" ` -ForegroundColor Red -BackgroundColor Black } # Prompt for Age until a valid value is provided. Do { $Age = Read-Host "Enter your age (in years)" If (($Age -lt $AgeL) -Or ($Age -gt $AgeU)) { Write-Host "Age must be in years, between $AgeL and $AgeU" ` -ForegroundColor Red -BackgroundColor Black } } Until (($Age -ge $AgeL) -And ($Age -le $AgeU)) } # Calculate estimated maximum heart rate based on age. # $Formula must have Script scope in PowerShell Version 5, so the value # can be assigned by the RadioButtons. $MaxHR = Estimate-MaxHR $Age $Script:Formula $Estimate = $True } } If (($RestingHR + $MaxRestingDiff) -gt $MaxHR) { # The maximum heart rate must be greater than the minimum by at least # the specified amount. Write-Host "Invalid values, the maximum heart rate ($MaxHR) must be at least" ` "$MaxRestingDiff greater than the resting heart rate ($RestingHR)" ` -ForegroundColor Red -BackgroundColor Black Break } } # End of code when PowerShell is constrained. Else { # PowerShell is not constrained. Windows forms can be used. [void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") # Specify the form. $Font = New-Object System.Drawing.Font("Times New Roman", 12, ` [System.Drawing.FontStyle]::Regular) $HRZForm = New-Object System.Windows.Forms.Form $HRZForm.Text = "Calculate Training Heart Rate Zones - Karvonen Method" $HRZForm.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen $HRZForm.Width = 600 $HRZForm.Height = 620 $HRZForm.Font = $Font $HRZForm.KeyPreview = $True $HRZForm.Add_KeyDown({ If ($_.KeyCode -eq "Enter") { # User pressed the Enter key (same as Return). Only exit if all values on the form # are valid. When the user clicks the Calculate button, the focus remains on the # button and the Enter key event is not recognized. The code for the Calculate # button ends by invoking the Down arrow key, so the Enter key is recognized. $Status = Validate-Form } If ($_.KeyCode -eq "Escape") { # User pressed the Esc key (same as Cancel). $HRZForm.DialogResult = "Cancel" $HRZForm.Close() } }) # Specify the controls on the form. $TopLabel = New-Object Windows.Forms.Label $TopLabel.Text = "Enter ""?"" (without the quotes) in any text box and press ""Enter"" for help on entry" $TopLabel.Top = 10 $TopLabel.Left = 20 $TopLabel.Width = 560 $TopLabel.ForeColor = "Green" $HRZForm.Controls.Add($TopLabel) $RestingLabel = New-Object Windows.Forms.Label $RestingLabel.Text = "Resting heart rate, bpm (integer from $RestingL to $RestingU)" $RestingLabel.Top = 50 $RestingLabel.Left = 20 $RestingLabel.Width = 400 $HRZForm.Controls.Add($RestingLabel) $Resting = New-Object System.Windows.Forms.TextBox $Resting.Top = 50 $Resting.Left = 420 $Resting.Width = 40 $HRZForm.Controls.Add($Resting) $MaxLabel = New-Object Windows.Forms.Label $MaxLabel.Text = "Maximum heart rate, bpm (integer from $MaxL to $MaxU)" $MaxLabel.Top = 80 $MaxLabel.Left = 20 $MaxLabel.Width = 400 $HRZForm.Controls.Add($MaxLabel) $Max = New-Object System.Windows.Forms.TextBox $Max.Top = 80 $Max.Left = 420 $Max.Width = 40 $HRZForm.Controls.Add($Max) $Warning = New-Object Windows.Forms.Label $Warning.Text = "Maximum HR must be at least $MaxRestingDiff bpm greater than resting!" $Warning.Top = 30 $Warning.Left= 20 $Warning.Width = 400 $Warning.ForeColor = "Red" $HRZForm.Controls.Add($Warning) $EstimateLabel = New-Object Windows.Forms.Label $EstimateLabel.Text = "Check the box to estimate maximum heart rate from age" $EstimateLabel.Top = 110 $EstimateLabel.Left = 20 $EstimateLabel.Width = 400 $HRZForm.Controls.Add($EstimateLabel) $FormulaLabel = New-Object Windows.Forms.Label $FormulaLabel.Text = "Select a formula to estimate max HR. Click here to compare >>" $FormulaLabel.Top = 140 $FormulaLabel.Left = 20 $FormulaLabel.Width = 430 $HRZForm.Controls.Add($FormulaLabel) $Formula1 = New-Object Windows.Forms.RadioButton $Formula1.Text = "Oakland1" $Formula1.Top = 170 $Formula1.Left = 20 $Formula1.Width = 90 $Formula1.Add_Click({ # $Formula must have Script scope in PowerShell Version 5, so the value # can be assigned by the RadioButtons. $Script:Formula = "Oakland1" }) $HRZForm.Controls.Add($Formula1) $Formula2 = New-Object Windows.Forms.RadioButton $Formula2.Text = "Oakland2" $Formula2.Top = 170 $Formula2.Left = 140 $Formula2.Width = 90 $Formula2.Add_Click({ $Script:Formula = "Oakland2" }) $HRZForm.Controls.Add($Formula2) $Formula3 = New-Object Windows.Forms.RadioButton $Formula3.Text = "Haskell" $Formula3.Top = 170 $Formula3.Left = 260 $Formula3.Width = 90 $Formula3.Add_Click({ $Script:Formula = "Haskell" }) $HRZForm.Controls.Add($Formula3) $Formula4 = New-Object Windows.Forms.RadioButton $Formula4.Text = "Cooper" $Formula4.Top = 170 $Formula4.Left = 380 $Formula4.Width = 90 $Formula4.Add_Click({ $Script:Formula = "Cooper" }) $HRZForm.Controls.Add($Formula4) $Formula5 = New-Object Windows.Forms.RadioButton $Formula5.Text = "Tanaka" $Formula5.Top = 200 $Formula5.Width = 90 $Formula5.Left = 20 $Formula5.Add_Click({ $Script:Formula = "Tanaka" }) $HRZForm.Controls.Add($Formula5) $Formula6 = New-Object Windows.Forms.RadioButton $Formula6.Text = "Gellish" $Formula6.Top = 200 $Formula6.Left = 140 $Formula6.Width = 90 $Formula6.Add_Click({ $Script:Formula = "Gellish" }) $HRZForm.Controls.Add($Formula6) $Formula7 = New-Object Windows.Forms.RadioButton $Formula7.Text = "Robergs" $Formula7.Top = 200 $Formula7.Left = 260 $Formula7.Width = 90 $Formula7.Add_Click({ $Script:Formula = "Robergs" }) $HRZForm.Controls.Add($Formula7) $Formula8 = New-Object Windows.Forms.RadioButton $Formula8.Text = "Nes, et al." $Formula8.Top = 200 $Formula8.Left = 380 $Formula8.Width = 90 $Formula8.Add_Click({ $Script:Formula = "Nes" }) $HRZForm.Controls.Add($Formula8) $AgeLabel = New-Object Windows.Forms.Label $AgeLabel.Text = "Age, years (integer from $AgeL to $AgeU)" $AgeLabel.Top = 260 $AgeLabel.Left = 20 $AgeLabel.Width = 400 $HRZForm.Controls.Add($AgeLabel) $AgeBox = New-Object System.Windows.Forms.TextBox $AgeBox.Top = 260 $AgeBox.Left = 420 $AgeBox.Width = 40 $HRZForm.Controls.Add($AgeBox) $EstimateMaxLabel = New-Object System.Windows.Forms.Label $EstimateMaxLabel.Text = "Estimated maximum heart rate, bpm" $EstimateMaxLabel.Top = 290 $EstimateMaxLabel.Left = 20 $EstimateMaxLabel.Width = 400 $HRZForm.Controls.Add($EstimateMaxLabel) $EstimateMax = New-Object System.Windows.Forms.Label $EstimateMax.Text = "" $EstimateMax.Top = 290 $EstimateMax.Left = 420 $EstimateMax.Width = 40 $HRZForm.Controls.Add($EstimateMax) $ReportLabel = New-Object System.Windows.Forms.Label $ReportLabel.Text = "Calculated training heart rate zones. Click here for help >>" $ReportLabel.Top = 320 $ReportLabel.Left = 20 $ReportLabel.Width = 400 $HRZForm.Controls.Add($ReportLabel) $ZonesHelp = New-Object Windows.Forms.Button $ZonesHelp.Text = "Zones Help" $ZonesHelp.Top = 320 $ZonesHelp.Left = 420 $ZonesHelp.Width = 110 $ZonesHelp.Add_Click({ # The user clicked the Zones Help button. Get-Help "Karvonen" }) # End of code for the Zones Help button, $ZonesHelp.Add_Click. $HRZForm.Controls.Add($ZonesHelp) $L0Label = New-Object System.Windows.Forms.Label $L0Label.Text = "Warmup 50-60% Intensity" $L0Label.Top = 350 $L0Label.Left = 40 $L0Label.Width = 340 $HRZForm.Controls.Add($L0Label) $L0BPM = New-Object System.Windows.Forms.Label $L0BPM.Text = "" $L0BPM.Top = 350 $L0BPM.Left = 380 $L0BPM.Width = 120 $HRZForm.Controls.Add($L0BPM) $L1Label = New-Object System.Windows.Forms.Label $L1Label.Text = "Level 1 (over distance) 61-70% Intensity" $L1Label.Top = 380 $L1Label.Left = 40 $L1Label.Width = 340 $HRZForm.Controls.Add($L1Label) $L1BPM = New-Object System.Windows.Forms.Label $L1BPM.Text = "" $L1BPM.Top = 380 $L1BPM.Left = 380 $L1BPM.Width = 120 $HRZForm.Controls.Add($L1BPM) $L2Label = New-Object System.Windows.Forms.Label $L2Label.Text = "Level 2 (endurance/easy speed) 71-75% Intensity" $L2Label.Top = 410 $L2Label.Left = 40 $L2Label.Width = 340 $HRZForm.Controls.Add($L2Label) $L2BPM = New-Object System.Windows.Forms.Label $L2BPM.Text = "" $L2BPM.Top = 410 $L2BPM.Left = 380 $L2BPM.Width = 120 $HRZForm.Controls.Add($L2BPM) $L3Label = New-Object System.Windows.Forms.Label $L3Label.Text = "Level 3 (endurance/long races) 76-80% Intensity" $L3Label.Top = 440 $L3Label.Left = 40 $L3Label.Width = 340 $HRZForm.Controls.Add($L3Label) $L3BPM = New-Object System.Windows.Forms.Label $L3BPM.Text = "" $L3BPM.Top = 440 $L3BPM.Left = 380 $L3BPM.Width = 120 $HRZForm.Controls.Add($L3BPM) $L4Label = New-Object System.Windows.Forms.Label $L4Label.Text = "Level 4 (anaerobic threshold) 81-90% Intensity" $L4Label.Top = 470 $L4Label.Left = 40 $L4Label.Width = 340 $HRZForm.Controls.Add($L4Label) $L4BPM = New-Object System.Windows.Forms.Label $L4BPM.Text = "" $L4BPM.Top = 470 $L4BPM.Left = 380 $L4BPM.Width = 120 $HRZForm.Controls.Add($L4BPM) $L5Label = New-Object System.Windows.Forms.Label $L5Label.Text = "Level 5 (peaking / racing) 91-100% Intensity" $L5Label.Top = 500 $L5Label.Left = 40 $L5Label.Width = 340 $HRZForm.Controls.Add($L5Label) $L5BPM = New-Object System.Windows.Forms.Label $L5BPM.Text = "" $L5BPM.Top = 500 $L5BPM.Left = 380 $L5BPM.Width = 120 $HRZForm.Controls.Add($L5BPM) $RestingFlag = New-Object Windows.Forms.Label $RestingFlag.Text = "<= Fix !!" $RestingFlag.ForeColor = "Red" $RestingFlag.Top = 50 $RestingFlag.Left = 460 $HRZForm.Controls.Add($RestingFlag) $MaxFlag = New-Object Windows.Forms.Label $MaxFlag.Text = "<= Fix !!" $MaxFlag.ForeColor = "Red" $MaxFlag.Top = 80 $MaxFlag.Left = 460 $HRZForm.Controls.Add($MaxFlag) $AgeFlag = New-Object Windows.Forms.Label $AgeFlag.Text = "<= Fix !!" $AgeFlag.ForeColor = "Red" $AgeFlag.Top = 260 $AgeFlag.Left = 460 $HRZForm.Controls.Add($AgeFlag) $FHelpLabel = New-Object Windows.Forms.Label $FHelpLabel.Text = "Select a formula and click here for help >>" $FHelpLabel.Top = 230 $FHelpLabel.Left = 120 $FHelpLabel.Width = 300 $HRZForm.Controls.Add($FHelpLabel) $FHelp = New-Object Windows.Forms.Button $FHelp.Text = "Formula Help" $FHelp.Top = 230 $FHelp.Left = 420 $FHelp.Width = 110 $FHelp.Add_Click({ # The user clicked the Formula Help button. Get-Help "$Script:Formula" }) # End of code for the Formula Help button, $FHelp.Add_Click. $HRZForm.Controls.Add($FHelp) $AllHelp = New-Object Windows.Forms.Button $AllHelp.Text = "Compare" $AllHelp.Top = 140 $AllHelp.Left = 450 $AllHelp.Width = 80 $AllHelp.Add_Click({ # The user clicked the Compare button. Get-Help "All Formulas" }) # End of code for the Formula Help button, $AllHelp.Add_Click. $HRZForm.Controls.Add($AllHelp) $Cancel = New-Object System.Windows.Forms.Button $Cancel.Text = "Cancel" $Cancel.Top = 540 $Cancel.Left = 420 $Cancel.Width = 80 $Cancel.Add_Click({ # The user clicked the Cancel button. $HRZForm.DialogResult = "Cancel" $HRZForm.Close() }) # End of code for Cancel button, $Cancel.Add_Click. $HRZForm.Controls.Add($Cancel) $Report = New-Object System.Windows.Forms.Button $Report.Text = "Exit/Report" $Report.Top = 540 $Report.Left = 210 $Report.Width = 110 $Report.Add_Click({ # The user clicked the Exit/Report button. Only exit if all values on the form # are valid. $Status = Validate-Form If ($Status -eq $True) { $HRZForm.DialogResult = "OK" $HRZForm.Close() } }) # End of code for the Exit/Report button, $Report.Add_Click. $HRZForm.Controls.Add($Report) $Calculate = New-Object System.Windows.Forms.Button $Calculate.Text = "Calculate" $Calculate.Top = 540 $Calculate.Left = 30 $Calculate.Width = 80 $Calculate.Add_Click({ # The user clicked the Calculate button. Refresh the form. # Retrieve values from the form. $RestingHR = [Int16]$Resting.Text $MaxHR = [Int16]$Max.Text $Age = [Int16]$AgeBox.Text If ($EstimateChk.CheckState -eq "Checked") {$Estimate = $True} Else {$Estimate = $False} $Status = Validate-Form If (-Not $RestingHR) { $RestingLabel.ForeColor = "Red" $RestingFlag.Visible = $True $Report.Visible = $False } If ((-Not $Estimate) -And (-Not $MaxHR)) { $MaxLabel.ForeColor = "Red" $MaxFlag.Visible = $True $Report.Visible = $False } If ($Estimate) { If (-Not $Age) { $AgeLabel.ForeColor = "Red" $AgeFlag.Visible = $True $Report.Visible = $False } } # Invoke the Down Arrow key to move the focus off of the Calculate button. # This allows the script to recognize when the user presses the Enter key. [System.Windows.Forms.SendKeys]::SendWait("{DOWN}") }) # End of code for the Calculate button, $Calculate.Add_Click. $HRZForm.Controls.Add($Calculate) $EstimateChk = New-Object System.Windows.Forms.CheckBox $EstimateChk.Top = 110 $EstimateChk.Left = 420 $EstimateChk.Add_Click({ # Refresh the form. $Status = Validate-Form If ($EstimateChk.CheckState -eq "Checked") { # The user checked the Estimate check box. # Show only the relevant controls on the form. $MaxLabel.Visible = $False $Max.Visible = $False $MaxFlag.Visible = $False $AgeLabel.Visible = $True $AgeBox.Visible = $True $FormulaLabel.Visible = $True $Formula1.Visible = $True $Formula2.Visible = $True $Formula3.Visible = $True $Formula4.Visible = $True $Formula5.Visible = $True $Formula6.Visible = $True $Formula7.Visible = $True $Formula8.Visible = $True } Else { # The user unchecked the Estimate check box. # Show only the relevant controls on the form. $MaxLabel.Visible = $True $Max.Visible = $True $AgeLabel.Visible = $False $AgeBox.Visible = $False $FormulaLabel.Visible = $False $Formula1.Visible = $False $Formula2.Visible = $False $Formula3.Visible = $False $Formula4.Visible = $False $Formula5.Visible = $False $Formula6.Visible = $False $Formula7.Visible = $False $Formula8.Visible = $False } }) # End of code for the EstimateChk checkbox, $EstimateChk.Add_Click. $HRZForm.Controls.Add($EstimateChk) # Retrieve parameters from the command line and populate the form. # $Formula must have Script scope in PowerShell Version 5, so the value # can be assigned by the RadioButtons. If (-Not $Script:Formula) {$Script:Formula = "Oakland1"} # Select formula for estimated maximum heart rate. Switch ($Script:Formula) { "Oakland1" {$Formula1.Checked = $True} "Oakland2" {$Formula2.Checked = $True} "Haskell" {$Formula3.Checked = $True} "Cooper" {$Formula4.Checked = $True} "Tanaka" {$Formula5.Checked = $True} "Gellish" {$Formula6.Checked = $True} "Robergs" {$Formula7.Checked = $True} "Nes" {$Formula8.Checked = $True} Default { Write-Host "Formula for estimating maximum heart rate ($Script:Formula) not" ` "recognized. Default to Oakland1." -ForegroundColor Red -BackgroundColor Black $Script:Formula = "Oakland1" $Formula1.Checked = $True } } If ($RestingHR) {$Resting.Text = $RestingHR} Else {$Resting.Text = ""} If ($MaxHR) {$Max.Text = $MaxHR} Else {$Max.Text = ""} If ($Estimate) {$EstimateChk.CheckState = "Checked"} Else { If ((-Not $MaxHR) -And $Age) { $EstimateChk.CheckState = "Checked" $Estimate = $True } } If ($Age) {$AgeBox.Text = $Age} Else {$AgeBox.Text = ""} # Validate the values on the form. $Status = Validate-Form $HRZForm.Add_Load({ $HRZForm.Activate() }) # Display the form to the user. $Result = $HRZForm.ShowDialog() If ($Result -eq "Cancel") { # Cancel button clicked. Write-Host "Script canceled" -ForegroundColor Red -BackgroundColor Black Break } If ($Result -eq "OK") { # Exit/Report button clicked. # Retrieve values from the form. $RestingHR = [Int16]$Resting.Text $MaxHR = [Int16]$Max.Text $Age = [Int16]$AgeBox.Text If ($EstimateChk.CheckState -eq "Checked") {$Estimate = $True} Else {$Estimate = $False} } } # End of code when PowerShell is not constrained. # User has exited from the form or supplied all values at the command line. Output results. # Standardize the case of the Formula. # $Formula must have Script scope in PowerShell Version 5, so the value # can be assigned by the RadioButtons. If ($Script:Formula) { $Script:Formula = $Script:Formula.SubString(0, 1).ToUpper() ` + $Script:Formula.SubString(1).ToLower() } If ($Estimate) { $MaxHR = Estimate-MaxHR $Age $Script:Formula } # Calculate the training heart rate zones. $L = Calculate-Zones $RestingHR $MaxHR # Display results. If ($Black) { # Output without using the Write-Host cmdlet so the output can be redirected to a text file. "HRZones.ps1" "$Version" If ($Age) {"Age: $Age"} "Resting heart rate: $RestingHR bpm" If ($Estimate -eq $True) {"Maximum heart rate: $MaxHR bpm (estimate, $Script:Formula)"} Else {"Maximum heart rate: $MaxHR bpm"} "Calculated training heart rate zones ($Today):" "Level Description Intensity bpm" "----- ---------------------- --------- ----------" " warmup 50-60% " + $L[0] + " - " + $L[1] " 1 over distance 61-70% " + $L[2] + " - " + $L[3] " 2 endurance / easy speed 71-75% " + $L[4] + " - " + $L[5] " 3 endurance / long races 76-80% " + $L[6] + " - " + $L[7] " 4 anaerobic threshold 81-90% " + $L[8] + " - " + $L[9] " 5 peaking / racing 91-100% " + $L[10] + " - " + $L[11] } Else { # Output using the Write-Host cmdlet and specify colors for emphasis. Write-Host "HRZones.ps1" -ForegroundColor green -BackgroundColor Black Write-Host "$Version" -ForegroundColor green -BackgroundColor Black If ($Age) {Write-Host "Age: $Age" -ForegroundColor green -BackgroundColor Black} Write-Host "Resting heart rate: $RestingHR bpm" ` -ForegroundColor green -BackgroundColor Black If ($Estimate -eq $True) {Write-Host "Maximum heart rate: $MaxHR bpm" ` "(estimate, $Script:Formula)" -ForegroundColor green -BackgroundColor Black} Else {Write-Host "Maximum heart rate: $MaxHR bpm" ` -ForegroundColor green -BackgroundColor Black} Write-Host "Calculated training heart rate zones ($Today):" ` -ForegroundColor Yellow -BackgroundColor Black Write-Host "Level Description Intensity bpm" ` -ForegroundColor Yellow -BackgroundColor Black Write-Host "----- ---------------------- --------- ---------" ` -ForegroundColor Yellow -BackgroundColor Black Write-Host " warmup 50-60% ", $L[0], "-", $L[1] ` -ForegroundColor Yellow -BackgroundColor Black Write-Host " 1 over distance 61-70% ", $L[2], "-", $L[3] ` -ForegroundColor Yellow -BackgroundColor Black Write-Host " 2 endurance / easy speed 71-75% ", $L[4], "-", $L[5] ` -ForegroundColor Yellow -BackgroundColor Black Write-Host " 3 endurance / long races 76-80% ", $L[6], "-", $L[7] ` -ForegroundColor Yellow -BackgroundColor Black Write-Host " 4 anaerobic threshold 81-90% ", $L[8], "-", $L[9] ` -ForegroundColor Yellow -BackgroundColor Black Write-Host " 5 peaking / racing 91-100% ", $L[10], "-", $L[11] ` -ForegroundColor Yellow -BackgroundColor Black }