Function Update-ISMBusinessObject {
    <#
.SYNOPSIS
  Updates business object field values for specific records.
.DESCRIPTION
  By providing the Business Object and the Record ID (RecID), the function will dynamically query the Business Object's metadata to provide a parameter list of all available fields for that particular business object. 

  Additionally, use of the -RawJSONBody parameter allows a raw JSON payload to be passed directly if desired.
.PARAMETER -BusinessObject
    The Business Object you are interacting with. (Incidents, CIs, CI__ActiveDirectorys, ServiceReqs, Locations, Employees, Manufacturers, StandardUserTeams, Problems, Changes, etc...)
.PARAMETER -RecID
    The Record ID (RecID) of the specific record you wish to interact with.
.PARAMETER -RawJSONBody
    Optional parameter for passing a raw JSON payload as opposed to letting the function dynamically query for the fields of the supplied business object and formatting the payload for you.
.PARAMETER -DetailedOutput
    Optional parameter that will return the API URI and JSON Payload in addition to the standard output.
.INPUTS
  Business Object, RecID and dynamic parameter values or a JSON payload.
.OUTPUTS
  Returns the updated business object.
.NOTES
  Version:        1.0
  Author:         Sean Carlton
  Creation Date:  08/16/2022
  Purpose/Change: Initial script development
.EXAMPLE
 Update-ISMBusinessObject -BusinessObject cis -RecID "5788C7AB6E1E44AD8464FED18A510609" -Description "Important Description" -SHS_BusinessCriticality "Entity Essential"

 =======
 This example demonstrates updating the Description and SHS_BusinessCriticality fields on a CI record.
 =======
.EXAMPLE
 $JSON_Payload = @"
    {
        "Description":  "Test Description",
        "SHS_BusinessCriticality":  "Normal"
    }
 "@

 Update-ISMBusinessObject -BusinessObject cis -RecID "5788C7AB6E1E44AD8464FED18A510609" -RawJSONBody $JSON_Payload

 =======
 This example demonstrates updating the Description and SHS_BusinessCriticality fields on a CI record by passing a raw JSON payload using the -RawJSONBody parameter. 
 =======
.EXAMPLE
 Update-ISMBusinessObject -BusinessObject employees -RecID "F922E4482A224E4FAE882D2B32AEBB6B" -DisplayName "John Smith"

 =======
 This example demonstrates updating the Display Name field on an employee record.
 =======
 
#>
    [CmdletBinding()]
    param (
        [Alias("BO")]
        [Parameter(HelpMessage="The business object you intend to update",
            Mandatory=$true)]
        [string]
        $BusinessObject,
        [Parameter(HelpMessage="The Record ID of the record you want to update",
            Mandatory=$true)]
        [string]
        $RecID,

        [Parameter(HelpMessage="Optional parameter to pass a raw JSON Payload as opposed to leveraging the dynamic parameter query and generating the payload",
            Mandatory=$false)]
        [string]
        $RawJSONBody,

        [Parameter(HelpMessage="Optional parameter ouput the JSON Payload that was generated/sent along with the standard output of the function",
            Mandatory=$false,
            DontShow)]
        [switch]
        $DetailedOutput,
     
        ### API Connection Parameters ###
        [Parameter(HelpMessage = 'Tenant URL', DontShow)]
        [string]$Tenant = (Connect-ISM)[1],
        [Parameter(HelpMessage = 'Authorization Header', DontShow)]
        [hashtable]$Headers = (Connect-ISM)[0]
    )

    dynamicparam
    {
        #Create a parameter dictionary. This object is ultimately leveraged to create a parameter for every field returned from the metadata. 
        $paramDictionary = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameterDictionary

        $BO_Attributes = (Get-ISMBusinessObject -BusinessObject $BusinessObject -Metadata)

        if ($BO_Attributes.EntityType.count){
            $BO_Attributes = $BO_Attributes.EntityType[-1].Property | Where-Object {$_.Name -ne "RecID"} | Sort-Object "Name"
        } else {
            $BO_Attributes = $BO_Attributes.EntityType.Property | Where-Object {$_.Name -ne "RecID"} | Sort-Object "Name"
        }
        
        Foreach ($Field in $BO_Attributes){
            # write-host "Parsing $($Field.name) with type $($Field.Type)"
            $Attribute = New-Object System.Management.Automation.ParameterAttribute
            
            ##Account for any datatype name discrepancies between Powershell and ISM
            switch ($Field.Type.split(".")[1]){
                "Date" {$AttributeType = "DateTime"}
                "Boolean" {$AttributeType = "bool"}
                "Byte" {$AttributeType = "Byte"}
                "String" {$AttributeType = "String"}
                default {$AttributeType = "String"}
            }

            $dynParam = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameter($Field.Name,
            $AttributeType, $Attribute)

            $paramDictionary.Add($Field.Name, $dynParam)

        }#End Foreach
        
        #Return the collection of dynamic parameters
        $paramDictionary

    }#END DYNAMIC PARAMETER

    BEGIN {

        $URI = "$Tenant/api/odata/businessobject/$BusinessObject('$RecID')"
        
        If ($RawJSONBody){
            $Params = $RawJSONBody
        } else {
            $Params = $PSBoundParameters
            $Params.Remove("BusinessObject") | Out-Null #//The Business Object is passed in the URI.
            $Params.Remove("RecID") | Out-Null #//The RecID is passed in the URI.
            $Params.Remove("DetailedOutput") | Out-Null #//Function-specific parameter.
            $Params.Remove("RawJSONBody") | Out-Null #//Function-specific parameter.
            $Params = $Params | ConvertTo-JSON
        }

        try {
    
            $UpdatedBusObj = Invoke-RestMethod -Method PATCH -URI $uri -Headers $headers -Body $Params

        }

        catch {
            write-warning "Failed updating the $BusinessObject Object with RecID $RecID!"
            $_.ErrorDetails.Message
            $_.Exception.Message
        }

    }


    END{
    
        if ($DetailedOutput){

            return $UpdatedBusObj, $Params, $uri

        } else {     
            
            return $UpdatedBusObj

        }

    }
     
}#END Update-ISMBusinessObject Function

New-Alias -Name Update-ISMBO -Value Update-ISMBusinessObject -Force