copy-intune-policy-crosstenant.ps1
#[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Scope='Function', Target='Get-MSGraphAllPages')] <#PSScriptInfo .VERSION 3.1.0 .GUID ec2a6c43-35ad-48cd-b23c-da987f1a528b .AUTHOR AndrewTaylor .DESCRIPTION Copies any Intune Policy via Microsoft Graph to "Copy of (policy name)". Displays list of policies using GridView to select which to copy. Cross tenant version .COMPANYNAME .COPYRIGHT GPL .TAGS intune endpoint MEM environment .LICENSEURI https://github.com/andrew-s-taylor/public/blob/main/LICENSE .PROJECTURI https://github.com/andrew-s-taylor/public .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES #> <# .SYNOPSIS Copies an Intune Policy. Cross tenant version .DESCRIPTION Copies any Intune Policy via Microsoft Graph to "Copy of (policy name)". Displays list of policies using GridView to select which to copy. Cross tenant version .INPUTS None .OUTPUTS Creates a log file in %Temp% .NOTES Version: 3.1.0 Author: Andrew Taylor Twitter: @AndrewTaylor_2 WWW: andrewstaylor.com Creation Date: 25/07/2022 Updated: 02/12/2022 Purpose/Change: Initial script development Change: Added support for multiple policy selection Change: Added Module installation Change: Declared $configuration as array Change: Amended Encoding for Applocker Policies Change: Added support for GPO Admin Templates Change: Fix for non custom admin templates Change: Added better credential management Change: Added AzureAD module connection Change: Added support for Conditional Access policies Change: Added support for Proactive Remediations Change: Added support for AAD Groups Change: Fixed issue with multiple admin templates (passed ID in array variable) Change: Switched to Graph Authentication API Change: Removed error text when looping through policies to inspect Change: Fixed Syntax on omaSettings Change: Added scope for CA policies Change: Added support for Winget Store Apps .EXAMPLE N/A #> $ErrorActionPreference = "Continue" ##Start Logging to %TEMP%\intune.log $date = get-date -format yyyyMMddTHHmmssffff Start-Transcript -Path $env:TEMP\intune-$date.log #Install MS Graph if not available Write-Host "Installing Microsoft Graph modules if required (current user scope)" #Install MS Graph if not available if (Get-Module -ListAvailable -Name Microsoft.Graph) { Write-Host "Microsoft Graph Already Installed" } else { try { Install-Module -Name Microsoft.Graph -Scope CurrentUser -Repository PSGallery -Force } catch [Exception] { $_.message exit } } # Load the Graph module Import-Module microsoft.graph.authentication import-module Microsoft.Graph.Identity.SignIns ##Disconnect just in case anything is lingering Disconnect-MgGraph ############################################################################################################### ###### Add Functions ###### ############################################################################################################### Function Get-IntuneApplication(){ <# .SYNOPSIS This function is used to get applications from the Graph API REST interface .DESCRIPTION The function connects to the Graph API Interface and gets any applications added .EXAMPLE Get-IntuneApplication Returns any applications configured in Intune .NOTES NAME: Get-IntuneApplication #> [cmdletbinding()] param ( $id ) $graphApiVersion = "Beta" $Resource = "deviceAppManagement/mobileApps" try { if($id){ $uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)/$id" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject) } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).Value | Where-Object { ($_.'@odata.type').Contains("#microsoft.graph.winGetApp") } } } catch { } } Function Get-DeviceConfigurationPolicyGP(){ <# .SYNOPSIS This function is used to get device configuration policies from the Graph API REST interface - Group Policies .DESCRIPTION The function connects to the Graph API Interface and gets any device configuration policies .EXAMPLE Get-DeviceConfigurationPolicy Returns any device configuration policies configured in Intune .NOTES NAME: Get-DeviceConfigurationPolicyGP #> [cmdletbinding()] param ( $id ) $graphApiVersion = "beta" $DCP_resource = "deviceManagement/groupPolicyConfigurations" try { if($id){ $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)?`$filter=id eq '$id'" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).value } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).Value } } catch {} } ############################################################################################################# Function Get-ConditionalAccessPolicy(){ <# .SYNOPSIS This function is used to get conditional access policies from the Graph API REST interface .DESCRIPTION The function connects to the Graph API Interface and gets any conditional access policies .EXAMPLE Get-ConditionalAccessPolicy Returns any conditional access policies in Azure .NOTES NAME: Get-ConditionalAccessPolicy #> [cmdletbinding()] param ( $id ) $graphApiVersion = "beta" $DCP_resource = "identity/conditionalAccess/policies" try { if($id){ $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)/$id" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject) } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject) } } catch {} } #################################################### Function Get-DeviceConfigurationPolicy(){ <# .SYNOPSIS This function is used to get device configuration policies from the Graph API REST interface .DESCRIPTION The function connects to the Graph API Interface and gets any device configuration policies .EXAMPLE Get-DeviceConfigurationPolicy Returns any device configuration policies configured in Intune .NOTES NAME: Get-DeviceConfigurationPolicy #> [cmdletbinding()] param ( $id ) $graphApiVersion = "beta" $DCP_resource = "deviceManagement/deviceConfigurations" try { if($id){ $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)?`$filter=id eq '$id'" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).value } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).Value } } catch {} } ########################################################################################## Function Get-GroupPolicyConfigurationsDefinitionValues() { <# .SYNOPSIS This function is used to get device configuration policies from the Graph API REST interface .DESCRIPTION The function connects to the Graph API Interface and gets any device configuration policies .EXAMPLE Get-DeviceConfigurationPolicy Returns any device configuration policies configured in Intune .NOTES NAME: Get-GroupPolicyConfigurations #> [cmdletbinding()] Param ( [Parameter(Mandatory = $true)] [string]$GroupPolicyConfigurationID ) $graphApiVersion = "Beta" #$DCP_resource = "deviceManagement/groupPolicyConfigurations/$GroupPolicyConfigurationID/definitionValues?`$filter=enabled eq true" $DCP_resource = "deviceManagement/groupPolicyConfigurations/$GroupPolicyConfigurationID/definitionValues" try { $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).Value } catch{} } #################################################### Function Get-GroupPolicyConfigurationsDefinitionValuesPresentationValues() { <# .SYNOPSIS This function is used to get device configuration policies from the Graph API REST interface .DESCRIPTION The function connects to the Graph API Interface and gets any device configuration policies .EXAMPLE Get-DeviceConfigurationPolicy Returns any device configuration policies configured in Intune .NOTES NAME: Get-GroupPolicyConfigurations #> [cmdletbinding()] Param ( [Parameter(Mandatory = $true)] [string]$GroupPolicyConfigurationID, [string]$GroupPolicyConfigurationsDefinitionValueID ) $graphApiVersion = "Beta" $DCP_resource = "deviceManagement/groupPolicyConfigurations/$GroupPolicyConfigurationID/definitionValues/$GroupPolicyConfigurationsDefinitionValueID/presentationValues" try { $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).Value } catch {} } Function Get-GroupPolicyConfigurationsDefinitionValuesdefinition () { <# .SYNOPSIS This function is used to get device configuration policies from the Graph API REST interface .DESCRIPTION The function connects to the Graph API Interface and gets any device configuration policies .EXAMPLE Get-DeviceConfigurationPolicy Returns any device configuration policies configured in Intune .NOTES NAME: Get-GroupPolicyConfigurations #> [cmdletbinding()] Param ( [Parameter(Mandatory = $true)] [string]$GroupPolicyConfigurationID, [Parameter(Mandatory = $true)] [string]$GroupPolicyConfigurationsDefinitionValueID ) $graphApiVersion = "Beta" $DCP_resource = "deviceManagement/groupPolicyConfigurations/$GroupPolicyConfigurationID/definitionValues/$GroupPolicyConfigurationsDefinitionValueID/definition" try { $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)" $responseBody = Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject } catch{} $responseBody } Function Get-GroupPolicyDefinitionsPresentations () { <# .SYNOPSIS This function is used to get device configuration policies from the Graph API REST interface .DESCRIPTION The function connects to the Graph API Interface and gets any device configuration policies .EXAMPLE Get-DeviceConfigurationPolicy Returns any device configuration policies configured in Intune .NOTES NAME: Get-GroupPolicyConfigurations #> [cmdletbinding()] Param ( [Parameter(Mandatory = $true)] [string]$groupPolicyDefinitionsID, [Parameter(Mandatory = $true)] [string]$GroupPolicyConfigurationsDefinitionValueID ) $graphApiVersion = "Beta" $DCP_resource = "deviceManagement/groupPolicyConfigurations/$groupPolicyDefinitionsID/definitionValues/$GroupPolicyConfigurationsDefinitionValueID/presentationValues?`$expand=presentation" $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)" try { (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).Value.presentation } catch {} } #################################################### Function Get-DeviceConfigurationPolicySC(){ <# .SYNOPSIS This function is used to get device configuration policies from the Graph API REST interface - SETTINGS CATALOG .DESCRIPTION The function connects to the Graph API Interface and gets any device configuration policies .EXAMPLE Get-DeviceConfigurationPolicySC Returns any device configuration policies configured in Intune .NOTES NAME: Get-DeviceConfigurationPolicySC #> [cmdletbinding()] param ( $id ) $graphApiVersion = "beta" $DCP_resource = "deviceManagement/configurationPolicies" try { if($id){ $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)?`$filter=id eq '$id'" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).value } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).Value } } catch {} } ################################################################################################ #################################################### Function Get-DeviceProactiveRemediations(){ <# .SYNOPSIS This function is used to get device proactive remediations from the Graph API REST interface .DESCRIPTION The function connects to the Graph API Interface and gets any device proactive remediations .EXAMPLE Get-DeviceproactiveRemediations Returns any device proactive remediations configured in Intune .NOTES NAME: Get-Deviceproactiveremediations #> [cmdletbinding()] param ( $id ) $graphApiVersion = "beta" $DCP_resource = "deviceManagement/devicehealthscripts" try { if($id){ $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)/$id" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject) } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).Value } } catch {} } ################################################################################################ Function Get-DeviceCompliancePolicy(){ <# .SYNOPSIS This function is used to get device compliance policies from the Graph API REST interface .DESCRIPTION The function connects to the Graph API Interface and gets any device compliance policies .EXAMPLE Get-DeviceCompliancepolicy Returns any device compliance policies configured in Intune .NOTES NAME: Get-devicecompliancepolicy #> [cmdletbinding()] param ( $id ) $graphApiVersion = "beta" $DCP_resource = "deviceManagement/deviceCompliancePolicies" try { if($id){ $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)?`$filter=id eq '$id'" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).value } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).Value } } catch {} } ################################################################################################# Function Get-DeviceSecurityPolicy(){ <# .SYNOPSIS This function is used to get device security policies from the Graph API REST interface .DESCRIPTION The function connects to the Graph API Interface and gets any device security policies .EXAMPLE Get-DeviceSecurityPolicy Returns any device compliance policies configured in Intune .NOTES NAME: Get-DeviceSecurityPolicy #> [cmdletbinding()] param ( $id ) $graphApiVersion = "beta" $DCP_resource = "deviceManagement/intents" try { if($id){ $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)?`$filter=id eq '$id'" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).value } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).Value } } catch {} } ################################################################################################# Function Get-ManagedAppProtectionAndroid(){ <# .SYNOPSIS This function is used to get managed app protection configuration from the Graph API REST interface Android .DESCRIPTION The function connects to the Graph API Interface and gets any managed app protection policy Android .EXAMPLE Get-ManagedAppProtectionAndroid .NOTES NAME: Get-ManagedAppProtectionAndroid #> param ( $id ) $graphApiVersion = "Beta" $Resource = "deviceAppManagement/androidManagedAppProtections" try { if($id){ $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource('$id')" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject) } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject } } catch {} } ################################################################################################# Function Get-ManagedAppProtectionIOS(){ <# .SYNOPSIS This function is used to get managed app protection configuration from the Graph API REST interface IOS .DESCRIPTION The function connects to the Graph API Interface and gets any managed app protection policy IOS .EXAMPLE Get-ManagedAppProtectionIOS .NOTES NAME: Get-ManagedAppProtectionIOS #> param ( $id ) $graphApiVersion = "Beta" $Resource = "deviceAppManagement/iOSManagedAppProtections" try { if($id){ $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource('$id')" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject) } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject } } catch {} } #################################################### Function Get-GraphAADGroups(){ <# .SYNOPSIS This function is used to get AAD Groups from the Graph API REST interface .DESCRIPTION The function connects to the Graph API Interface and gets any AAD Groups .EXAMPLE Get-GraphAADGroups Returns any AAD Groups .NOTES NAME: Get-GraphAADGroups #> [cmdletbinding()] param ( $id ) $graphApiVersion = "beta" $DCP_resource = "Groups" try { if($id){ $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)/$id" Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)?`$Filter=onPremisesSyncEnabled ne true&`$count=true" #(Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).Value Get-MgGroup | Where-Object OnPremisesSyncEnabled -NE true } } catch {} } ################################################################################################# Function Get-AutoPilotProfile(){ <# .SYNOPSIS This function is used to get autopilot profiles from the Graph API REST interface .DESCRIPTION The function connects to the Graph API Interface and gets any autopilot profiles .EXAMPLE Get-AutoPilotProfile Returns any autopilot profiles configured in Intune .NOTES NAME: Get-AutoPilotProfile #> [cmdletbinding()] param ( $id ) $graphApiVersion = "beta" $DCP_resource = "deviceManagement/windowsAutopilotDeploymentProfiles" try { if($id){ $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)?`$filter=id eq '$id'" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).value } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).Value } } catch {} } ################################################################################################# Function Get-AutoPilotESP(){ <# .SYNOPSIS This function is used to get autopilot ESP from the Graph API REST interface .DESCRIPTION The function connects to the Graph API Interface and gets any autopilot ESP .EXAMPLE Get-AutoPilotESP Returns any autopilot ESPs configured in Intune .NOTES NAME: Get-AutoPilotESP #> [cmdletbinding()] param ( $id ) $graphApiVersion = "beta" $DCP_resource = "deviceManagement/deviceEnrollmentConfigurations" try { if($id){ $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)?`$filter=id eq '$id'" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).value } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)" (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).Value } } catch{} } ################################################################################################# Function Get-DecryptedDeviceConfigurationPolicy(){ <# .SYNOPSIS This function is used to decrypt device configuration policies from an json array with the use of the Graph API REST interface .DESCRIPTION The function connects to the Graph API Interface and decrypt Windows custom device configuration policies that is encrypted .EXAMPLE Decrypt-DeviceConfigurationPolicy -dcps $DCPs Returns any device configuration policies configured in Intune in clear text without encryption .NOTES NAME: Decrypt-DeviceConfigurationPolicy #> [cmdletbinding()] param ( $dcpid ) $graphApiVersion = "Beta" $DCP_resource = "deviceManagement/deviceConfigurations" $dcp = Get-DeviceConfigurationPolicy -id $dcpid if ($dcp.'@odata.type' -eq "#microsoft.graph.windows10CustomConfiguration") { # Convert policy of type windows10CustomConfiguration foreach ($omaSetting in $dcp.omaSettings) { if ($omaSetting.isEncrypted -eq $true) { $DCP_resource_function = "$($DCP_resource)/$($dcp.id)/getOmaSettingPlainTextValue(secretReferenceValueId='$($omaSetting.secretReferenceValueId)')" $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource_function)" $value = ((Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).Value) #Remove any unnecessary properties $omaSetting.PsObject.Properties.Remove("isEncrypted") $omaSetting.PsObject.Properties.Remove("secretReferenceValueId") $omaSetting.value = $value } } } $dcp } ################################################################################################# function getpolicyjson() { <# .SYNOPSIS This function is used to add a new device policy by copying an existing policy, manipulating the JSON and then adding via Graph .DESCRIPTION The function grabs an existing policy, decrypts if requires, renames, removes any GUIDs and then returns the JSON .EXAMPLE getpolicyjson -policy $policy -name $name .NOTES NAME: getpolicyjson #> param ( $resource, $policyid ) write-host $resource $graphApiVersion = "beta" switch ($resource) { "deviceManagement/deviceConfigurations" { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" $policy = Get-DecryptedDeviceConfigurationPolicy -dcpid $id $oldname = $policy.displayName $newname = "Copy Of " + $oldname $policy.displayName = $newname ##Custom settings only for OMA-URI ##Remove settings which break Custom OMA-URI $policyconvert = $policy.omaSettings if ($null -ne $policyconvert) { $policyconvert = $policyconvert | Select-Object -Property * -ExcludeProperty isEncrypted, secretReferenceValueId foreach ($pvalue in $policyconvert) { $unencoded = $pvalue.value $EncodedText =[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($unencoded)) $pvalue.value = $EncodedText } $policy.omaSettings = $policyconvert } # Set SupportsScopeTags to $false, because $true currently returns an HTTP Status 400 Bad Request error. if ($policy.supportsScopeTags) { $policy.supportsScopeTags = $false } $policy.PSObject.Properties | Foreach-Object { if ($null -ne $_.Value) { if ($_.Value.GetType().Name -eq "DateTime") { $_.Value = (Get-Date -Date $_.Value -Format s) + "Z" } if ($_.Value.GetType().Name -eq "isEncrypted") { $_.Value = "false" } } } } "deviceManagement/groupPolicyConfigurations" { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" $policy = Get-DeviceConfigurationPolicyGP -id $id $oldname = $policy.DisplayName $newname = "Copy Of " + $oldname $policy.displayName = $newname # Set SupportsScopeTags to $false, because $true currently returns an HTTP Status 400 Bad Request error. if ($policy.supportsScopeTags) { $policy.supportsScopeTags = $false } $policy.PSObject.Properties | Foreach-Object { if ($null -ne $_.Value) { if ($_.Value.GetType().Name -eq "DateTime") { $_.Value = (Get-Date -Date $_.Value -Format s) + "Z" } } } } "deviceManagement/devicehealthscripts" { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" $policy = Get-DeviceProactiveRemediations -id $id $oldname = $policy.DisplayName $newname = "Copy Of " + $oldname $policy.displayName = $newname # Set SupportsScopeTags to $false, because $true currently returns an HTTP Status 400 Bad Request error. if ($policy.supportsScopeTags) { $policy.supportsScopeTags = $false } $policy.PSObject.Properties | Foreach-Object { if ($null -ne $_.Value) { if ($_.Value.GetType().Name -eq "DateTime") { $_.Value = (Get-Date -Date $_.Value -Format s) + "Z" } } } } "deviceManagement/configurationPolicies" { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" $policy = Get-DeviceConfigurationPolicysc -id $id $policy | Add-Member -MemberType NoteProperty -Name 'settings' -Value @() -Force #$settings = Invoke-MSGraphRequest -HttpMethod GET -Url "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies/$id/settings" | Get-MSGraphAllPages $settings = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies/$id/settings" -OutputType PSObject $settings = $settings.value $settings = $settings | select-object * -ExcludeProperty '@odata.count' if ($settings -isnot [System.Array]) { $policy.Settings = @($settings) } else { $policy.Settings = $settings } # $oldname = $policy.Name $newname = "Copy Of " + $oldname $policy.Name = $newname } "deviceManagement/deviceCompliancePolicies" { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" $policy = Get-DeviceCompliancePolicy -id $id $oldname = $policy.DisplayName $newname = "Copy Of " + $oldname $policy.DisplayName = $newname $scheduledActionsForRule = @( @{ ruleName = "PasswordRequired" scheduledActionConfigurations = @( @{ actionType = "block" gracePeriodHours = 0 notificationTemplateId = "" } ) } ) $policy | Add-Member -NotePropertyName scheduledActionsForRule -NotePropertyValue $scheduledActionsForRule } "deviceManagement/intents" { $policy = Get-DeviceSecurityPolicy -id $id $templateid = $policy.templateID $uri = "https://graph.microsoft.com/beta/deviceManagement/templates/$templateId/createInstance" #$template = Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/deviceManagement/templates/$templateid" -Headers $authToken -Method Get $template = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/beta/deviceManagement/templates/$templateid" -OutputType PSObject #$templateCategory = Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/deviceManagement/templates/$templateid/categories" -Headers $authToken -Method Get $templateCategory = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/beta/deviceManagement/templates/$templateid/categories" -OutputType PSObject #$intentSettingsDelta = (Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/deviceManagement/intents/$id/categories/$($templateCategory.id)/settings" -Headers $authToken -Method Get).value $intentSettingsDelta = (Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/beta/deviceManagement/intents/$id/categories/$($templateCategory.id)/settings" -OutputType PSObject).value $oldname = $policy.displayName $newname = "Copy Of " + $oldname $policy = @{ "displayName" = $newname "description" = $policy.description "settingsDelta" = $intentSettingsDelta "roleScopeTagIds" = $policy.roleScopeTagIds } $policy | Add-Member -NotePropertyName displayName -NotePropertyValue $newname } "deviceManagement/windowsAutopilotDeploymentProfiles" { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" $policy = Get-AutoPilotProfile -id $id $oldname = $policy.displayName $newname = "Copy Of " + $oldname $policy.displayName = $newname } "groups" { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" $policy = Get-GraphAADGroups -id $id $oldname = $policy.displayName $newname = "Copy Of " + $oldname $policy.displayName = $newname $policy = $policy | Select-Object description, DisplayName, groupTypes, mailEnabled, mailNickname, securityEnabled, isAssignabletoRole, membershiprule, MembershipRuleProcessingState } "deviceManagement/deviceEnrollmentConfigurations" { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" $policy = Get-AutoPilotESP -id $id $oldname = $policy.displayName $newname = "Copy Of " + $oldname $policy.displayName = $newname } "deviceAppManagement/managedAppPoliciesandroid" { $uri = "https://graph.microsoft.com/$graphApiVersion/deviceAppManagement/managedAppPolicies" #$policy = Invoke-RestMethod -Uri "https://graph.microsoft.com/$graphApiVersion/deviceAppManagement/managedAppPolicies('$id')" -Headers $authToken -Method Get $policy = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/$graphApiVersion/deviceAppManagement/managedAppPolicies('$id')" -OutputType PSObject $oldname = $policy.displayName $newname = "Copy Of " + $oldname $policy.displayName = $newname # Set SupportsScopeTags to $false, because $true currently returns an HTTP Status 400 Bad Request error. if ($policy.supportsScopeTags) { $policy.supportsScopeTags = $false } $policy.PSObject.Properties | Foreach-Object { if ($null -ne $_.Value) { if ($_.Value.GetType().Name -eq "DateTime") { $_.Value = (Get-Date -Date $_.Value -Format s) + "Z" } } } } "deviceAppManagement/managedAppPoliciesios" { $uri = "https://graph.microsoft.com/$graphApiVersion/deviceAppManagement/managedAppPolicies" #$policy = Invoke-RestMethod -Uri "https://graph.microsoft.com/$graphApiVersion/deviceAppManagement/managedAppPolicies('$id')" -Headers $authToken -Method Get $policy = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/$graphApiVersion/deviceAppManagement/managedAppPolicies('$id')" -OutputType PSObject $oldname = $policy.displayName $newname = "Copy Of " + $oldname $policy.displayName = $newname # Set SupportsScopeTags to $false, because $true currently returns an HTTP Status 400 Bad Request error. if ($policy.supportsScopeTags) { $policy.supportsScopeTags = $false } $policy.PSObject.Properties | Foreach-Object { if ($null -ne $_.Value) { if ($_.Value.GetType().Name -eq "DateTime") { $_.Value = (Get-Date -Date $_.Value -Format s) + "Z" } } } } "conditionalaccess" { $uri = "conditionalaccess" $policy = Get-ConditionalAccessPolicy -id $id } "deviceAppManagement/mobileApps" { $uri = "https://graph.microsoft.com/$graphApiVersion/deviceAppManagement/mobileApps" $policy = Get-IntuneApplication -id $id $oldname = $policy.displayName $newname = "Restored " + $oldname $policy.displayName = $newname $policy = $policy | Select-Object * -ExcludeProperty uploadState, publishingState, isAssigned, dependentAppCount, supersedingAppCount, supersededAppCount } } ##We don't want to convert CA policy to JSON if (($resource -eq "conditionalaccess")) { $policy = $policy } else { # Remove any GUIDs or dates/times to allow Intune to regenerate $policy = $policy | Select-Object * -ExcludeProperty id, createdDateTime, LastmodifieddateTime, version, creationSource, '@odata.count' | ConvertTo-Json -Depth 100 } return $policy, $uri } ############################################################################################################### ###### MS Graph Implementations ###### ############################################################################################################### Select-MgProfile -Name Beta Connect-MgGraph -Scopes Policy.Read.All, DeviceManagementServiceConfig.ReadWrite.All, RoleAssignmentSchedule.ReadWrite.Directory, Domain.Read.All, Domain.ReadWrite.All, Directory.Read.All, Policy.ReadWrite.ConditionalAccess, DeviceManagementApps.ReadWrite.All, DeviceManagementConfiguration.ReadWrite.All, DeviceManagementManagedDevices.ReadWrite.All, openid, profile, email, offline_access ############################################################################################################### ###### Grab the Profiles ###### ############################################################################################################### $profiles = @() $configuration = @() ##Get Config Policies $configuration += Get-DeviceConfigurationPolicy | Select-Object ID, DisplayName, Description, @{N='Type';E={"Config Policy"}} ##Get Admin Template Policies $configuration += Get-DeviceConfigurationPolicyGP | Select-Object ID, DisplayName, Description, @{N='Type';E={"Admin Template"}} ##Get Settings Catalog Policies $configuration += Get-DeviceConfigurationPolicySC | Select-Object ID, @{N='DisplayName';E={$_.Name}}, Description , @{N='Type';E={"Settings Catalog"}} ##Get Compliance Policies $configuration += Get-DeviceCompliancePolicy | Select-Object ID, DisplayName, Description, @{N='Type';E={"Compliance Policy"}} ##Get Proactive Remediations $configuration += Get-DeviceProactiveRemediations | Select-Object ID, DisplayName, Description, @{N='Type';E={"Proactive Remediation"}} ##Get Security Policies $configuration += Get-DeviceSecurityPolicy | Select-Object ID, DisplayName, Description, @{N='Type';E={"Security Policy"}} ##Get Autopilot Profiles $configuration += Get-AutoPilotProfile | Select-Object ID, DisplayName, Description, @{N='Type';E={"Autopilot Profile"}} ##Get AAD Groups $configuration += Get-GraphAADGroups | Select-Object ID, DisplayName, Description, @{N='Type';E={"AAD Group"}} ##Get Autopilot ESP $configuration += Get-AutoPilotESP | Select-Object ID, DisplayName, Description, @{N='Type';E={"Autopilot ESP"}} ##Get App Protection Policies #Android $androidapp = Get-ManagedAppProtectionAndroid | Select-Object -expandproperty Value $configuration += $androidapp | Select-Object ID, DisplayName, Description, @{N='Type';E={"Android App Protection"}} #IOS $iosapp = Get-ManagedAppProtectionios | Select-Object -expandproperty Value $configuration += $iosapp | Select-Object ID, DisplayName, Description, @{N='Type';E={"iOS App Protection"}} ##Get Conditional Access Policies $configuration += Get-ConditionalAccessPolicy | Select-Object ID, DisplayName, @{N='Type';E={"Conditional Access Policy"}} ##Get Winget Apps $configuration += Get-IntuneApplication | Select-Object ID, DisplayName, Description, @{N='Type';E={"Winget Application"}} $configuration | Out-GridView -PassThru -Title "Select policies to copy" | ForEach-Object { ##Find out what it is $id = $_.ID write-host $id $policy = Get-DeviceConfigurationPolicy -id $id $catalog = Get-DeviceConfigurationPolicysc -id $id $compliance = Get-DeviceCompliancePolicy -id $id $security = Get-DeviceSecurityPolicy -id $id $autopilot = Get-AutoPilotProfile -id $id $esp = Get-AutoPilotESP -id $id $android = Get-ManagedAppProtectionAndroid -id $id $ios = Get-ManagedAppProtectionios -id $id $gp = Get-DeviceConfigurationPolicyGP -id $id $ca = Get-ConditionalAccessPolicy -id $id $proac = Get-DeviceProactiveRemediations -id $id $aad = Get-GraphAADGroups -id $id $wingetapp = Get-IntuneApplication -id $id # Copy it if ($null -ne $policy) { # Standard Device Configuratio Policy write-host "It's a policy" $id = $policy.id $Resource = "deviceManagement/deviceConfigurations" $copypolicy = getpolicyjson -resource $Resource -policyid $id $profiles+= ,(@($copypolicy[0],$copypolicy[1], $id)) } if ($null -ne $gp) { # Standard Device Configuratio Policy write-host "It's an Admin Template" $id = $gp.id $Resource = "deviceManagement/groupPolicyConfigurations" $copypolicy = getpolicyjson -resource $Resource -policyid $id $profiles+= ,(@($copypolicy[0],$copypolicy[1], $id)) } if ($null -ne $catalog) { # Settings Catalog Policy write-host "It's a Settings Catalog" $id = $catalog.id $Resource = "deviceManagement/configurationPolicies" $copypolicy = getpolicyjson -resource $Resource -policyid $id $profiles+= ,(@($copypolicy[0],$copypolicy[1], $id)) } if ($null -ne $compliance) { # Compliance Policy write-host "It's a Compliance Policy" $id = $compliance.id $Resource = "deviceManagement/deviceCompliancePolicies" $copypolicy = getpolicyjson -resource $Resource -policyid $id $profiles+= ,(@($copypolicy[0],$copypolicy[1], $id)) } if ($null -ne $proac) { # Proactive Remediations write-host "It's a Proactive Remediation" $id = $proac.id $Resource = "deviceManagement/devicehealthscripts" $copypolicy = getpolicyjson -resource $Resource -policyid $id $profiles+= ,(@($copypolicy[0],$copypolicy[1], $id)) } if ($null -ne $security) { # Security Policy write-host "It's a Security Policy" $id = $security.id $Resource = "deviceManagement/intents" $copypolicy = getpolicyjson -resource $Resource -policyid $id $profiles+= ,(@($copypolicy[0],$copypolicy[1], $id)) } if ($null -ne $autopilot) { # Autopilot Profile write-host "It's an Autopilot Profile" $id = $autopilot.id $Resource = "deviceManagement/windowsAutopilotDeploymentProfiles" $copypolicy = getpolicyjson -resource $Resource -policyid $id $profiles+= ,(@($copypolicy[0],$copypolicy[1], $id)) } if ($null -ne $esp) { # Autopilot ESP write-host "It's an AutoPilot ESP" $id = $esp.id $Resource = "deviceManagement/deviceEnrollmentConfigurations" $copypolicy = getpolicyjson -resource $Resource -policyid $id $profiles+= ,(@($copypolicy[0],$copypolicy[1], $id)) } if ($null -ne $android) { # Android App Protection write-host "It's an Android App Protection Policy" $id = $android.id $Resource = "deviceAppManagement/managedAppPoliciesandroid" $copypolicy = getpolicyjson -resource $Resource -policyid $id $profiles+= ,(@($copypolicy[0],$copypolicy[1], $id)) } if ($null -ne $ios) { # iOS App Protection write-host "It's an iOS App Protection Policy" $id = $ios.id $Resource = "deviceAppManagement/managedAppPoliciesios" $copypolicy = getpolicyjson -resource $Resource -policyid $id $profiles+= ,(@($copypolicy[0],$copypolicy[1], $id)) } if ($null -ne $aad) { # AAD Groups write-host "It's an AAD Group" $id = $aad.id $Resource = "groups" $copypolicy = getpolicyjson -resource $Resource -policyid $id $profiles+= ,(@($copypolicy[0],$copypolicy[1], $id)) } if ($null -ne $ca) { # Conditional Access write-host "It's a Conditional Access Policy" $id = $ca.id $Resource = "ConditionalAccess" $copypolicy = getpolicyjson -resource $Resource -policyid $id $profiles+= ,(@($copypolicy[0],$copypolicy[1], $id)) } if ($null -ne $wingetapp) { # Winget App write-host "It's a Windows Application" $id = $wingetapp.id $Resource = "deviceAppManagement/mobileApps" $copypolicy = getpolicyjson -resource $Resource -policyid $id $profiles+= ,(@($copypolicy[0],$copypolicy[1], $id)) } } ##Clear Tenant Connections Disconnect-MgGraph ##Get new Tenant details write-host "Connecting to destination tenant" Select-MgProfile -Name Beta Connect-MgGraph -Scopes Policy.Read.All, DeviceManagementServiceConfig.ReadWrite.All, RoleAssignmentSchedule.ReadWrite.Directory, Domain.Read.All, Domain.ReadWrite.All, Directory.Read.All, Policy.ReadWrite.ConditionalAccess, DeviceManagementApps.ReadWrite.All, DeviceManagementConfiguration.ReadWrite.All, DeviceManagementManagedDevices.ReadWrite.All, openid, profile, email, offline_access ##Loop through array and create Profiles foreach ($toupload in $profiles) { $policyuri = $toupload[1] $policyjson = $toupload[0] $id = $toupload[2] $policy = $policyjson ##If policy is conditional access, we need special config if ($policyuri -eq "conditionalaccess") { write-host "Creating Conditional Access Policy" $uri = "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" $NewDisplayName = "Copy of " + $Policy.DisplayName $Parameters = @{ displayName = $NewDisplayName state = $policy.State conditions = $policy.Conditions grantControls = $policy.GrantControls sessionControls = $policy.SessionControls } $body = $Parameters | ConvertTo-Json -depth 50 $null = Invoke-MgGraphRequest -Method POST -uri $uri -Body $body -ContentType "application/json" } else { # Add the policy $body = ([System.Text.Encoding]::UTF8.GetBytes($policyjson.tostring())) #$copypolicy = Invoke-RestMethod -Uri $policyuri -Headers $authToken -Method Post -Body $body -ContentType "application/json; charset=utf-8" $copypolicy = Invoke-MgGraphRequest -Uri $policyuri -Method Post -Body $body -ContentType "application/json; charset=utf-8" ##If policy is an admin template, we need to loop through and add the settings if ($policyuri -eq "https://graph.microsoft.com/beta/deviceManagement/groupPolicyConfigurations") { ##Now grab the JSON $GroupPolicyConfigurationsDefinitionValues = Get-GroupPolicyConfigurationsDefinitionValues -GroupPolicyConfigurationID $id $OutDefjson = @() foreach ($GroupPolicyConfigurationsDefinitionValue in $GroupPolicyConfigurationsDefinitionValues) { $GroupPolicyConfigurationsDefinitionValue $DefinitionValuedefinition = Get-GroupPolicyConfigurationsDefinitionValuesdefinition -GroupPolicyConfigurationID $id -GroupPolicyConfigurationsDefinitionValueID $GroupPolicyConfigurationsDefinitionValue.id $DefinitionValuedefinitionID = $DefinitionValuedefinition.id $DefinitionValuedefinitionDisplayName = $DefinitionValuedefinition.displayName $GroupPolicyDefinitionsPresentations = Get-GroupPolicyDefinitionsPresentations -groupPolicyDefinitionsID $id -GroupPolicyConfigurationsDefinitionValueID $GroupPolicyConfigurationsDefinitionValue.id $DefinitionValuePresentationValues = Get-GroupPolicyConfigurationsDefinitionValuesPresentationValues -GroupPolicyConfigurationID $id -GroupPolicyConfigurationsDefinitionValueID $GroupPolicyConfigurationsDefinitionValue.id $OutDef = New-Object -TypeName PSCustomObject $OutDef | Add-Member -MemberType NoteProperty -Name "definition@odata.bind" -Value "https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('$definitionValuedefinitionID')" $OutDef | Add-Member -MemberType NoteProperty -Name "enabled" -value $($GroupPolicyConfigurationsDefinitionValue.enabled.tostring().tolower()) if ($DefinitionValuePresentationValues) { $i = 0 $PresValues = @() foreach ($Pres in $DefinitionValuePresentationValues) { $P = $pres | Select-Object -Property * -ExcludeProperty id, createdDateTime, lastModifiedDateTime, version $GPDPID = $groupPolicyDefinitionsPresentations[$i].id $P | Add-Member -MemberType NoteProperty -Name "presentation@odata.bind" -Value "https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('$definitionValuedefinitionID')/presentations('$GPDPID')" $PresValues += $P $i++ } $OutDef | Add-Member -MemberType NoteProperty -Name "presentationValues" -Value $PresValues } $OutDefjson += ($OutDef | ConvertTo-Json -Depth 10).replace("\u0027","'") foreach ($json in $OutDefjson) { $graphApiVersion = "beta" $policyid = $copypolicy.id $DCP_resource = "deviceManagement/groupPolicyConfigurations/$($policyid)/definitionValues" $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)" #Invoke-RestMethod -ErrorAction SilentlyContinue -Uri $uri -Headers $authToken -Method Post -Body $json -ContentType "application/json" try { Invoke-MgGraphRequest -Uri $uri -Method Post -Body $json -ContentType "application/json" } catch {} } } } } } ##Clear Tenant Connections Disconnect-MgGraph Stop-Transcript |