1.0.4/BackTheGraphUp.psm1

Function Get-BGUAccessToken {
    <#
    .SYNOPSIS
        This function is used to obtain the access token for the BackTheGraph Up commandlets, This will store a global variable with the access token for your current session.
    .DESCRIPTION
        This function is used to obtain the access token for the BackTheGraph Up commandlets, This will store a global variable with the access token for your current session.
         
        This module requires the Connect-AZAD_Token module to be installed, if this is not already installed, It will install it for you.
    .EXAMPLE
        PS C:\> Get-BGUAccessToken
 
        This will connect you to the tenant your account is associated with.
    .EXAMPLE
        PS C:\> Get-BGUAccessToken -TenantID <TenantID>
 
        This will allow you connect to another tenant even as a guest account as long as you have the privileges.
    .EXAMPLE
        PS C:\> Get-BGUAccessToken -DelegateID <ClientApplicationID>
 
        This will be required to manage conditional access modules, as these require additional permissions not granted to the Default Powershell Module.
    .EXAMPLE
        PS C:\> Get-BGUAccessToken -TenantID <TenantID> -ClientID <ClientApplicationID> -ClientSecret <ClientSecret>
 
        This will connect you to a tenant without been prompted to login.
    .INPUTS
        -TenantID : Used to connect to another Tenant
        -ClientID : Used to connect to the Graph API using a Client ID and Secret, Also requires TenantID (AKA. Application Access)
        -ClientSecret : See ClientID
        -DelegateID : This will be required to manage conditional access modules, as these require additional permissions not granted to the Default Powershell Module.
    .OUTPUTS
        $BGUAccessToken : This contains all of the information used in other modules.
    .NOTES
    #>

    [CmdletBinding()]
    param (
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [string]
        $ClientID,
        [string]
        $ClientSecret,
        #Your Azure Tenent ID
        [string]
        $TenantId,
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion",
        [string]
        $DelegateID
    )

    begin {
        $RequireMod = Get-Module -Name "Connect-AzAD_Token" -ListAvailable
        if (!($RequireMod)) {
            try {
                Write-Host -ForegroundColor Cyan "Attempting to Install the Connect-AzADToken Powershell module..."
                Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -ErrorAction Stop | Out-Null
                Install-Module "Connect-AzAD_token" -Force -ErrorAction Stop
            }
            catch {
                Throw "Failed to install the AzureAD PowerShell Module" 
            }   
        }

        Import-Module Connect-AzAD_Token

        $ConnectParams = @{}
        IF ($ClientID){$ConnectParams.Add('ClientID', $ClientID)}
        IF ($ClientSecret){$ConnectParams.Add('ClientSecret', $ClientSecret)}
        IF ($DelegateID){$ConnectParams.Add('DelegateID', $DelegateID)}
        IF ($TenantId){
            $ConnectParams.Add('Tenant', $TenantId)
        } ELSE {
            $TenantID = $UserInfo.TenantID
        }

    }
    #Process The Function
    Process {
        try {
            $Global:BGUAccessToken = Connect-AzAD_Token @ConnectParams
        }
        catch {
            $Error[0]
            throw "Failed to obtain access token"
        }
    }
}

##################################################################################
##################################################################################
# #
# Admin Templates #
# #
##################################################################################
##################################################################################

Function Get-AdminTemplates {
    <#
    .SYNOPSIS
        This function is used to get Administrative Template policies from the GraphAPI Associated with your connected tenant.
    .DESCRIPTION
        This function is used to get Administrative Template policies from the GraphAPI Associated with your connected tenant.
        It is possible to filter these by using -Type FilterQuery -FilterID <policyID>, you can also user Where-Object to filter these.
    .EXAMPLE
        PS C:\> Get-AdminTemplates
 
        This will return all of the policies within your connected tenant
    .EXAMPLE
        PS C:\> Get-AdminTemplates -Type FilterQuery -FilterID <PolicyID>
 
        This will return the single policy for the ID you specify
    .INPUTS
        -Type : Used when you want to specify if you want to Filter the ID.
        -FilterID : The ID of the Policy
    .OUTPUTS
        Sample:
            createdDateTime : 2020-11-19T09:40:16.901865Z
            displayName : Prod - AdminTemplate
            description :
            roleScopeTagIds : {0}
            id : 7f0bb273-xxx-xxx-xx-823aff445xxx
            lastModifiedDateTime : 2020-11-19T09:40:17.4799505Z
    .NOTES
    #>

    [CmdletBinding()]
    param (
        [ValidateSet('All','FilterQuery')]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Type) {
            FilterQuery {
                $FAttrib = New-Object System.Management.Automation.ParameterAttribute
                $FAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FAttrib)
                #add our paramater specifying the attribute collection
                $FilterID = New-Object System.Management.Automation.RuntimeDefinedParameter('FilterID', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('FilterID', $FilterID)
                return $paramDictionary
            }
        }
    }

    begin {
       IF (-Not ($BGUAccessToken)) {
           Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
       } 
       elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
           Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
       }

        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}

    }
    #Process The Function
    Process {

        try {
            $GraphParams = @{
                Method = "GET"
                URI = "$GraphURI/deviceManagement/groupPolicyConfigurations"
                Headers = $GraphHeader
            }
    
            $GraphRequest = Invoke-RestMethod @GraphParams -ErrorAction Stop
            $global:All_GraphRequest = @()
            $All_GraphRequest += $GraphRequest
            while($GraphRequest.'@odata.nextLink') {
                $GraphRequest_NextLink = @{
                    Method = "GET"
                    URI = $GraphRequest.'@odata.nextLink'
                    Headers = $GraphHeader
                    ContentType = "application/JSON"
                }
                $GraphRequest = Invoke-RestMethod @$GraphRequest_NextLink -ErrorAction Stop
                $All_GraphRequest += $GraphRequest
            }
        }
        catch {
            $Error[0]
            Throw "The Microsoft Graph Query Failed,"
        }
        
        Switch ($Type) {
            Default {
                $All_GraphRequest | Select-Object -ExpandProperty Value
            }
            FilterQuery {
                $All_GraphRequest | Select-Object -ExpandProperty Value | Where-Object id -Match $($PSBoundParameters.FilterID)
            }
        }
    }
}
Function Import-AdminTemplate {
    [CmdletBinding()]
    param (
        [ValidateSet('Object','File')]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        switch ($Type) {
            File { 
                #If the Import Param is used, Create the File Param
                $FileAttribute = New-Object System.Management.Automation.ParameterAttribute
                $FileAttribute.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FileAttribute)
                #add our paramater specifying the attribute collection
                $File = New-Object System.Management.Automation.RuntimeDefinedParameter('File', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('File', $File)
                return $paramDictionary 
            }
            Object {
                $ObjectAttrib = New-Object System.Management.Automation.ParameterAttribute
                $ObjectAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom ObjectAttrib attribute
                $attributeCollection.Add($ObjectAttrib)
                #add our paramater specifying the attribute collection
                $ImportObject = New-Object System.Management.Automation.RuntimeDefinedParameter('ImportObject', [Object], $attributeCollection)
                $ImportObject_Settings = New-Object System.Management.Automation.RuntimeDefinedParameter('ImportObject_Settings', [Object], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ImportObject', $ImportObject)
                $paramDictionary.Add('ImportObject_Settings', $ImportObject_Settings)
                return $paramDictionary 
            }
        }
        
    }

    begin {
        #If the File Param is used, Test the Path to make sure its accessible, If not throw an error. If it does exist set the Import_File Param to the AttributeValue
        IF ($PSBoundParameters.File){
            IF(-not (Test-Path -Path $PSBoundParameters.File)) {
                Throw "Unable to locate $PSBoundParameters.File"
            } else {
                $Import_File = $PSBoundParameters.File
            }
        }
        
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
         $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
 
    } 

    #Process The Function
    Process {
        switch ($Type) {
            File { 
                $File_Info = Get-Item $Import_File | Select-Object -Property *

                $ImportSettingsFile = Join-Path -Path $File_Info.DirectoryName -ChildPath ($File_Info.BaseName + "_settings.json")
                if(Test-Path -Path $ImportSettingsFile) {
                    $Settings = (ConvertFrom-Json -InputObject (Get-Content $ImportSettingsFile -Raw))
                }
                $BasePolicyJSON = Get-Content $Import_File | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty Version,LastModifiedTime,CreatedDateTime,id,supportsScopeTags | ConvertTo-Json -Depth 10
            }
            Object {
                $BasePolicyJSON = $PSBoundParameters.ImportObject | Select-Object -Property * -ExcludeProperty Version,LastModifiedTime,CreatedDateTime,id,supportsScopeTags,lastModifiedDateTime | ConvertTo-Json -Depth 10
                $Settings = $PSBoundParameters.ImportObject_Settings
            }
        }
        
        $GraphBasePolicyImportParams = @{
            Method = "POST"
            URI = "$GraphURI/deviceManagement/groupPolicyConfigurations"
            BODY = $BasePolicyJSON
            Headers = $GraphHeader
            CONTENTTYPE = "application/Json"
        }
        $BasePolicyImport_Request = Invoke-RestMethod @GraphBasePolicyImportParams

        IF ($BasePolicyImport_Request){
            foreach ($Setting in $Settings) {
                $Setting.psobject.Properties.Remove('presentation')
                $Setting.psobject.Properties.Remove('ID')
                $Setting.psobject.Properties.Remove('lastModifiedDateTime')
                $Setting.psobject.Properties.Remove('createdDateTime')
                IF ($Setting.presentationValues) {
                    $CurrentSettings = $Setting.presentationValues | Select-Object * -ExcludeProperty presentation,id,lastmodifieddatetime,createddatetime
                    $Setting.presentationValues = @()
                    $Setting.presentationValues += $CurrentSettings
                }
                $GraphImportParams = @{
                    Method = "POST"
                    URI = "$GraphURI/deviceManagement/groupPolicyConfigurations/$($BasePolicyImport_Request.id)/definitionValues"
                    BODY = ($Setting | ConvertTo-Json -Depth 10)
                    Headers = $GraphHeader
                    CONTENTTYPE = "application/Json"
                }
                Invoke-RestMethod @GraphImportParams
            }
        }
    }
}

function Get-AdminTemplate_Settings {
    <#
    .SYNOPSIS
        This function is used to get Administrative Template policy settings from the GraphAPI Associated with your connected tenant.
    .DESCRIPTION
        This function is used to get Administrative Template policy settings from the GraphAPI Associated with your connected tenant.
         
        This function accepts the Object input from Get-AdminTemplates
    .EXAMPLE
        PS C:\> Get-AdminTemplates_Settings -InputObject (Get-AdminTemplates -Type FilterQuery -FilterID <PolicyID>)
 
        This will return all of the policy settings for that AdminTemplate
    .INPUTS
        -InputObject : The object output of Get-AdminTemplates
    .OUTPUTS
        Sample:
            Name Value
            ---- -----
            definition@odata.bind https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('43bd9826-a322-4562-ad44-3541e19bdb37')
            enabled True
            definition@odata.bind https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('e44011cd-6e22-4068-a722-4f3aa7d50423')
            enabled True
    .NOTES
    #>

    param(
        [Parameter(Mandatory = $true)]
        $InputObject,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    begin {
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
         $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
 
    }

    Process {
        $adm_settings = @()
        # Get all policies set for the profile
        $GraphDefinitionValuesParam = @{
            METHOD = "GET"
            URI = "$GraphURI/deviceManagement/groupPolicyConfigurations/$($InputObject.id)/definitionValues?`$expand=definition"
            HEADERS = $GraphHeader
        }
        $Definition_Values =  Invoke-RestMethod @GraphDefinitionValuesParam
        #For Each definition value, Get the presentation value with its settings
        foreach($Def in $Definition_Values.value)
        {
            # Get presentation values for the passed in object
            $GraphPresentationValuesParams = @{
                METHOD = "GET"
                URI = "$GraphURI/deviceManagement/groupPolicyConfigurations/$($InputObject.id)/definitionValues/$($Def.id)/presentationValues?`$expand=presentation"
                HEADERS = $GraphHeader
            }
            $presnetation_values =  Invoke-RestMethod @GraphPresentationValuesParams
            
            $adm_obj = @{
                "enabled" = $Def.enabled
                "definition@odata.bind" = "$($GraphURI)/deviceManagement/groupPolicyDefinitions('$($Def.definition.id)')"
            }

            #If presentation_Values is not blank, Get the settings
            if($presnetation_values.value)
            {
                # Policy presentation values
                $adm_obj.presentationValues = @()
                $presnetation = $null
                foreach ($presentation in $presnetation_values.value) 
                {
                    $presentation | Add-Member -MemberType NoteProperty -Name "presentation@odata.bind" -Value "$($GraphURI)/deviceManagement/groupPolicyDefinitions('$($Def.definition.id)')/presentations('$($presentation.presentation.id)')"
                    $adm_obj.presentationValues += $presentation
                }
            }
            $adm_settings += $adm_obj
        }
        $adm_settings
    }
}

function Export-AdminTemplate {
    param(
        [Parameter(Mandatory = $True)]
        $PolicyID, 
        [ValidateSet('Object','File')]
        [Parameter(Mandatory = $True)]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Type) {
            File {
                $FileAttribute = New-Object System.Management.Automation.ParameterAttribute
                $FileAttribute.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FileAttribute)
                #add our paramater specifying the attribute collection
                $ExportLocation = New-Object System.Management.Automation.RuntimeDefinedParameter('ExportLocation', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ExportLocation', $ExportLocation)
                return $paramDictionary
            }
        }
    }

    begin {
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
         $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
 
    }
    Process {
        $GraphObjectParams = @{
            METHOD = "GET"
            URI = "$GraphURI/deviceManagement/groupPolicyConfigurations/$($PolicyID)"
            HEADERS = $GraphHeader
        }

        $export_obj =  Invoke-RestMethod @GraphObjectParams

        if($export_obj)
        {       
            switch ($Type) {
                Object {
                    $export_obj
                }
                File {
                    # Export The Base Admin Template
                    ConvertTo-Json $export_obj -Depth 10 | Out-File "$ExportLocation\$(($export_obj.displayName)).json" -Force

                    # Export the settings from the Admin Template
                    $adm_settings = Get-AdminTemplate_Settings -InputObject $export_obj
                    ConvertTo-Json $adm_settings -Depth 10 | Out-File "$ExportLocation\$($export_obj.displayName)_Settings.json" -Force
                }
            }     
        }
    }
}
function Copy-AdminTemplate {
    param(
        [string]
        [Parameter(Mandatory = $True)]
        $PolicyID, 
        [Parameter(Mandatory = $True)]
        [ValidateSet('Copy','Test','PreProd','Dev','Prod','Pilot','Custom')]
        $Prefix,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Prefix) {
            Custom {
                $CustomAttrib = New-Object System.Management.Automation.ParameterAttribute
                $CustomAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom CustomAttrib attribute
                $attributeCollection.Add($CustomAttrib)
                #add our paramater specifying the attribute collection
                $CustomPrefix = New-Object System.Management.Automation.RuntimeDefinedParameter('CustomPrefix', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('CustomPrefix', $CustomPrefix)
                return $paramDictionary
            }
        }
    }

    begin {
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }

        switch ($Prefix) {
            Custom { 
                $PolicyPrefix = $PSBoundParameters.CustomPrefix.ToUpper()
            }
            Default {
                $PolicyPrefix = $Prefix.ToUpper()
            }
        }
    }
    
    process {
        Write-Output "Object iD: $($PolicyID)"

        $BaseObject = Export-AdminTemplate -Type Object $PolicyID
        $BaseObject.displayName = "$PolicyPrefix-$($BaseObject.displayName)"
        $BaseObject_Settings = Get-AdminTemplate_Settings -InputObject $BaseObject
        Import-AdminTemplate -Type Object -ImportObject $BaseObject -ImportObject_Settings $BaseObject_Settings
    }
}

##################################################################################
##################################################################################
# #
# Scripts #
# #
##################################################################################
##################################################################################
function Invoke-Encoder {
    param (
        [Parameter(Mandatory = $true)]
        [ValidateSet('Encode','Decode')]
        $Type,
        [Parameter(Mandatory = $true)]
        [string]
        $Value
    )

    switch ($Type) {
        Encode { 
            [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($Value))
        }
        Decode {
            [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($Value))
        }
    }
}
Function Get-IntuneScript {
    [CmdletBinding()]
    param (
        [ValidateSet('All','FilterQuery')]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Type) {
            FilterQuery {
                $FAttrib = New-Object System.Management.Automation.ParameterAttribute
                $FAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FAttrib)
                #add our paramater specifying the attribute collection
                $FilterID = New-Object System.Management.Automation.RuntimeDefinedParameter('FilterID', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('FilterID', $FilterID)
                return $paramDictionary
            }
        }
    }

    begin {
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
         $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
 
    } 
    #Process The Function
    Process {
        
        try {
            $GraphParams = @{
                Method = "GET"
                URI = "$GraphURI/deviceManagement/deviceManagementScripts"
                Headers = $GraphHeader
            }
            $GraphRequest = Invoke-RestMethod @GraphParams -ErrorAction Stop
            $global:All_GraphRequest = @()
            $All_GraphRequest += $GraphRequest
            while($GraphRequest.'@odata.nextLink') {
                $GraphRequest_NextLink = @{
                    Method = "GET"
                    URI = $GraphRequest.'@odata.nextLink'
                    Headers = $GraphHeader
                    ContentType = "application/JSON"
                }
                $GraphRequest = Invoke-RestMethod @$GraphRequest_NextLink -ErrorAction Stop
                $All_GraphRequest += $GraphRequest
            }
        }
        catch {
            $Error[0]
            Throw "The Microsoft Graph Query Failed,"
        }
      
        Switch ($Type) {
            Default {
                $All_GraphRequest | Select-Object -ExpandProperty Value
            }
            FilterQuery {
                $All_GraphRequest | Select-Object -ExpandProperty Value | Where-Object id -Match $($PSBoundParameters.FilterID)
            }
        }
    }
}
Function Import-IntuneScript {
    [CmdletBinding()]
    param (
        [ValidateSet('Object','File')]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        switch ($Type) {
            File { 
                #If the Import Param is used, Create the File Param
                $FileAttribute = New-Object System.Management.Automation.ParameterAttribute
                $FileAttribute.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FileAttribute)
                #add our paramater specifying the attribute collection
                $File = New-Object System.Management.Automation.RuntimeDefinedParameter('File', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('File', $File)
                return $paramDictionary 
            }
            Object {
                $ObjectAttrib = New-Object System.Management.Automation.ParameterAttribute
                $ObjectAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom ObjectAttrib attribute
                $attributeCollection.Add($ObjectAttrib)
                #add our paramater specifying the attribute collection
                $ImportObject = New-Object System.Management.Automation.RuntimeDefinedParameter('ImportObject', [Object], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ImportObject', $ImportObject)
                return $paramDictionary 
            }
        }
        
    }

    begin {
        #If the File Param is used, Test the Path to make sure its accessible, If not throw an error. If it does exist set the JSONImport Param to the AttributeValue
        IF ($PSBoundParameters.File){
            IF(-not (Test-Path -Path $PSBoundParameters.File)) {
                Throw "Unable to locate $PSBoundParameters.File"
            } else {
                $Import_File = $PSBoundParameters.File
            }
        }

        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
 
    } 

    #Process The Function
    Process {
        switch ($Type) {
            File { 
                $File_Info = Get-Item $Import_File | Select-Object -Property *

                $ImportScript = Join-Path -Path $File_Info.DirectoryName -ChildPath ($File_Info.BaseName + ".ps1")
                
                $ImportObject =  Get-Content $Import_File | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty Version,LastModifiedTime,CreatedDateTime,id,supportsScopeTags
                
                if(Test-Path -Path $ImportScript) {
                    $ImportObject.scriptContent = (Invoke-Encoder -Type Encode (Get-Content $ImportScript -Raw))
                }
                $ImportJSON  = $ImportObject | ConvertTo-Json -Depth 10
            }
            Object {
                $ImportJSON = $PSBoundParameters.ImportObject | Select-Object -Property * -ExcludeProperty Version,LastModifiedTime,CreatedDateTime,id,supportsScopeTags,lastModifiedDateTime | ConvertTo-Json -Depth 10
            }
        }
        
        $GraphImportParams = @{
            Method = "POST"
            URI = "$GraphURI/deviceManagement/deviceManagementScripts"
            BODY = $ImportJSON
            Headers = $GraphHeader
            CONTENTTYPE = "application/Json"
        }
        
        Invoke-RestMethod @GraphImportParams
    }
}
function Export-IntuneScript {
    param(
        [Parameter(Mandatory = $True)]
        $PolicyID, 
        [ValidateSet('Object','File','ScriptOnly')]
        [Parameter(Mandatory = $True)]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Type) {
            File {
                $FileAttribute = New-Object System.Management.Automation.ParameterAttribute
                $FileAttribute.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FileAttribute)
                #add our paramater specifying the attribute collection
                $ExportLocation = New-Object System.Management.Automation.RuntimeDefinedParameter('ExportLocation', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ExportLocation', $ExportLocation)
                return $paramDictionary
            }
            ScriptOnly {
                $FileAttribute = New-Object System.Management.Automation.ParameterAttribute
                $FileAttribute.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FileAttribute)
                #add our paramater specifying the attribute collection
                $ExportLocation = New-Object System.Management.Automation.RuntimeDefinedParameter('ExportLocation', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ExportLocation', $ExportLocation)
                return $paramDictionary
            }
        }
    }

    begin {
        IF ($PSBoundParameters.ExportLocation){
            $ExportLocation = $PSBoundParameters.ExportLocation
        }
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    }
    Process {
        $GraphObjectParams = @{
            METHOD = "GET"
            URI = "$GraphURI/deviceManagement/deviceManagementScripts/$($PolicyID)"
            HEADERS = $GraphHeader
        }

        $export_obj =  Invoke-RestMethod @GraphObjectParams

        if($export_obj)
        {       
            switch ($Type) {
                Object {
                    $export_obj
                }
                File {
                    # Export The Base Admin Template
                    ConvertTo-Json $export_obj -Depth 10 | Out-File "$ExportLocation\$(($export_obj.displayName)).json" -Force
                    Invoke-Encoder -Type Decode -Value $export_obj.ScriptContent | Out-File "$ExportLocation\$(($export_obj.displayName)).PS1" -Encoding ascii -Force
                }
                ScriptOnly {
                    Invoke-Encoder -Type Decode -Value $export_obj.ScriptContent | Out-File "$ExportLocation\$(($export_obj.displayName)).PS1" -Encoding ascii -Force
                }
            }     
        }
    }
}
function Copy-IntuneScript {
    param(
        [string]
        [Parameter(Mandatory = $True)]
        $PolicyID, 
        [Parameter(Mandatory = $True)]
        [ValidateSet('Copy','Test','PreProd','Dev','Prod','Pilot','Custom')]
        $Prefix,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Prefix) {
            Custom {
                $CustomAttrib = New-Object System.Management.Automation.ParameterAttribute
                $CustomAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom CustomAttrib attribute
                $attributeCollection.Add($CustomAttrib)
                #add our paramater specifying the attribute collection
                $CustomPrefix = New-Object System.Management.Automation.RuntimeDefinedParameter('CustomPrefix', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('CustomPrefix', $CustomPrefix)
                return $paramDictionary
            }
        }
    }

    begin {
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }

        switch ($Prefix) {
            Custom { 
                $PolicyPrefix = $PSBoundParameters.CustomPrefix.ToUpper()
            }
            Default {
                $PolicyPrefix = $Prefix.ToUpper()
            }
        }
    }
    
    
    process {
        Write-Output "Object iD: $($PolicyID)"

        $BaseObject = Export-IntuneScript -Type Object $PolicyID
        $BaseObject.displayName = "$PolicyPrefix-$($BaseObject.displayName)"

        Import-IntuneScript -Type Object -ImportObject $BaseObject
    }
}

function Update-IntuneScript {
    param(
        [string]
        [Parameter(Mandatory = $True)]
        $PolicyID, 
        [Parameter(Mandatory = $True)]
        [ValidateSet('Object','File')]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        switch ($Type) {
            File { 
                #If the Import Param is used, Create the File Param
                $PSAttrib = New-Object System.Management.Automation.ParameterAttribute
                $PSAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom PSAttrib attribute
                $attributeCollection.Add($PSAttrib)
                #add our paramater specifying the attribute collection
                $File = New-Object System.Management.Automation.RuntimeDefinedParameter('File', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('File', $File)
                return $paramDictionary 
            }
            Object {
                $ObjectAttrib = New-Object System.Management.Automation.ParameterAttribute
                $ObjectAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom ObjectAttrib attribute
                $attributeCollection.Add($ObjectAttrib)
                #add our paramater specifying the attribute collection
                $ScriptObject = New-Object System.Management.Automation.RuntimeDefinedParameter('ScriptObject', [Object], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ScriptObject', $ScriptObject)
                return $paramDictionary 
            }
        }
        
    }

    begin {
        IF ($PSBoundParameters.File){
            IF(-not (Test-Path -Path $PSBoundParameters.File)) {
                Throw "Unable to locate $PSBoundParameters.File"
            } else {
                $ScriptImport = $PSBoundParameters.File
            }
        }
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }

        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    } 

    Process {
        Write-Output "Object iD: $($PolicyID)"

        $Policy = Get-IntuneScript -Type FilterQuery -FilterID $PolicyID

        switch ($Type) {
            File { 
                $Policy.ScriptContent = Invoke-Encoder -Type Encode -Value (Get-Content $ScriptImport -Raw)
            }
            Object {
                $Policy.ScriptContent = Invoke-Encoder -Type Encode -Value $ScriptObject
            }
        }

        $GraphImportParams = @{
            Method = "PATCH"
            URI = "$GraphURI/deviceManagement/deviceManagementScripts/$PolicyID"
            BODY = ($Policy | Select-Object -Property * -ExcludeProperty Version,LastModifiedDateTime,CreatedDateTime,id,supportsScopeTags | ConvertTo-Json -Depth 10)
            Headers = $GraphHeader
            CONTENTTYPE = "application/Json"
        }
        
        Invoke-RestMethod @GraphImportParams
        
    }
    
}

##################################################################################
##################################################################################
# #
# AppProtection Policies #
# #
##################################################################################
##################################################################################

Function Get-AppProtectionPolicies {
    [CmdletBinding()]
    param (
        [ValidateSet('All','FilterQuery')]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Type) {
            FilterQuery {
                $FAttrib = New-Object System.Management.Automation.ParameterAttribute
                $FAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FAttrib)
                #add our paramater specifying the attribute collection
                $FilterID = New-Object System.Management.Automation.RuntimeDefinedParameter('FilterID', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('FilterID', $FilterID)
                return $paramDictionary
            }
        }
    }

    begin {
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
         $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    } 
    #Process The Function
    Process {
        try {
            $GraphParams = @{
                Method = "GET"
                URI = "$GraphURI/deviceAppManagement/managedAppPolicies"
                Headers = $GraphHeader
            }
            $GraphRequest = Invoke-RestMethod @GraphParams -ErrorAction Stop
            $global:All_GraphRequest = @()
            $All_GraphRequest += $GraphRequest
            while($GraphRequest.'@odata.nextLink') {
                $GraphRequest_NextLink = @{
                    Method = "GET"
                    URI = $GraphRequest.'@odata.nextLink'
                    Headers = $GraphHeader
                    ContentType = "application/JSON"
                }
                $GraphRequest = Invoke-RestMethod @$GraphRequest_NextLink -ErrorAction Stop
                $All_GraphRequest += $GraphRequest
            }
        }
        catch {
            $Error[0]
            Throw "The Microsoft Graph Query Failed,"
        }
      
        Switch ($Type) {
            Default {
                $All_GraphRequest | Select-Object -ExpandProperty Value
            }
            FilterQuery {
                $All_GraphRequest | Select-Object -ExpandProperty Value | Where-Object id -Match $($PSBoundParameters.FilterID)
            }
        }
    }
}
Function Import-AppProtectionPolicies {
    [CmdletBinding()]
    param (
        [ValidateSet('Object','File')]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        switch ($Type) {
            File { 
                #If the Import Param is used, Create the File Param
                $FileAttribute = New-Object System.Management.Automation.ParameterAttribute
                $FileAttribute.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FileAttribute)
                #add our paramater specifying the attribute collection
                $File = New-Object System.Management.Automation.RuntimeDefinedParameter('File', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('File', $File)
                return $paramDictionary 
            }
            Object {
                $ObjectAttrib = New-Object System.Management.Automation.ParameterAttribute
                $ObjectAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom ObjectAttrib attribute
                $attributeCollection.Add($ObjectAttrib)
                #add our paramater specifying the attribute collection
                $ImportObject = New-Object System.Management.Automation.RuntimeDefinedParameter('ImportObject', [Object], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ImportObject', $ImportObject)
                return $paramDictionary 
            }
        }
        
    }

    begin {
        #If the File Param is used, Test the Path to make sure its accessible, If not throw an error. If it does exist set the JSONImport Param to the AttributeValue
        IF ($PSBoundParameters.File){
            IF(-not (Test-Path -Path $PSBoundParameters.File)) {
                Throw "Unable to locate $PSBoundParameters.File"
            } else {
                $JSONImport = $PSBoundParameters.File
            }
        }

        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    } 

    #Process The Function
    Process {

        switch ($Type) {
            File { 
                $ImportBody = Get-Content $JSONImport | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty Version,LastModifiedTime,CreatedDateTime,id | ConvertTo-Json -Depth 10
            }
            Object {
                $ImportBody = $PSBoundParameters.ImportObject | Select-Object -Property * -ExcludeProperty Version,LastModifiedTime,CreatedDateTime,id,supportsScopeTags,lastModifiedDateTime | ConvertTo-Json -Depth 10
            }
        }
        
        $GraphImportParams = @{
            Method = "POST"
            URI = "$GraphURI/deviceAppManagement/managedAppPolicies"
            BODY = $ImportBody
            Headers = $GraphHeader
            CONTENTTYPE = "application/Json"
        }
        
        Invoke-RestMethod @GraphImportParams
    }
}
function Export-AppProtectionPolicies {
    param(
        [Parameter(Mandatory = $True)]
        $PolicyID, 
        [ValidateSet('Object','File')]
        [Parameter(Mandatory = $True)]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Type) {
            File {
                $FileAttribute = New-Object System.Management.Automation.ParameterAttribute
                $FileAttribute.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FileAttribute)
                #add our paramater specifying the attribute collection
                $ExportLocation = New-Object System.Management.Automation.RuntimeDefinedParameter('ExportLocation', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ExportLocation', $ExportLocation)
                return $paramDictionary
            }
        }
    }

    begin {
        IF ($PSBoundParameters.ExportLocation){
            $ExportLocation = $PSBoundParameters.ExportLocation
        }
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    }
    Process {
        $GraphObjectParams = @{
            METHOD = "GET"
            URI = "$GraphURI/deviceAppManagement/managedAppPolicies/$($PolicyID)"
            HEADERS = $GraphHeader
        }

        $export_obj =  Invoke-RestMethod @GraphObjectParams

        if($export_obj)
        {       
            switch ($Type) {
                Object {
                    $export_obj
                }
                File {
                    # Export The Base Admin Template
                    ConvertTo-Json $export_obj -Depth 10 | Out-File "$ExportLocation\$(($export_obj.displayName)).json" -Force
                }
            }     
        }
    }
}
function Copy-AppProtectionPolicies {
    param(
        [string]
        [Parameter(Mandatory = $True)]
        $PolicyID, 
        [Parameter(Mandatory = $True)]
        [ValidateSet('Copy','Test','PreProd','Dev','Prod','Pilot','Custom')]
        $Prefix,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Prefix) {
            Custom {
                $CustomAttrib = New-Object System.Management.Automation.ParameterAttribute
                $CustomAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom CustomAttrib attribute
                $attributeCollection.Add($CustomAttrib)
                #add our paramater specifying the attribute collection
                $CustomPrefix = New-Object System.Management.Automation.RuntimeDefinedParameter('CustomPrefix', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('CustomPrefix', $CustomPrefix)
                return $paramDictionary
            }
        }
    }

    begin {
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }

        switch ($Prefix) {
            Custom { 
                $PolicyPrefix = $PSBoundParameters.CustomPrefix.ToUpper()
            }
            Default {
                $PolicyPrefix = $Prefix.ToUpper()
            }
        }
    }
        
    process {
        Write-Output "Object iD: $($PolicyID)"

        $BaseObject = Export-AppProtectionPolicies -Type Object $PolicyID
        $BaseObject.displayName = "$PolicyPrefix-$($BaseObject.displayName)"

        Import-AppProtectionPolicies -Type Object -ImportObject $BaseObject
    }
}

##################################################################################
##################################################################################
# #
# Compliance Policies #
# #
##################################################################################
##################################################################################

Function Get-CompliancePolicies {
    [CmdletBinding()]
    param (
        [ValidateSet('All','FilterQuery')]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Type) {
            FilterQuery {
                $FAttrib = New-Object System.Management.Automation.ParameterAttribute
                $FAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FAttrib)
                #add our paramater specifying the attribute collection
                $FilterID = New-Object System.Management.Automation.RuntimeDefinedParameter('FilterID', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('FilterID', $FilterID)
                return $paramDictionary
            }
        }
    }

    begin {
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    } 
    #Process The Function
    Process {
        try {
            $GraphParams = @{
                Method = "GET"
                URI = "$GraphURI/deviceManagement/deviceCompliancePolicies?`$expand=scheduledActionsForRule(`$expand=scheduledActionConfigurations)"
                Headers = $GraphHeader
            }
        
            $GraphRequest = Invoke-RestMethod @GraphParams -ErrorAction Stop
            $global:All_GraphRequest = @()
            $All_GraphRequest += $GraphRequest
            while($GraphRequest.'@odata.nextLink') {
                $GraphRequest_NextLink = @{
                    Method = "GET"
                    URI = $GraphRequest.'@odata.nextLink'
                    Headers = $GraphHeader
                    ContentType = "application/JSON"
                }
                $GraphRequest = Invoke-RestMethod @$GraphRequest_NextLink -ErrorAction Stop
                $All_GraphRequest += $GraphRequest
            }
        }
        catch {
            $Error[0]
            Throw "The Microsoft Graph Query Failed,"
        }
      
        Switch ($Type) {
            Default {
                $All_GraphRequest | Select-Object -ExpandProperty Value
            }
            FilterQuery {
                $All_GraphRequest | Select-Object -ExpandProperty Value | Where-Object id -Match $($PSBoundParameters.FilterID)
            }
        }
    }
}
Function Import-CompliancePolicies {
    [CmdletBinding()]
    param (
        [ValidateSet('Object','File')]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        switch ($Type) {
            File { 
                #If the Import Param is used, Create the File Param
                $FileAttribute = New-Object System.Management.Automation.ParameterAttribute
                $FileAttribute.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FileAttribute)
                #add our paramater specifying the attribute collection
                $File = New-Object System.Management.Automation.RuntimeDefinedParameter('File', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('File', $File)
                return $paramDictionary 
            }
            Object {
                $ObjectAttrib = New-Object System.Management.Automation.ParameterAttribute
                $ObjectAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom ObjectAttrib attribute
                $attributeCollection.Add($ObjectAttrib)
                #add our paramater specifying the attribute collection
                $ImportObject = New-Object System.Management.Automation.RuntimeDefinedParameter('ImportObject', [Object], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ImportObject', $ImportObject)
                return $paramDictionary 
            }
        }
        
    }

    begin {
        IF ($PSBoundParameters.File){
            IF(-not (Test-Path -Path $PSBoundParameters.File)) {
                Throw "Unable to locate $PSBoundParameters.File"
            } else {
                $JSONImport = $PSBoundParameters.File
            }
        }
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    } 

    #Process The Function
    Process {

        switch ($Type) {
            File { 
                $ImportBody = Get-Content $JSONImport | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty Version,lastModifiedDateTime,CreatedDateTime,id,scheduledActionsForRule@odata.context
                
                IF (-Not ($ImportBody.scheduledActionsForRule)) {
                    $SAFRuleOBJ = @(
                        @{
                            "ruleName" = "PasswordRequired" 
                            "scheduledActionConfigurations" = @(
                                @{
                                    "actionType" = "block"
                                    "gracePeriodHours" = 0
                                    "notificationTemplateId" = ""
                                    "notificationMessageCCList" = @()
                                }
                            )
                        }
                    )
                    $ImportBody | Add-Member -MemberType NoteProperty -Name "scheduledActionsForRule" -Value $SAFRuleOBJ
                } else {
                    $CurrentSettings = $ImportBody.scheduledActionsForRule | Select-Object * -ExcludeProperty id,scheduledActionConfigurations@odata.context
                    $CurrentSettings_SAC = $CurrentSettings.scheduledActionConfigurations | Select-Object * -ExcludeProperty id
                    IF ($CurrentSettings_SAC.notificationTemplateId -match "00000000-0000-0000-0000-000000000000") {
                        $CurrentSettings_SAC.notificationTemplateId = ""
                    }
                    $CurrentSettings.scheduledActionConfigurations = @($CurrentSettings_SAC)
                    $ImportBody.scheduledActionsForRule = @($CurrentSettings)
                    #$ImportBody.scheduledActionsForRule.scheduledActionConfigurations = $CurrentSettings_SAC
                }
            }
            Object {
                $ImportBody = $PSBoundParameters.ImportObject | Select-Object -Property * -ExcludeProperty Version,lastModifiedDateTime,CreatedDateTime,id,supportsScopeTags,lastModifiedDateTime
                IF (-Not ($ImportBody.scheduledActionsForRule)) {
                    $SAFRuleOBJ = @(
                        @{
                            "ruleName" = "PasswordRequired" 
                            "scheduledActionConfigurations" = @(
                                @{
                                    "actionType" = "block"
                                    "gracePeriodHours" = 0
                                    "notificationTemplateId" = ""
                                    "notificationMessageCCList" = @()
                                }
                            )
                        }
                    )
                    $ImportBody | Add-Member -MemberType NoteProperty -Name "scheduledActionsForRule" -Value $SAFRuleOBJ
                } else {
                    $CurrentSettings = $ImportBody.scheduledActionsForRule | Select-Object * -ExcludeProperty id,scheduledActionConfigurations@odata.context
                    $CurrentSettings_SAC = $CurrentSettings.scheduledActionConfigurations | Select-Object * -ExcludeProperty id
                    IF ($CurrentSettings_SAC.notificationTemplateId -match "00000000-0000-0000-0000-000000000000") {
                        $CurrentSettings_SAC.notificationTemplateId = ""
                    }
                    $CurrentSettings.scheduledActionConfigurations = @($CurrentSettings_SAC)
                    $ImportBody.scheduledActionsForRule = @($CurrentSettings)
                }
            }
        }
        
        $GraphImportParams = @{
            Method = "POST"
            URI = "$GraphURI/deviceManagement/deviceCompliancePolicies"
            BODY = ($ImportBody | ConvertTo-Json -Depth 10)
            Headers = $GraphHeader
            CONTENTTYPE = "application/Json"
        }
        
        Invoke-RestMethod @GraphImportParams
    }
}
function Export-CompliancePolicies {
    param(
        [Parameter(Mandatory = $True)]
        $PolicyID, 
        [ValidateSet('Object','File')]
        [Parameter(Mandatory = $True)]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Type) {
            File {
                $FileAttribute = New-Object System.Management.Automation.ParameterAttribute
                $FileAttribute.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FileAttribute)
                #add our paramater specifying the attribute collection
                $ExportLocation = New-Object System.Management.Automation.RuntimeDefinedParameter('ExportLocation', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ExportLocation', $ExportLocation)
                return $paramDictionary
            }
        }
    }

    begin {
        IF ($PSBoundParameters.ExportLocation){
            $ExportLocation = $PSBoundParameters.ExportLocation
        }
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    }
    Process {
        $GraphObjectParams = @{
            METHOD = "GET"
            URI = "$GraphURI/deviceManagement/deviceCompliancePolicies/$($PolicyID)?`$expand=scheduledActionsForRule(`$expand=scheduledActionConfigurations)"
            HEADERS = $GraphHeader
        }

        $export_obj =  Invoke-RestMethod @GraphObjectParams

        if($export_obj)
        {       
            switch ($Type) {
                Object {
                    $export_obj
                }
                File {
                    # Export The Base Admin Template
                    ConvertTo-Json $export_obj -Depth 10 | Out-File "$ExportLocation\$(($export_obj.displayName)).json" -Force
                }
            }     
        }
    }
}
function Copy-CompliancePolicies {
    param(
        [string]
        [Parameter(Mandatory = $True)]
        $PolicyID, 
        [Parameter(Mandatory = $True)]
        [ValidateSet('Copy','Test','PreProd','Dev','Prod','Pilot','Custom')]
        $Prefix,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Prefix) {
            Custom {
                $CustomAttrib = New-Object System.Management.Automation.ParameterAttribute
                $CustomAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom CustomAttrib attribute
                $attributeCollection.Add($CustomAttrib)
                #add our paramater specifying the attribute collection
                $CustomPrefix = New-Object System.Management.Automation.RuntimeDefinedParameter('CustomPrefix', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('CustomPrefix', $CustomPrefix)
                return $paramDictionary
            }
        }
    }

    begin {
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }

        switch ($Prefix) {
            Custom { 
                $PolicyPrefix = $PSBoundParameters.CustomPrefix.ToUpper()
            }
            Default {
                $PolicyPrefix = $Prefix.ToUpper()
            }
        }
    }
    
    process {
        Write-Output "Object iD: $($PolicyID)"
        $BaseObject = Export-CompliancePolicies -Type Object $PolicyID
        $BaseObject.displayName = "$PolicyPrefix-$($BaseObject.displayName)"

        Import-CompliancePolicies -Type Object -ImportObject $BaseObject
    }
}

##################################################################################
##################################################################################
# #
# Conditional Access Policies #
# #
##################################################################################
##################################################################################

Function Get-ConditionalAccessPolicies {
    [CmdletBinding()]
    param (
        [ValidateSet('All','FilterQuery')]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion" 
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Type) {
            FilterQuery {
                $FAttrib = New-Object System.Management.Automation.ParameterAttribute
                $FAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FAttrib)
                #add our paramater specifying the attribute collection
                $FilName = New-Object System.Management.Automation.RuntimeDefinedParameter('FilterID', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('FilterID', $FilName)
                return $paramDictionary
            }
        }
    }

    begin {
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    } 
    #Process The Function
    Process {
        try {
            $GraphParams = @{
                Method = "GET"
                URI = "$GraphURI/identity/conditionalAccess/policies"
                Headers = $GraphHeader
            }
            $GraphRequest = Invoke-RestMethod @GraphParams -ErrorAction Stop
            $global:All_GraphRequest = @()
            $All_GraphRequest += $GraphRequest
            while($GraphRequest.'@odata.nextLink') {
                $GraphRequest_NextLink = @{
                    Method = "GET"
                    URI = $GraphRequest.'@odata.nextLink'
                    Headers = $GraphHeader
                    ContentType = "application/JSON"
                }
                $GraphRequest = Invoke-RestMethod @$GraphRequest_NextLink -ErrorAction Stop
                $All_GraphRequest += $GraphRequest
            }
        }
        catch {
            $Error[0]
            Throw "The Microsoft Graph Query Failed,"
        }

        Switch ($Type) {
            Default {
                $All_GraphRequest | Select-Object -ExpandProperty Value
            }
            FilterQuery {
                $All_GraphRequest | Select-Object -ExpandProperty Value | Where-Object id -Match $($PSBoundParameters.FilterID)
            }
        }
    }
}
Function Import-ConditionalAccessPolicies {
    [CmdletBinding()]
    param (
        [ValidateSet('Object','File')]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        switch ($Type) {
            File { 
                #If the Import Param is used, Create the File Param
                $FileAttribute = New-Object System.Management.Automation.ParameterAttribute
                $FileAttribute.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FileAttribute)
                #add our paramater specifying the attribute collection
                $File = New-Object System.Management.Automation.RuntimeDefinedParameter('File', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('File', $File)
                return $paramDictionary 
            }
            Object {
                $ObjectAttrib = New-Object System.Management.Automation.ParameterAttribute
                $ObjectAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom ObjectAttrib attribute
                $attributeCollection.Add($ObjectAttrib)
                #add our paramater specifying the attribute collection
                $ImportObject = New-Object System.Management.Automation.RuntimeDefinedParameter('ImportObject', [Object], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ImportObject', $ImportObject)
                return $paramDictionary 
            }
        }
        
    }

    begin {
        IF ($PSBoundParameters.File){
            IF(-not (Test-Path -Path $PSBoundParameters.File)) {
                Throw "Unable to locate $PSBoundParameters.File"
            } else {
                $JSONImport = $PSBoundParameters.File
            }
        }
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    } 
    Process {

        switch ($Type) {
            File { 
                $ImportBody = Get-Content $JSONImport | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty Version,ModifiedDateTime,CreatedDateTime,id,supportsScopeTags
            }
            Object {
                $ImportBody = $PSBoundParameters.ImportObject | Select-Object -Property * -ExcludeProperty Version,ModifiedDateTime,CreatedDateTime,id,supportsScopeTags
            }
        }
        
        $GraphImportParams = @{
            Method = "POST"
            URI = "$GraphURI/identity/conditionalAccess/policies"
            BODY = ($ImportBody | ConvertTo-Json -Depth 10)
            Headers = $GraphHeader
            CONTENTTYPE = "application/Json"
        }
        
        Invoke-RestMethod @GraphImportParams
    }
}
function Export-ConditionalAccessPolicies {
    param(
        [Parameter(Mandatory = $True)]
        $PolicyID, 
        [ValidateSet('Object','File')]
        [Parameter(Mandatory = $True)]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Type) {
            File {
                $FileAttribute = New-Object System.Management.Automation.ParameterAttribute
                $FileAttribute.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FileAttribute)
                #add our paramater specifying the attribute collection
                $ExportLocation = New-Object System.Management.Automation.RuntimeDefinedParameter('ExportLocation', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ExportLocation', $ExportLocation)
                return $paramDictionary
            }
        }
    }

    begin {
        IF ($PSBoundParameters.ExportLocation){
            $ExportLocation = $PSBoundParameters.ExportLocation
        }
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    }
    Process {
        $GraphObjectParams = @{
            METHOD = "GET"
            URI = "$GraphURI/identity/conditionalAccess/policies/$($PolicyID)"
            HEADERS = $GraphHeader
        }

        $export_obj =  Invoke-RestMethod @GraphObjectParams

        if($export_obj)
        {       
            switch ($Type) {
                Object {
                    $export_obj
                }
                File {
                    # Export The Base Admin Template
                    ConvertTo-Json $export_obj -Depth 10 | Out-File "$ExportLocation\$(($export_obj.displayName)).json" -Force
                }
            }     
        }
    }
}
function Copy-ConditionalAccessPolicies {
    param(
        [string]
        [Parameter(Mandatory = $True)]
        $PolicyID, 
        [Parameter(Mandatory = $True)]
        [ValidateSet('Copy','Test','PreProd','Dev','Prod','Pilot','Custom')]
        $Prefix,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Prefix) {
            Custom {
                $CustomAttrib = New-Object System.Management.Automation.ParameterAttribute
                $CustomAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom CustomAttrib attribute
                $attributeCollection.Add($CustomAttrib)
                #add our paramater specifying the attribute collection
                $CustomPrefix = New-Object System.Management.Automation.RuntimeDefinedParameter('CustomPrefix', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('CustomPrefix', $CustomPrefix)
                return $paramDictionary
            }
        }
    }

    begin {
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }

        switch ($Prefix) {
            Custom { 
                $PolicyPrefix = $PSBoundParameters.CustomPrefix.ToUpper()
            }
            Default {
                $PolicyPrefix = $Prefix.ToUpper()
            }
        }
    }
    
    process {
        Write-Output "Object iD: $($PolicyID)"
        $BaseObject = Export-ConditionalAccessPolicies -Type Object -PolicyID $PolicyID
        $BaseObject.displayName = "$PolicyPrefix-$($BaseObject.displayName)"
        Import-ConditionalAccessPolicies -Type Object -ImportObject $BaseObject
    }
}

##################################################################################
##################################################################################
# #
# Configuration Profiles #
# #
##################################################################################
##################################################################################

Function Get-ConfigurationProfiles {
    [CmdletBinding()]
    param (
        [ValidateSet('All','FilterQuery')]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Type) {
            FilterQuery {
                $FAttrib = New-Object System.Management.Automation.ParameterAttribute
                $FAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FAttrib)
                #add our paramater specifying the attribute collection
                $FilterID = New-Object System.Management.Automation.RuntimeDefinedParameter('FilterID', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('FilterID', $FilterID)
                return $paramDictionary
            }
        }
    }

    begin {
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    } 
    #Process The Function
    Process {
        try {
            $GraphParams = @{
                Method = "GET"
                URI = "$GraphURI/deviceManagement/deviceConfigurations"
                Headers = $GraphHeader
            }
        
            $GraphRequest = Invoke-RestMethod @GraphParams -ErrorAction Stop
            $global:All_GraphRequest = @()
            $All_GraphRequest += $GraphRequest
            while($GraphRequest.'@odata.nextLink') {
                $GraphRequest_NextLink = @{
                    Method = "GET"
                    URI = $GraphRequest.'@odata.nextLink'
                    Headers = $GraphHeader
                    ContentType = "application/JSON"
                }
                $GraphRequest = Invoke-RestMethod @$GraphRequest_NextLink -ErrorAction Stop
                $All_GraphRequest += $GraphRequest
            }
        }
        catch {
            $Error[0]
            Throw "The Microsoft Graph Query Failed,"
        }

        Switch ($Type) {
            Default {
                $All_GraphRequest | Select-Object -ExpandProperty Value
            }
            FilterQuery {
                $All_GraphRequest | Select-Object -ExpandProperty Value | Where-Object id -Match $($PSBoundParameters.FilterID)
            }
        }
    }
}
Function Import-ConfigurationProfiles {
    [CmdletBinding()]
    param (
        [ValidateSet('Object','File')]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion" 
    )

    DynamicParam {
        switch ($Type) {
            File { 
                #If the Import Param is used, Create the File Param
                $FileAttribute = New-Object System.Management.Automation.ParameterAttribute
                $FileAttribute.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FileAttribute)
                #add our paramater specifying the attribute collection
                $File = New-Object System.Management.Automation.RuntimeDefinedParameter('File', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('File', $File)
                return $paramDictionary 
            }
            Object {
                $ObjectAttrib = New-Object System.Management.Automation.ParameterAttribute
                $ObjectAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom ObjectAttrib attribute
                $attributeCollection.Add($ObjectAttrib)
                #add our paramater specifying the attribute collection
                $ImportObject = New-Object System.Management.Automation.RuntimeDefinedParameter('ImportObject', [Object] , $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ImportObject', $ImportObject)
                return $paramDictionary 
            }
        }
        
    }

    begin {
        #If the File Param is used, Test the Path to make sure its accessible, If not throw an error. If it does exist set the JSONImport Param to the AttributeValue
        IF ($PSBoundParameters.File){
            IF(-not (Test-Path -Path $PSBoundParameters.File)) {
                Throw "Unable to locate $PSBoundParameters.File"
            } else {
                $JSONImport = $PSBoundParameters.File
            }
        }
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    } 

    #Process The Function
    Process {

        switch ($Type) {
            File { 
                $ImportBody = Get-Content $JSONImport | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty Version,LastModifiedDateTime,CreatedDateTime,id | ConvertTo-Json -Depth 10
            }
            Object {
                $ImportBody = $PSBoundParameters.ImportObject | Select-Object -Property * -ExcludeProperty Version,LastModifiedDateTime,CreatedDateTime,id,supportsScopeTags,lastModifiedDateTime | ConvertTo-Json -Depth 10
            }
        }
        
        $GraphImportParams = @{
            Method = "POST"
            URI = "$GraphURI/deviceManagement/deviceConfigurations"
            BODY = $ImportBody
            Headers = $GraphHeader
            CONTENTTYPE = "application/Json"
        }
        
        Invoke-RestMethod @GraphImportParams
    }
}

function Export-ConfigurationProfiles {
    param(
        [Parameter(Mandatory = $True)]
        $PolicyID, 
        [ValidateSet('Object','File')]
        [Parameter(Mandatory = $True)]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Type) {
            File {
                $FileAttribute = New-Object System.Management.Automation.ParameterAttribute
                $FileAttribute.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FileAttribute)
                #add our paramater specifying the attribute collection
                $ExportLocation = New-Object System.Management.Automation.RuntimeDefinedParameter('ExportLocation', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ExportLocation', $ExportLocation)
                return $paramDictionary
            }
        }
    }

    begin {
        IF ($PSBoundParameters.ExportLocation){
            $ExportLocation = $PSBoundParameters.ExportLocation
        }
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    }
    Process {
        $GraphObjectParams = @{
            METHOD = "GET"
            URI = "$GraphURI/deviceManagement/deviceConfigurations/$($PolicyID)"
            HEADERS = $GraphHeader
        }

        $export_obj =  Invoke-RestMethod @GraphObjectParams

        if($export_obj)
        {       
            switch ($Type) {
                Object {
                    $export_obj
                }
                File {
                    # Export The Base Admin Template
                    ConvertTo-Json $export_obj -Depth 10 | Out-File "$ExportLocation\$(($export_obj.displayName)).json" -Force
                }
            }     
        }
    }
}
function Copy-ConfigurationProfiles {
    param(
        [string]
        [Parameter(Mandatory = $True)]
        $PolicyID, 
        [Parameter(Mandatory = $True)]
        [ValidateSet('Copy','Test','PreProd','Dev','Prod','Pilot','Custom')]
        $Prefix,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Prefix) {
            Custom {
                $CustomAttrib = New-Object System.Management.Automation.ParameterAttribute
                $CustomAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom CustomAttrib attribute
                $attributeCollection.Add($CustomAttrib)
                #add our paramater specifying the attribute collection
                $CustomPrefix = New-Object System.Management.Automation.RuntimeDefinedParameter('CustomPrefix', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('CustomPrefix', $CustomPrefix)
                return $paramDictionary
            }
        }
    }

    begin {
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }

        switch ($Prefix) {
            Custom { 
                $PolicyPrefix = $PSBoundParameters.CustomPrefix.ToUpper()
            }
            Default {
                $PolicyPrefix = $Prefix.ToUpper()
            }
        }
    }
    
    process {
        Write-Output "Object iD: $($PolicyID)"
        $BaseObject = Export-ConfigurationProfiles -Type Object $PolicyID
        $BaseObject.displayName = "$PolicyPrefix-$($BaseObject.displayName)"
        Import-ConfigurationProfiles -Type Object -ImportObject $BaseObject
    }
}

##################################################################################
##################################################################################
# #
# Endpoint Security Profiles #
# #
##################################################################################
##################################################################################

Function Get-EndpointSecurityProfiles {
    [CmdletBinding()]
    param (
        [ValidateSet('All','FilterQuery')]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Type) {
            FilterQuery {
                $FAttrib = New-Object System.Management.Automation.ParameterAttribute
                $FAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FAttrib)
                #add our paramater specifying the attribute collection
                $FilterID = New-Object System.Management.Automation.RuntimeDefinedParameter('FilterID', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('FilterID', $FilterID)
                return $paramDictionary
            }
        }
    }

    begin {
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    } 
    #Process The Function
    Process {
        try {
            $GraphParams = @{
                Method = "GET"
                URI = "$GraphURI/deviceManagement/intents"
                Headers = $GraphHeader
            }
        
            $GraphRequest = Invoke-RestMethod @GraphParams -ErrorAction Stop
            $All_GraphRequest = @()
            $All_GraphRequest += $GraphRequest
            while($GraphRequest.'@odata.nextLink') {
                $GraphRequest_NextLink = @{
                    Method = "GET"
                    URI = $GraphRequest.'@odata.nextLink'
                    Headers = $GraphHeader
                    ContentType = "application/JSON"
                }
                $GraphRequest = Invoke-RestMethod @$GraphRequest_NextLink -ErrorAction Stop
                $All_GraphRequest += $GraphRequest
            }
        }
        catch {
            $Error[0]
            Throw "The Microsoft Graph Query Failed,"
        }

        Switch ($Type) {
            Default {
                $All_GraphRequest | Select-Object -ExpandProperty Value
            }
            FilterQuery {
                $All_GraphRequest | Select-Object -ExpandProperty Value | Where-Object id -Match $($PSBoundParameters.FilterID)
            }
        }
    }
}
Function Import-EndpointSecurityProfiles {
    [CmdletBinding()]
    param (
        [ValidateSet('Object','File')]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion" 
    )

    DynamicParam {
        switch ($Type) {
            File { 
                #If the Import Param is used, Create the File Param
                $FileAttribute = New-Object System.Management.Automation.ParameterAttribute
                $FileAttribute.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FileAttribute)
                #add our paramater specifying the attribute collection
                $File = New-Object System.Management.Automation.RuntimeDefinedParameter('File', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('File', $File)
                return $paramDictionary 
            }
            Object {
                $ObjectAttrib = New-Object System.Management.Automation.ParameterAttribute
                $ObjectAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom ObjectAttrib attribute
                $attributeCollection.Add($ObjectAttrib)
                #add our paramater specifying the attribute collection
                $ImportObject = New-Object System.Management.Automation.RuntimeDefinedParameter('ImportObject', [array] ,$attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ImportObject', $ImportObject)
                return $paramDictionary 
            }
        }
        
    }

    begin {
        #If the File Param is used, Test the Path to make sure its accessible, If not throw an error. If it does exist set the JSONImport Param to the AttributeValue
        IF ($PSBoundParameters.File){
            IF(-not (Test-Path -Path $PSBoundParameters.File)) {
                Throw "Unable to locate $PSBoundParameters.File"
            } else {
                $JSONImport = $PSBoundParameters.File
            }
        }
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    } 

    #Process The Function
    Process {

        switch ($Type) {
            File { 
                $JSONContent = Get-Content $JSONImport | ConvertFrom-Json
                $TemplateID = $JSONContent.templateID
                $ImportBody = $JSONContent | Select-Object -Property * -ExcludeProperty templateID
            }
            Object {
                $TemplateID = $PSBoundParameters.ImportObject.templateID

                $ImportBody = @{
                    "displayName" = $PSBoundParameters.ImportObject.displayName
                    "description" = $PSBoundParameters.ImportObject.description
                    "settingDelta" = $PSBoundParameters.ImportObject.settingDelta
                    "roleScopeTagIds" = @($PSBoundParameters.ImportObject.roleScopeTagIds)
                }
            }
        }
        
        $GraphImportParams = @{
            Method = "POST"
            URI = "$GraphURI/deviceManagement/templates/$($TemplateID)/createinstance"
            BODY = ($ImportBody | ConvertTo-Json -Depth 10 )
            Headers = $GraphHeader
            CONTENTTYPE = "application/Json"
        }
        
        Invoke-RestMethod @GraphImportParams
    }
}

function Export-EndpointSecurityProfiles {
    param(
        [Parameter(Mandatory = $True)]
        $PolicyID, 
        [ValidateSet('Object','File')]
        [Parameter(Mandatory = $True)]
        $Type,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Type) {
            File {
                $FileAttribute = New-Object System.Management.Automation.ParameterAttribute
                $FileAttribute.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom FileAttribute attribute
                $attributeCollection.Add($FileAttribute)
                #add our paramater specifying the attribute collection
                $ExportLocation = New-Object System.Management.Automation.RuntimeDefinedParameter('ExportLocation', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ExportLocation', $ExportLocation)
                return $paramDictionary
            }
        }
    }

    begin {
        IF ($PSBoundParameters.ExportLocation){
            $ExportLocation = $PSBoundParameters.ExportLocation
        }
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }
 
        $GraphHeader = @{Authorization = "Bearer $($BGUAccessToken.AccessToken)"}
    }
    Process {

        $GraphDeviceIntentParams = @{
            METHOD = "GET"
            URI = "$GraphURI/deviceManagement/Intents/$($PolicyID)"
            HEADERS = $GraphHeader
        }

        $IntentPolicy =  Invoke-RestMethod @GraphDeviceIntentParams

        if($IntentPolicy){       

            $GraphTemplateCategoriesParams = @{
                METHOD = "GET"
                URI = "$GraphURI/deviceManagement/templates/$($IntentPolicy.templateId)/categories"
                HEADERS = $GraphHeader
            }
            $IntentPolicy_Template_Categories =  Invoke-RestMethod @GraphTemplateCategoriesParams
            $All_IntentPolicy_Template_Categories = @()
            $All_IntentPolicy_Template_Categories += $IntentPolicy_Template_Categories
            while ($IntentPolicy_Template_Categories.'@odata.nextLink') {
                $GraphRequest_NextLink = @{
                    Method = "GET"
                    URI = $IntentPolicy_Template_Categories.'@odata.nextLink'
                    Headers = $GraphHeader
                    ContentType = "application/JSON"
                }
                $IntentPolicy_Template_Categories = Invoke-RestMethod @GraphRequest_NextLink -ErrorAction Stop
                $All_IntentPolicy_Template_Categories += $IntentPolicy_Template_Categories
            }
            
            
            $IntentPolicy_Settings = @()
            FOREACH ($Category in $All_IntentPolicy_Template_Categories.value) {
                $GraphIntentSettingParams = @{
                    METHOD = "GET"
                    URI = "$GraphURI/deviceManagement/intents/$($IntentPolicy.Id)/categories/$($Category.id)/settings"
                    HEADERS = $GraphHeader
                }

                $IntentPolicy_Settings += Invoke-RestMethod @GraphIntentSettingParams
                $All_IntentPolicy_Settings = @()
                $All_IntentPolicy_Settings += $IntentPolicy_Settings
                while($IntentPolicy_Settings.'@odata.nextLink') {
                    $GraphRequest_NextLink = @{
                        Method = "GET"
                        URI = $IntentPolicy_Settings.'@odata.nextLink'
                        Headers = $GraphHeader
                        ContentType = "application/JSON"
                    }
                    $IntentPolicy_Settings = Invoke-RestMethod @GraphRequest_NextLink -ErrorAction Stop
                    $All_IntentPolicy_Settings += $IntentPolicy_Settings
                }
            }
            
            $export_obj = @{
                "displayName" = $IntentPolicy.displayName
                "templateID" = $IntentPolicy.templateId
                "description" = $IntentPolicy.description
                "settingsDelta" = $All_IntentPolicy_Settings.value
                "roleScopeTagIds" = $IntentPolicy.roleScopeTagIds

            }
            switch ($Type) {
                Object {
                    $export_obj
                }
                File {
                    # Export The Base Admin Template
                    ConvertTo-Json $export_obj -Depth 10 | Out-File "$ExportLocation\$(($export_obj.displayName)).json" -Force
                }
            }     
        }
    }
}
function Copy-EndpointSecurityProfiles {
    param(
        [string]
        [Parameter(Mandatory = $True)]
        $PolicyID, 
        [Parameter(Mandatory = $True)]
        [ValidateSet('Copy','Test','PreProd','Dev','Prod','Pilot','Custom')]
        $Prefix,
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion"
    )

    DynamicParam {
        #If the Import Param is used, Create the File Param
        switch ($Prefix) {
            Custom {
                $CustomAttrib = New-Object System.Management.Automation.ParameterAttribute
                $CustomAttrib.Mandatory = $true
                #create an attributecollection object for the attribute we just created.
                $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
                #add custom CustomAttrib attribute
                $attributeCollection.Add($CustomAttrib)
                #add our paramater specifying the attribute collection
                $CustomPrefix = New-Object System.Management.Automation.RuntimeDefinedParameter('CustomPrefix', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('CustomPrefix', $CustomPrefix)
                return $paramDictionary
            }
        }
    }

    begin {
        IF (-Not ($BGUAccessToken)) {
            Throw "You must first obtain an access token by running Get-BGUAccessToken, please obtain a token and retry this action"
        } 
        elseif ($BGUAccessToken.ExpiresOn.LocalDateTime -LT $(Get-Date)) {
            Throw "You're access token expired $($BGUAccessToken.ExpiresOn.LocalDateTime), you must obtain a new access token by running Get-BGUAccessToken."
        }

        switch ($Prefix) {
            Custom { 
                $PolicyPrefix = $PSBoundParameters.CustomPrefix.ToUpper()
            }
            Default {
                $PolicyPrefix = $Prefix.ToUpper()
            }
        }
    }
    
    process {
        Write-Output "Object iD: $($PolicyID)"
        $BaseObject = Export-EndpointSecurityProfiles -Type Object $PolicyID
        $BaseObject.displayName = "$PolicyPrefix-$($BaseObject.displayName)"
        Import-EndpointSecurityProfiles -Type Object -ImportObject $BaseObject
    }
}


Export-ModuleMember -Alias * -Function *