Collecteur local
Un script lisible, exécuté chez l'admin.
Le SaaS ne conserve pas de token. L'admin exécute le collecteur localement, ouvre le JSON s'il veut, puis décide de l'importer.
0 token
Mode idéal pour PME prudentes et MSP.
Télécharger le collecteur PowerShell
Lecture seule, aucune modification du tenant, JSON vérifiable avant import. Le script installe/import les modules Microsoft Graph nécessaires.
Téléchargerparam(
[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