Microsoft.Entra.Groups.psm1

# ------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All Rights Reserved.
# Licensed under the MIT License. See License in the project root for license information.
# ------------------------------------------------------------------------------
Set-StrictMode -Version 5 

function Add-EntraGroupMember {
    [CmdletBinding(DefaultParameterSetName = 'ByGroupIdAndMemberId', SupportsShouldProcess = $true)]
    param (
        [Alias('ObjectId')]
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $false, ParameterSetName = 'ByGroupIdAndMemberId', 
            HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId,
                
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, 
            HelpMessage = "Unique ID of the member to add to the group. You can add users, security groups, Microsoft 365 groups, devices, service principals, and organizational contacts to security groups. Only users can be added to Microsoft 365 groups.")]
        [Alias('RefObjectId', 'Id')]
        [ValidateNotNullOrEmpty()]
        [Guid] $MemberId
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Group.ReadWrite.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
        
        # Get the Graph endpoint from the current environment
        $environment = (Get-EntraContext).Environment
        $graphEndpoint = (Get-EntraEnvironment | Where-Object Name -eq $environment).GraphEndPoint
        
        # Default to global endpoint if not found
        if (-not $graphEndpoint) {
            $graphEndpoint = "https://graph.microsoft.com"
            Write-Verbose "Using default Graph endpoint: $graphEndpoint"
        }
        else {
            Write-Verbose "Using environment-specific Graph endpoint: $graphEndpoint"
        }
    }

    PROCESS {
        try {
            # Get custom headers for Microsoft Graph API requests
            $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
            
            # Set up the request parameters
            $params = @{
                Method      = "POST"
                Uri         = "/v1.0/groups/$GroupId/members/`$ref"
                Headers     = $customHeaders
                Body        = @{
                    "@odata.id" = "$graphEndpoint/v1.0/directoryObjects/$MemberId"
                } | ConvertTo-Json
                ContentType = "application/json"
            }
            
            # Debug output
            Write-Debug("============================ TRANSFORMATIONS ============================")
            Write-Debug("Uri : $($params.Uri)")
            Write-Debug("Method : $($params.Method)")
            Write-Debug("Body : $($params.Body)")
            Write-Debug("GroupId : $GroupId")
            Write-Debug("MemberId : $MemberId")
            Write-Debug("=========================================================================`n")
            
            # Add ShouldProcess to prevent accidental modifications
            if ($PSCmdlet.ShouldProcess("Add member '$MemberId' to group '$GroupId'")) {
                Write-Verbose "Adding member $MemberId to group $GroupId"
                
                # Make the API call
                $response = Invoke-MgGraphRequest @params
                
                # Create a custom object for output
                if ($null -eq $response) {
                    $result = [PSCustomObject]@{
                        GroupId  = $GroupId
                        MemberId = $MemberId
                        Status   = "Success"
                        Action   = "Added"
                    }
                    return $result
                }
                
                return $response
            }
        }
        catch {
            # Handle error messages based on the failure
            $statusCode = $null
            if ($_.Exception.Response -and $_.Exception.Response.StatusCode) {
                $statusCode = $_.Exception.Response.StatusCode.value__
            }
            
            if ($statusCode -eq 404) {
                Write-Error "Either group $GroupId or member $MemberId not found."
            }
            elseif ($statusCode -eq 403) {
                Write-Error "You don't have permission to add members to this group. To connect, use 'Connect-Entra -Scopes Group.ReadWrite.All'"
            }
            elseif ($statusCode -eq 400 -and $_.Exception.Message -match "One or more added object references already exist") {
                Write-Warning "Member $MemberId is already a member of group $GroupId."
            }
            else {
                Write-Error "Failed to add member: $_"
            }
        }
    }
}
Set-Alias -Name New-EntraGroupMember -Value Add-EntraGroupMember -Scope Global -Force
Set-Alias -Name Add-EntraGroupMembership -Value Add-EntraGroupMember -Scope Global -Force

function Add-EntraGroupOwner {
    [CmdletBinding(DefaultParameterSetName = 'ByGroupIdAndOwnerId', SupportsShouldProcess = $true)]
    param (
        [Alias('ObjectId')]
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $false, ParameterSetName = 'ByGroupIdAndOwnerId', 
            HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId,
                
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, 
            HelpMessage = "Object ID of a user or service principal to assign as a group owner.")]
        [Alias('RefObjectId', 'Id')]
        [ValidateNotNullOrEmpty()]
        [Guid] $OwnerId
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Group.ReadWrite.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
        
        # Get the Graph endpoint from the current environment
        $environment = (Get-EntraContext).Environment
        $graphEndpoint = (Get-EntraEnvironment | Where-Object Name -eq $environment).GraphEndPoint
        
        # Default to global endpoint if not found
        if (-not $graphEndpoint) {
            $graphEndpoint = "https://graph.microsoft.com"
            Write-Verbose "Using default Graph endpoint: $graphEndpoint"
        }
        else {
            Write-Verbose "Using environment-specific Graph endpoint: $graphEndpoint"
        }
    }

    PROCESS {
        try {
            # Get custom headers for Microsoft Graph API requests
            $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
            
            # Set up the request parameters
            $params = @{
                Method      = "POST"
                Uri         = "/v1.0/groups/$GroupId/owners/`$ref"
                Headers     = $customHeaders
                Body        = @{
                    "@odata.id" = "$graphEndpoint/v1.0/directoryObjects/$OwnerId"
                } | ConvertTo-Json
                ContentType = "application/json"
            }
            
            # Debug output
            Write-Debug("============================ TRANSFORMATIONS ============================")
            Write-Debug("Uri : $($params.Uri)")
            Write-Debug("Method : $($params.Method)")
            Write-Debug("Body : $($params.Body)")
            Write-Debug("GroupId : $GroupId")
            Write-Debug("OwnerId : $OwnerId")
            Write-Debug("=========================================================================`n")
            
            # Add ShouldProcess to prevent accidental modifications
            if ($PSCmdlet.ShouldProcess("Add owner '$OwnerId' to group '$GroupId'")) {
                Write-Verbose "Adding owner $OwnerId to group $GroupId"
                
                # Make the API call
                $response = Invoke-MgGraphRequest @params
                
                # Create a custom object for output
                if ($null -eq $response) {
                    $result = [PSCustomObject]@{
                        GroupId = $GroupId
                        OwnerId = $OwnerId
                        Status  = "Success"
                        Action  = "Added"
                    }
                    return $result
                }
                
                return $response
            }
        }
        catch {
            # Handle error messages based on the failure
            $statusCode = $null
            if ($_.Exception.Response -and $_.Exception.Response.StatusCode) {
                $statusCode = $_.Exception.Response.StatusCode.value__
            }
            
            if ($statusCode -eq 404) {
                Write-Error "Either group $GroupId or owner $OwnerId not found."
            }
            elseif ($statusCode -eq 403) {
                Write-Error "You don't have permission to add owners to this group. To connect, use 'Connect-Entra -Scopes Group.ReadWrite.All'"
            }
            elseif ($statusCode -eq 400 -and $_.Exception.Message -match "One or more added object references already exist") {
                Write-Warning "Owner $OwnerId is already a owner of group $GroupId."
            }
            else {
                Write-Error "Failed to add owner: $_"
            }
        }
    }
}
Set-Alias -Name New-EntraGroupOwner -Value Add-EntraGroupOwner -Scope Global -Force

function Add-EntraLifecyclePolicyGroup {
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param (
        [Parameter(ParameterSetName = "Default", Mandatory = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId,
        
        [Alias('Id')]            
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of the lifecycle policy object in Microsoft Entra ID.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupLifecyclePolicyId
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Directory.ReadWrite.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
    
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["GroupId"]) {
            $params["GroupId"] = $PSBoundParameters["GroupId"]
        }
        if ($null -ne $PSBoundParameters["GroupLifecyclePolicyId"]) {
            $params["GroupLifecyclePolicyId"] = $PSBoundParameters["GroupLifecyclePolicyId"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = Add-MgGroupToLifecyclePolicy @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}



function Get-EntraDeletedGroup {
    [CmdletBinding(DefaultParameterSetName = 'GetQuery')]
    param (                
        [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Filter the results based on the specified criteria.")]
        [System.String] $Filter,
                
        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies whether to return all objects.")]
        [switch] $All,
                
        [Parameter(ParameterSetName = "GetVague", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Search for a group by its name, email, or mail nickname.")]
        [System.String] $SearchString,

        [Alias('Id')]            
        [Parameter(ParameterSetName = "GetById", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId,
                
        [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The maximum number of items to return.")]
        [Alias("Limit")]
        [System.Nullable`1[System.Int32]] $Top,

        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")]
        [Alias("Select")]
        [System.String[]] $Property
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Group.Read.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
        $keysChanged = @{SearchString = "Filter" }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["Filter"]) {
            $TmpValue = $PSBoundParameters["Filter"]
            foreach ($i in $keysChanged.GetEnumerator()) {
                $TmpValue = $TmpValue.Replace($i.Key, $i.Value)
            }
            $Value = $TmpValue
            $params["Filter"] = $Value
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["All"]) {
            if ($PSBoundParameters["All"]) {
                $params["All"] = $PSBoundParameters["All"]
            }
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["SearchString"]) {
            $TmpValue = $PSBoundParameters["SearchString"]
            $Value = "mailNickName eq '$TmpValue' or (mail eq '$TmpValue' or (displayName eq '$TmpValue' or startsWith(displayName,'$TmpValue')))"
            $params["Filter"] = $Value
        }
        if ($null -ne $PSBoundParameters["GroupId"]) {
            $params["DirectoryObjectId"] = $PSBoundParameters["GroupId"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Top")) {
            $params["Top"] = $PSBoundParameters["Top"]
        }
        if ($null -ne $PSBoundParameters["Property"]) {
            $params["Property"] = $PSBoundParameters["Property"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
        
        $response = Get-MgDirectoryDeletedItemAsGroup @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

                if ($null -ne $_.DeletedDateTime) {
                    # Add DeletionAgeInDays property
                    $deletionAgeInDays = (Get-Date) - ($_.DeletedDateTime)
                    Add-Member -InputObject $_ -MemberType NoteProperty -Name DeletionAgeInDays -Value ($deletionAgeInDays.Days) -Force
                }

            }
        }
        $response
    }    
}


function Get-EntraGroup {
    [CmdletBinding(DefaultParameterSetName = 'GetQuery')]
    param (                
        [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The maximum number of items to return.")]
        [Alias("Limit")]
        [System.Nullable`1[System.Int32]] $Top,
                
        [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Filter the results based on the specified criteria.")]
        [System.String] $Filter,
                
        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies whether to return all objects.")]
        [switch] $All,
                
        [Parameter(ParameterSetName = "GetVague", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Search for a group by its name, email, or mail nickname.")]
        [System.String] $SearchString,
        
        [Alias('ObjectId')]            
        [Parameter(ParameterSetName = "GetById", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The ID of the group to retrieve. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId,

        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")]
        [Alias("Select")]
        [System.String[]] $Property
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes GroupMember.Read.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
        $keysChanged = @{SearchString = "Filter"; ObjectId = "Id" }
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Top")) {
            $params["Top"] = $PSBoundParameters["Top"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["Filter"]) {
            $TmpValue = $PSBoundParameters["Filter"]
            foreach ($i in $keysChanged.GetEnumerator()) {
                $TmpValue = $TmpValue.Replace($i.Key, $i.Value)
            }
            $Value = $TmpValue
            $params["Filter"] = $Value
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["All"]) {
            if ($PSBoundParameters["All"]) {
                $params["All"] = $PSBoundParameters["All"]
            }
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["SearchString"]) {
            $TmpValue = $PSBoundParameters["SearchString"]
            $Value = "mailNickName eq '$TmpValue' or (mail eq '$TmpValue' or (displayName eq '$TmpValue' or startswith(displayName,'$TmpValue')))"
            $params["Filter"] = $Value
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["GroupId"]) {
            $params["GroupId"] = $PSBoundParameters["GroupId"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }
        if ($null -ne $PSBoundParameters["Property"]) {
            $params["Property"] = $PSBoundParameters["Property"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = Get-MgGroup @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}


function Get-EntraGroupAppRoleAssignment {
    [CmdletBinding(DefaultParameterSetName = 'GetQuery')]
    param (                
        [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The maximum number of items to return.")]
        [Alias("Limit")]
        [System.Nullable`1[System.Int32]] $Top,
                
        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies whether to return all objects.")]
        [switch] $All,
        
        [Alias('ObjectId')]            
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId,

        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")]
        [Alias("Select")]
        [System.String[]] $Property
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Directory.Read.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
    
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Top")) {
            $params["Top"] = $PSBoundParameters["Top"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["All"]) {
            if ($PSBoundParameters["All"]) {
                $params["All"] = $PSBoundParameters["All"]
            }
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["GroupId"]) {
            $params["GroupId"] = $PSBoundParameters["GroupId"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }
        if ($null -ne $PSBoundParameters["Property"]) {
            $params["Property"] = $PSBoundParameters["Property"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = Get-MgGroupAppRoleAssignment @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}


function Get-EntraGroupLifecyclePolicy {
    [CmdletBinding(DefaultParameterSetName = 'GetQuery')]
    param (
        [Alias('Id')]            
        [Parameter(ParameterSetName = "GetById", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group lifecycle policy. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [System.String] $GroupLifecyclePolicyId,

        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")]
        [Alias("Select")]
        [System.String[]] $Property
    )
    
    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Directory.Read.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
    
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["GroupLifecyclePolicyId"]) {
            $params["GroupLifecyclePolicyId"] = $PSBoundParameters["GroupLifecyclePolicyId"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }
        if ($null -ne $PSBoundParameters["Property"]) {
            $params["Property"] = $PSBoundParameters["Property"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = Get-MgGroupLifecyclePolicy @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}


function Get-EntraGroupMember {
    [CmdletBinding(DefaultParameterSetName = 'GetQuery')]
    param (
        [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The maximum number of items to return.")]
        [Alias("Limit")]
        [System.Nullable`1[System.Int32]] $Top,

        [Alias('ObjectId')]
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId,

        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies whether to return all objects.")]
        [switch] $All,

        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "The properties to include in the response.")]
        [Alias("Select")]
        [System.String[]] $Property
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes GroupMember.Read.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }
    
    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
        $topCount = $null
        $baseUri = '/v1.0/groups'
        $properties = '$select=*'
        $Method = "GET"

        if ($null -ne $PSBoundParameters["Property"]) {
            $selectProperties = $PSBoundParameters["Property"]
            $selectProperties = $selectProperties -Join ','
            $properties = "`$select=$($selectProperties)"
        }
        if ($null -ne $PSBoundParameters["GroupId"]) {
            $params["GroupId"] = $PSBoundParameters["GroupId"]
            $URI = "$baseUri/$($params.GroupId)/members?$properties"
        }
        if ($null -ne $PSBoundParameters["All"]) {
            $URI = "$baseUri/$($params.GroupId)/members?$properties"
        }
        if ($PSBoundParameters.ContainsKey("Top")) {
            $topCount = $PSBoundParameters["Top"]
            if ($topCount -gt 999) {
                $minTop = 999
                $URI = "$baseUri/$($params.GroupId)/members?`$top=999&$properties"
            }
            else {
                $URI = "$baseUri/$($params.GroupId)/members?`$top=$topCount&$properties"
            }
        }
    
        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = Invoke-GraphRequest -Headers $customHeaders -Uri $URI -Method $Method | ConvertTo-Json -Depth 10 | ConvertFrom-Json
        $data = $response
        try {
            $data = @($response.value) 
            $all = $All.IsPresent
            $increment = $topCount - $data.Count
            while (($response.'@odata.nextLink' -and (($all -and ($increment -lt 0)) -or $increment -gt 0))) {
                $URI = $response.'@odata.nextLink'
                if ($increment -gt 0) {
                    $topValue = [Math]::Min($increment, 999)
                    if ($minTop) {
                        $URI = $URI.Replace("`$top=$minTop", "`$top=$topValue")
                    }
                    else {
                        $URI = $URI.Replace("`$top=$topCount", "`$top=$topValue")
                    }
                    $increment -= $topValue
                }
                $response = Invoke-GraphRequest -Uri $URI -Method $Method
                $data += $response.value | ConvertTo-Json -Depth 10 | ConvertFrom-Json
            }
        }
        catch {} 
        $data | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id
            }
        }
        $serviceprincipal = @()
        if (($data.count -eq 0) -or $data.'@odata.type' -notcontains 'microsoft.graph.servicePrincipal') {
            $URI = "$baseUri/$($params.GroupId)/members/microsoft.graph.servicePrincipal?$properties"
            $topCount = $Top - $data.count
            if ($PSBoundParameters.ContainsKey("Top") -and $topCount -gt 0) {
                $increment = $topCount - $data.Count 
                $increment = 1 
                $hasNextLink = $false  

                do {
                    $topValue = [Math]::Min($topCount, 999)
                    $URI = "$baseUri/$($params.GroupId)/members/microsoft.graph.servicePrincipal?`$top=$topValue&$properties"
                    $response = Invoke-GraphRequest -Uri $URI -Method $Method -Headers $customHeaders 
                    $serviceprincipal += $response.value | ConvertTo-Json -Depth 10 | ConvertFrom-Json
                    $hasNextLink = $null -ne $response.PSObject.Properties.Match('@odata.nextLink')
                    $increment--
                } while ($increment -gt 0 -and $hasNextLink)
            }
            elseif ($null -eq $PSBoundParameters["Top"]) {
                $response = Invoke-GraphRequest -Uri $URI -Method $Method -Headers $customHeaders 
                $serviceprincipal += $response.value | ConvertTo-Json -Depth 10 | ConvertFrom-Json
            }
            try {
                $serviceprincipal | ForEach-Object {
                    if ($null -ne $_) {
                        Add-Member -InputObject $_ -MemberType NoteProperty -Name '@odata.type' -Value '#microsoft.graph.servicePrincipal' -Force
                    }
                }
                $data += $serviceprincipal
            }
            catch {}
        }
        if ($data) {
            $userList = @()
            foreach ($response in $data) {
                $userType = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphDirectoryObject
                if (-not ($response -is [psobject])) {
                    $response = [pscustomobject]@{ Value = $response }
                }
                $response.PSObject.Properties | ForEach-Object {
                    $propertyName = $_.Name
                    $propertyValue = $_.Value
                    $userType | Add-Member -MemberType NoteProperty -Name $propertyName -Value $propertyValue -Force
                }
                $userList += $userType
            }
            $userList  
        }
    }       
}


function Get-EntraGroupOwner {
    [CmdletBinding(DefaultParameterSetName = 'GetQuery')]
    param (
        [Alias('ObjectId')]
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId,

        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies whether to return all object items.")]
        [switch] $All,

        [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The maximum number of items to return.")]
        [Alias("Limit")]
        [System.Nullable`1[System.Int32]] $Top,
        
        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")]
        [Alias("Select")]
        [System.String[]] $Property
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes GroupMember.Read.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }
    
    PROCESS {
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
        $topCount = $null
        $baseUri = '/v1.0/groups'
        $properties = '$select=*'
        $Method = "GET"        
        if ($null -ne $PSBoundParameters["Property"]) {
            $selectProperties = $PSBoundParameters["Property"]
            $selectProperties = $selectProperties -Join ','
            $properties = "`$select=$($selectProperties)"
        }
        if ($null -ne $PSBoundParameters["GroupId"]) {
            $params["GroupId"] = $PSBoundParameters["GroupId"]
            $URI = "$baseUri/$($params.GroupId)/owners?$properties"
        }
        if ($null -ne $PSBoundParameters["All"]) {
            $URI = "$baseUri/$($params.GroupId)/owners?$properties"
        }
        if ($PSBoundParameters.ContainsKey("Top")) {
            $topCount = $PSBoundParameters["Top"]
            $URI = "$baseUri/$($params.GroupId)/owners?`$top=$topCount&$properties"
        }
        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
        $response = (Invoke-GraphRequest -Headers $customHeaders -Uri $URI -Method $Method).value
        $response = $response | ConvertTo-Json -Depth 10 | ConvertFrom-Json
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id
            }
        }
        if ($response) {
            $userList = @()
            foreach ($data in $response) {
                $userType = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphDirectoryObject
                $data.PSObject.Properties | ForEach-Object {
                    $propertyName = $_.Name
                    $propertyValue = $_.Value
                    $userType | Add-Member -MemberType NoteProperty -Name $propertyName -Value $propertyValue -Force
                }
                $userList += $userType
            }
            $userList
        }
    }    
}


function Get-EntraGroupPermissionGrant {
    [CmdletBinding(DefaultParameterSetName = 'GetQuery')]
    param (
        [Alias('Id')]            
        [Parameter(ParameterSetName = "GetQuery", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId,
        
        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")]
        [Alias("Select")]
        [System.String[]] $Property
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes GroupMember.Read.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
    
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["GroupId"]) {
            $params["GroupId"] = $PSBoundParameters["GroupId"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }
        if ($null -ne $PSBoundParameters["Property"]) {
            $params["Property"] = $PSBoundParameters["Property"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = Get-MgGroupPermissionGrant @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}


function Get-EntraLifecyclePolicyGroup {
    [CmdletBinding(DefaultParameterSetName = 'GetQuery')]
    param (
        [Alias('Id')]            
        [Parameter(ParameterSetName = "GetQuery", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId,
        
        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")]
        [Alias("Select")]
        [System.String[]] $Property
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Directory.Read.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
    
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["GroupId"]) {
            $params["GroupId"] = $PSBoundParameters["GroupId"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }
        if ($null -ne $PSBoundParameters["Property"]) {
            $params["Property"] = $PSBoundParameters["Property"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = Get-MgGroupLifecyclePolicyByGroup @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}


function Get-EntraObjectSetting {
    [CmdletBinding(DefaultParameterSetName = 'GetQuery')]
    param (
        [Parameter(ParameterSetName = "GetById", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the object setting. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [System.String] $Id,

        [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The maximum number of items to return.")]
        [Alias("Limit")]
        [System.Int32] $Top,

        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies whether to return all object items.")]
        [switch] $All,

        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The type of object to retrieve settings for. For example, 'users', 'groups', 'servicePrincipals', etc.")]
        [ValidateNotNullOrEmpty()]
        [System.String] $TargetType,

        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the target object. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [System.String] $TargetObjectId,
        
        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")]
        [Alias("Select")]
        [System.String[]] $Property
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Directory.Read.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
        $params = @{}
        $topCount = $null
        $baseUri = "/v1.0/$TargetType/$TargetObjectId/settings"
        $params["Method"] = "GET"
        $params["Uri"] = $baseUri + '?$select=*'
        if ($null -ne $PSBoundParameters["Property"]) {
            $selectProperties = $PSBoundParameters["Property"]
            $selectProperties = $selectProperties -Join ','
            $params["Uri"] = $baseUri + "?`$select=$($selectProperties)"
        }
        if ($PSBoundParameters.ContainsKey("Top") -and (-not $PSBoundParameters.ContainsKey("All"))) {
            $topCount = $PSBoundParameters["Top"]
            if ($topCount -gt 999) {
                $params["Uri"] += "&`$top=999"
            }
            else {
                $params["Uri"] += "&`$top=$topCount"
            }
        }
        if ($null -ne $PSBoundParameters["Id"]) {
            $Id = $PSBoundParameters["Id"]
            $params["Uri"] = "$baseUri/$($Id)"
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")

        $response = Invoke-GraphRequest @params -Headers $customHeaders
        $data = $response | ConvertTo-Json -Depth 10 | ConvertFrom-Json
        try {
            $data = $response.value | ConvertTo-Json -Depth 10 | ConvertFrom-Json
            $all = $All.IsPresent
            $increment = $topCount - $data.Count
            while ($response.'@odata.nextLink' -and (($all) -or ($increment -gt 0 -and -not $all))) {
                $params["Uri"] = $response.'@odata.nextLink'
                if (-not $all) {
                    $topValue = [Math]::Min($increment, 999)
                    $params["Uri"] = $params["Uri"].Replace('$top=999', "`$top=$topValue")
                    $increment -= $topValue
                }
                $response = Invoke-GraphRequest @params
                $data += $response.value | ConvertTo-Json -Depth 10 | ConvertFrom-Json
            }
        }
        catch {}

        $targetTypeList = @()

        if ($TargetType.ToLower() -eq 'groups') {
            foreach ($res in $data) {
                $groupType = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphGroupSetting
                $res.PSObject.Properties | ForEach-Object {
                    $propertyName = $_.Name.Substring(0, 1).ToUpper() + $_.Name.Substring(1)
                    $propertyValue = $_.Value
                    $groupType | Add-Member -MemberType NoteProperty -Name $propertyName -Value $propertyValue -Force
                }
                $targetTypeList += $groupType
            }
        }

        if ($TargetType.ToLower() -eq 'users') {
            foreach ($res in $data) {
                $userType = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphUserSettings
                $res.PSObject.Properties | ForEach-Object {
                    $propertyName = $_.Name.Substring(0, 1).ToUpper() + $_.Name.Substring(1)
                    $propertyValue = $_.Value
                    $userType | Add-Member -MemberType NoteProperty -Name $propertyName -Value $propertyValue -Force
                }
                $targetTypeList += $userType
            }
        }

        $targetTypeList
    }
}


function Get-EntraUnsupportedCommand {
    Throw [System.NotSupportedException] "This command is not supported by Microsoft Entra PowerShell."
}


function New-EntraCustomHeaders {
    <#
    .SYNOPSIS
        Creates a custom header for use in telemetry.
    .DESCRIPTION
        The custom header created is a User-Agent with header value "<PowerShell version> EntraPowershell/<EntraPowershell version> <Entra PowerShell command>"
    .PARAMETER Command
        The command that is being executed.
    .EXAMPLE
        New-EntraCustomHeaders -Command Get-EntraUser
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]
        $Command
    )
    
    $psVersion = $global:PSVersionTable.PSVersion
    $entraVersion = $ExecutionContext.SessionState.Module.Version.ToString()
    $userAgentHeaderValue = "PowerShell/$psVersion EntraPowershell/$entraVersion $Command"
    $customHeaders = New-Object 'system.collections.generic.dictionary[string,string]'
    $customHeaders["User-Agent"] = $userAgentHeaderValue
    
    $customHeaders
}

function New-EntraGroup {
    [CmdletBinding(DefaultParameterSetName = 'ByGroupIdentityParameters')]
    param (
        [Parameter(ParameterSetName = 'ByGroupIdentityParameters', Mandatory = $true, HelpMessage = 'Specifies whether the group is a security group.')]
        [Alias('SecurityEnabledGroup')]
        [ValidateSet('true', 'false', IgnoreCase = $true)]
        [ValidateNotNullOrEmpty()]
        [System.Nullable`1[System.Boolean]] $SecurityEnabled,

        [Parameter(ParameterSetName = 'ByGroupIdentityParameters', Mandatory = $true, HelpMessage = 'Specifies whether the group is mail-enabled.')]
        [Alias('MailEnabledGroup')]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('true', 'false', IgnoreCase = $true)]
        [System.Nullable`1[System.Boolean]] $MailEnabled,

        [Parameter(ParameterSetName = 'ByGroupIdentityParameters', HelpMessage = 'Description of the group.')]
        [System.String] $Description,

        [Parameter(ParameterSetName = 'ByGroupIdentityParameters', HelpMessage = 'Specifies the group type and its membership.')]
        [Alias('GroupType')]
        [System.Collections.Generic.List`1[System.String]] $GroupTypes,

        [Parameter(ParameterSetName = 'ByGroupIdentityParameters', Mandatory = $true, HelpMessage = 'A unique mail alias for the group (max 64 characters). It must use ASCII characters (0-127).')]
        [ValidateNotNullOrEmpty()]
        [System.String] $MailNickname,

        [Parameter(ParameterSetName = 'ByGroupIdentityParameters', HelpMessage = 'Indicates whether this group can be assigned to a Microsoft Entra role.')]
        [ValidateSet('true', 'false', IgnoreCase = $true)]
        [System.Nullable`1[System.Boolean]] $IsAssignableToRole,

        [Parameter(ParameterSetName = 'ByGroupIdentityParameters', HelpMessage = 'Sets the group join policy and content visibility. Options are: Private, Public, or HiddenMembership.')]
        [System.String] $Visibility,

        [Parameter(ParameterSetName = 'ByGroupIdentityParameters', Mandatory = $true, HelpMessage = 'Display name of the group.')]
        [ValidateNotNullOrEmpty()]
        [ValidateLength(1, 256)]
        [System.String] $DisplayName
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Group.ReadWrite.All, Group.Create' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand

        if ($null -ne $PSBoundParameters['OutVariable']) {
            $params['OutVariable'] = $PSBoundParameters['OutVariable']
        }
        if ($null -ne $PSBoundParameters['SecurityEnabled']) {
            $params['SecurityEnabled'] = $PSBoundParameters['SecurityEnabled']
        }
        if ($null -ne $PSBoundParameters['MailEnabled']) {
            $params['MailEnabled'] = $PSBoundParameters['MailEnabled']
        }
        if ($null -ne $PSBoundParameters['Description']) {
            $params['Description'] = $PSBoundParameters['Description']
        }
        if ($PSBoundParameters.ContainsKey('Debug')) {
            $params['Debug'] = $PSBoundParameters['Debug']
        }
        if ($null -ne $PSBoundParameters['PipelineVariable']) {
            $params['PipelineVariable'] = $PSBoundParameters['PipelineVariable']
        }
        if ($null -ne $PSBoundParameters['InformationVariable']) {
            $params['InformationVariable'] = $PSBoundParameters['InformationVariable']
        }
        if ($null -ne $PSBoundParameters['GroupTypes']) {
            $params['GroupTypes'] = $PSBoundParameters['GroupTypes']
        }
        if ($null -ne $PSBoundParameters['MailNickname']) {
            $params['MailNickname'] = $PSBoundParameters['MailNickname']
        }
        if ($null -ne $PSBoundParameters['OutBuffer']) {
            $params['OutBuffer'] = $PSBoundParameters['OutBuffer']
        }
        if ($null -ne $PSBoundParameters['WarningVariable']) {
            $params['WarningVariable'] = $PSBoundParameters['WarningVariable']
        }
        if ($PSBoundParameters.ContainsKey('Verbose')) {
            $params['Verbose'] = $PSBoundParameters['Verbose']
        }
        if ($null -ne $PSBoundParameters['IsAssignableToRole']) {
            $params['IsAssignableToRole'] = $PSBoundParameters['IsAssignableToRole']
        }
        if ($null -ne $PSBoundParameters['ErrorVariable']) {
            $params['ErrorVariable'] = $PSBoundParameters['ErrorVariable']
        }
        if ($null -ne $PSBoundParameters['ErrorAction']) {
            $params['ErrorAction'] = $PSBoundParameters['ErrorAction']
        }
        if ($null -ne $PSBoundParameters['Visibility']) {
            $params['Visibility'] = $PSBoundParameters['Visibility']
        }
        if ($null -ne $PSBoundParameters['InformationAction']) {
            $params['InformationAction'] = $PSBoundParameters['InformationAction']
        }
        if ($null -ne $PSBoundParameters['WarningAction']) {
            $params['WarningAction'] = $PSBoundParameters['WarningAction']
        }
        if ($null -ne $PSBoundParameters['ProgressAction']) {
            $params['ProgressAction'] = $PSBoundParameters['ProgressAction']
        }
        if ($null -ne $PSBoundParameters['DisplayName']) {
            $params['DisplayName'] = $PSBoundParameters['DisplayName']
        }

        Write-Debug('============================ TRANSFORMATIONS ============================')
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")

        $response = New-MgGroup @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}

function New-EntraGroupAppRoleAssignment {
    [CmdletBinding(DefaultParameterSetName = 'ByGroupIdAndRoleParameters')]
    param (     
        [Parameter(ParameterSetName = "ByGroupIdAndRoleParameters", Mandatory = $true, HelpMessage = "The ID of the group to which you're assigning the app role.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $PrincipalId,
                
        [Parameter(ParameterSetName = "ByGroupIdAndRoleParameters", Mandatory = $true, HelpMessage = "The ID of the resource service Principal, which has defined the app role.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $ResourceId,
    
        [Alias('Id')]            
        [Parameter(ParameterSetName = "ByGroupIdAndRoleParameters", Mandatory = $true, HelpMessage = "The ID of the appRole (defined on the resource service principal) to assign to the group")]
        [ValidateNotNullOrEmpty()]
        [Guid] $AppRoleId,

        [Alias('ObjectId')]            
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes AppRoleAssignment.ReadWrite.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
    
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($null -ne $PSBoundParameters["PrincipalId"]) {
            $params["PrincipalId"] = $PSBoundParameters["PrincipalId"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["ResourceId"]) {
            $params["ResourceId"] = $PSBoundParameters["ResourceId"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["AppRoleId"]) {
            $params["AppRoleId"] = $PSBoundParameters["AppRoleId"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["GroupId"]) {
            $params["GroupId"] = $PSBoundParameters["GroupId"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = New-MgGroupAppRoleAssignment @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}


function New-EntraGroupLifecyclePolicy {
    [CmdletBinding(DefaultParameterSetName = 'ByLifecycleSettings')]
    param (                
        [Parameter(ParameterSetName = "ByLifecycleSettings", Mandatory = $true, HelpMessage = "A list of email addresses to which notifications are sent. The email addresses must be valid and separated by semicolons.")]
        [ValidateNotNullOrEmpty()]
        [System.String] $AlternateNotificationEmails,
                
        [Parameter(ParameterSetName = "ByLifecycleSettings", Mandatory = $true, HelpMessage = "The group type for which the expiration policy applies. Possible values are All, Selected or None.")]
        [ValidateSet("All", "Selected", "None", IgnoreCase = $true)]
        [ValidateNotNullOrEmpty()]
        [System.String] $ManagedGroupTypes,
                
        [Parameter(ParameterSetName = "ByLifecycleSettings", Mandatory = $true, HelpMessage = "Number of days before a group expires and needs to be renewed. Once renewed, the group expiration is extended by the number of days defined.")]
        [ValidateNotNullOrEmpty()]
        [System.Nullable`1[System.Int32]] $GroupLifetimeInDays
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Directory.ReadWrite.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
    
        if ($null -ne $PSBoundParameters["AlternateNotificationEmails"]) {
            $params["AlternateNotificationEmails"] = $PSBoundParameters["AlternateNotificationEmails"]
        }
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($null -ne $PSBoundParameters["ManagedGroupTypes"]) {
            $params["ManagedGroupTypes"] = $PSBoundParameters["ManagedGroupTypes"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["GroupLifetimeInDays"]) {
            $params["GroupLifetimeInDays"] = $PSBoundParameters["GroupLifetimeInDays"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = New-MgGroupLifecyclePolicy @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}


function Remove-EntraGroup {
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param (
        [Alias('ObjectId')]            
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Group.ReadWrite.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
    
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["GroupId"]) {
            $params["GroupId"] = $PSBoundParameters["GroupId"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = Remove-MgGroup @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}


function Remove-EntraGroupAppRoleAssignment {
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param (                
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "A unique identifier for the appRoleAssignment key. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [System.String] $AppRoleAssignmentId,

        [Alias('ObjectId')]            
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Directory.ReadWrite.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
    
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($null -ne $PSBoundParameters["AppRoleAssignmentId"]) {
            $params["AppRoleAssignmentId"] = $PSBoundParameters["AppRoleAssignmentId"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["GroupId"]) {
            $params["GroupId"] = $PSBoundParameters["GroupId"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = Remove-MgGroupAppRoleAssignment @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}


function Remove-EntraGroupLifecyclePolicy {
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param (
        [Alias('Id')]            
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "A unique identifier for a policy. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupLifecyclePolicyId
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Directory.ReadWrite.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
    
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["GroupLifecyclePolicyId"]) {
            $params["GroupLifecyclePolicyId"] = $PSBoundParameters["GroupLifecyclePolicyId"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = Remove-MgGroupLifecyclePolicy @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}


function Remove-EntraGroupMember {
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param (
        [Alias('ObjectId')]            
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId,
                
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the member. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $MemberId
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes GroupMember.ReadWrite.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
    
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["GroupId"]) {
            $params["GroupId"] = $PSBoundParameters["GroupId"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }
        if ($null -ne $PSBoundParameters["MemberId"]) {
            $params["DirectoryObjectId"] = $PSBoundParameters["MemberId"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = Remove-MgGroupMemberByRef @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}


function Remove-EntraGroupOwner {
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param (
        [Alias('ObjectId')]            
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId,
                
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the owner. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $OwnerId
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes GroupMember.ReadWrite.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
    
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["GroupId"]) {
            $params["GroupId"] = $PSBoundParameters["GroupId"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }
        if ($null -ne $PSBoundParameters["OwnerId"]) {
            $params["DirectoryObjectId"] = $PSBoundParameters["OwnerId"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = Remove-MgGroupOwnerByRef @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}


function Remove-EntraLifecyclePolicyGroup {
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param (                
        [Parameter(ParameterSetName = "Default", Mandatory = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId,

        [Alias('Id')]            
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group lifecycle policy. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupLifecyclePolicyId
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Directory.ReadWrite.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
    
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["GroupId"]) {
            $params["GroupId"] = $PSBoundParameters["GroupId"]
        }
        if ($null -ne $PSBoundParameters["GroupLifecyclePolicyId"]) {
            $params["GroupLifecyclePolicyId"] = $PSBoundParameters["GroupLifecyclePolicyId"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = Remove-MgGroupFromLifecyclePolicy @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}


function Reset-EntraLifeCycleGroup {
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param (                
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Alias('ObjectId', 'Id')]
        [Guid] $GroupId
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Group.ReadWrite.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
    
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["GroupId"]) {
            $params["GroupId"] = $PSBoundParameters["GroupId"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = Invoke-MgRenewGroup @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}


function Select-EntraGroupIdsContactIsMemberOf {
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID values.")]
        [ValidateNotNullOrEmpty()]
        [Microsoft.Open.AzureAD.Model.GroupIdsForMembershipCheck] $GroupIdsForMembershipCheck,
                
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the contact. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Alias("ObjectId")]
        [Guid] $OrgContactId
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes OrgContact.Read.All,Group.Read.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
        if ($null -ne $PSBoundParameters["OrgContactId"]) {
            $params["OrgContactId"] = $PSBoundParameters["OrgContactId"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
        $initalResponse = Get-MgContactMemberOfAsGroup @params -Headers $customHeaders
        $response = $initalResponse | Where-Object -Filterscript { $_.Id -in ($GroupIdsForMembershipCheck.GroupIds) } 
        if ($response) {
            $response.Id
        }
    }     
}


function Select-EntraGroupIdsGroupIsMemberOf {
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID values.")]
        [ValidateNotNullOrEmpty()]
        [Microsoft.Open.AzureAD.Model.GroupIdsForMembershipCheck] $GroupIdsForMembershipCheck,
                
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes GroupMember.Read.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
        if ($null -ne $PSBoundParameters["GroupId"]) {
            $params["GroupId"] = $PSBoundParameters["GroupId"]
        }
        if ($null -ne $PSBoundParameters["GroupIdsForMembershipCheck"]) {            
            $GroupIdData = Get-EntraGroup -All
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }        
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
        $initalResponse = Get-MgGroupMemberOf @params -Headers $customHeaders
        $response = $initalResponse | Where-Object -Filterscript { $_.Id -in ($GroupIdsForMembershipCheck.GroupIds) } 
        $result = @()
        if ($response) {
            $result = $response.Id
        }
        $notMember = $GroupIdsForMembershipCheck.GroupIds | Where-Object -Filterscript { $_ -notin $result }
        foreach ($Id in $notMember) {
            if ($GroupIdData.Id -notcontains $Id) {
                Write-Error "Error occurred while executing SelectEntraGroupIdsGroupIsMemberOf
Code: Request_BadRequest
Message: Invalid GUID:$Id"

                return
            }
        }
        if ($response) {
            $response.Id
        }
    }     
}


function Select-EntraGroupIdsUserIsMemberOf {
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the group. Should be a valid GUID values.")]
        [ValidateNotNullOrEmpty()]
        [Microsoft.Open.AzureAD.Model.GroupIdsForMembershipCheck] $GroupIdsForMembershipCheck,
                
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Unique ID of the user. Should be a valid GUID or User principal name value.")]
        [ValidateNotNullOrEmpty()]
        [Alias("ObjectId")]
        [Guid] $UserId
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Application.Read.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
        if ($null -ne $PSBoundParameters["UserId"]) {
            $params["UserId"] = $PSBoundParameters["UserId"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
        $initalResponse = Get-MgUserMemberOfAsGroup -Headers $customHeaders -UserId $params["UserId"]
        $response = $initalResponse | Where-Object -Filterscript { $_.ID -in ($GroupIdsForMembershipCheck.GroupIds) } 
        if ($response) {
            $response.ID
        }
    }    
}


function Set-EntraGroup {
    [CmdletBinding(DefaultParameterSetName = 'UpdateGroupByGroupId')]
    param (
        [Parameter(ParameterSetName = 'UpdateGroupByGroupId', HelpMessage = 'Specifies whether the group is a security group.')]
        [Alias('SecurityEnabledGroup')]
        [ValidateSet('true', 'false', IgnoreCase = $true)]
        [System.Nullable`1[System.Boolean]] $SecurityEnabled,

        [Parameter(ParameterSetName = 'UpdateGroupByGroupId', HelpMessage = 'Specifies whether the group is mail-enabled.')]
        [Alias('MailEnabledGroup')]
        [ValidateSet('true', 'false', IgnoreCase = $true)]
        [System.Nullable`1[System.Boolean]] $MailEnabled,

        [Parameter(ParameterSetName = 'UpdateGroupByGroupId', HelpMessage = 'Description of the group.')]
        [System.String] $Description,

        [Parameter(ParameterSetName = 'UpdateGroupByGroupId', HelpMessage = 'Specifies the group type and its membership.')]
        [System.Collections.Generic.List`1[System.String]] $GroupTypes,

        [Parameter(ParameterSetName = 'UpdateGroupByGroupId', HelpMessage = 'A unique mail alias for the group (max 64 characters). It must use ASCII characters (0-127).')]
        [System.String] $MailNickname,

        [Alias('Id')]
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = 'Unique ID of the group. Should be a valid GUID value.')]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupId,

        [Parameter(ParameterSetName = 'UpdateGroupByGroupId', HelpMessage = 'Indicates whether this group can be assigned to a Microsoft Entra role.')]
        [ValidateSet('true', 'false', IgnoreCase = $true)]
        [System.Nullable`1[System.Boolean]] $IsAssignableToRole,

        [Parameter(ParameterSetName = 'UpdateGroupByGroupId', HelpMessage = 'Indicates whether this group can be assigned to a Microsoft Entra role.')]
        [ValidateSet('true', 'false', IgnoreCase = $true)]
        [System.String] $Visibility,

        [Parameter(ParameterSetName = 'UpdateGroupByGroupId', HelpMessage = 'Display name of the group.')]
        [ValidateLength(1, 256)]
        [System.String] $DisplayName
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Group.ReadWrite.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand

        if ($null -ne $PSBoundParameters['OutVariable']) {
            $params['OutVariable'] = $PSBoundParameters['OutVariable']
        }
        if ($null -ne $PSBoundParameters['SecurityEnabled']) {
            $params['SecurityEnabled'] = $PSBoundParameters['SecurityEnabled']
        }
        if ($null -ne $PSBoundParameters['MailEnabled']) {
            $params['MailEnabled'] = $PSBoundParameters['MailEnabled']
        }
        if ($null -ne $PSBoundParameters['Description']) {
            $params['Description'] = $PSBoundParameters['Description']
        }
        if ($PSBoundParameters.ContainsKey('Debug')) {
            $params['Debug'] = $PSBoundParameters['Debug']
        }
        if ($null -ne $PSBoundParameters['PipelineVariable']) {
            $params['PipelineVariable'] = $PSBoundParameters['PipelineVariable']
        }
        if ($null -ne $PSBoundParameters['InformationVariable']) {
            $params['InformationVariable'] = $PSBoundParameters['InformationVariable']
        }
        if ($null -ne $PSBoundParameters['GroupTypes']) {
            $params['GroupTypes'] = $PSBoundParameters['GroupTypes']
        }
        if ($null -ne $PSBoundParameters['MailNickname']) {
            $params['MailNickname'] = $PSBoundParameters['MailNickname']
        }
        if ($null -ne $PSBoundParameters['OutBuffer']) {
            $params['OutBuffer'] = $PSBoundParameters['OutBuffer']
        }
        if ($null -ne $PSBoundParameters['WarningVariable']) {
            $params['WarningVariable'] = $PSBoundParameters['WarningVariable']
        }
        if ($PSBoundParameters.ContainsKey('Verbose')) {
            $params['Verbose'] = $PSBoundParameters['Verbose']
        }
        if ($null -ne $PSBoundParameters['GroupId']) {
            $params['GroupId'] = $PSBoundParameters['GroupId']
        }
        if ($null -ne $PSBoundParameters['IsAssignableToRole']) {
            $params['IsAssignableToRole'] = $PSBoundParameters['IsAssignableToRole']
        }
        if ($null -ne $PSBoundParameters['ErrorVariable']) {
            $params['ErrorVariable'] = $PSBoundParameters['ErrorVariable']
        }
        if ($null -ne $PSBoundParameters['ErrorAction']) {
            $params['ErrorAction'] = $PSBoundParameters['ErrorAction']
        }
        if ($null -ne $PSBoundParameters['Visibility']) {
            $params['Visibility'] = $PSBoundParameters['Visibility']
        }
        if ($null -ne $PSBoundParameters['InformationAction']) {
            $params['InformationAction'] = $PSBoundParameters['InformationAction']
        }
        if ($null -ne $PSBoundParameters['WarningAction']) {
            $params['WarningAction'] = $PSBoundParameters['WarningAction']
        }
        if ($null -ne $PSBoundParameters['ProgressAction']) {
            $params['ProgressAction'] = $PSBoundParameters['ProgressAction']
        }
        if ($null -ne $PSBoundParameters['DisplayName']) {
            $params['DisplayName'] = $PSBoundParameters['DisplayName']
        }

        Write-Debug('============================ TRANSFORMATIONS ============================')
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")

        $response = Update-MgGroup @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}

function Set-EntraGroupLifecyclePolicy {
    [CmdletBinding(DefaultParameterSetName = 'ByGroupLifecyclePolicyId')]
    param (                
        [Parameter(ParameterSetName = "ByGroupLifecyclePolicyId", HelpMessage = "A list of email addresses to which notifications are sent. The email addresses must be valid and separated by semicolons.")]
        [System.String] $AlternateNotificationEmails,
                
        [Parameter(ParameterSetName = "ByGroupLifecyclePolicyId", HelpMessage = "The group type for which the expiration policy applies. Possible values are All, Selected or None.")]
        [System.String] $ManagedGroupTypes,
        
        [Alias('Id')]            
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "A unique identifier for a policy. Should be a valid GUID value.")]
        [ValidateNotNullOrEmpty()]
        [Guid] $GroupLifecyclePolicyId,
                
        [Parameter(ParameterSetName = "ByGroupLifecyclePolicyId", HelpMessage = "Number of days before a group expires and needs to be renewed. Once renewed, the group expiration is extended by the number of days defined.")]
        [System.Nullable`1[System.Int32]] $GroupLifetimeInDays
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Directory.ReadWrite.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    PROCESS {    
        $params = @{}
        $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
    
        if ($null -ne $PSBoundParameters["AlternateNotificationEmails"]) {
            $params["AlternateNotificationEmails"] = $PSBoundParameters["AlternateNotificationEmails"]
        }
        if ($null -ne $PSBoundParameters["OutVariable"]) {
            $params["OutVariable"] = $PSBoundParameters["OutVariable"]
        }
        if ($null -ne $PSBoundParameters["ManagedGroupTypes"]) {
            $params["ManagedGroupTypes"] = $PSBoundParameters["ManagedGroupTypes"]
        }
        if ($PSBoundParameters.ContainsKey("Debug")) {
            $params["Debug"] = $PSBoundParameters["Debug"]
        }
        if ($null -ne $PSBoundParameters["PipelineVariable"]) {
            $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"]
        }
        if ($null -ne $PSBoundParameters["InformationVariable"]) {
            $params["InformationVariable"] = $PSBoundParameters["InformationVariable"]
        }
        if ($null -ne $PSBoundParameters["OutBuffer"]) {
            $params["OutBuffer"] = $PSBoundParameters["OutBuffer"]
        }
        if ($null -ne $PSBoundParameters["WarningVariable"]) {
            $params["WarningVariable"] = $PSBoundParameters["WarningVariable"]
        }
        if ($PSBoundParameters.ContainsKey("Verbose")) {
            $params["Verbose"] = $PSBoundParameters["Verbose"]
        }
        if ($null -ne $PSBoundParameters["GroupLifecyclePolicyId"]) {
            $params["GroupLifecyclePolicyId"] = $PSBoundParameters["GroupLifecyclePolicyId"]
        }
        if ($null -ne $PSBoundParameters["ErrorVariable"]) {
            $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"]
        }
        if ($null -ne $PSBoundParameters["ErrorAction"]) {
            $params["ErrorAction"] = $PSBoundParameters["ErrorAction"]
        }
        if ($null -ne $PSBoundParameters["GroupLifetimeInDays"]) {
            $params["GroupLifetimeInDays"] = $PSBoundParameters["GroupLifetimeInDays"]
        }
        if ($null -ne $PSBoundParameters["InformationAction"]) {
            $params["InformationAction"] = $PSBoundParameters["InformationAction"]
        }
        if ($null -ne $PSBoundParameters["WarningAction"]) {
            $params["WarningAction"] = $PSBoundParameters["WarningAction"]
        }
        if ($null -ne $PSBoundParameters["ProgressAction"]) {
            $params["ProgressAction"] = $PSBoundParameters["ProgressAction"]
        }

        Write-Debug("============================ TRANSFORMATIONS ============================")
        $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug
        Write-Debug("=========================================================================`n")
    
        $response = Update-MgGroupLifecyclePolicy @params -Headers $customHeaders
        $response | ForEach-Object {
            if ($null -ne $_) {
                Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id

            }
        }
        $response
    }
}


Export-ModuleMember -Function @('Add-EntraGroupMember', 'Add-EntraGroupOwner', 'Add-EntraLifecyclePolicyGroup', 'Get-EntraDeletedGroup', 'Get-EntraGroup', 'Get-EntraGroupAppRoleAssignment', 'Get-EntraGroupLifecyclePolicy', 'Get-EntraGroupMember', 'Get-EntraGroupOwner', 'Get-EntraGroupPermissionGrant', 'Get-EntraLifecyclePolicyGroup', 'Get-EntraObjectSetting', 'Get-EntraUnsupportedCommand', 'New-EntraCustomHeaders', 'New-EntraGroup', 'New-EntraGroupAppRoleAssignment', 'New-EntraGroupLifecyclePolicy', 'Remove-EntraGroup', 'Remove-EntraGroupAppRoleAssignment', 'Remove-EntraGroupLifecyclePolicy', 'Remove-EntraGroupMember', 'Remove-EntraGroupOwner', 'Remove-EntraLifecyclePolicyGroup', 'Reset-EntraLifeCycleGroup', 'Select-EntraGroupIdsContactIsMemberOf', 'Select-EntraGroupIdsGroupIsMemberOf', 'Select-EntraGroupIdsUserIsMemberOf', 'Set-EntraGroup', 'Set-EntraGroupLifecyclePolicy')

# Typedefs
# ------------------------------------------------------------------------------
# Type definitions required for commands inputs
# ------------------------------------------------------------------------------

$def = @"
 
namespace Microsoft.Open.AzureAD.Graph.PowerShell.Custom
{
 
    using System.Linq;
            public enum KeyType{
            Symmetric = 0,
            AsymmetricX509Cert = 1,
        }
        public enum KeyUsage{
            Sign = 0,
            Verify = 1,
            Decrypt = 2,
            Encrypt = 3,
        }
}
 
namespace Microsoft.Open.AzureAD.Model
{
 
    using System.Linq;
    public class AlternativeSecurityId
    {
        public System.String IdentityProvider;
        public System.Byte[] Key;
        public System.Nullable<System.Int32> Type;
         
    }
    public class AppRole
    {
        public System.Collections.Generic.List<System.String> AllowedMemberTypes;
        public System.String Description;
        public System.String DisplayName;
        public System.String Id;
        public System.Nullable<System.Boolean> IsEnabled;
        public System.String Origin;
        public System.String Value;
    }
    public class AssignedLicense
    {
        public System.Collections.Generic.List<System.String> DisabledPlans;
        public System.String SkuId;
         
    }
    public class AssignedLicenses
    {
        public System.Collections.Generic.List<Microsoft.Open.AzureAD.Model.AssignedLicense> AddLicenses;
        public System.Collections.Generic.List<System.String> RemoveLicenses;
         
    }
    public class CertificateAuthorityInformation
    {
        public enum AuthorityTypeEnum{
            RootAuthority = 0,
            IntermediateAuthority = 1,
        }
        public System.Nullable<AuthorityTypeEnum> AuthorityType;
        public System.String CrlDistributionPoint;
        public System.String DeltaCrlDistributionPoint;
        public System.Byte[] TrustedCertificate;
        public System.String TrustedIssuer;
        public System.String TrustedIssuerSki;
         
    }
    public class CrossCloudVerificationCodeBody
    {
        public System.String CrossCloudVerificationCode;
        public CrossCloudVerificationCodeBody()
        {
        }
         
        public CrossCloudVerificationCodeBody(System.String value)
        {
            CrossCloudVerificationCode = value;
        }
    }
    public class GroupIdsForMembershipCheck
    {
        public System.Collections.Generic.List<System.String> GroupIds;
        public GroupIdsForMembershipCheck()
        {
        }
         
        public GroupIdsForMembershipCheck(System.Collections.Generic.List<System.String> value)
        {
            GroupIds = value;
        }
    }
    public class KeyCredential
    {
        public System.Byte[] CustomKeyIdentifier;
        public System.Nullable<System.DateTime> EndDate;
        public System.String KeyId;
        public System.Nullable<System.DateTime> StartDate;
        public System.String Type;
        public System.String Usage;
        public System.Byte[] Value;
         
    }
    public class PasswordCredential
    {
        public System.Byte[] CustomKeyIdentifier;
        public System.Nullable<System.DateTime> EndDate;
        public System.String KeyId;
        public System.Nullable<System.DateTime> StartDate;
        public System.String Value;
         
    }
    public class PasswordProfile
    {
        public System.String Password;
        public System.Nullable<System.Boolean> ForceChangePasswordNextLogin;
        public System.Nullable<System.Boolean> EnforceChangePasswordPolicy;
         
    }
    public class PrivacyProfile
    {
        public System.String ContactEmail;
        public System.String StatementUrl;
         
    }
    public class SignInName
    {
        public System.String Type;
        public System.String Value;
         
    }
}
 
namespace Microsoft.Open.MSGraph.Model
{
 
    using System.Linq;
    public class AddIn
    {
        public System.String Id;
        public System.String Type;
        public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.KeyValue> Properties;
         
    }
    public class ApiApplication
    {
        public System.Nullable<System.Boolean> AcceptMappedClaims;
        public System.Collections.Generic.List<System.String> KnownClientApplications;
        public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.PreAuthorizedApplication> PreAuthorizedApplications;
        public System.Nullable<System.Int32> RequestedAccessTokenVersion;
        public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.PermissionScope> Oauth2PermissionScopes;
         
    }
    public class AppRole
    {
        public System.Collections.Generic.List<System.String> AllowedMemberTypes;
        public System.String Description;
        public System.String DisplayName;
        public System.String Id;
        public System.Nullable<System.Boolean> IsEnabled;
        public System.String Origin;
        public System.String Value;
         
    }
    public class ConditionalAccessApplicationCondition
    {
        public System.Collections.Generic.List<System.String> IncludeApplications;
        public System.Collections.Generic.List<System.String> ExcludeApplications;
        public System.Collections.Generic.List<System.String> IncludeUserActions;
        public System.Collections.Generic.List<System.String> IncludeProtectionLevels;
         
    }
    public class ConditionalAccessApplicationEnforcedRestrictions
    {
        public System.Nullable<System.Boolean> IsEnabled;
        public ConditionalAccessApplicationEnforcedRestrictions()
        {
        }
         
        public ConditionalAccessApplicationEnforcedRestrictions(System.Nullable<System.Boolean> value)
        {
            IsEnabled = value;
        }
    }
    public class ConditionalAccessCloudAppSecurity
    {
        public enum CloudAppSecurityTypeEnum{
            McasConfigured = 0,
            MonitorOnly = 1,
            BlockDownloads = 2,
        }
        public System.Nullable<CloudAppSecurityTypeEnum> CloudAppSecurityType;
        public System.Nullable<System.Boolean> IsEnabled;
         
    }
    public class ConditionalAccessConditionSet
    {
        public Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition Applications;
        public Microsoft.Open.MSGraph.Model.ConditionalAccessUserCondition Users;
        public Microsoft.Open.MSGraph.Model.ConditionalAccessPlatformCondition Platforms;
        public Microsoft.Open.MSGraph.Model.ConditionalAccessLocationCondition Locations;
        public enum ConditionalAccessRiskLevel{
            Low = 0,
            Medium = 1,
            High = 2,
            Hidden = 3,
            None = 4,
            UnknownFutureValue = 5,
        }
        public System.Collections.Generic.List<ConditionalAccessRiskLevel> SignInRiskLevels;
        public enum ConditionalAccessClientApp{
            All = 0,
            Browser = 1,
            MobileAppsAndDesktopClients = 2,
            ExchangeActiveSync = 3,
            EasSupported = 4,
            Other = 5,
        }
        public System.Collections.Generic.List<ConditionalAccessClientApp> ClientAppTypes;
         
    }
    public class ConditionalAccessGrantControls
    {
        public System.String _Operator;
        public enum ConditionalAccessGrantControl{
            Block = 0,
            Mfa = 1,
            CompliantDevice = 2,
            DomainJoinedDevice = 3,
            ApprovedApplication = 4,
            CompliantApplication = 5,
            PasswordChange = 6,
        }
        public System.Collections.Generic.List<ConditionalAccessGrantControl> BuiltInControls;
        public System.Collections.Generic.List<System.String> CustomAuthenticationFactors;
        public System.Collections.Generic.List<System.String> TermsOfUse;
         
    }
    public class ConditionalAccessLocationCondition
    {
        public System.Collections.Generic.List<System.String> IncludeLocations;
        public System.Collections.Generic.List<System.String> ExcludeLocations;
         
    }
    public class ConditionalAccessPersistentBrowser
    {
        public enum ModeEnum{
            Always = 0,
            Never = 1,
        }
        public System.Nullable<ModeEnum> Mode;
        public System.Nullable<System.Boolean> IsEnabled;
         
    }
    public class ConditionalAccessPlatformCondition
    {
        public enum ConditionalAccessDevicePlatforms{
            Android = 0,
            IOS = 1,
            Windows = 2,
            WindowsPhone = 3,
            MacOS = 4,
            All = 5,
        }
        public System.Collections.Generic.List<ConditionalAccessDevicePlatforms> IncludePlatforms;
        public System.Collections.Generic.List<ConditionalAccessDevicePlatforms> ExcludePlatforms;
         
    }
    public class ConditionalAccessSessionControls
    {
        public Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationEnforcedRestrictions ApplicationEnforcedRestrictions;
        public Microsoft.Open.MSGraph.Model.ConditionalAccessCloudAppSecurity CloudAppSecurity;
        public Microsoft.Open.MSGraph.Model.ConditionalAccessSignInFrequency SignInFrequency;
        public Microsoft.Open.MSGraph.Model.ConditionalAccessPersistentBrowser PersistentBrowser;
         
    }
    public class ConditionalAccessSignInFrequency
    {
        public enum TypeEnum{
            Days = 0,
            Hours = 1,
        }
        public System.Nullable<TypeEnum> Type;
        public System.Nullable<System.Int32> Value;
        public System.Nullable<System.Boolean> IsEnabled;
         
    }
    public class ConditionalAccessUserCondition
    {
        public System.Collections.Generic.List<System.String> IncludeUsers;
        public System.Collections.Generic.List<System.String> ExcludeUsers;
        public System.Collections.Generic.List<System.String> IncludeGroups;
        public System.Collections.Generic.List<System.String> ExcludeGroups;
        public System.Collections.Generic.List<System.String> IncludeRoles;
        public System.Collections.Generic.List<System.String> ExcludeRoles;
         
    }
        public enum CountriesAndRegion{
            AD = 0,
            AE = 1,
            AF = 2,
            AG = 3,
            AI = 4,
            AL = 5,
            AM = 6,
            AN = 7,
            AO = 8,
            AQ = 9,
            AR = 10,
            AS = 11,
            AT = 12,
            AU = 13,
            AW = 14,
            AX = 15,
            AZ = 16,
            BA = 17,
            BB = 18,
            BD = 19,
            BE = 20,
            BF = 21,
            BG = 22,
            BH = 23,
            BI = 24,
            BJ = 25,
            BL = 26,
            BM = 27,
            BN = 28,
            BO = 29,
            BQ = 30,
            BR = 31,
            BS = 32,
            BT = 33,
            BV = 34,
            BW = 35,
            BY = 36,
            BZ = 37,
            CA = 38,
            CC = 39,
            CD = 40,
            CF = 41,
            CG = 42,
            CH = 43,
            CI = 44,
            CK = 45,
            CL = 46,
            CM = 47,
            CN = 48,
            CO = 49,
            CR = 50,
            CU = 51,
            CV = 52,
            CW = 53,
            CX = 54,
            CY = 55,
            CZ = 56,
            DE = 57,
            DJ = 58,
            DK = 59,
            DM = 60,
            DO = 61,
            DZ = 62,
            EC = 63,
            EE = 64,
            EG = 65,
            EH = 66,
            ER = 67,
            ES = 68,
            ET = 69,
            FI = 70,
            FJ = 71,
            FK = 72,
            FM = 73,
            FO = 74,
            FR = 75,
            GA = 76,
            GB = 77,
            GD = 78,
            GE = 79,
            GF = 80,
            GG = 81,
            GH = 82,
            GI = 83,
            GL = 84,
            GM = 85,
            GN = 86,
            GP = 87,
            GQ = 88,
            GR = 89,
            GS = 90,
            GT = 91,
            GU = 92,
            GW = 93,
            GY = 94,
            HK = 95,
            HM = 96,
            HN = 97,
            HR = 98,
            HT = 99,
            HU = 100,
            ID = 101,
            IE = 102,
            IL = 103,
            IM = 104,
            IN = 105,
            IO = 106,
            IQ = 107,
            IR = 108,
            IS = 109,
            IT = 110,
            JE = 111,
            JM = 112,
            JO = 113,
            JP = 114,
            KE = 115,
            KG = 116,
            KH = 117,
            KI = 118,
            KM = 119,
            KN = 120,
            KP = 121,
            KR = 122,
            KW = 123,
            KY = 124,
            KZ = 125,
            LA = 126,
            LB = 127,
            LC = 128,
            LI = 129,
            LK = 130,
            LR = 131,
            LS = 132,
            LT = 133,
            LU = 134,
            LV = 135,
            LY = 136,
            MA = 137,
            MC = 138,
            MD = 139,
            ME = 140,
            MF = 141,
            MG = 142,
            MH = 143,
            MK = 144,
            ML = 145,
            MM = 146,
            MN = 147,
            MO = 148,
            MP = 149,
            MQ = 150,
            MR = 151,
            MS = 152,
            MT = 153,
            MU = 154,
            MV = 155,
            MW = 156,
            MX = 157,
            MY = 158,
            MZ = 159,
            NA = 160,
            NC = 161,
            NE = 162,
            NF = 163,
            NG = 164,
            NI = 165,
            NL = 166,
            NO = 167,
            NP = 168,
            NR = 169,
            NU = 170,
            NZ = 171,
            OM = 172,
            PA = 173,
            PE = 174,
            PF = 175,
            PG = 176,
            PH = 177,
            PK = 178,
            PL = 179,
            PM = 180,
            PN = 181,
            PR = 182,
            PS = 183,
            PT = 184,
            PW = 185,
            PY = 186,
            QA = 187,
            RE = 188,
            RO = 189,
            RS = 190,
            RU = 191,
            RW = 192,
            SA = 193,
            SB = 194,
            SC = 195,
            SD = 196,
            SE = 197,
            SG = 198,
            SH = 199,
            SI = 200,
            SJ = 201,
            SK = 202,
            SL = 203,
            SM = 204,
            SN = 205,
            SO = 206,
            SR = 207,
            SS = 208,
            ST = 209,
            SV = 210,
            SX = 211,
            SY = 212,
            SZ = 213,
            TC = 214,
            TD = 215,
            TF = 216,
            TG = 217,
            TH = 218,
            TJ = 219,
            TK = 220,
            TL = 221,
            TM = 222,
            TN = 223,
            TO = 224,
            TR = 225,
            TT = 226,
            TV = 227,
            TW = 228,
            TZ = 229,
            UA = 230,
            UG = 231,
            UM = 232,
            US = 233,
            UY = 234,
            UZ = 235,
            VA = 236,
            VC = 237,
            VE = 238,
            VG = 239,
            VI = 240,
            VN = 241,
            VU = 242,
            WF = 243,
            WS = 244,
            YE = 245,
            YT = 246,
            ZA = 247,
            ZM = 248,
            ZW = 249,
        }
    public class DefaultUserRolePermissions
    {
        public System.Nullable<System.Boolean> AllowedToCreateApps;
        public System.Nullable<System.Boolean> AllowedToCreateSecurityGroups;
        public System.Nullable<System.Boolean> AllowedToReadOtherUsers;
        public System.Collections.Generic.List<System.String> PermissionGrantPoliciesAssigned;
         
    }
    public class DelegatedPermissionClassification
    {
        public enum ClassificationEnum{
            Low = 0,
            Medium = 1,
            High = 2,
        }
        public System.Nullable<ClassificationEnum> Classification;
        public System.String Id;
        public System.String PermissionId;
        public System.String PermissionName;
         
    }
    public class EmailAddress
    {
        public System.String Name;
        public System.String Address;
         
    }
    public class ImplicitGrantSettings
    {
        public System.Nullable<System.Boolean> EnableIdTokenIssuance;
        public System.Nullable<System.Boolean> EnableAccessTokenIssuance;
         
    }
    public class InformationalUrl
    {
        public System.String TermsOfServiceUrl;
        public System.String MarketingUrl;
        public System.String PrivacyStatementUrl;
        public System.String SupportUrl;
        public System.String LogoUrl;
         
    }
    public class InvitedUserMessageInfo
    {
        public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.Recipient> CcRecipients;
        public System.String CustomizedMessageBody;
        public System.String MessageLanguage;
         
    }
    public class IpRange
    {
        public System.String CidrAddress;
        public IpRange()
        {
        }
         
        public IpRange(System.String value)
        {
            CidrAddress = value;
        }
    }
    public class KeyCredential
    {
        public System.Byte[] CustomKeyIdentifier;
        public System.String DisplayName;
        public System.Nullable<System.DateTime> EndDateTime;
        public System.String KeyId;
        public System.Nullable<System.DateTime> StartDateTime;
        public System.String Type;
        public System.String Usage;
        public System.Byte[] Key;
         
    }
    public class KeyValue
    {
        public System.String Key;
        public System.String Value;
         
    }
    public class MsDirectoryObject
    {
        public System.String Id;
        public System.String OdataType;
    }
 
    public class MsRoleMemberInfo
    {
       public System.String Id;
    }
 
    public class OptionalClaim
    {
        public System.String Name;
        public System.String Source;
        public System.Nullable<System.Boolean> Essential;
        public System.Collections.Generic.List<System.String> AdditionalProperties;
         
    }
    public class OptionalClaims
    {
        public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.OptionalClaim> IdToken;
        public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.OptionalClaim> AccessToken;
        public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.OptionalClaim> Saml2Token;
         
    }
    public class ParentalControlSettings
    {
        public enum LegalAgeGroupRuleEnum{
            Allow = 0,
            RequireConsentForPrivacyServices = 1,
            RequireConsentForMinors = 2,
            RequireConsentForKids = 3,
            BlockMinors = 4,
        }
        public System.Nullable<LegalAgeGroupRuleEnum> LegalAgeGroupRule;
        public System.Collections.Generic.List<System.String> CountriesBlockedForMinors;
         
    }
    public class PasswordCredential
    {
        public System.Byte[] CustomKeyIdentifier;
        public System.Nullable<System.DateTime> EndDateTime;
        public System.String DisplayName;
        public System.String KeyId;
        public System.Nullable<System.DateTime> StartDateTime;
        public System.String SecretText;
        public System.String Hint;
         
    }
    public class PermissionScope
    {
        public System.String AdminConsentDescription;
        public System.String AdminConsentDisplayName;
        public System.String Id;
        public System.Nullable<System.Boolean> IsEnabled;
        public System.String Type;
        public System.String UserConsentDescription;
        public System.String UserConsentDisplayName;
        public System.String Value;
         
    }
    public class PreAuthorizedApplication
    {
        public System.String AppId;
        public System.Collections.Generic.List<System.String> DelegatedPermissionIds;
         
    }
    public class PublicClientApplication
    {
        public System.Collections.Generic.List<System.String> RedirectUris;
        public PublicClientApplication()
        {
        }
         
        public PublicClientApplication(System.Collections.Generic.List<System.String> value)
        {
            RedirectUris = value;
        }
    }
    public class Recipient
    {
        public Microsoft.Open.MSGraph.Model.EmailAddress EmailAddress;
        public Recipient()
        {
        }
         
        public Recipient(Microsoft.Open.MSGraph.Model.EmailAddress value)
        {
            EmailAddress = value;
        }
    }
    public class RequiredResourceAccess
    {
        public System.String ResourceAppId;
        public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.ResourceAccess> ResourceAccess;
         
    }
    public class ResourceAccess
    {
        public System.String Id;
        public System.String Type;
         
    }
    public class RolePermission
    {
        public System.Collections.Generic.List<System.String> AllowedResourceActions;
        public System.String Condition;
         
    }
    public class SetVerifiedPublisherRequest
    {
        public System.String VerifiedPublisherId;
        public SetVerifiedPublisherRequest()
        {
        }
         
        public SetVerifiedPublisherRequest(System.String value)
        {
            VerifiedPublisherId = value;
        }
    }
    public class User
    {
        public System.String Id;
        public System.String OdataType;
         
    }
    public class WebApplication
    {
        public System.String HomePageUrl;
        public System.String LogoutUrl;
        public System.Collections.Generic.List<System.String> RedirectUris;
        public Microsoft.Open.MSGraph.Model.ImplicitGrantSettings ImplicitGrantSettings;
         
    }
}
"@


try {
    Add-Type -TypeDefinition $def -ErrorAction SilentlyContinue
} catch {
    # No error message will be displayed, and type will be added if it doesn't exist
}


# ------------------------------------------------------------------------------
# End of Type definitions required for commands inputs
# ------------------------------------------------------------------------------


# SIG # Begin signature block
# MIIoKgYJKoZIhvcNAQcCoIIoGzCCKBcCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDdBQgeo7Oc5QEj
# SZxy9zej5QmmmH8B+tpGyHRKmkRhR6CCDXYwggX0MIID3KADAgECAhMzAAAEBGx0
# Bv9XKydyAAAAAAQEMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjQwOTEyMjAxMTE0WhcNMjUwOTExMjAxMTE0WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQC0KDfaY50MDqsEGdlIzDHBd6CqIMRQWW9Af1LHDDTuFjfDsvna0nEuDSYJmNyz
# NB10jpbg0lhvkT1AzfX2TLITSXwS8D+mBzGCWMM/wTpciWBV/pbjSazbzoKvRrNo
# DV/u9omOM2Eawyo5JJJdNkM2d8qzkQ0bRuRd4HarmGunSouyb9NY7egWN5E5lUc3
# a2AROzAdHdYpObpCOdeAY2P5XqtJkk79aROpzw16wCjdSn8qMzCBzR7rvH2WVkvF
# HLIxZQET1yhPb6lRmpgBQNnzidHV2Ocxjc8wNiIDzgbDkmlx54QPfw7RwQi8p1fy
# 4byhBrTjv568x8NGv3gwb0RbAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU8huhNbETDU+ZWllL4DNMPCijEU4w
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
# MBQGA1UEBRMNMjMwMDEyKzUwMjkyMzAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAIjmD9IpQVvfB1QehvpC
# Ge7QeTQkKQ7j3bmDMjwSqFL4ri6ae9IFTdpywn5smmtSIyKYDn3/nHtaEn0X1NBj
# L5oP0BjAy1sqxD+uy35B+V8wv5GrxhMDJP8l2QjLtH/UglSTIhLqyt8bUAqVfyfp
# h4COMRvwwjTvChtCnUXXACuCXYHWalOoc0OU2oGN+mPJIJJxaNQc1sjBsMbGIWv3
# cmgSHkCEmrMv7yaidpePt6V+yPMik+eXw3IfZ5eNOiNgL1rZzgSJfTnvUqiaEQ0X
# dG1HbkDv9fv6CTq6m4Ty3IzLiwGSXYxRIXTxT4TYs5VxHy2uFjFXWVSL0J2ARTYL
# E4Oyl1wXDF1PX4bxg1yDMfKPHcE1Ijic5lx1KdK1SkaEJdto4hd++05J9Bf9TAmi
# u6EK6C9Oe5vRadroJCK26uCUI4zIjL/qG7mswW+qT0CW0gnR9JHkXCWNbo8ccMk1
# sJatmRoSAifbgzaYbUz8+lv+IXy5GFuAmLnNbGjacB3IMGpa+lbFgih57/fIhamq
# 5VhxgaEmn/UjWyr+cPiAFWuTVIpfsOjbEAww75wURNM1Imp9NJKye1O24EspEHmb
# DmqCUcq7NqkOKIG4PVm3hDDED/WQpzJDkvu4FrIbvyTGVU01vKsg4UfcdiZ0fQ+/
# V0hf8yrtq9CkB8iIuk5bBxuPMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg
# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03
# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr
# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg
# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy
# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9
# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh
# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB
# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn
# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90
# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w
# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o
# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD
# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa
# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG
# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG
# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl
# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb
# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l
# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6
# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0
# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560
# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam
# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa
# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
# /Xmfwb1tbWrJUnMTDXpQzTGCGgowghoGAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
# Z25pbmcgUENBIDIwMTECEzMAAAQEbHQG/1crJ3IAAAAABAQwDQYJYIZIAWUDBAIB
# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIIid/iHy7DmFBOvlEgB8iNqB
# PtpAAcmVe5iwH3DaWnmHMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
# BQAEggEAZw84NJhcudx2ReCR0NeEQeCxUkc1jFYZSLLEHd1HYYgejeZ3ENdW0DhY
# vAM5oplxqR2JOqj8tn6w/0tOin5LDGuBi0NlYLfFg3CCAvS4ZuWQJ8/LM+gEV2vY
# 83qf5yMH+bt1Z5bigmcQMOy3qOdjm1aThKBexjT4UUT71Kgg7Y5Cie1XQn/cxfyL
# /0DZnBjmwX91mtCm+0xvuW0Aq+HTvP8avuXwXA3aAvLe2velT+Z+YOU3r49SkdBV
# 8ud1wTutTKPs2ru0NZAoBR93+b55TpAgLkqA3neOlfuszLyi4dNMF7WEYdE7u5dv
# vsPqlCl9mxCC2rzA1bJwF7yhkBOft6GCF5QwgheQBgorBgEEAYI3AwMBMYIXgDCC
# F3wGCSqGSIb3DQEHAqCCF20wghdpAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsq
# hkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
# AwQCAQUABCBOxsYIiFBQ5EjRe0Wpu0a/8SuIp7VOkw9nnWC6h36O9gIGaBKws8hz
# GBMyMDI1MDUwNTEzMjUzNC40NjRaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l
# cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046REMwMC0w
# NUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wg
# ghHqMIIHIDCCBQigAwIBAgITMwAAAgO7HlwAOGx0ygABAAACAzANBgkqhkiG9w0B
# AQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yNTAxMzAxOTQy
# NDZaFw0yNjA0MjIxOTQyNDZaMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv
# cnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25z
# MScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046REMwMC0wNUUwLUQ5NDcxJTAjBgNV
# BAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQChl0MH5wAnOx8Uh8RtidF0J0yaFDHJYHTpPvRR16X1
# KxGDYfT8PrcGjCLCiaOu3K1DmUIU4Rc5olndjappNuOgzwUoj43VbbJx5PFTY/a1
# Z80tpqVP0OoKJlUkfDPSBLFgXWj6VgayRCINtLsUasy0w5gysD7ILPZuiQjace5K
# xASjKf2MVX1qfEzYBbTGNEijSQCKwwyc0eavr4Fo3X/+sCuuAtkTWissU64k8rK6
# 0jsGRApiESdfuHr0yWAmc7jTOPNeGAx6KCL2ktpnGegLDd1IlE6Bu6BSwAIFHr7z
# OwIlFqyQuCe0SQALCbJhsT9y9iy61RJAXsU0u0TC5YYmTSbEI7g10dYx8Uj+vh9I
# nLoKYC5DpKb311bYVd0bytbzlfTRslRTJgotnfCAIGMLqEqk9/2VRGu9klJi1j9n
# VfqyYHYrMPOBXcrQYW0jmKNjOL47CaEArNzhDBia1wXdJANKqMvJ8pQe2m8/ciby
# DM+1BVZquNAov9N4tJF4ACtjX0jjXNDUMtSZoVFQH+FkWdfPWx1uBIkc97R+xRLu
# PjUypHZ5A3AALSke4TaRBvbvTBYyW2HenOT7nYLKTO4jw5Qq6cw3Z9zTKSPQ6D5l
# yiYpes5RR2MdMvJS4fCcPJFeaVOvuWFSQ/EGtVBShhmLB+5ewzFzdpf1UuJmuOQT
# TwIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFLIpWUB+EeeQ29sWe0VdzxWQGJJ9MB8G
# A1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCG
# Tmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy
# MFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4w
# XAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy
# dHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwG
# A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD
# AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQCQEMbesD6TC08R0oYCdSC452AQrGf/O89G
# Q54CtgEsbxzwGDVUcmjXFcnaJSTNedBKVXkBgawRonP1LgxH4bzzVj2eWNmzGIwO
# 1FlhldAPOHAzLBEHRoSZ4pddFtaQxoabU/N1vWyICiN60It85gnF5JD4MMXyd6pS
# 8eADIi6TtjfgKPoumWa0BFQ/aEzjUrfPN1r7crK+qkmLztw/ENS7zemfyx4kGRgw
# Y1WBfFqm/nFlJDPQBicqeU3dOp9hj7WqD0Rc+/4VZ6wQjesIyCkv5uhUNy2LhNDi
# 2leYtAiIFpmjfNk4GngLvC2Tj9IrOMv20Srym5J/Fh7yWAiPeGs3yA3QapjZTtfr
# 7NfzpBIJQ4xT/ic4WGWqhGlRlVBI5u6Ojw3ZxSZCLg3vRC4KYypkh8FdIWoKirji
# dEGlXsNOo+UP/YG5KhebiudTBxGecfJCuuUspIdRhStHAQsjv/dAqWBLlhorq2OC
# aP+wFhE3WPgnnx5pflvlujocPgsN24++ddHrl3O1FFabW8m0UkDHSKCh8QTwTkYO
# wu99iExBVWlbYZRz2qOIBjL/ozEhtCB0auKhfTLLeuNGBUaBz+oZZ+X9UAECoMhk
# ETjb6YfNaI1T7vVAaiuhBoV/JCOQT+RYZrgykyPpzpmwMNFBD1vdW/29q9nkTWoE
# hcEOO0L9NzCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZI
# hvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# MjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAy
# MDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
# AQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25Phdg
# M/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPF
# dvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6
# GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBp
# Dco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50Zu
# yjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3E
# XzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0
# lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1q
# GFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ
# +QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PA
# PBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkw
# EgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxG
# NSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARV
# MFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAK
# BggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC
# AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX
# zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v
# cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI
# KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG
# 9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0x
# M7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmC
# VgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449
# xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wM
# nosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDS
# PeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2d
# Y3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxn
# GSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+Crvs
# QWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokL
# jzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL
# 6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNN
# MIICNQIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEn
# MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOkRDMDAtMDVFMC1EOTQ3MSUwIwYDVQQD
# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQDN
# rxRX/iz6ss1lBCXG8P1LFxD0e6CBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
# IFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA68MdlTAiGA8yMDI1MDUwNTExMjA1
# M1oYDzIwMjUwNTA2MTEyMDUzWjB0MDoGCisGAQQBhFkKBAExLDAqMAoCBQDrwx2V
# AgEAMAcCAQACAiEJMAcCAQACAhLyMAoCBQDrxG8VAgEAMDYGCisGAQQBhFkKBAIx
# KDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZI
# hvcNAQELBQADggEBADo86D1mOpEjZ479gIg+7COqzpoif29/+6ZoW0GYP4MrBitL
# ekku1IPhstVA+pu7HY7SIecxDQ/oXZaqbd4qWl1AgGcfqBe/7A1auQEP2PLVTg+8
# 96zXM4QL/mQfo+qULd0pgSipvmGbiWd0mtnRdVHNtHr8Dos1ZK/ZEDCoEkJq6x2m
# b0704tMMYXT4XRJltZMh3oeUtXCDoD+MNF85G9MYjbe/zOR9+FBZVEiw3owTSM41
# eL/5C6y7cVJV3zudPLZ0j9eXy1B2fmKCyydLIfS2ZEqgQ1ysL3wZ3d8kN1Mo42RY
# c+bbWkFU/E/Aw36EI3DFYH9jicRFtqZtbvnBIeQxggQNMIIECQIBATCBkzB8MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNy
# b3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAgO7HlwAOGx0ygABAAACAzAN
# BglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8G
# CSqGSIb3DQEJBDEiBCBhsquOk60l/JJl/PgenjZPFUmvJEG1ZbUQiEGdIxMc8jCB
# +gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EIEsD3RtxlvaTxFOZZnpQw0DksPmV
# duo5SyK9h9w++hMtMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh
# c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
# b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw
# MTACEzMAAAIDux5cADhsdMoAAQAAAgMwIgQg+oK1qxrsysN6KhXNvpU2qVLGGyum
# HVgNnOvh0Oo1rqUwDQYJKoZIhvcNAQELBQAEggIAh/NDZGJolpavzDJLmfpQINpu
# ak7ud+cm+mwGV+Gwnmba4L5/WlS22b1bR1N7Gsm8oXGuTx1vdxqo5sBjYip09Eyx
# JbbrB/Bslfz424PwNx/wJrLsBTEa9j4DPM+Zrw1M8p2JdNXsYLHFSMQSVgAsMqGH
# EMs4iHZBWqdsqdYKq8YC6rEXdCmsFwwEetBP23RdUkvvW76xcc1kiv9LYCgkN8pG
# mWBxBZtQIS5QPMcWrTn7QOafNM5OTog0sj/PRbthzcWWwErMVphdqTx7sYNcoh12
# p7TJHouAiH/ZHbtYZlYXC8uBMtjPDGoOO5DYOAC2l7lOPO19HlBXSXvd/Jynx3CL
# /3iE4tOQOXMeM40yh/gv0+5xd6QI+oMnNxKkEGFin8862F+XNl9gMwRuwam2FGf2
# yEpveBO9hya2bRoH80Yxhm0ZdViFyTMnA4Pt3P+TS/eI1G1IQ2+Qlm0BPyrs+pmW
# OH4czy8BP1g7wnVvexKSBE7f7bPwx/ICWDTHoGUG3K2zasduIICNIy+8SkjfcOSR
# BgIGYlouWr5y35KFAkwBLWp20d6ICiYY2Z1SpXsVqrqBSm+8e+RtYdZFIledSDg0
# xWInRotlYVJZLugQitNzozSeeF6QIC4SM0jZQPOlK5c/GE39qEwuUSLkD6xxlUWK
# nTFRhl3kLxyrVoImZiU=
# SIG # End signature block