Skip to content

Commit b4468cc

Browse files
authored
Merge pull request #131 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents f715071 + a7b7d4d commit b4468cc

8 files changed

Lines changed: 807 additions & 0 deletions

File tree

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
function Invoke-ExecRemoveEnrollmentProfile {
2+
<#
3+
.FUNCTIONALITY
4+
Entrypoint
5+
.ROLE
6+
Endpoint.MEM.ReadWrite
7+
.DESCRIPTION
8+
Deletes an Apple ADE or Android Enterprise enrollment profile.
9+
#>
10+
[CmdletBinding()]
11+
param($Request, $TriggerMetadata)
12+
13+
$APIName = $Request.Params.CIPPEndpoint
14+
$Headers = $Request.Headers
15+
$TenantFilter = $Request.Body.tenantFilter
16+
$ProfileId = $Request.Body.profileId ?? $Request.Body.id
17+
$ProfileType = $Request.Body.profileType ?? 'apple'
18+
$TokenId = $Request.Body.tokenId
19+
$DisplayName = $Request.Body.displayName ?? $ProfileId
20+
21+
try {
22+
if ([string]::IsNullOrWhiteSpace($ProfileId)) { throw 'No profile id was supplied.' }
23+
24+
if ($ProfileType -eq 'android') {
25+
$Uri = "https://graph.microsoft.com/beta/deviceManagement/androidDeviceOwnerEnrollmentProfiles/$ProfileId"
26+
} else {
27+
if ([string]::IsNullOrWhiteSpace($TokenId)) { throw 'No Apple ADE token id was supplied.' }
28+
$Uri = "https://graph.microsoft.com/beta/deviceManagement/depOnboardingSettings/$TokenId/enrollmentProfiles/$ProfileId"
29+
}
30+
31+
$null = New-GraphPOSTRequest -uri $Uri -tenantid $TenantFilter -type DELETE
32+
$Result = "Deleted enrollment profile $DisplayName"
33+
Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev Info
34+
$StatusCode = [HttpStatusCode]::OK
35+
} catch {
36+
$StatusCode = [HttpStatusCode]::InternalServerError
37+
$ErrorMessage = Get-CippException -Exception $_
38+
$Result = "Failed to delete enrollment profile ${DisplayName}: $($ErrorMessage.NormalizedMessage)"
39+
Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev Error -LogData $ErrorMessage
40+
}
41+
42+
return ([HttpResponseContext]@{
43+
StatusCode = $StatusCode
44+
Body = @{ Results = $Result }
45+
})
46+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
function Invoke-ListAndroidEnrollmentProfiles {
2+
<#
3+
.FUNCTIONALITY
4+
Entrypoint
5+
.ROLE
6+
Endpoint.MEM.Read
7+
.DESCRIPTION
8+
Lists Android Enterprise enrollment profiles and hydrates token fields when Graph omits them from the list response.
9+
#>
10+
[CmdletBinding()]
11+
param($Request, $TriggerMetadata)
12+
13+
$APIName = $Request.Params.CIPPEndpoint
14+
$Headers = $Request.Headers
15+
$TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter
16+
$Select = 'id,displayName,description,enrollmentMode,enrollmentTokenType,enrolledDeviceCount,tokenExpirationDateTime,lastModifiedDateTime,tokenValue,qrCodeContent,qrCodeImage'
17+
$EncodedSelect = [System.Uri]::EscapeDataString($Select)
18+
$BaseUri = 'https://graph.microsoft.com/beta/deviceManagement/androidDeviceOwnerEnrollmentProfiles'
19+
20+
try {
21+
$EnrollmentProfiles = @(New-GraphGetRequest -uri "${BaseUri}?`$select=$EncodedSelect" -tenantid $TenantFilter)
22+
$Results = foreach ($EnrollmentProfile in $EnrollmentProfiles) {
23+
$ProfileObject = $EnrollmentProfile | Select-Object *
24+
$MissingTokenData = [string]::IsNullOrWhiteSpace($ProfileObject.tokenValue) -and
25+
[string]::IsNullOrWhiteSpace($ProfileObject.qrCodeContent) -and
26+
[string]::IsNullOrWhiteSpace($ProfileObject.qrCodeImage.value)
27+
28+
if (($ProfileObject.enrollmentMode -eq 'corporateOwnedAOSPUserlessDevice' -or $ProfileObject.enrollmentMode -eq 'corporateOwnedAOSPUserAssociatedDevice') -and $MissingTokenData -and -not [string]::IsNullOrWhiteSpace($ProfileObject.id)) {
29+
try {
30+
$ProfileDetails = New-GraphGetRequest -uri "$BaseUri/$($ProfileObject.id)?`$select=$EncodedSelect" -tenantid $TenantFilter
31+
foreach ($Property in $ProfileDetails.PSObject.Properties) {
32+
$ProfileObject | Add-Member -NotePropertyName $Property.Name -NotePropertyValue $Property.Value -Force
33+
}
34+
} catch {
35+
$ErrorMessage = Get-CippException -Exception $_
36+
Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message "Failed to hydrate Android enrollment token fields for profile $($ProfileObject.displayName ?? $ProfileObject.id)" -Sev Warning -LogData $ErrorMessage
37+
}
38+
}
39+
40+
$ProfileObject
41+
}
42+
43+
$StatusCode = [HttpStatusCode]::OK
44+
} catch {
45+
$StatusCode = [HttpStatusCode]::InternalServerError
46+
$ErrorMessage = Get-CippException -Exception $_
47+
$Results = "Failed to list Android enrollment profiles: $($ErrorMessage.NormalizedMessage)"
48+
Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Results -Sev Error -LogData $ErrorMessage
49+
}
50+
51+
return ([HttpResponseContext]@{
52+
StatusCode = $StatusCode
53+
Body = @{ Results = @($Results) }
54+
})
55+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
function Invoke-ListAppleEnrollmentProfiles {
2+
<#
3+
.FUNCTIONALITY
4+
Entrypoint
5+
.ROLE
6+
Endpoint.MEM.Read
7+
.DESCRIPTION
8+
Lists Apple Automated Device Enrollment tokens and enrollment profiles.
9+
#>
10+
[CmdletBinding()]
11+
param($Request, $TriggerMetadata)
12+
13+
$APIName = $Request.Params.CIPPEndpoint
14+
$Headers = $Request.Headers
15+
$TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter
16+
17+
try {
18+
$DepOnboardingSettings = @(New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/depOnboardingSettings' -tenantid $TenantFilter)
19+
$Tokens = foreach ($DepSetting in $DepOnboardingSettings) {
20+
$Token = $DepSetting | Select-Object *
21+
$Token | Add-Member -NotePropertyName 'daysUntilExpiration' -NotePropertyValue $(
22+
if ($Token.tokenExpirationDateTime) {
23+
[math]::Floor(([datetime]$Token.tokenExpirationDateTime - [datetime]::UtcNow).TotalDays)
24+
} else {
25+
$null
26+
}
27+
) -Force
28+
$Token | Add-Member -NotePropertyName 'isExpired' -NotePropertyValue $(
29+
if ($Token.tokenExpirationDateTime) { ([datetime]$Token.tokenExpirationDateTime) -lt [datetime]::UtcNow } else { $false }
30+
) -Force
31+
$Token
32+
}
33+
34+
$Profiles = foreach ($DepSetting in $DepOnboardingSettings) {
35+
if ([string]::IsNullOrWhiteSpace($DepSetting.id)) { continue }
36+
37+
try {
38+
$EnrollmentProfiles = @(New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/depOnboardingSettings/$($DepSetting.id)/enrollmentProfiles" -tenantid $TenantFilter)
39+
foreach ($EnrollmentProfile in $EnrollmentProfiles) {
40+
$ProfileType = $EnrollmentProfile.'@odata.type'
41+
$Platform = switch -Regex ($ProfileType) {
42+
'depMacOSEnrollmentProfile' { 'macOS'; break }
43+
'depIOSEnrollmentProfile' { 'iOS/iPadOS'; break }
44+
'depVisionOSEnrollmentProfile' { 'visionOS'; break }
45+
'depTvOSEnrollmentProfile' { 'tvOS'; break }
46+
default { 'Unknown' }
47+
}
48+
49+
$ProfileObject = $EnrollmentProfile | Select-Object *
50+
$ProfileObject | Add-Member -NotePropertyName 'platform' -NotePropertyValue $Platform -Force
51+
$ProfileObject | Add-Member -NotePropertyName 'profileType' -NotePropertyValue 'apple' -Force
52+
$ProfileObject | Add-Member -NotePropertyName 'tokenId' -NotePropertyValue $DepSetting.id -Force
53+
$ProfileObject | Add-Member -NotePropertyName 'tokenName' -NotePropertyValue $DepSetting.tokenName -Force
54+
$ProfileObject | Add-Member -NotePropertyName 'appleIdentifier' -NotePropertyValue $DepSetting.appleIdentifier -Force
55+
$ProfileObject | Add-Member -NotePropertyName 'tokenExpirationDateTime' -NotePropertyValue $DepSetting.tokenExpirationDateTime -Force
56+
$ProfileObject | Add-Member -NotePropertyName 'tokenType' -NotePropertyValue $DepSetting.tokenType -Force
57+
$ProfileObject
58+
}
59+
} catch {
60+
$ErrorMessage = Get-CippException -Exception $_
61+
Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message "Failed to list Apple ADE profiles for token $($DepSetting.tokenName)" -Sev Warning -LogData $ErrorMessage
62+
}
63+
}
64+
65+
$StatusCode = [HttpStatusCode]::OK
66+
$Body = @{
67+
Results = @{
68+
Tokens = @($Tokens)
69+
Profiles = @($Profiles)
70+
}
71+
}
72+
} catch {
73+
$StatusCode = [HttpStatusCode]::InternalServerError
74+
$ErrorMessage = Get-CippException -Exception $_
75+
$Body = @{ Results = "Failed to list Apple ADE enrollment profiles: $($ErrorMessage.NormalizedMessage)" }
76+
Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Body.Results -Sev Error -LogData $ErrorMessage
77+
}
78+
79+
return ([HttpResponseContext]@{
80+
StatusCode = $StatusCode
81+
Body = $Body
82+
})
83+
}

‎Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntunePolicy.ps1‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,49 @@ function Invoke-ListIntunePolicy {
7878
}
7979

8080
if ($DefinitionRequests.Count -gt 0) {
81+
$HasDefinitionFailures = $false
8182
$DefinitionResults = New-GraphBulkRequest -Requests @($DefinitionRequests) -tenantid $TenantFilter
8283
foreach ($DefinitionResult in $DefinitionResults) {
84+
if ($DefinitionResult.status -ne 200) {
85+
$HasDefinitionFailures = $true
86+
continue
87+
}
88+
8389
$SettingId = $SettingIdMap[$DefinitionResult.id]
8490
$Setting = $GraphRequest.settings | Where-Object { $_.id -eq $SettingId } | Select-Object -First 1
8591
if ($Setting) {
8692
$Definitions = @($DefinitionResult.body.value ?? $DefinitionResult.body)
8793
$Setting | Add-Member -NotePropertyName settingDefinitions -NotePropertyValue $Definitions -Force
8894
}
8995
}
96+
97+
if ($HasDefinitionFailures -and $GraphRequest.templateReference.templateId) {
98+
try {
99+
$TemplateSettingsResponse = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicyTemplates('$($GraphRequest.templateReference.templateId)')/settingTemplates?`$expand=settingDefinitions&`$top=1000" -tenantid $TenantFilter
100+
$TemplateSettings = @($TemplateSettingsResponse.value ?? $TemplateSettingsResponse)
101+
$TemplateDefinitionsByInstanceId = @{}
102+
103+
foreach ($TemplateSetting in $TemplateSettings) {
104+
$TemplateInstanceId = $TemplateSetting.settingInstanceTemplate.settingInstanceTemplateId
105+
$TemplateDefinitions = @($TemplateSetting.settingDefinitions | Where-Object { $_.id })
106+
if ($TemplateInstanceId -and $TemplateDefinitions.Count -gt 0) {
107+
$TemplateDefinitionsByInstanceId[$TemplateInstanceId] = $TemplateDefinitions
108+
}
109+
}
110+
111+
foreach ($Setting in $GraphRequest.settings) {
112+
$ExistingDefinitions = @($Setting.settingDefinitions | Where-Object { $_.id })
113+
if ($ExistingDefinitions.Count -gt 0) { continue }
114+
115+
$TemplateInstanceId = $Setting.settingInstance.settingInstanceTemplateReference.settingInstanceTemplateId
116+
if ($TemplateInstanceId -and $TemplateDefinitionsByInstanceId.ContainsKey($TemplateInstanceId)) {
117+
$Setting | Add-Member -NotePropertyName settingDefinitions -NotePropertyValue $TemplateDefinitionsByInstanceId[$TemplateInstanceId] -Force
118+
}
119+
}
120+
} catch {
121+
Write-Information "Could not retrieve configuration policy template definitions for ${ID}: $($_.Exception.Message)"
122+
}
123+
}
90124
}
91125
}
92126
} elseif ($URLName -ieq 'GroupPolicyConfigurations') {
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
function Invoke-ExecRemoveAdminRole {
2+
<#
3+
.FUNCTIONALITY
4+
Entrypoint
5+
.ROLE
6+
Identity.Role.ReadWrite
7+
8+
.DESCRIPTION
9+
Removes a user from an assigned Microsoft Entra admin role.
10+
#>
11+
[CmdletBinding()]
12+
param($Request, $TriggerMetadata)
13+
14+
$APIName = $Request.Params.CIPPEndpoint
15+
$Headers = $Request.Headers
16+
$TenantFilter = $Request.Body.tenantFilter.value ?? $Request.Body.tenantFilter
17+
$RoleId = $Request.Body.RoleId.value ?? $Request.Body.RoleId
18+
$RoleName = $Request.Body.RoleName.label ?? $Request.Body.RoleName.value ?? $Request.Body.RoleName
19+
$Users = if ($Request.Body.Users) { @($Request.Body.Users) } else { @() }
20+
21+
# Input validation
22+
if ([string]::IsNullOrWhiteSpace($TenantFilter) -or [string]::IsNullOrWhiteSpace($RoleId) -or $Users.Count -eq 0) {
23+
$Result = 'TenantFilter, RoleId, and Users are required to remove an admin role assignment.'
24+
Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev 'Error'
25+
return [HttpResponseContext]@{
26+
StatusCode = [HttpStatusCode]::BadRequest
27+
Body = @{ 'Results' = @($Result) }
28+
}
29+
}
30+
31+
$Results = [System.Collections.Generic.List[string]]::new()
32+
$Failures = 0
33+
34+
foreach ($User in $Users) {
35+
# Handle both roles and view user pages where user info is in different properties
36+
$UserId = $User.value ?? $User.id ?? $User.UserId ?? $User
37+
$UserName = $User.addedFields.userPrincipalName ?? $User.addedFields.displayName ?? $User.userPrincipalName ?? $User.displayName ?? $User.label ?? $User.UserName ?? $UserId
38+
39+
if ([string]::IsNullOrWhiteSpace($UserId)) {
40+
$Failures++
41+
$Result = "Skipped a $RoleName role removal request because UserId was empty."
42+
$Results.Add($Result)
43+
Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev 'Error'
44+
continue
45+
}
46+
47+
try {
48+
$null = New-GraphPOSTRequest -type DELETE -uri "https://graph.microsoft.com/v1.0/directoryRoles/$RoleId/members/$UserId/`$ref" -tenantid $TenantFilter
49+
$Result = "Successfully removed $UserName from admin role $RoleName."
50+
$Results.Add($Result)
51+
Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev 'Info'
52+
} catch {
53+
$Failures++
54+
$ErrorMessage = Get-CippException -Exception $_
55+
$Result = "Failed to remove $UserName from admin role $RoleName. $($ErrorMessage.NormalizedError)"
56+
$Results.Add($Result)
57+
Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev 'Error' -LogData $ErrorMessage
58+
}
59+
}
60+
61+
$StatusCode = $Failures -gt 0 ? [HttpStatusCode]::InternalServerError : [HttpStatusCode]::OK
62+
63+
return [HttpResponseContext]@{
64+
StatusCode = $StatusCode
65+
Body = @{ 'Results' = @($Results) }
66+
}
67+
}

0 commit comments

Comments
 (0)