mirror of
https://github.com/Micke-K/IntuneManagement.git
synced 2026-09-28 10:55:38 +02:00
692 lines
31 KiB
PowerShell
692 lines
31 KiB
PowerShell
#ImportOrder 220
|
|
|
|
#########################################################################################
|
|
#
|
|
# Script Group
|
|
#
|
|
#########################################################################################
|
|
|
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("TypeNotFound","", Justification = "")]
|
|
class DeviceEnrollmentGroup : IntunePolicyGroupBase
|
|
{
|
|
DeviceEnrollmentGroup() : Base()
|
|
{
|
|
$this.Init()
|
|
}
|
|
|
|
Init()
|
|
{
|
|
$this._ID = "DeviceEnrollments"
|
|
$this._Name = "Device enrollment"
|
|
$this._Icon = "WindowsEnrollments"
|
|
}
|
|
}
|
|
|
|
#########################################################################################
|
|
#
|
|
# Autopilot
|
|
#
|
|
#########################################################################################
|
|
|
|
# region Autopilot
|
|
class AutopilotType : IntunePolicyTypeBase
|
|
{
|
|
AutopilotType() : Base()
|
|
{
|
|
$this.Init()
|
|
}
|
|
|
|
Init()
|
|
{
|
|
$this._PolicyGroup = (Get-SingletonObject "DeviceEnrollmentGroup")
|
|
$this._PolicyName = "Autopilot"
|
|
$this._ID = "Autopilot"
|
|
# Platform default: the endpoint serves exactly one platform and the
|
|
# objects carry no platforms/platformType field, so the column would
|
|
# otherwise be blank (windowsAutopilotDeploymentProfiles is
|
|
# Windows-only).
|
|
$this._PlatformName = Get-LanguageString "Platform.windows" -IgnoreMissing
|
|
$this._API = "deviceManagement/windowsAutopilotDeploymentProfiles"
|
|
$this._CopyDefaultName = "%Name% Copy"
|
|
$this._Permissions = @("DeviceManagementServiceConfig.ReadWrite.All")
|
|
$this._ObjectClass = "AutopilotObject"
|
|
$this._PropertiesToRemoveForUpdate = @('managementServiceAppId')
|
|
|
|
if($null -ne $this._PolicyGroup) {
|
|
$this._PolicyGroup.AddPolicyType($this)
|
|
}
|
|
}
|
|
|
|
[Hashtable]PreDeleteCommand([IntunePolicyBase]$PolicyObject)
|
|
{
|
|
Write-Log "Delete AutoPilot profile assignments"
|
|
|
|
foreach($assignment in $PolicyObject.Assignments)
|
|
{
|
|
if($assignment.Source -ne "direct") { continue }
|
|
|
|
$api = "$($PolicyObject.PolicyType.API)/$($PolicyObject.Id)/assignments/$($assignment.Id)"
|
|
|
|
$repsone = Invoke-MSGraphAPI -Url $api -HttpMethod "DELETE" -TokenId $PolicyObject._TokenId -FullResponseObject
|
|
if($repsone.Success)
|
|
{
|
|
Write-LogDebug "Assignemnt with Id $($assignment.Id) deleted successfully"
|
|
}
|
|
}
|
|
return $null
|
|
}
|
|
|
|
[Hashtable]PreImportAssignmentsCommand([PSCustomObject]$PolicyObject, [PSCustomObject]$SourceObject)
|
|
{
|
|
return (Add-GraphAssignmentsToObject $PolicyObject $SourceObject)
|
|
}
|
|
|
|
}
|
|
|
|
Class AutopilotObject : IntunePolicyBase
|
|
{
|
|
AutopilotObject([PSCustomObject]$JsonObj) : Base($JsonObj) { $this.Init() }
|
|
|
|
AutopilotObject() : Base()
|
|
{
|
|
$this.Init()
|
|
|
|
$this._PlatformName = Get-LanguageString "Platform.windows" -IgnoreMissing
|
|
}
|
|
|
|
Hidden Init()
|
|
{
|
|
|
|
$this._PolicyType = (Get-SingletonObject "AutopilotType")
|
|
}
|
|
}
|
|
|
|
#########################################################################################
|
|
#
|
|
# Device Enrollment
|
|
#
|
|
#########################################################################################
|
|
|
|
# region Device Enrollment
|
|
|
|
# DeviceEnrollmentType is the SHARED BASE for everything served by
|
|
# /deviceManagement/deviceEnrollmentConfigurations. The Graph endpoint returns
|
|
# eight subtypes of an abstract base type (per the schema):
|
|
# deviceEnrollmentLimitConfiguration ('limit' / 'defaultLimit')
|
|
# deviceEnrollmentPlatformRestrictionConfiguration ('singlePlatformRestriction')
|
|
# deviceEnrollmentPlatformRestrictionsConfiguration ('platformRestrictions' / 'defaultPlatformRestrictions')
|
|
# deviceEnrollmentWindowsHelloForBusinessConfiguration('windowsHelloForBusiness' / 'defaultWindowsHelloForBusiness')
|
|
# windows10EnrollmentCompletionPageConfiguration ('windows10EnrollmentCompletionPageConfiguration' / 'defaultWindows10EnrollmentCompletionPageConfiguration')
|
|
# deviceComanagementAuthorityConfiguration ('deviceComanagementAuthorityConfiguration')
|
|
# deviceEnrollmentNotificationConfiguration ('enrollmentNotificationsConfiguration')
|
|
# windowsRestoreDeviceEnrollmentConfiguration ('windowsRestore')
|
|
#
|
|
# Each logical bucket gets its own thin subtype below. The base only carries
|
|
# import/export/replace behavior — it is NOT registered as a policy type itself
|
|
# (no _PolicyGroup), so $script:IntuneTypes only contains the concrete buckets.
|
|
#
|
|
# Server-side filtering by `deviceEnrollmentConfigurationType eq '...'` is value-exact
|
|
# and excludes the 'default*' variants, so subtypes filter client-side via CheckPolicy
|
|
# on @odata.type. With identical _API/_QueryList across siblings, Get-GraphPolicies
|
|
# coalesces them into ONE batch sub-request and fans rows out to the matching subtype.
|
|
class DeviceEnrollmentType : IntunePolicyTypeBase
|
|
{
|
|
# Abstract: only concrete subtypes (EnrollmentStatusPageType, EnrollmentLimitType, ...)
|
|
# may be instantiated. Auto-discovery loops in Invoke-IntuneEventAppInitialized and
|
|
# the UI extensions consult Test-ClassIsAbstract on each candidate and skip those
|
|
# declaring this static marker, so $script:IntuneTypes only contains concrete buckets.
|
|
static [bool] $IsAbstract = $true
|
|
|
|
DeviceEnrollmentType() : Base()
|
|
{
|
|
([DeviceEnrollmentType]$this).Init()
|
|
}
|
|
|
|
Init()
|
|
{
|
|
# Everything in this Init is shared across every concrete bucket. Subtypes only
|
|
# override _ID, _APITitle, _PolicyName, _Folder, _QueryList, _PlatformName (when
|
|
# platform-specific), and CheckPolicy. Subtypes do NOT need to call this Init
|
|
# explicitly — the constructor chain already runs it via : Base() → DeviceEnrollmentType()
|
|
# body's ([DeviceEnrollmentType]$this).Init().
|
|
$this._API = "deviceManagement/deviceEnrollmentConfigurations"
|
|
# Endpoint rejects a name $filter (verified live 2026-08-27) - searches filter client-side.
|
|
$this._SupportsNameFilter = $false
|
|
$this._Permissions = @("DeviceManagementServiceConfig.ReadWrite.All")
|
|
$this._SkipRemoveProperties = @('Id')
|
|
$this._PropertiesToRemoveForUpdate = @('priority')
|
|
$this._Dependencies = @('Applications')
|
|
$this._AssignmentsType = "enrollmentConfigurationAssignments"
|
|
$this._Icon = "EnrollmentStatusPage"
|
|
$this._PolicyGroup = (Get-SingletonObject "DeviceEnrollmentGroup")
|
|
$this._ObjectClass = "DeviceEnrollmentObject"
|
|
$this._VerifyObject = $true
|
|
# _ExpandAssignmentsList stays at its default ($true) so the list URL appends
|
|
# &$expand=assignments. The Intune portal does this on every enrollment-config
|
|
# subtype, and Graph accepts it here, so we get assignments inline and skip the
|
|
# follow-up /assignments round-trip in Add-GraphPolicyAssignments.
|
|
# No _QueryList here — each subtype owns its filter. Combining filters across
|
|
# subtypes via OR was unreliable (Graph's batch endpoint dropped most matches).
|
|
}
|
|
|
|
[Hashtable]PreImportCommand([PSCustomObject]$PolicyObject)
|
|
{
|
|
if($PolicyObject.Object.Priority -eq 0)
|
|
{
|
|
$ret = @{}
|
|
$ret.Add("API","$($PolicyObject.PolicyType.API)/$($PolicyObject.Id)")
|
|
$ret.Add("Method","PATCH") # Default profile always exists so update them
|
|
$ret
|
|
}
|
|
else
|
|
{
|
|
Remove-Property $PolicyObject.Object "Id"
|
|
}
|
|
return $null
|
|
}
|
|
|
|
[Hashtable]PreImportAssignmentsCommand([PSCustomObject]$PolicyObject, [PSCustomObject]$SourceObject)
|
|
{
|
|
if($SourceObject.Object.Priority -eq 0) { return @{ "Import" = $false } }
|
|
return $null
|
|
}
|
|
|
|
[Hashtable]PreDeleteCommand([IntunePolicyBase]$PolicyObject)
|
|
{
|
|
if($PolicyObject.Object.Priority -eq 0) { return @{ "Delete" = $false } }
|
|
return $null
|
|
}
|
|
|
|
[Hashtable]PreReplaceCommand([IntunePolicyBase]$PolicyObject)
|
|
{
|
|
if($PolicyObject.Object.Priority -eq 0) { return @{ "Delete" = $false } }
|
|
return $null
|
|
}
|
|
|
|
PostReplaceCommand([IntunePolicyBase]$PolicyObject, [IntunePolicyBase]$SourceObject)
|
|
{
|
|
Set-EnrollmentRestrictionsPriority $PolicyObject $SourceObject
|
|
}
|
|
}
|
|
|
|
# Shared Object class for every DeviceEnrollment subtype. PolicyName, Folder and
|
|
# Platform routing all flow from the subtype's TYPE class (_PolicyName / _Folder /
|
|
# _PlatformName), not per-instance switches on @odata.type:
|
|
# * IntunePolicyTypeBase.GetObject sets policyObject._PolicyType = $this (the calling
|
|
# subtype) after construction, so $obj.PolicyType.Folder / .PolicyName resolve to
|
|
# the right subtype's values.
|
|
# * IntunePolicyBase.Platform getter falls back to _PolicyType._PlatformName when the
|
|
# instance doesn't set its own — that's how Windows-only buckets (ESP, WHfB,
|
|
# CoMgmt, WindowsRestore) report Platform=Windows.
|
|
# The constructor is intentionally empty: IntunePolicyBase's : Base($JsonObj) chain
|
|
# already runs the Add-ObjectProperty setup. Anything we'd add to a subclass Init here
|
|
# is per-subtype concern and lives on the subtype TYPE.
|
|
Class DeviceEnrollmentObject : IntunePolicyBase
|
|
{
|
|
DeviceEnrollmentObject([PSCustomObject]$JsonObj) : Base($JsonObj) { }
|
|
DeviceEnrollmentObject() : Base() { }
|
|
|
|
[String]GetFileName([String]$Path)
|
|
{
|
|
# Default policies (priority=0) have a localized boilerplate displayName
|
|
# ("All users and all devices") that collides across subtypes — both
|
|
# DefaultLimit and DefaultPlatformRestrictions land on the same name and
|
|
# one overwrites the other. Their id-suffix is unique per subtype
|
|
# (DefaultLimit / DefaultPlatformRestrictions / DefaultWindowsHelloForBusiness /
|
|
# DefaultWindows10EnrollmentCompletionPageConfiguration), so we use that.
|
|
# Non-default policies have id format <randomGuid>_<configTypeSuffix> where
|
|
# the suffix is identical for every policy of a given subtype, so we use
|
|
# displayName instead.
|
|
# We use TWO signals — priority OR a TenantId-prefixed id — because each
|
|
# has a failure mode on its own:
|
|
# * priority alone: depends on Graph exposing 'priority' on every payload
|
|
# and on it staying =0 for default policies (mostly true but not
|
|
# guaranteed across endpoints / future schema changes).
|
|
# * TenantId prefix alone: requires $this.TenantId to be populated by the
|
|
# time GetFileName runs; it isn't always (file-load paths, certain
|
|
# bulk-export code paths skip the TenantId-set step).
|
|
# Combining them is robust: a row that's a default in EITHER sense uses the
|
|
# id-suffix, everything else uses displayName.
|
|
|
|
$isDefault = ($this.Object.priority -eq 0) -or `
|
|
($this.TenantId -and $this.Id -and $this.Id.StartsWith($this.TenantId + "_"))
|
|
|
|
if($isDefault) {
|
|
$parts = $this.Id -split '_', 2
|
|
$name = if($parts.Count -ge 2) { $parts[1] } else { $null }
|
|
}
|
|
else {
|
|
$name = $this.Object.displayName
|
|
}
|
|
if(-not $name) { $name = $this.Id }
|
|
|
|
# Same id-suffix rule as IntunePolicyBase.GetFileName, which this override
|
|
# replaced wholesale and therefore silently dropped: both the user-facing
|
|
# AddIDToExportFile setting AND the bulk-export collision flag were ignored
|
|
# here, so two non-default enrollment policies of the same subtype sharing a
|
|
# displayName still wrote the same file and one overwrote the other - the
|
|
# collision was DETECTED and then not acted on.
|
|
#
|
|
# A default policy takes its name from the id suffix already, which is unique
|
|
# per subtype, so the flag will not normally fire for one; the rule is applied
|
|
# unconditionally anyway rather than only in the else-branch, so an id-suffix
|
|
# name that does somehow collide is still disambiguated.
|
|
$forceId = (Get-SettingValue "AddIDToExportFile") -eq $true -or $this._NeedsIdInFilename -eq $true
|
|
if($forceId -and $this.Id -and $this.PolicyType.SkipAddIDOnFileName -ne $true -and $name -ne $this.Id) {
|
|
$name = ($name + "_" + $this.Id)
|
|
}
|
|
|
|
$fileName = "$((Remove-InvalidFileNameChars $name)).json"
|
|
if($Path) { $fileName = [IO.Path]::Combine($Path, $fileName) }
|
|
return $fileName
|
|
}
|
|
}
|
|
|
|
# Concrete bucket conventions:
|
|
# * Constructor delegates to : Base() (= DeviceEnrollmentType) which runs the shared
|
|
# Init via the constructor chain. Subtype Init does NOT call the base Init
|
|
# explicitly — that would run the base Init twice.
|
|
# * Subtype Init only sets bucket-specific fields: _ID, _APITitle, _PolicyName,
|
|
# _Folder, _QueryList, optionally _PlatformName, then registers via AddPolicyType.
|
|
# * CheckPolicy stays as a defensive client-side filter; @odata.type is the primary
|
|
# discriminator with deviceEnrollmentConfigurationType as a fallback.
|
|
|
|
class EnrollmentStatusPageType : DeviceEnrollmentType
|
|
{
|
|
EnrollmentStatusPageType() : Base() { ([EnrollmentStatusPageType]$this).Init() }
|
|
Init()
|
|
{
|
|
$this._ID = "EnrollmentStatusPage"
|
|
$this._APITitle = "Enrollment Status Page"
|
|
$this._PolicyName = "Enrollment Status Page"
|
|
$this._Folder = "EnrollmentStatusPage"
|
|
$this._PlatformName = Get-LanguageString "Platform.windows" -IgnoreMissing
|
|
# Single eq is enough: empirically Graph returns both default and non-default
|
|
# ESPs for this filter. (Adding 'defaultWindows10…' as a second clause causes
|
|
# a 400 — that enum value is in the schema but rejected by the live filter parser.)
|
|
$this._QueryList = "?`$filter=deviceEnrollmentConfigurationType eq 'windows10EnrollmentCompletionPageConfiguration'"
|
|
if($null -ne $this._PolicyGroup) { $this._PolicyGroup.AddPolicyType($this) }
|
|
}
|
|
[Boolean]CheckPolicy([PSCustomObject]$PolicyObject)
|
|
{
|
|
if ($PolicyObject.'@odata.type' -eq '#microsoft.graph.windows10EnrollmentCompletionPageConfiguration') { return $true }
|
|
return ($PolicyObject.deviceEnrollmentConfigurationType -eq 'windows10EnrollmentCompletionPageConfiguration')
|
|
}
|
|
}
|
|
|
|
class EnrollmentRestrictionsPageType : DeviceEnrollmentType
|
|
{
|
|
EnrollmentRestrictionsPageType() : Base() { ([EnrollmentRestrictionsPageType]$this).Init() }
|
|
Init()
|
|
{
|
|
$this._ID = "EnrollmentRestrictions"
|
|
$this._APITitle = "Enrollment Restrictions"
|
|
$this._PolicyName = "Device platform restrictions"
|
|
$this._Folder = "EnrollmentRestrictions"
|
|
# Cross-platform (covers iOS / Android / Windows etc.) — no _PlatformName.
|
|
# Single eq clause empirically returns BOTH per-platform Block Android-style
|
|
# configs (@odata.type singular) AND the default combined platform restrictions
|
|
# (@odata.type plural, id-suffix _DefaultPlatformRestrictions). 'limit' lives
|
|
# on EnrollmentLimitType because stacking a second eq clause on the same
|
|
# property in batch mode caused Graph's batch endpoint to drop most matches.
|
|
$this._QueryList = "?`$filter=deviceEnrollmentConfigurationType eq 'singlePlatformRestriction'"
|
|
if($null -ne $this._PolicyGroup) { $this._PolicyGroup.AddPolicyType($this) }
|
|
}
|
|
[Boolean]CheckPolicy([PSCustomObject]$PolicyObject)
|
|
{
|
|
if ($PolicyObject.'@odata.type' -in @(
|
|
'#microsoft.graph.deviceEnrollmentPlatformRestrictionConfiguration',
|
|
'#microsoft.graph.deviceEnrollmentPlatformRestrictionsConfiguration')) { return $true }
|
|
return ($PolicyObject.deviceEnrollmentConfigurationType -in @(
|
|
'singlePlatformRestriction',
|
|
'platformRestrictions',
|
|
'defaultPlatformRestrictions'))
|
|
}
|
|
}
|
|
|
|
class EnrollmentLimitType : DeviceEnrollmentType
|
|
{
|
|
EnrollmentLimitType() : Base() { ([EnrollmentLimitType]$this).Init() }
|
|
Init()
|
|
{
|
|
$this._ID = "EnrollmentLimit"
|
|
$this._HasPlatform = $false
|
|
$this._APITitle = "Enrollment Limit"
|
|
$this._PolicyName = "Device limit restrictions"
|
|
# Same folder as platform restrictions — matches the OLD baseline export where
|
|
# EnrollmentRestrictions/ bundled limit + platform restriction policies together.
|
|
$this._Folder = "EnrollmentRestrictions"
|
|
$this._QueryList = "?`$filter=deviceEnrollmentConfigurationType eq 'limit'"
|
|
if($null -ne $this._PolicyGroup) { $this._PolicyGroup.AddPolicyType($this) }
|
|
}
|
|
[Boolean]CheckPolicy([PSCustomObject]$PolicyObject)
|
|
{
|
|
if ($PolicyObject.'@odata.type' -eq '#microsoft.graph.deviceEnrollmentLimitConfiguration') { return $true }
|
|
return ($PolicyObject.deviceEnrollmentConfigurationType -in @('limit', 'defaultLimit'))
|
|
}
|
|
}
|
|
|
|
class WindowsHelloForBusinessType : DeviceEnrollmentType
|
|
{
|
|
WindowsHelloForBusinessType() : Base() { ([WindowsHelloForBusinessType]$this).Init() }
|
|
Init()
|
|
{
|
|
$this._ID = "WindowsHelloForBusiness"
|
|
$this._APITitle = "Windows Hello for Business"
|
|
$this._PolicyName = "Windows Hello for Business"
|
|
$this._Folder = "WindowsHelloForBusiness"
|
|
$this._PlatformName = Get-LanguageString "Platform.windows" -IgnoreMissing
|
|
$this._QueryList = "?`$filter=deviceEnrollmentConfigurationType eq 'windowsHelloForBusiness'"
|
|
if($null -ne $this._PolicyGroup) { $this._PolicyGroup.AddPolicyType($this) }
|
|
}
|
|
[Boolean]CheckPolicy([PSCustomObject]$PolicyObject)
|
|
{
|
|
if ($PolicyObject.'@odata.type' -eq '#microsoft.graph.deviceEnrollmentWindowsHelloForBusinessConfiguration') { return $true }
|
|
return ($PolicyObject.deviceEnrollmentConfigurationType -eq 'windowsHelloForBusiness')
|
|
}
|
|
}
|
|
|
|
class CoManagementSettingsType : DeviceEnrollmentType
|
|
{
|
|
CoManagementSettingsType() : Base() { ([CoManagementSettingsType]$this).Init() }
|
|
Init()
|
|
{
|
|
$this._ID = "CoManagementSettings"
|
|
$this._APITitle = "Co-Management Settings"
|
|
$this._PolicyName = "Co-Management Settings"
|
|
$this._Folder = "CoManagementSettings"
|
|
$this._PlatformName = Get-LanguageString "Platform.windows" -IgnoreMissing
|
|
$this._QueryList = "?`$filter=deviceEnrollmentConfigurationType eq 'deviceComanagementAuthorityConfiguration'"
|
|
if($null -ne $this._PolicyGroup) { $this._PolicyGroup.AddPolicyType($this) }
|
|
}
|
|
[Boolean]CheckPolicy([PSCustomObject]$PolicyObject)
|
|
{
|
|
if ($PolicyObject.'@odata.type' -eq '#microsoft.graph.deviceComanagementAuthorityConfiguration') { return $true }
|
|
return ($PolicyObject.deviceEnrollmentConfigurationType -eq 'deviceComanagementAuthorityConfiguration')
|
|
}
|
|
}
|
|
|
|
class WindowsRestoreType : DeviceEnrollmentType
|
|
{
|
|
WindowsRestoreType() : Base() { ([WindowsRestoreType]$this).Init() }
|
|
Init()
|
|
{
|
|
$this._ID = "WindowsRestore"
|
|
$this._APITitle = "Windows Restore"
|
|
$this._PolicyName = "Windows Restore"
|
|
$this._Folder = "WindowsRestore"
|
|
$this._PlatformName = Get-LanguageString "Platform.windows" -IgnoreMissing
|
|
$this._QueryList = "?`$filter=deviceEnrollmentConfigurationType eq 'windowsRestore'"
|
|
if($null -ne $this._PolicyGroup) { $this._PolicyGroup.AddPolicyType($this) }
|
|
}
|
|
[Boolean]CheckPolicy([PSCustomObject]$PolicyObject)
|
|
{
|
|
if ($PolicyObject.'@odata.type' -eq '#microsoft.graph.windowsRestoreDeviceEnrollmentConfiguration') { return $true }
|
|
return ($PolicyObject.deviceEnrollmentConfigurationType -eq 'windowsRestore')
|
|
}
|
|
}
|
|
|
|
#########################################################################################
|
|
#
|
|
# Enrollment Notification
|
|
#
|
|
#########################################################################################
|
|
|
|
# region Enrollment Notification
|
|
# Note: Email and Push notifications are defined in the Notifications class in the Compliance class file.
|
|
# This bucket follows the same shape as the other DeviceEnrollment subtypes:
|
|
# no _QueryList (so the URL coalesces with siblings in Get-GraphPolicies), client-side
|
|
# filter via CheckPolicy on @odata.type, shared DeviceEnrollmentObject.
|
|
class EnrollmentNotificationType : DeviceEnrollmentType
|
|
{
|
|
EnrollmentNotificationType() : Base() { ([EnrollmentNotificationType]$this).Init() }
|
|
Init()
|
|
{
|
|
$this._ID = "EnrollmentNotification"
|
|
$this._HasPlatform = $false
|
|
$this._APITitle = "Enrollment notifications"
|
|
$this._PolicyName = "Enrollment notification"
|
|
$this._Folder = "EnrollmentNotifications"
|
|
# Cross-platform (email + push notifications target any enrolled device).
|
|
$this._QueryList = "?`$filter=deviceEnrollmentConfigurationType eq 'enrollmentNotificationsConfiguration'"
|
|
if($null -ne $this._PolicyGroup) { $this._PolicyGroup.AddPolicyType($this) }
|
|
}
|
|
[Boolean]CheckPolicy([PSCustomObject]$PolicyObject)
|
|
{
|
|
if ($PolicyObject.'@odata.type' -eq '#microsoft.graph.deviceEnrollmentNotificationConfiguration') { return $true }
|
|
return ($PolicyObject.deviceEnrollmentConfigurationType -eq 'enrollmentNotificationsConfiguration')
|
|
}
|
|
|
|
# ToDo: Add support for importing, exporting, copying Notifications between environment eg
|
|
# notificationTemplates property has a string list of actual notification template policies Email_<GUID of Notification Template>
|
|
}
|
|
|
|
#########################################################################################
|
|
#
|
|
# Generic functions
|
|
#
|
|
#########################################################################################
|
|
function Set-EnrollmentRestrictionsPriority
|
|
{
|
|
param($PolicyObject, $SourceObj)
|
|
|
|
if($PolicyObject.Object.Priority -eq 0) { return }
|
|
|
|
$api = "$($PolicyObject.PolicyType.API)/$($PolicyObject.Id)/setpriority"
|
|
|
|
$priority = [PSCustomObject]@{
|
|
priority = $SourceObj.Object.Priority
|
|
}
|
|
$json = $priority | ConvertTo-Json -Depth 20
|
|
|
|
Write-Log "Update priority for $($PolicyObject.Name) to $($PolicyObject.Object.Priority)"
|
|
Invoke-MSGraphAPI -Url $api -HttpMethod "POST" -Content $json -TokenId $PolicyObject._TokenId
|
|
}
|
|
|
|
#########################################################################################
|
|
#
|
|
# Android Device Owner Enrollment Profiles
|
|
#
|
|
#########################################################################################
|
|
#
|
|
# Profile used to enrol corporate-owned Android devices (dedicated devices,
|
|
# fully-managed, AOSP, Teams devices) via QR code or token. Listed flat at
|
|
# /deviceManagement/androidDeviceOwnerEnrollmentProfiles — not part of the
|
|
# deviceEnrollmentConfigurations multi-subtype tree.
|
|
|
|
# region AndroidDeviceOwnerEnrollmentProfilesType
|
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("TypeNotFound","", Justification = "")]
|
|
class AndroidDeviceOwnerEnrollmentProfilesType : IntunePolicyTypeBase
|
|
{
|
|
AndroidDeviceOwnerEnrollmentProfilesType() : Base()
|
|
{
|
|
$this.Init()
|
|
}
|
|
|
|
Init()
|
|
{
|
|
$this._PolicyGroup = (Get-SingletonObject "DeviceEnrollmentGroup")
|
|
$this._PolicyName = "Android Enterprise — corporate"
|
|
$this._ID = "AndroidDeviceOwnerEnrollmentProfiles"
|
|
$this._API = "deviceManagement/androidDeviceOwnerEnrollmentProfiles"
|
|
# AndroidCOWP icon (Corporate-Owned With Profile) is the closest
|
|
# existing match for the Device Owner enrolment surface.
|
|
$this._Icon = "AndroidCOWP"
|
|
$this._Permissions = @("DeviceManagementServiceConfig.ReadWrite.All")
|
|
# Server-generated bits that come back on GET but Graph rejects on
|
|
# POST/PATCH. enrolledDeviceCount + token{*} + qrCode* are derived;
|
|
# accountId is set from the calling tenant.
|
|
$this._PropertiesToRemove = @('accountId','enrolledDeviceCount','enrollmentTokenUsageCount','qrCodeContent','qrCodeImage','tokenCreationDateTime','tokenExpirationDateTime','tokenValue')
|
|
$this._PropertiesToRemoveForUpdate = @('accountId','enrolledDeviceCount','enrollmentTokenUsageCount','qrCodeContent','qrCodeImage','tokenCreationDateTime','tokenExpirationDateTime','tokenValue','enrollmentMode','enrollmentTokenType')
|
|
# Profile, not policy — no group assignments.
|
|
$this._SupportsAssignments = $false
|
|
# Graph returns HTTP 400 on `androidDeviceOwnerEnrollmentProfiles?$expand=assignments`,
|
|
# even though SupportsAssignments=$false; the list-URL builder still
|
|
# appends the expand unless this is explicitly suppressed.
|
|
$this._ExpandAssignmentsList = $false
|
|
$this._ObjectClass = "AndroidDeviceOwnerEnrollmentProfileObject"
|
|
|
|
if($null -ne $this._PolicyGroup) {
|
|
$this._PolicyGroup.AddPolicyType($this)
|
|
}
|
|
}
|
|
}
|
|
|
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("TypeNotFound","", Justification = "")]
|
|
class AndroidDeviceOwnerEnrollmentProfileObject : IntunePolicyBase
|
|
{
|
|
AndroidDeviceOwnerEnrollmentProfileObject([PSCustomObject]$JsonObj) : Base($JsonObj) { $this.Init() }
|
|
|
|
AndroidDeviceOwnerEnrollmentProfileObject() : Base()
|
|
{
|
|
$this.Init()
|
|
}
|
|
|
|
Hidden Init()
|
|
{
|
|
$this._PolicyType = (Get-SingletonObject "AndroidDeviceOwnerEnrollmentProfilesType")
|
|
# Language pack uses Platform.androidForWork for AOSP/Android Enterprise
|
|
# surfaces; fall back to a literal if the key is missing in en-US.
|
|
$this._PlatformName = Get-LanguageString "Platform.androidForWork" -IgnoreMissing
|
|
if(-not $this._PlatformName) { $this._PlatformName = "Android Enterprise" }
|
|
}
|
|
}
|
|
|
|
#########################################################################################
|
|
#
|
|
# Android For Work Enrollment Profiles
|
|
#
|
|
#########################################################################################
|
|
#
|
|
# Profile used to enrol personal Android devices into a managed Work Profile
|
|
# (BYOD). Endpoint at /deviceManagement/androidForWorkEnrollmentProfiles. No
|
|
# scope tag support, no assignments — purely token + QR for the end user.
|
|
|
|
# region AndroidForWorkEnrollmentProfilesType
|
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("TypeNotFound","", Justification = "")]
|
|
class AndroidForWorkEnrollmentProfilesType : IntunePolicyTypeBase
|
|
{
|
|
AndroidForWorkEnrollmentProfilesType() : Base()
|
|
{
|
|
$this.Init()
|
|
}
|
|
|
|
Init()
|
|
{
|
|
$this._PolicyGroup = (Get-SingletonObject "DeviceEnrollmentGroup")
|
|
$this._PolicyName = "Android Enterprise — work profile"
|
|
$this._ID = "AndroidForWorkEnrollmentProfiles"
|
|
$this._API = "deviceManagement/androidForWorkEnrollmentProfiles"
|
|
# AndroidGooglePlay icon — work-profile enrolment is the personal-device
|
|
# / Play-store-managed surface, so the GP icon reads better than the
|
|
# corporate AndroidCOWP one used for the Device Owner type.
|
|
$this._Icon = "AndroidGooglePlay"
|
|
$this._Permissions = @("DeviceManagementServiceConfig.ReadWrite.All")
|
|
# Schema has no roleScopeTagIds, so disable the scope-tag column /
|
|
# detail-view widget for this type. Leaving the default ("roleScopeTagIds")
|
|
# would surface an empty UI and a 400 on save.
|
|
$this._ScopeTagProperty = $null
|
|
# Server-generated fields Graph rejects on POST/PATCH.
|
|
$this._PropertiesToRemove = @('accountId','enrolledDeviceCount','qrCodeContent','qrCodeImage','tokenValue','tokenExpirationDateTime')
|
|
$this._PropertiesToRemoveForUpdate = @('accountId','enrolledDeviceCount','qrCodeContent','qrCodeImage','tokenValue','tokenExpirationDateTime')
|
|
$this._SupportsAssignments = $false
|
|
# Graph returns HTTP 400 on `androidForWorkEnrollmentProfiles?$expand=assignments`.
|
|
$this._ExpandAssignmentsList = $false
|
|
$this._ObjectClass = "AndroidForWorkEnrollmentProfileObject"
|
|
|
|
if($null -ne $this._PolicyGroup) {
|
|
$this._PolicyGroup.AddPolicyType($this)
|
|
}
|
|
}
|
|
}
|
|
|
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("TypeNotFound","", Justification = "")]
|
|
class AndroidForWorkEnrollmentProfileObject : IntunePolicyBase
|
|
{
|
|
AndroidForWorkEnrollmentProfileObject([PSCustomObject]$JsonObj) : Base($JsonObj) { $this.Init() }
|
|
|
|
AndroidForWorkEnrollmentProfileObject() : Base()
|
|
{
|
|
$this.Init()
|
|
}
|
|
|
|
Hidden Init()
|
|
{
|
|
$this._PolicyType = (Get-SingletonObject "AndroidForWorkEnrollmentProfilesType")
|
|
$this._PlatformName = Get-LanguageString "Platform.androidForWork" -IgnoreMissing
|
|
if(-not $this._PlatformName) { $this._PlatformName = "Android Enterprise" }
|
|
}
|
|
}
|
|
|
|
#########################################################################################
|
|
#
|
|
# Settings Catalog
|
|
#
|
|
#########################################################################################
|
|
|
|
# region Settings Catalog
|
|
|
|
class EnrollmentSettingsCatalogType : SettingsCatalogTypeBase
|
|
{
|
|
EnrollmentSettingsCatalogType() : Base()
|
|
{
|
|
([EnrollmentSettingsCatalogType]$this).Init()
|
|
}
|
|
|
|
Init()
|
|
{
|
|
$this._PolicyGroup = (Get-SingletonObject "DeviceEnrollmentGroup")
|
|
$this._APITitle = "Enrollment Policies (Settings Catalog)"
|
|
$this._ID = "EnrollmentSettingsCatalog"
|
|
# Startup default only - Invoke-IntuneSettingsCatalogAuthenticated rebuilds
|
|
# this from _FamilyTypes once Graph reports the live template list.
|
|
# windowsOsRecoveryPolicies is NOT listed here: it falls to SettingsCatalog's
|
|
# catch-all spec, so claiming it would only fetch rows CheckPolicy rejects.
|
|
$this._QueryList = "?`$filter=templateReference/templateFamily eq 'enrollmentConfiguration'"
|
|
$this._Icon = "EnrollmentStatusPage"
|
|
|
|
if($null -ne $this._PolicyGroup) {
|
|
$this._PolicyGroup.AddPolicyType($this)
|
|
}
|
|
|
|
$this._PolicyTypeOrder = 160
|
|
}
|
|
}
|
|
|
|
<#
|
|
class AutopilotDevicePreparationSettingsCatalogType : SettingsCatalogTypeBase
|
|
{
|
|
AutopilotDevicePreparationSettingsCatalogType() : Base()
|
|
{
|
|
$this.Init()
|
|
}
|
|
|
|
Init()
|
|
{
|
|
$this._PolicyGroup = (Get-SingletonObject "DeviceEnrollmentGroup")
|
|
$this._ID = "AutopilotDevicePreparationSettingsCatalog"
|
|
$this._APITitle = "Autopilot Device Preparation (Settings Catalog)"
|
|
#$this._QueryList = "?`$filter=(technologies has 'enrollment') and (platforms eq 'windows10') and (TemplateReference/templateId eq '80d33118-b7b4-40d8-b15f-81be745e053f_1') and (Templatereference/templateFamily eq 'enrollmentConfiguration')"
|
|
$this._QueryList = "?`$filter=(technologies has 'enrollment') and (platforms eq 'windows10') and (Templatereference/templateFamily eq 'enrollmentConfiguration')"
|
|
$this._Folder = "SettingsCatalog"
|
|
|
|
if($null -ne $this._PolicyGroup) {
|
|
$this._PolicyGroup.AddPolicyType($this)
|
|
}
|
|
|
|
$this._PolicyTypeOrder = 100
|
|
}
|
|
|
|
[Boolean]CheckPolicy([PSCustomObject]$PolicyObject)
|
|
{
|
|
if($PolicyObject.'@odata.type' -ne "#microsoft.graph.deviceManagementConfigurationPolicy") { return $false }
|
|
|
|
if($PolicyObject.templateReference.templateFamily -and $PolicyObject.templateReference.templateFamily -eq 'enrollmentConfiguration') {
|
|
return $true
|
|
}
|
|
|
|
return $false
|
|
}
|
|
}
|
|
#>
|
|
#endregion |