diff --git a/app/Console/Commands/ReclassifyEnrollmentConfigurations.php b/app/Console/Commands/ReclassifyEnrollmentConfigurations.php new file mode 100644 index 0000000..a7bf0c5 --- /dev/null +++ b/app/Console/Commands/ReclassifyEnrollmentConfigurations.php @@ -0,0 +1,104 @@ +resolveTenantOrNull(); + $dryRun = ! (bool) $this->option('write'); + + $query = PolicyVersion::query() + ->with('policy') + ->where('policy_type', 'enrollmentRestriction'); + + if ($tenant) { + $query->where('tenant_id', $tenant->id); + } + + $candidates = $query->get(); + + $changedVersions = 0; + $changedPolicies = 0; + + foreach ($candidates as $version) { + $snapshot = is_array($version->snapshot) ? $version->snapshot : []; + $odataType = $snapshot['@odata.type'] ?? null; + $configurationType = $snapshot['deviceEnrollmentConfigurationType'] ?? null; + + $isEsp = (is_string($odataType) && strcasecmp($odataType, '#microsoft.graph.windows10EnrollmentCompletionPageConfiguration') === 0) + || (is_string($configurationType) && $configurationType === 'windows10EnrollmentCompletionPageConfiguration'); + + if (! $isEsp) { + continue; + } + + $this->line(sprintf( + 'ESP detected: policy_version=%s policy=%s tenant_id=%s', + (string) $version->getKey(), + $version->policy_id ? (string) $version->policy_id : 'n/a', + (string) $version->tenant_id, + )); + + if ($dryRun) { + continue; + } + + $version->forceFill([ + 'policy_type' => 'windowsEnrollmentStatusPage', + 'platform' => $version->platform ?: 'all', + ])->save(); + $changedVersions++; + + if ($version->policy instanceof Policy && $version->policy->policy_type === 'enrollmentRestriction') { + $version->policy->forceFill([ + 'policy_type' => 'windowsEnrollmentStatusPage', + ])->save(); + $changedPolicies++; + } + } + + $this->info('Done.'); + $this->info('PolicyVersions changed: '.$changedVersions); + $this->info('Policies changed: '.$changedPolicies); + $this->info('Mode: '.($dryRun ? 'dry-run' : 'write')); + + return Command::SUCCESS; + } + + private function resolveTenantOrNull(): ?Tenant + { + $tenantOption = $this->option('tenant'); + + if (! $tenantOption) { + return null; + } + + return Tenant::query() + ->forTenant($tenantOption) + ->firstOrFail(); + } +} diff --git a/config/tenantpilot.php b/config/tenantpilot.php index 2e8c4b0..7ee583b 100644 --- a/config/tenantpilot.php +++ b/config/tenantpilot.php @@ -124,16 +124,6 @@ 'restore' => 'enabled', 'risk' => 'medium', ], - [ - 'type' => 'enrollmentRestriction', - 'label' => 'Enrollment Restrictions', - 'category' => 'Enrollment', - 'platform' => 'all', - 'endpoint' => 'deviceManagement/deviceEnrollmentConfigurations', - 'backup' => 'full', - 'restore' => 'preview-only', - 'risk' => 'high', - ], [ 'type' => 'windowsAutopilotDeploymentProfile', 'label' => 'Windows Autopilot Profiles', @@ -155,6 +145,16 @@ 'restore' => 'enabled', 'risk' => 'medium', ], + [ + 'type' => 'enrollmentRestriction', + 'label' => 'Enrollment Restrictions', + 'category' => 'Enrollment', + 'platform' => 'all', + 'endpoint' => 'deviceManagement/deviceEnrollmentConfigurations', + 'backup' => 'full', + 'restore' => 'preview-only', + 'risk' => 'high', + ], [ 'type' => 'endpointSecurityIntent', 'label' => 'Endpoint Security Intents', diff --git a/tests/Feature/ReclassifyEnrollmentConfigurationsCommandTest.php b/tests/Feature/ReclassifyEnrollmentConfigurationsCommandTest.php new file mode 100644 index 0000000..d2bd58a --- /dev/null +++ b/tests/Feature/ReclassifyEnrollmentConfigurationsCommandTest.php @@ -0,0 +1,61 @@ + 'tenant-reclassify', + 'name' => 'Tenant Reclassify', + 'metadata' => [], + 'is_current' => true, + ]); + + $tenant->makeCurrent(); + + $policy = Policy::create([ + 'tenant_id' => $tenant->id, + 'external_id' => 'esp-1', + 'policy_type' => 'enrollmentRestriction', + 'display_name' => 'ESP Misclassified', + 'platform' => 'all', + ]); + + $version = PolicyVersion::create([ + 'tenant_id' => $tenant->id, + 'policy_id' => $policy->id, + 'version_number' => 1, + 'policy_type' => 'enrollmentRestriction', + 'platform' => 'all', + 'created_by' => 'tester@example.com', + 'captured_at' => CarbonImmutable::now(), + 'snapshot' => [ + '@odata.type' => '#microsoft.graph.windows10EnrollmentCompletionPageConfiguration', + 'deviceEnrollmentConfigurationType' => 'windows10EnrollmentCompletionPageConfiguration', + 'displayName' => 'ESP Misclassified', + ], + ]); + + $this->artisan('intune:reclassify-enrollment-configurations', ['--tenant' => $tenant->tenant_id]) + ->assertSuccessful(); + + $version->refresh(); + $policy->refresh(); + + expect($version->policy_type)->toBe('enrollmentRestriction'); + expect($policy->policy_type)->toBe('enrollmentRestriction'); + + $this->artisan('intune:reclassify-enrollment-configurations', ['--tenant' => $tenant->tenant_id, '--write' => true]) + ->assertSuccessful(); + + $version->refresh(); + $policy->refresh(); + + expect($version->policy_type)->toBe('windowsEnrollmentStatusPage'); + expect($policy->policy_type)->toBe('windowsEnrollmentStatusPage'); +});