param( [string]$OutputPath = (Join-Path ([Environment]::GetFolderPath("Desktop")) "tenantradar-export.json"), [switch]$SkipModuleInstall ) $ErrorActionPreference = "Stop" if ($PSVersionTable.PSEdition -eq "Desktop") { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } Write-Host "Tenant Radar Collector" -ForegroundColor Cyan Write-Host "Lecture seule. Aucune modification ne sera effectuée." -ForegroundColor Yellow Write-Host "Export cible : $OutputPath" -ForegroundColor DarkGray $requiredModules = @( "Microsoft.Graph.Authentication", "Microsoft.Graph.Users", "Microsoft.Graph.Identity.DirectoryManagement" ) $missingModules = @() foreach ($moduleName in $requiredModules) { if (-not (Get-Module -ListAvailable -Name $moduleName)) { $missingModules += $moduleName } } if ($missingModules.Count -gt 0) { Write-Host "Modules Microsoft Graph manquants : $($missingModules -join ', ')" -ForegroundColor Yellow if ($SkipModuleInstall) { throw "Modules manquants. Relancez sans -SkipModuleInstall ou installez-les avec Install-Module." } $install = Read-Host "Installer les modules manquants pour l'utilisateur courant ? (O/N)" if ($install -notin @("O", "o", "Oui", "oui", "Y", "y", "Yes", "yes")) { throw "Installation annulée. Le collecteur ne peut pas continuer sans ces modules." } if (-not (Get-PackageProvider -Name NuGet -ListAvailable -ErrorAction SilentlyContinue)) { Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Scope CurrentUser -Force } foreach ($moduleName in $missingModules) { Write-Host "Installation de $moduleName..." -ForegroundColor Cyan Install-Module -Name $moduleName -Scope CurrentUser -Repository PSGallery -Force -AllowClobber } } foreach ($moduleName in $requiredModules) { Import-Module $moduleName -ErrorAction Stop } $requiredCommands = @( "Connect-MgGraph", "Get-MgContext", "Get-MgOrganization", "Get-MgDomain", "Get-MgUser", "Get-MgSubscribedSku", "Get-MgDirectoryRole", "Get-MgDirectoryRoleMember", "Invoke-MgGraphRequest" ) $missingCommands = @() foreach ($commandName in $requiredCommands) { if (-not (Get-Command $commandName -ErrorAction SilentlyContinue)) { $missingCommands += $commandName } } if ($missingCommands.Count -gt 0) { throw "Commandes Graph indisponibles après import : $($missingCommands -join ', '). Vérifiez l'installation du SDK Microsoft Graph PowerShell." } $scopes = @( "User.Read.All", "Directory.Read.All", "Group.Read.All", "Domain.Read.All", "Organization.Read.All", "LicenseAssignment.Read.All", "RoleManagement.Read.Directory", "AuditLog.Read.All", "UserAuthenticationMethod.Read.All" ) try { Connect-MgGraph -Scopes $scopes -NoWelcome } catch { Connect-MgGraph -Scopes $scopes } $context = Get-MgContext if (-not $context) { throw "Connexion Microsoft Graph impossible." } Write-Host "Connecté au tenant : $($context.TenantId)" -ForegroundColor Green $organization = Get-MgOrganization $domains = Get-MgDomain -All $users = Get-MgUser -All -Property "id,displayName,userPrincipalName,mail,accountEnabled,userType,createdDateTime,assignedLicenses,signInActivity,department,jobTitle,companyName" $skus = Get-MgSubscribedSku -All $roles = Get-MgDirectoryRole -All $roleMembers = @() foreach ($role in $roles) { try { $members = Get-MgDirectoryRoleMember -DirectoryRoleId $role.Id -All foreach ($member in $members) { $roleMembers += [PSCustomObject]@{ roleId = $role.Id roleName = $role.DisplayName memberId = $member.Id memberType = $member.AdditionalProperties.'@odata.type' displayName = $member.AdditionalProperties.displayName userPrincipalName = $member.AdditionalProperties.userPrincipalName } } } catch { Write-Warning "Impossible de lire les membres du rôle $($role.DisplayName)" } } $guests = $users | Where-Object { $_.UserType -eq "Guest" } $mfaRegistration = @() try { $mfaRegistration = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/v1.0/reports/authenticationMethods/userRegistrationDetails" } catch { Write-Warning "Impossible de récupérer les détails MFA. Vérifiez les permissions/licences. Le reste de l'export continue." } $export = [PSCustomObject]@{ generator = "Tenant Radar Collector" generatorVersion = "0.2.0" generatedAt = (Get-Date).ToUniversalTime().ToString("o") tenantId = $context.TenantId account = $context.Account organization = $organization domains = $domains users = $users subscribedSkus = $skus directoryRoles = $roles roleMembers = $roleMembers guests = $guests mfaRegistration = $mfaRegistration } $folder = Split-Path -Parent $OutputPath if ($folder -and -not (Test-Path $folder)) { New-Item -ItemType Directory -Path $folder -Force | Out-Null } $export | ConvertTo-Json -Depth 10 | Out-File -FilePath $OutputPath -Encoding utf8 Write-Host "Export terminé : $OutputPath" -ForegroundColor Green Write-Host "Vous pouvez ouvrir le fichier avant import dans Tenant Radar." -ForegroundColor Green