plugins/MsDynamicsCRM365/Public/DataVerse/Get-Record.ps1




function Get-Record {

    [CmdletBinding(DefaultParameterSetName='RecordSet')]
    param (
         [Parameter(Mandatory=$true)][String]$TableName
        ,[Parameter(Mandatory=$false)][Switch]$ResolveLookups = $false

        ,[Parameter(Mandatory=$false,ParameterSetName='RecordSet')][int]$Top = 0
        #,[Parameter(Mandatory=$false,ParameterSetName='RecordSet')][int]$Skip = 0
        ,[Parameter(Mandatory=$false,ParameterSetName='RecordSet')][String]$Filter = ""
        ,[Parameter(Mandatory=$false,ParameterSetName='RecordSet')][String]$Expand = ""
        #,[Parameter(Mandatory=$false,ParameterSetName='RecordSet')][String]$Search = ""
        ,[Parameter(Mandatory=$false,ParameterSetName='RecordSet')][String[]]$Select = ""
        ,[Parameter(Mandatory=$false,ParameterSetName='RecordSet')][String[]]$OrderBy = ""
        ,[Parameter(Mandatory=$false,ParameterSetName='RecordSet')][Switch]$Count = $false
        ,[Parameter(Mandatory=$false,ParameterSetName='RecordSet')][Switch]$Paging = $false
        ,[Parameter(Mandatory=$false,ParameterSetName='RecordSet')][Switch]$DeltaTracking = $false

        ,[Parameter(Mandatory=$false,ParameterSetName='RecordById')][String]$Id = ""
        #,[Parameter(Mandatory=$false,ParameterSetName='RecordsById')][String[]]$Id = ""

        ,[Parameter(Mandatory=$false,ParameterSetName='RecordByDelta')][Switch]$LoadDelta = $false


    )

    begin {

        #-----------------------------------------------
        # DEBUG / NOTES
        #-----------------------------------------------

        Write-Verbose $PSCmdlet.ParameterSetName -verbose

        <#
 
            TODO implement oData options https://learn.microsoft.com/en-us/odata/concepts/queryoptions-overview
            https://learn.microsoft.com/de-de/power-apps/developer/data-platform/webapi/query-data-web-api
            https://github.com/MicrosoftDocs/powerapps-docs/blob/main/powerapps-docs/developer/data-platform/webapi/web-api-query-data-sample.md
            [x] $filter
            [x] $select
            [x] $expand
            [x] $orderby
            [x] $top
            [x] $count
            [ ] $apply -> used to aggregate data, not needed now
            [x] $skip -> not supported in dynamics
            [x] $search -> not supported in dynamics
 
 
        #>


        #-----------------------------------------------
        # DEFAULT OUTPUT
        #-----------------------------------------------

        $records = [Array]@()


        #-----------------------------------------------
        # DEFAULT PARAMETERS
        #-----------------------------------------------

        $callParams = [Hashtable]@{
            "Method" = "GET"
        }
        $preferOptions = [System.Collections.ArrayList]@()

        # Resolve GUIDS with lookup values
        If ( $ResolveLookups -eq $true ) {
            [void]$preferOptions.add('odata.include-annotations="*"')
            #'odata.include-annotations="OData.Community.Display.V1.FormattedValue"'
            # also available: "Microsoft.Dynamics.CRM.associatednavigationproperty,Microsoft.Dynamics.CRM.lookuplogicalname"
        }

        If ( $Count -eq $true) {
            [void]$preferOptions.add("odata.maxpagesize=1")
        }

        If ( $Paging -eq $true ) {
            [void]$preferOptions.add("odata.maxpagesize=4500")
        }

        If ( $DeltaTracking -eq $true ) {
            [void]$preferOptions.add("odata.track-changes")
        }

        If ( $preferOptions.count -gt 0 ) {
            $header = [Hashtable]@{
                "Prefer" = ( $preferOptions -join ", " ) #'odata.include-annotations="*", odata.maxpagesize=2'
                #"Prefer" = 'odata.include-annotations="OData.Community.Display.V1.FormattedValue"' # also available: "Microsoft.Dynamics.CRM.associatednavigationproperty,Microsoft.Dynamics.CRM.lookuplogicalname"
            }
            $callParams.Add("Headers", $header)
        }


        #-----------------------------------------------
        # GET DELTALINKS
        #-----------------------------------------------

        $deltaTrackingFile = ".\deltalinks.json" # TODO put this into settings?
        If ( $DeltaTracking -eq $true -or $PSCmdlet.ParameterSetName -eq "RecordByDelta") {

            # Load the file, if existing, otherwise create a new object
            If ( (Test-Path -Path $deltaTrackingFile) -eq $true ) {
                $deltaLinks = Get-Content -Path $deltaTrackingFile -Encoding UTF8 -Raw | convertfrom-json
            } else {
                $deltaLinks = [PSCustomObject]@{}
            }

        }


    }

    process {


        #-----------------------------------------------
        # LOAD RECORD(S)
        #-----------------------------------------------

        Switch ( $PSCmdlet.ParameterSetName ) {

            #-----------------------------------------------
            # LOAD RECORDSET
            #-----------------------------------------------

            # Load multiple records
            "RecordSet" {

                #-----------------------------------------------
                # BUILD THE QUERY
                #-----------------------------------------------

                $query = [PSCustomObject]@{}

                If ( $Top -ne 0 ) {
                    $query | Add-Member -MemberType NoteProperty -Name '$top' -Value $Top
                }

                # If ( $Skip -ne 0 ) {
                # $query | Add-Member -MemberType NoteProperty -Name '$skip' -Value $Skip
                # }

                If ( $Filter -ne "" ) {
                    $query | Add-Member -MemberType NoteProperty -Name '$filter' -Value $Filter
                }

                If ( $Expand -ne "" ) {
                    $query | Add-Member -MemberType NoteProperty -Name '$expand' -Value $Expand
                }

                # If ( $Search -ne "" ) {
                # $query | Add-Member -MemberType NoteProperty -Name '$search' -Value $Search
                # }

                If ( $Select -ne "" ) {
                    $query | Add-Member -MemberType NoteProperty -Name '$select' -Value ( $Select -join "," )
                }

                If ( $OrderBy -ne "" ) {
                    $query | Add-Member -MemberType NoteProperty -Name '$orderby' -Value ( $OrderBy -join ", " )
                }

                If ( $Count -eq $true ) {
                    $query | Add-Member -MemberType NoteProperty -Name '$count' -Value "true"
                }


                #-----------------------------------------------
                # BUILD QUERY
                #-----------------------------------------------

                If (( $query.psobject.properties ).count -gt 0 ) {
                    $callParams.Add("Query", $query)
                }


                #-----------------------------------------------
                # DEFINE THE PATH AND PAGING AND EXECUTE THE CALL
                #-----------------------------------------------

                # Add path
                $callParams.Add("Path", $TableName)

                # Activate paging, if used
                If ( $Paging -eq $true ) {
                    $callParams.Add("Paging", $true)
                }

                # Execute the call
                $records = Invoke-Dynamics @callParams #@( ( Invoke-Dynamics @callParams ).value )


                #-----------------------------------------------
                # CHOOSE WHICH DATA TO RETURN
                #-----------------------------------------------

                If ( $Count -eq $true ) {
                    $return = $records."@odata.count"
                } else {
                    $return = $records.value
                    # If ( $Paging -eq $true ) {
                    # $return = $records
                    # } else {
                    # $return = $records.value
                    # }
                }


                #-----------------------------------------------
                # SAVE DELTA LINK, IF USED
                #-----------------------------------------------

                If ( $DeltaTracking -eq $true ) {

                    # Overwrite existing value or create a new one
                    If ( $deltaLinks.PSObject.Properties.Name -contains $TableName ) {
                        $deltaLinks.$TableName = $records."@odata.deltaLink"
                    } else {
                        $deltaLinks | Add-Member -MemberType NoteProperty -Name $TableName -Value $records."@odata.deltaLink"
                    }

                    # Save that file
                    ConvertTo-Json -InputObject $deltaLinks | Set-Content -Path $deltaTrackingFile -Encoding UTF8

                }


            }


            #-----------------------------------------------
            # LOAD DELTA
            #-----------------------------------------------

            "RecordByDelta" {

                $query = [PSCustomObject]@{}

                #-----------------------------------------------
                # CHANGE PARAMETERS, IF WE USE DELTAS
                #-----------------------------------------------

                If ( $deltaLinks.psobject.properties.name -contains $TableName ) {

                    #@odata.deltaLink : [uri]'https://orgbdda5a9d.crm11.dynamics.com/api/data/v9.2/contacts?$select=fullname,lastname&$deltatoken=4949752%2110%2f20%2f2023%2014%3a55%3a21'
                    #$table = $u.segments[-1]
                    $deltalink = [uri]$deltaLinks.$TableName
                    $deltaQuery = [System.Web.HttpUtility]::ParseQueryString($deltalink.Query)

                    $query | Add-Member -MemberType NoteProperty -Name '$select' -Value $deltaQuery['$select']
                    $query | Add-Member -MemberType NoteProperty -Name '$deltatoken' -Value $deltaQuery['$deltatoken']

                    If (( $query.psobject.properties ).count -gt 0 ) {
                        $callParams.Add("Query", $query)
                    }

                    # Activate paging for deltaload
                    $callParams.Add("Paging", $true)

                } else {

                    $msg = "There is no deltalink for your table available"
                    Write-Log -severity ERROR -Message $msg
                    throw $msg

                }


                #-----------------------------------------------
                # DEFINE THE PATH AND PAGING AND EXECUTE THE CALL
                #-----------------------------------------------

                # Add path
                $callParams.Add("Path", $TableName)

                # Execute the call
                $records = Invoke-Dynamics @callParams #@( ( Invoke-Dynamics @callParams ).value )

                # Return value
                $return = $records.value
                #$Script:pluginDebug = $records

                #-----------------------------------------------
                # SAVE DELTA LINK, IF USED
                #-----------------------------------------------

                # Overwrite existing value or create a new one
                If ( $deltaLinks.PSObject.Properties.Name -contains $TableName ) {
                    $deltaLinks.$TableName = $records."@odata.deltaLink"
                } else {
                    $deltaLinks | Add-Member -MemberType NoteProperty -Name $TableName -Value $records."@odata.deltaLink"
                }

                # Save that file
                ConvertTo-Json -InputObject $deltaLinks | Set-Content -Path $deltaTrackingFile -Encoding UTF8


            }


            #-----------------------------------------------
            # LOAD SINGLE RECORD
            #-----------------------------------------------

            "RecordById" {

                #-----------------------------------------------
                # DEFINE THE PATH AND EXECUTE THE CALL
                #-----------------------------------------------

                $callParams.Add("Path", "$( $TableName )($( $Id ))")

                #If ( (Test-IsGuid -StringGuid $Id) -eq $true ) {
                    $return = Invoke-Dynamics @callParams
                #}

            }

            # "RecordsById" {
                # TODO not implemented yet
            # }

        }


        #-----------------------------------------------
        # RETURN
        #-----------------------------------------------

        $return


    }

    end {

    }

}