163 lines
4.7 KiB
PHP
163 lines
4.7 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\Policy;
|
|
use App\Models\PolicyVersion;
|
|
use App\Models\Tenant;
|
|
use App\Services\Graph\GraphClientInterface;
|
|
use Illuminate\Console\Command;
|
|
|
|
class ReclassifyEnrollmentConfigurations extends Command
|
|
{
|
|
/**
|
|
* The name and signature of the console command.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $signature = 'intune:reclassify-enrollment-configurations {--tenant=} {--write : Write changes (default is dry-run)}';
|
|
|
|
/**
|
|
* The console command description.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $description = 'Reclassify enrollment configuration items (e.g. ESP) that were synced under the wrong policy type.';
|
|
|
|
/**
|
|
* Execute the console command.
|
|
*/
|
|
public function __construct(private readonly GraphClientInterface $graphClient)
|
|
{
|
|
parent::__construct();
|
|
}
|
|
|
|
public function handle(): int
|
|
{
|
|
$tenant = $this->resolveTenantOrNull();
|
|
$dryRun = ! (bool) $this->option('write');
|
|
|
|
$query = Policy::query()
|
|
->with(['tenant'])
|
|
->active()
|
|
->where('policy_type', 'enrollmentRestriction');
|
|
|
|
if ($tenant) {
|
|
$query->where('tenant_id', $tenant->id);
|
|
}
|
|
|
|
$candidates = $query->get();
|
|
|
|
$changedVersions = 0;
|
|
$changedPolicies = 0;
|
|
$ignoredPolicies = 0;
|
|
|
|
foreach ($candidates as $policy) {
|
|
$latestVersion = $policy->versions()->latest('version_number')->first();
|
|
$snapshot = $latestVersion?->snapshot;
|
|
|
|
if (! is_array($snapshot)) {
|
|
$snapshot = $this->fetchSnapshotOrNull($policy);
|
|
}
|
|
|
|
if (! is_array($snapshot)) {
|
|
continue;
|
|
}
|
|
|
|
if (! $this->isEspSnapshot($snapshot)) {
|
|
continue;
|
|
}
|
|
|
|
$this->line(sprintf(
|
|
'ESP detected: policy=%s tenant_id=%s external_id=%s',
|
|
(string) $policy->getKey(),
|
|
(string) $policy->tenant_id,
|
|
(string) $policy->external_id,
|
|
));
|
|
|
|
if ($dryRun) {
|
|
continue;
|
|
}
|
|
|
|
$existingTarget = Policy::query()
|
|
->where('tenant_id', $policy->tenant_id)
|
|
->where('external_id', $policy->external_id)
|
|
->where('policy_type', 'windowsEnrollmentStatusPage')
|
|
->first();
|
|
|
|
if ($existingTarget) {
|
|
$policy->forceFill(['ignored_at' => now()])->save();
|
|
$ignoredPolicies++;
|
|
|
|
continue;
|
|
}
|
|
|
|
$policy->forceFill([
|
|
'policy_type' => 'windowsEnrollmentStatusPage',
|
|
])->save();
|
|
$changedPolicies++;
|
|
|
|
$changedVersions += PolicyVersion::query()
|
|
->where('policy_id', $policy->id)
|
|
->where('policy_type', 'enrollmentRestriction')
|
|
->update(['policy_type' => 'windowsEnrollmentStatusPage']);
|
|
}
|
|
|
|
$this->info('Done.');
|
|
$this->info('PolicyVersions changed: '.$changedVersions);
|
|
$this->info('Policies changed: '.$changedPolicies);
|
|
$this->info('Policies ignored: '.$ignoredPolicies);
|
|
$this->info('Mode: '.($dryRun ? 'dry-run' : 'write'));
|
|
|
|
return Command::SUCCESS;
|
|
}
|
|
|
|
private function isEspSnapshot(array $snapshot): bool
|
|
{
|
|
$odataType = $snapshot['@odata.type'] ?? null;
|
|
$configurationType = $snapshot['deviceEnrollmentConfigurationType'] ?? null;
|
|
|
|
return (is_string($odataType) && strcasecmp($odataType, '#microsoft.graph.windows10EnrollmentCompletionPageConfiguration') === 0)
|
|
|| (is_string($configurationType) && $configurationType === 'windows10EnrollmentCompletionPageConfiguration');
|
|
}
|
|
|
|
private function fetchSnapshotOrNull(Policy $policy): ?array
|
|
{
|
|
$tenant = $policy->tenant;
|
|
|
|
if (! $tenant) {
|
|
return null;
|
|
}
|
|
|
|
$tenantIdentifier = $tenant->tenant_id ?? $tenant->external_id;
|
|
|
|
$response = $this->graphClient->getPolicy('enrollmentRestriction', $policy->external_id, [
|
|
'tenant' => $tenantIdentifier,
|
|
'client_id' => $tenant->app_client_id,
|
|
'client_secret' => $tenant->app_client_secret,
|
|
'platform' => $policy->platform,
|
|
]);
|
|
|
|
if ($response->failed()) {
|
|
return null;
|
|
}
|
|
|
|
$payload = $response->data['payload'] ?? null;
|
|
|
|
return is_array($payload) ? $payload : null;
|
|
}
|
|
|
|
private function resolveTenantOrNull(): ?Tenant
|
|
{
|
|
$tenantOption = $this->option('tenant');
|
|
|
|
if (! $tenantOption) {
|
|
return null;
|
|
}
|
|
|
|
return Tenant::query()
|
|
->forTenant($tenantOption)
|
|
->firstOrFail();
|
|
}
|
|
}
|