Public/Set-BMSParameter.ps1

Function Set-BMSParameter {
    [CmdletBinding()]
    Param([Parameter(Mandatory=$true)]$Value)
    DynamicParam {
     
        # Set the dynamic parameters' name
        $ParameterName = 'Instruction'

        # Create the dictionary
        $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary

        # Create the collection of attributes
        $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]

        # Create and set the parameters' attributes
        $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
        $ParameterAttribute.Mandatory = $true
        $ParameterAttribute.Position = 0

        # Add the attributes to the attributes collection
        $AttributeCollection.Add($ParameterAttribute)

        # Generate and set the ValidateSet
        $arrSet = (Get-BMSInstructionList -Type Configurable).Instruction
        $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)

        # Add the ValidateSet to the attributes collection
        $AttributeCollection.Add($ValidateSetAttribute)

        # Create and return the dynamic parameter
        $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection)
        $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter)
        return $RuntimeParameterDictionary
    }

    begin {
        $Instruction = $PSBoundParameters[$ParameterName]
        trap {
            $Error[0].Exception
            $Error[0].InvocationInfo
            break
        }
    }
    
    
       
    process {
        $InstructionPair = Build-BMSMessage (Assert-BMSMessage -Command @{$Instruction=$Value})
        $OldParameter = Get-BMSParameter $Instruction
        ("--------- Existing Value ---------")
        ("Name: [" + $OldParameter.Description + "]")
        ("Value: [" + $OlDParameter.Value + " " + $OldParameter.Unit + "]")
        ("--------- Proposed Value ---------")
        ("Name: [" + $InstructionPair.Instruction.Name + "]")
        ("Value: [" + $InstructionPair.Plain + " " + $InstructionPair.Instruction.Return.Unit + "]")
        ("---------------------------------- ")
        
        Write-Warning "Setting BMS parameters to incorrect values can permanently damage equipment! `r`nExceeding chemistry boundries can cause fire and explosion risk."
        $confirmation = Read-Host -Prompt "Confirm the name of the instruction you are attempting to set and press [Enter]`r`nPressing [Enter] without confirmation word will abort."
        if ($Confirmation -cne $InstructionPair.Command) {
            Throw "Command not confirmed."
        }
        
        $r = 0
        do {
            try {
                $SetParameter = Convert-BMSMessage (Send-BMSMessage $InstructionPair)
                break
            }
            catch [System.Management.Automation.MethodInvocationException] {
                $port.BaseStream.Dispose()
                Remove-Variable port -Scope Global
                Write-Warning "Retrying $r"
            }    
            $r++
        }
        until ($r -eq $BMSInstructionSet.Config.Session.Retries)
        
        Switch (($SetParameter.BMSData.0).Value) {
            SET {
                #get the value again from the BMS to check if it changed
                $NewParameter = Get-BMSParameter $Instruction

                #because the "Set" object is carried forward from a string value, we need to get the value type
                #according to the library definition, then format accordingly so they compare properly.
                Switch ($NewParameter.Instruction.Return.Value) {
                    float {$SetValue = [single]("{0:N}" -f [float]$SetParameter.Plain)}
                    int {$SetValue = [int]("{0:D}" -f [int]$SetParameter.Plain)}
                    Default {$SetValue = $SetParameter.Plain}
                }

                $Result = @{
                    "Description" = $NewParameter.Description;
                    "Unit"= $NewParameter.Unit;
                    "Set" = $SetValue;
                    "Get" = $NewParameter.Value
                }

                #cast comparison to string because some cases compare single to double
                #or some are comparing an integer to a char, and there's no reason to write a robust handler
                #for those cases.
                if ([string]$Result.Get -eq [string]$Result.Set) {
                    $Result.Add("Success",$true)
                }
                else {
                    $Result.Add("Success",$false)
                }
            }

            ERROR1 {
                Write-Error ("BMS Returned [ERROR1] during parameter set attempt. Value Unchanged.")
            }

            Default {
                Write-Error ("Unknown state found: [" + ($SetParameter.BMSData.0).Value + "]")
            }
        }
        
    }

    end {
        return [PSCustomObject]$Result
    }
}