1.1.1/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
            $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" -Encoding ascii -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" -Encoding ascii -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]::ASCII.GetBytes($Value))
        }
        Decode {
            [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($Value))
        }
    }
}
Function Get-IntuneScript {
    <#
    .SYNOPSIS
        This function is used to get Intune Based Scripts from the GraphAPI Associated with your connected tenant.
    .DESCRIPTION
        This function is used to get Intune Based Scripts 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-IntuneScript
 
        This will return all of the scripts within your connected tenant
    .EXAMPLE
        PS C:\> Get-IntuneScripts -Type FilterQuery -FilterID <PolicyID>
 
        This will return the single script 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:
            enforceSignatureCheck : False
            runAs32Bit : False
            id : 5ab5bc74-xxxx-xxxx-xxxx-64e12xxxabcb
            displayName : ScriptDisplay
            description : Updated 04/23/2021 08:26:41
                                    Updated 04/23/2021 08:28:51
            scriptContent :
            createdDateTime : 2021-04-20T14:00:12.9934699Z
            lastModifiedDateTime : 2021-04-23T07:28:51.4886844Z
            runAsAccount : system
            fileName : ScriptDisplay.ps1
            roleScopeTagIds : {0}
    .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/deviceManagementScripts"
                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-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" -Encoding ascii -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",
        [switch]
        $DoNotAppendDescription
    )

    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
                $ScriptFile = New-Object System.Management.Automation.RuntimeDefinedParameter('ScriptFile', [string], $attributeCollection)
                #expose the name of our parameter
                $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $paramDictionary.Add('ScriptFile', $ScriptFile)
                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.ScriptFile){
            IF(-not (Test-Path -Path $PSBoundParameters.ScriptFile)) {
                Throw "Unable to locate $PSBoundParameters.ScriptFile"
            } else {
                $ScriptImport = $PSBoundParameters.ScriptFile
            }
        }
        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
            }
        }
        
        
        switch ($DoNotAppendDescription) {
            false {
                if ([string]::IsNullOrEmpty($Policy.description)) {
                    $NewDescription = "Updated $(Get-Date)"
                } else {
                    $CurrentDescription = $Policy.description
                    $NewDescription = "$CurrentDescription `nUpdated $(Get-Date)"
                }
                $Policy.description = $NewDescription
            }
        }

        $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
        
    }
    
}

function Edit-IntuneScript {
    param(
        [Parameter(Mandatory = $True)]
        $PolicyID, 
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphVersion = "beta",
        [Parameter(DontShow = $true)]
        [string]
        $MsGraphHost = "graph.microsoft.com",
        [Parameter(DontShow = $true)]
        $GraphURI = "https://$MSGraphHost/$MsGraphVersion",
        [switch]
        $DoNotAppendDescription
    )

    DynamicParam {
    }

    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/deviceManagementScripts/$($PolicyID)"
            HEADERS = $GraphHeader
        }

        $export_obj =  Invoke-RestMethod @GraphObjectParams

        if($export_obj)
        {       
            $TempFile = "$env:TEMP\$(($export_obj.displayName)).PS1"
            Invoke-Encoder -Type Decode -Value $export_obj.ScriptContent | Out-File $TempFile -Encoding ascii -Force

            Start-Job -Name "EditIntuneScript_$($export_obj.displayname)" -ScriptBlock { param($TempFile) Start-Process notepad -ArgumentList "$TempFile" -wait } -ArgumentList $TempFile | Wait-Job | Out-Null
            #Start-Process "NotePad.exe" -ArgumentList "$TempFile" -Wait
            switch ($DoNotAppendDescription) {
                false { 
                    Update-IntuneScript -PolicyID $PolicyID -Type File -ScriptFile $TempFile
                }
                true {
                    Update-IntuneScript -PolicyID $PolicyID -Type File -ScriptFile $TempFile -DoNotAppendDescription
                }
            }
            Remove-Item -Path $TempFile -Force
        }
    }
}

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

Function Get-AppProtectionPolicies {
    <#
    .SYNOPSIS
        This function is used to get App Protection policies from the GraphAPI Associated with your connected tenant.
    .DESCRIPTION
        This function is used to get App Protection 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-AppProtectionPolicies
 
        This will return all of the policies within your connected tenant
    .EXAMPLE
        PS C:\> Get-AppProtectionPolicies -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:
            @odata.type : #microsoft.graph.windowsInformationProtectionPolicy
            displayName : AppProtection Policy Name
            description :
            createdDateTime : 2021-04-13T06:58:28.6163181Z
            lastModifiedDateTime : 2021-04-13T06:58:28.6163181Z
            roleScopeTagIds : {0}
            id : W_24415669-xxxx-xxxx-xxxx-5b4598e23da4
            version : 0.0
            enforcementLevel : encryptAuditAndPrompt
            enterpriseDomain : YourDomain.co.uk
            protectionUnderLockConfigRequired : False
            dataRecoveryCertificate :
            revokeOnUnenrollDisabled : False
            rightsManagementServicesTemplateId :
            azureRightsManagementServicesAllowed : False
            iconsVisible : False
            enterpriseIPRangesAreAuthoritative : False
            enterpriseProxyServersAreAuthoritative : False
            indexingEncryptedStoresOrItemsBlocked : False
            isAssigned : False
            revokeOnMdmHandoffDisabled : False
            mdmEnrollmentUrl : https://enrollment.manage.microsoft.com/enrollmentserver/discovery.svc
            windowsHelloForBusinessBlocked : False
            pinMinimumLength : 4
            pinUppercaseLetters : notAllow
            pinLowercaseLetters : notAllow
            pinSpecialCharacters : notAllow
            pinExpirationDays : 0
            numberOfPastPinsRemembered : 0
            passwordMaximumAttemptCount : 0
            minutesOfInactivityBeforeDeviceLock : 0
            daysWithoutContactBeforeUnenroll : 90
            enterpriseProtectedDomainNames : {}
            protectedApps : {}
            exemptApps : {}
            enterpriseNetworkDomainNames : {}
            enterpriseProxiedDomains : {}
            enterpriseIPRanges : {}
            enterpriseProxyServers : {}
            enterpriseInternalProxyServers : {}
            neutralDomainResources : {}
            smbAutoEncryptedFileExtensions : {}
    .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/deviceAppManagement/managedAppPolicies"
                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-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" -Encoding ascii -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 {
    <#
    .SYNOPSIS
        This function is used to get Compliance Policies from the GraphAPI Associated with your connected tenant.
    .DESCRIPTION
        This function is used to get Compliance 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-CompliancePolicies
 
        This will return all of the policies within your connected tenant
    .EXAMPLE
        PS C:\> Get-CompliancePolicies -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:
            @odata.type : #microsoft.graph.windows10CompliancePolicy
            roleScopeTagIds : {0}
            id : 148f61df-xxxx-xxxx-xxxx-e0202a883a7c
            createdDateTime : 2020-10-30T05:52:25.7143691Z
            description :
            lastModifiedDateTime : 2020-10-30T05:52:25.7143691Z
            displayName : Compliance_Device_Security
            version : 1
            passwordRequired : False
            passwordBlockSimple : False
            passwordRequiredToUnlockFromIdle : False
            passwordMinutesOfInactivityBeforeLock :
            passwordExpirationDays :
            passwordMinimumLength :
            passwordMinimumCharacterSetCount :
            passwordRequiredType : deviceDefault
            passwordPreviousPasswordBlockCount :
            requireHealthyDeviceReport : False
            osMinimumVersion :
            osMaximumVersion :
            mobileOsMinimumVersion :
            mobileOsMaximumVersion :
            earlyLaunchAntiMalwareDriverEnabled : False
            bitLockerEnabled : False
            secureBootEnabled : False
            codeIntegrityEnabled : False
            storageRequireEncryption : False
            activeFirewallRequired : True
            defenderEnabled : False
            defenderVersion :
            signatureOutOfDate : False
            rtpEnabled : False
            antivirusRequired : True
            antiSpywareRequired : False
            deviceThreatProtectionEnabled : False
            deviceThreatProtectionRequiredSecurityLevel : unavailable
            configurationManagerComplianceRequired : False
            tpmRequired : False
            deviceCompliancePolicyScript :
            validOperatingSystemBuildRanges : {}
            scheduledActionsForRule@odata.context : https://graph.microsoft.com/beta/$metadata#deviceManagement/deviceCompliancePolicies('148f61df-e7a3-40f2-b728-e0202a883a7c')/microsoft.graph.windows10CompliancePolicy/schedul
                                                        edActionsForRule(scheduledActionConfigurations())
            scheduledActionsForRule : {@{id=148f61df-xxxx-xxxx-xxxx-e0202a883a7c; ruleName=; scheduledActionConfigurations@odata.context=https://graph.microsoft.com/beta/$metadata#deviceManagement/deviceComplianc
                                                        ePolicies('148f61df-xxxx-xxxx-xxxx-e0202a883a7c')/microsoft.graph.windows10CompliancePolicy/scheduledActionsForRule('148f61df-xxxx-xxxx-xxxx-e0202a883a7c')/scheduledActionCon
                                                        figurations; scheduledActionConfigurations=System.Object[]}}
    .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/deviceCompliancePolicies?`$expand=scheduledActionsForRule(`$expand=scheduledActionConfigurations)"
                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-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" -Encoding ascii -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 {
    <#
    .SYNOPSIS
        This function is used to get Conditional Access policies from the GraphAPI Associated with your connected tenant.
    .DESCRIPTION
        This function is used to get Conditional Access 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-ConditionalAccessPolicies
 
        This will return all of the policies within your connected tenant
    .EXAMPLE
        PS C:\> Get-ConditionalAccessPolicies -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
    
    .NOTES
        This requires you to call the Get-BGUAccess Token with a Delegate ID, Use Get-Help -Name Get-BGUAccessToken -Full for more details and visit https://euc365.com/backup-and-import-conditional-access-policies/ for additional Information
    #>

    [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
            $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" -Encoding ascii -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 {
    <#
    .SYNOPSIS
        This function is used to get Configuration Profiles from the GraphAPI Associated with your connected tenant.
    .DESCRIPTION
        This function is used to get Configuration Profiles 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-ConfigurationProfiles
 
        This will return all of the policies within your connected tenant
    .EXAMPLE
        PS C:\> Get-ConfigurationProfiles -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
    .NOTES
        This covers all policies, excluding the settings catalogue, Administrative Templates and Endpoint Security Profiles
    #>

    [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
            $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" -Encoding ascii -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 {
    <#
    .SYNOPSIS
        This function is used to get Endpoint Security Profile policies from the GraphAPI Associated with your connected tenant.
    .DESCRIPTION
        This function is used to get Endpoint Security Profile 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-EndpointSecurityProfiles
 
        This will return all of the policies within your connected tenant
    .EXAMPLE
        PS C:\> Get-EndpointSecurityProfiles -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:
            id : f460338c-xxxx-xxxx-xxxx-e41053d5227f
            displayName : Firewall_Policy
            description :
            isAssigned : False
            lastModifiedDateTime : 2021-04-16T14:23:07.5112048Z
            templateId : c53e5a9f-2eec-4175-98a1-2b3d38084b91
            roleScopeTagIds : {0}
    
    .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/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" -Encoding ascii -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 *