Get-AZTableEntity.psm1

$FunctionScriptName = "Get-AZTableEntity"
Write-Verbose "Import-Start| [$($FunctionScriptName)]"

#* Dependencies
# Import-Function -Scope "Support" -Function "Get-SAStokenValidity" -Version "1.X"

function Get-AZTableEntity {
    <#
        .SYNOPSIS
            Get Table entrys
         
        .DESCRIPTION
            Get all or filtered entrys from AZ table API.
            Using SAS token to auth.
            Basic error handling & token validation
                 
        .PARAMETER Config
            Config param
            Expects following values: StorageAccount / TableName / Sastoken
            All 3 can be forced by direct param
         
        .PARAMETER paramConfig
            Same as 'Config' but multiple
         
        .PARAMETER StorageAccount
            Storageaccount to use
            Overrides value from config param
         
        .PARAMETER TableName
            TableName to use
            Overrides value from config param
         
        .PARAMETER sastoken
            sastoken to use
            Overrides value from config param
         
        .PARAMETER PartitionKey
            PartitionKey used in filter
            None = *
         
        .PARAMETER RowKey
            RowKey used in filter
            None = *
         
        .PARAMETER filter
            Custom filter according to Azure Table filter property
            e.g.: "Lastname eq 'John'"
            None = *
 
        .PARAMETER select
            Custom select query according to Azure Table filter property
            e.g.: "Partitionkey,RowKey,Name
            None = *
         
        .PARAMETER ignoreTables
            ignored Tables from piped config selection
         
        .PARAMETER skipSAScheck
            ignore SAStoken check
            recommended if a lot of tables with the same token shall be used
         
        .EXAMPLE
            Get-AZTableEntity -Config $Config -ALL
            $MoreConfigs | Get-AZTableEntity -ALL
            Get-AZTableEntity -Config $Config -sastoken $sastoken -RowKey $RowKey -ALL
         
        .NOTES
            AUTHOR: Ken Dobrunz // Ken.Dobrunz@Direkt-Gruppe.de | Direkt Gruppe
            WEBSITE: http://kensmagic.site
             
            LASTEDIT: 07.08.2023 - Version: 3.4
        #>

    [cmdletbinding()]
    Param(
        # Tableconfig - Config or other 3 needed
        [Parameter()]$Config,
        [parameter(ValueFromPipeline = $True)]$paramConfig,
        [Parameter()][Alias('Storage')]$StorageAccount,
        [Parameter()][Alias('Table')]$TableName,
        [Parameter()][Alias('sas')]$sastoken, 

        [Parameter()][Alias('PKey')]$PartitionKey,
        [Parameter()][Alias('RKey')]$RowKey,
        [Parameter()]$filter,
        [Parameter()]$select,
        
        #* Generic
        [Parameter()]$ignoreTables,
        [Parameter()][switch]$skipSAScheck
    )
    Begin {
        $SelfIdentifier = "GETtable"
        
        # API Header
        $headers = @{
            "x-ms-version" = "2019-07-07"
            Accept         = "application/json;odata=minimalmetadata"
        }
        $ProgressPreference = 'SilentlyContinue'
        
        $returnlist = New-Object PSObject
        $functionverbosecount = 0
    }
    Process {
        #* Get / set / check param
        if ($paramConfig) { $Config = @(); $Config = $paramConfig }
        $TableName = if ($TableName) { $TableName }elseif ($Config.Table) { $Config.Table }else { Write-Error "[$($SelfIdentifier)] No TableName provided" }
        $StorageAccount = if ($StorageAccount) { $StorageAccount }elseif ($Config.StorageAccount) { $Config.StorageAccount }else { Write-Error "[$($SelfIdentifier)] No StorageAccount provided" }
        $sastoken = if ($sastoken) { $sastoken }elseif ($Config.sastoken) { $Config.sastoken }else { Write-Error "[$($SelfIdentifier)] No sastoken provided" }
            
        if (!$skipSAScheck) {
            if (!(Get-SAStokenValidity -ReadOnlyObject -Table -sastoken $sastoken)) { throw "[$($SelfIdentifier)] Sastoken not valid" }
        } else {
            Write-Verbose "[$($SelfIdentifier)] Skipped sas check due to skip flag"
        }

        Write-Verbose "[$($SelfIdentifier)] Using table: $($Tablename) @ $($StorageAccount)"
        
        #* URI
        $base_uri = "https://$($StorageAccount).table.core.windows.net/" + $TableName
        $table_uri = $base_uri + $sastoken
        
        #* Add filterstring
        if (!$PartitionKey -and !$RowKey -and !$filter) {
            Write-Debug "[$($SelfIdentifier)] No Filter used [$($PartitionKey)] [$($RowKey)]"
        } else {
            $filterstring = "filter="
            if ($PartitionKey) { $filterstring = $filterstring + "PartitionKey eq '$PartitionKey'" }
            
            if ($Rowkey) {
                if ($PartitionKey) { $filterstring = $filterstring + " and " }
                $filterstring = $filterstring + "RowKey eq '$RowKey'"
            }
            
            if($filter) {
                if ($PartitionKey -or $RowKey) { $filterstring = $filterstring + " and " }
                $filterstring = $filterstring + $filter
            }
            
            # Set URI
            $table_uri = $table_uri + "&$" + $filterstring
        }

        #* Add selectstring
        if ($select) {
            $selectstring = "select=" + $select
            # Set URI
            $table_uri = $table_uri + "&$" + $selectstring
        }
        
        Write-Debug "[$($SelfIdentifier)] Using TableURI: $($table_uri)"
        
        #* Get data [Loop]
        $nextURI = $table_uri
        $plist = @( )
        if ($TableName -in $ignoreTables) { $nextURI = $null; Write-Verbose "[$($SelfIdentifier)] Skipping table [$($TableName)] due to ignorelist" }
        while ($null -ne $nextURI) {
            $whilesink = @{ }
            $restresponse = Invoke-WebRequest -Method GET -Uri $nextURI -Headers $headers -ContentType application/json -UseBasicParsing
            $plist += (($restresponse.Content | ConvertFrom-Json).value)
            $whilesink.NextPKey = $restresponse.Headers.'x-ms-continuation-NextPartitionKey'
            $whilesink.NextRKey = $restresponse.Headers.'x-ms-continuation-NextRowKey'

            if ($null -ne $whilesink.NextPKey) {
                $nextURI = $table_uri + "&NextPartitionKey=$($whilesink.NextPKey)"
                if ($null -ne $whilesink.NextRKey) { $nextURI = $nextURI + "&NextRowKey=$($whilesink.NextRKey)" }
                Write-Debug "[$($SelfIdentifier)] NextURI: $($nextURI)"
            } else {
                $nextURI = $null
            }
        }
              
        if ($TableName -in $ignoreTables) { Write-Debug "[$($SelfIdentifier)] Skip" }else { Add-Member -InputObject $returnlist -MemberType NoteProperty -Name ($TableName + "_List") -Value $plist }
        $functionverbosecount++
        Write-Debug "[$($SelfIdentifier)] [Process] block end"
    }
    End {
        Write-Debug "[$($SelfIdentifier)] [End] block start"
        if ($functionverbosecount -gt 1) { Write-Verbose "[$($SelfIdentifier)] Ran $($functionverbosecount) configs" }

        $returncount = ((Get-Member -InputObject $returnlist -MemberType NoteProperty).Name).Count
        Write-Verbose "[$($SelfIdentifier)] returning [$($returncount)] different entries"
        if ($returncount -eq 0) {
            Write-Verbose "[$($SelfIdentifier)] Get - 0 return"; return @{ }
        } elseif ($null -eq $returncount) {
            Write-Verbose "[$($SelfIdentifier)] Get - null return"; return @{ }
        } elseif ($returncount -eq 1) {
            return ($returnlist.((Get-Member -InputObject $returnlist -MemberType NoteProperty).Name)); Write-Debug "[$($SelfIdentifier)] return eq1"
        } elseif ($returncount -gt 1) {
            return $returnlist
        } else { Write-Error "[$($SelfIdentifier)] unexpected return" }
    }
} #v3.4

Export-ModuleMember -Function *
Write-Verbose "Import-END| [$($FunctionScriptName)]"