Private/NestedFunctions/Get-JCObject.ps1

Function Get-JCObject
{
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    Param()
    DynamicParam
    {
        $JCTypes = Get-JCType
        # Build parameter array
        $RuntimeParameterDictionary = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameterDictionary
        New-DynamicParameter -Name:('Type') -Type:([System.String]) -Mandatory -Position:(0) -ValueFromPipelineByPropertyName -ValidateNotNullOrEmpty -ValidateSet:($JCTypes.Types) -RuntimeParameterDictionary:($RuntimeParameterDictionary) | Out-Null
        New-DynamicParameter -Name:('Id') -Type([System.String[]]) -Mandatory -Position(1) -ValueFromPipelineByPropertyName -ValidateNotNullOrEmpty -ParameterSets(@('ById')) -Alias:(($JCTypes.ById) | Where-Object {$_ -ne 'Id'} | Select-Object -Unique) -RuntimeParameterDictionary:($RuntimeParameterDictionary) | Out-Null
        New-DynamicParameter -Name:('Name') -Type([System.String[]]) -Mandatory -Position(1) -ValueFromPipelineByPropertyName -ValidateNotNullOrEmpty -ParameterSets:(@('ByName')) -Alias:(($JCTypes.ByName) | Where-Object {$_ -ne 'Name'} | Select-Object -Unique) -RuntimeParameterDictionary:($RuntimeParameterDictionary) | Out-Null
        New-DynamicParameter -Name:('SearchBy') -Type:([System.String]) -Mandatory -Position:(1) -ValueFromPipelineByPropertyName -ValidateNotNullOrEmpty -ParameterSets:('ByValue') -ValidateSet:(@('ById', 'ByName')) -RuntimeParameterDictionary:($RuntimeParameterDictionary) | Out-Null
        New-DynamicParameter -Name:('SearchByValue') -Type:([System.String[]]) -Mandatory -Position:(2) -ValueFromPipelineByPropertyName -ValidateNotNullOrEmpty -ParameterSets:('ByValue') -HelpMessage:('Specify the item which you want to search for. Supports wildcard searches using: *') -RuntimeParameterDictionary:($RuntimeParameterDictionary) | Out-Null
        New-DynamicParameter -Name:('Fields') -Type:([System.Array]) -Position:(3) -ValueFromPipelineByPropertyName -ValidateNotNullOrEmpty -HelpMessage:('An array of the fields/properties/columns you want to return from the search.') -RuntimeParameterDictionary:($RuntimeParameterDictionary) | Out-Null
        New-DynamicParameter -Name:('Limit') -Type:([System.Int32]) -Position:(4) -ValueFromPipelineByPropertyName -ValidateRange:(1, [int]::MaxValue) -RuntimeParameterDictionary:($RuntimeParameterDictionary) | Out-Null
        New-DynamicParameter -Name:('Skip') -Type:([System.Int32]) -Position:(5) -ValueFromPipelineByPropertyName -ValidateRange:(1, [int]::MaxValue) -RuntimeParameterDictionary:($RuntimeParameterDictionary) | Out-Null
        New-DynamicParameter -Name:('ReturnHashTable') -Type:([switch]) -Position:(6) -ValueFromPipelineByPropertyName -RuntimeParameterDictionary:($RuntimeParameterDictionary) -DefaultValue:($false) | Out-Null
        New-DynamicParameter -Name:('ReturnCount') -Type:([switch]) -Position:(7) -ValueFromPipelineByPropertyName -RuntimeParameterDictionary:($RuntimeParameterDictionary) -DefaultValue:($false) | Out-Null
        Return $RuntimeParameterDictionary
    }
    Begin
    {
        # Debug message for parameter call
        Invoke-Command -ScriptBlock:($ScriptBlock_DefaultDebugMessageBegin) -ArgumentList:($MyInvocation, $PsBoundParameters, $PSCmdlet) -NoNewScope
        $Results = @()
        $CurrentErrorActionPreference = $ErrorActionPreference
        $ErrorActionPreference = 'Stop'
    }
    Process
    {
        # For DynamicParam with a default value set that value and then convert the DynamicParam inputs into new variables for the script to use
        Invoke-Command -ScriptBlock:($ScriptBlock_DefaultDynamicParamProcess) -ArgumentList:($PsBoundParameters, $PSCmdlet, $RuntimeParameterDictionary) -NoNewScope
        Try
        {
            # Identify the command type to run to get the object for the specified item
            $JCTypeItem = $JCTypes | Where-Object { $Type -in $_.Types }
            If ($JCTypeItem)
            {
                $JCTypeItem.Types = $Type
                $TypeName = $JCTypeItem.TypeName
                $TypeNameSingular = $TypeName.TypeNameSingular
                $TypeNamePlural = $TypeName.TypeNamePlural
                $Targets = $JCTypeItem.Targets
                $TargetSingular = $Targets.TargetSingular
                $TargetPlural = $Targets.TargetPlural
                $Url = $JCTypeItem.Url
                $Method = $JCTypeItem.Method
                $ById = $JCTypeItem.ById
                $ByName = $JCTypeItem.ByName
                $Paginate = $JCTypeItem.Paginate
                $SupportRegexFilter = $JCTypeItem.SupportRegexFilter
                $Limit = $JCTypeItem.Limit
                $UrlObject = @()
                # If searching ByValue add filters to query string and body. # Hacky logic to get g_suite and office_365 directories
                If ($PSCmdlet.ParameterSetName -eq 'Default' -or $Type -in ('gsuites', 'g_suite', 'office365s', 'office_365'))
                {
                    $UrlObject += [PSCustomObject]@{
                        'Url'           = $Url;
                        'Body'          = $null;
                        'SearchByValue' = $null;
                    }
                }
                Else
                {
                    If ($PSCmdlet.ParameterSetName -eq 'ById')
                    {
                        $SearchBy = 'ById'
                        $SearchByValue = $Id
                        $PropertyIdentifier = $JCTypeItem.ById
                    }
                    ElseIf ($PSCmdlet.ParameterSetName -eq 'ByName')
                    {
                        $SearchBy = 'ByName'
                        $SearchByValue = $Name
                        $PropertyIdentifier = $JCTypeItem.ByName
                    }
                    ElseIf ($PSCmdlet.ParameterSetName -eq 'ByValue')
                    {
                        $SearchBy = $SearchBy
                        $SearchByValue = $SearchByValue
                        $PropertyIdentifier = Switch ($SearchBy)
                        {
                            'ById' { $JCTypeItem.ById };
                            'ByName' { $JCTypeItem.ByName };
                        }
                    }
                    ForEach ($SearchByValueItem In $SearchByValue)
                    {
                        $QueryStrings = @()
                        $BodyParts = @()
                        # Populate Url placeholders. Assumption is that if an endpoint requires an Id to be passed in the Url that it does not require a filter because its looking for an exact match already.
                        If ($Url -match '({)(.*?)(})')
                        {
                            Write-Verbose ('Populating ' + $Matches[0] + ' with ' + $SearchByValueItem)
                            $UrlOut = $Url.Replace($Matches[0], $SearchByValueItem)
                        }
                        Else
                        {
                            Switch ($SearchBy)
                            {
                                'ById'
                                {
                                    $UrlOut = $Url + '/' + $SearchByValueItem
                                }
                                'ByName'
                                {
                                    $UrlOut = $Url
                                    # Add filters for exact match and wildcards
                                    If ($SearchByValueItem -match '\*')
                                    {
                                        If ($SupportRegexFilter)
                                        {
                                            $BodyParts += ('"filter":[{"' + $PropertyIdentifier + '":{"$regex": "(?i)(' + $SearchByValueItem.Replace('*', ')(.*?)(') + ')"}}]').Replace('()', '')
                                        }
                                        Else
                                        {
                                            Write-Error ('The endpoint ' + $UrlOut + ' does not support wildcards in the $SearchByValueItem. Please remove "*" from "' + $SearchByValueItem + '".')
                                        }
                                    }
                                    Else
                                    {
                                        $QueryStrings += 'filter=' + $PropertyIdentifier + ':eq:' + $SearchByValueItem
                                        $BodyParts += '"filter":[{"' + $PropertyIdentifier + '":"' + $SearchByValueItem + '"}]'
                                    }
                                }
                            }
                        }
                        # Build query string and body
                        $JoinedQueryStrings = $QueryStrings -join '&'
                        $JoinedBodyParts = $BodyParts -join ','
                        # Build final body and url
                        If ($JoinedBodyParts)
                        {
                            $Body = '{' + $JoinedBodyParts + '}'
                        }
                        If ($JoinedQueryStrings)
                        {
                            $UrlOut = $UrlOut + '?' + $JoinedQueryStrings
                        }
                        $UrlObject += [PSCustomObject]@{
                            'Url'           = $UrlOut;
                            'Body'          = $Body;
                            'SearchByValue' = $SearchByValue;
                        }
                    }
                }
                ForEach ($UrlItem In $UrlObject)
                {
                    $Url = $UrlItem.Url
                    $Body = $UrlItem.Body
                    $SearchByValue = $UrlItem.SearchByValue
                    ## Escape Url????
                    # $Url = ([uri]::EscapeDataString($Url)
                    # Build function parameters
                    $FunctionParameters = [ordered]@{ }
                    If ($Url) { $FunctionParameters.Add('Url', $Url) }
                    If ($Method) { $FunctionParameters.Add('Method', $Method) }
                    If ($Body) { $FunctionParameters.Add('Body', $Body) }
                    If ($Limit) { $FunctionParameters.Add('Limit', $Limit) }
                    If ($Skip) { $FunctionParameters.Add('Skip', $Skip) }
                    If ($ReturnHashTable)
                    {
                        $Values = $Fields
                        $Key = If ($PropertyIdentifier) { $PropertyIdentifier } Else { $ById }
                        If ($Key) { $FunctionParameters.Add('Key', $Key) }
                        If ($Values) { $FunctionParameters.Add('Values', $Values) }
                    }
                    Else
                    {
                        If ($Fields) { $FunctionParameters.Add('Fields', $Fields) }
                        $FunctionParameters.Add('Paginate', $Paginate)
                        If ($ReturnCount -eq $true) { $FunctionParameters.Add('ReturnCount', $ReturnCount) }
                    }
                    # Hacky logic for organization
                    If ($Type -in ('organization', 'organizations'))
                    {
                        $Organization = Invoke-JCApi @FunctionParameters
                        $FunctionParameters['Url'] = $Url + '/' + $Organization.$ById
                    }
                    # Run command
                    $Result = Switch ($ReturnHashTable)
                    {
                        $true { Get-JCHash @FunctionParameters }
                        Default { Invoke-JCApi @FunctionParameters }
                    }
                    # Hacky logic to get g_suite and office_365directories
                    If ($Type -in ('gsuites', 'g_suite', 'office365s', 'office_365'))
                    {
                        If ($ReturnCount -eq $true)
                        {
                            $Directory = $Result.results | Where-Object { $_.Type -eq $TypeNameSingular }
                            $Result.totalCount = ($Directory | Measure-Object).Count
                            $Result.results = $Directory
                        }
                        Else
                        {
                            $Result = $Result | Where-Object { $_.Type -eq $TypeNameSingular }
                        }
                    }
                    If ($Result)
                    {
                        # Set some properties to be hidden in the results
                        $HiddenProperties = @('ById', 'ByName', 'TypeName', 'TypeNameSingular', 'TypeNamePlural', 'Targets', 'TargetSingular', 'TargetPlural')
                        $Result | ForEach-Object {
                            # Create the default property display set
                            $defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet', [string[]]$_.PSObject.Properties.Name)
                            $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)
                            # Add the list of standard members
                            Add-Member -InputObject:($_) -MemberType:('MemberSet') -Name:('PSStandardMembers') -Value:($PSStandardMembers)
                            # Add ById and ByName as hidden properties to results
                            ForEach ($HiddenProperty In $HiddenProperties)
                            {
                                Add-Member -InputObject:($_) -MemberType:('NoteProperty') -Name:($HiddenProperty) -Value:(Get-Variable -Name:($HiddenProperty) -ValueOnly)
                            }
                        }
                        $Results += $Result
                    }
                    Else
                    {
                        If ($SearchByValue)
                        {
                            Write-Warning ('A "' + $TypeNameSingular + '" called "' + $SearchByValue + '" does not exist. Note the search is case sensitive.')
                        }
                        Else
                        {
                            Write-Warning ('The search value is blank or no "' + $TypeNamePlural + '" have been setup in your org. SearchValue:"' + $SearchByValue + '"')
                        }
                    }
                }
            }
            Else
            {
                Write-Error ('$Type of "' + $Type + '" not found. $Type must be:' + ($JCTypes.Types -join ','))
            }
        }
        Catch
        {
            Invoke-Command -ScriptBlock:($ScriptBlock_TryCatchError) -ArgumentList:($_) -NoNewScope
        }
    }
    End
    {
        Return $Results
        $ErrorActionPreference = $CurrentErrorActionPreference
    }
}