#requires -Version 7.0 <# .SYNOPSIS Liste les Computer Groups (Management Rights) effectifs par UTILISATEUR et par USER GROUP, en affichant les NOMS (pas les mrgroup_*). - Auth depuis config.json (TaniumUrl, TaniumApiToken) via CLIXML -> Initialize-TaniumSession - Déplie .group.id avec Get-MRGroupsFromGroup et mappe ID->Nom via Get-ManagementRightsGroup (fallback REST) #> # ========================= # Block 1 - Prérequis # ========================= $ErrorActionPreference = 'Stop' try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} Import-Module Redden-TanREST -Force # ========================= # Block 2 - Chargement config & init session # ========================= $configPath = Join-Path $PSScriptRoot 'config.json' $TempXml = Join-Path $env:TEMP 'tanium-session-tmp.apicred' if (-not (Test-Path $configPath -PathType Leaf)) { throw "Configuration file not found: $configPath (expected: TaniumUrl, TaniumApiToken)" } Write-Host "Reading configuration from: $configPath" $config = Get-Content -Path $configPath -Raw | ConvertFrom-Json $TaniumUrl = $config.TaniumUrl $TaniumToken = $config.TaniumApiToken if ([string]::IsNullOrWhiteSpace($TaniumUrl) -or [string]::IsNullOrWhiteSpace($TaniumToken)) { throw "Both TaniumUrl and TaniumApiToken must be provided." } if ($TaniumUrl -match '^https?://') { $TaniumUrl = $TaniumUrl -replace '^https?://','' -replace '/+$','' Write-Host "Normalized TaniumUrl to host: $TaniumUrl" } $ExportObject = @{ baseURI = $TaniumUrl token = ($TaniumToken | ConvertTo-SecureString -AsPlainText -Force) } $ExportObject | Export-Clixml -Path $TempXml Write-Host "Initializing Tanium session..." Initialize-TaniumSession -PathToXML $TempXml Write-Host "Tanium session initialized." # ========================= # Block 3 - Index MR id -> nom (module puis REST fallback) # ========================= $Script:MRIndex = @{} try { $allMR = Get-ManagementRightsGroup -All } catch { $allMR = @() } if (-not $allMR -or $allMR.Count -eq 0) { # fallback REST $baseUri = $TaniumUrl; if ($baseUri -notmatch '^https?://') { $baseUri = "https://$baseUri" } $headers = @{ 'Accept' = 'application/json' 'Content-Type' = 'application/json' 'X-Api-Token' = $TaniumToken 'session' = $TaniumToken } try { $resp = Invoke-RestMethod -Method GET -Uri "$baseUri/api/v2/management_rights_groups?limit=5000" -Headers $headers $allMR = @($resp.items ?? $resp.data ?? $resp) } catch { Write-Warning "Could not fetch Management Rights groups via REST: $($_.Exception.Message)" $allMR = @() } } foreach ($g in $allMR) { if ($null -ne $g.id) { $Script:MRIndex[[int]$g.id] = [string]$g.name } } # ========================= # Block 4 - Helpers # ========================= function Expand-NamedMRGroups { <# .SYNOPSIS A partir d'un ID de groupe fusionné (.group.id), retourne les Computer Groups *nommés* (id/name). Utilise Get-MRGroupsFromGroup puis mappe ID->Nom via $Script:MRIndex et filtre mrgroup_*. #> param([Parameter(Mandatory)][int]$MergedGroupID) if ($MergedGroupID -lt 0) { return @() } $items = @() try { $items = @( Get-MRGroupsFromGroup -ID $MergedGroupID ) } catch { $items = @() } $mapped = @() foreach ($i in $items) { $id = [int]$i.id $name = [string]$i.name if (-not $name -or $name -like 'mrgroup_*') { $name = $Script:MRIndex[$id] } if ($name) { $mapped += [pscustomobject]@{ id = $id; name = $name } } } if ($mapped.Count -gt 0) { $mapped = $mapped | Sort-Object id -Unique } return $mapped } function Get-UsersWithComputerGroups { <# .SYNOPSIS Récupère Users + leurs Computer Groups effectifs (nommés). #> $users = @() try { $users = @(Get-User -All) } catch { $users = @(Get-User -Summary) } $rows = @() foreach ($u in $users) { $uid = [int]($u.id) $name = [string]($u.display_name ?? $u.displayName ?? $u.name ?? $u.username) $login = [string]($u.username) $mergedId = 0 try { if ($u.group -and $u.group.id -ne $null) { $mergedId = [int]$u.group.id } } catch {} $cgNamed = if ($mergedId -ge 0) { Expand-NamedMRGroups -MergedGroupID $mergedId } else { @() } $cgNames = $cgNamed.name | Sort-Object -Unique $cgIds = $cgNamed.id | Sort-Object -Unique $rows += [pscustomobject]@{ id = $uid name = $name username = $login mergedGroup = $mergedId groupsCount = @($cgNames).Count groupNames = ($cgNames -join ', ') groupIDs = ($cgIds -join ', ') } } if ($rows.Count -gt 0) { $rows = $rows | Sort-Object name } return $rows } function Get-UserGroupsWithComputerGroups { <# .SYNOPSIS Récupère User Groups + leurs Computer Groups effectifs (nommés). #> $ugs = @(Get-UserGroup -All) $rows = @() foreach ($g in $ugs) { $gid = [int]($g.id) $gname = [string]($g.name) $mergedId = 0 try { if ($g.group -and $g.group.id -ne $null) { $mergedId = [int]$g.group.id } } catch {} $cgNamed = if ($mergedId -ge 0) { Expand-NamedMRGroups -MergedGroupID $mergedId } else { @() } $cgNames = $cgNamed.name | Sort-Object -Unique $cgIds = $cgNamed.id | Sort-Object -Unique $rows += [pscustomobject]@{ id = $gid name = $gname mergedGroup = $mergedId groupsCount = @($cgNames).Count groupNames = ($cgNames -join ', ') groupIDs = ($cgIds -join ', ') } } if ($rows.Count -gt 0) { $rows = $rows | Sort-Object name } return $rows } # ========================= # Block 5 - Exécution + affichage # ========================= Write-Host ">> Gathering Users + Effective Computer Groups..." -ForegroundColor Cyan $UsersWithCG = Get-UsersWithComputerGroups Write-Host ">> Gathering User Groups + Effective Computer Groups..." -ForegroundColor Cyan $UGsWithCG = Get-UserGroupsWithComputerGroups $hasOGV = $null -ne (Get-Command Out-GridView -ErrorAction SilentlyContinue) if ($hasOGV) { $UsersWithCG | Out-GridView -Title 'Tanium Users – Effective Computer Groups (by name)' -Wait $UGsWithCG | Out-GridView -Title 'Tanium User Groups – Effective Computer Groups (by name)' -Wait } else { Write-Host "`n=== USERS – EFFECTIVE COMPUTER GROUPS ===" -ForegroundColor Green $UsersWithCG | Format-Table id,name,username,groupsCount,groupNames -AutoSize Write-Host "`n=== USER GROUPS – EFFECTIVE COMPUTER GROUPS ===" -ForegroundColor Green $UGsWithCG | Format-Table id,name,groupsCount,groupNames -AutoSize Write-Host "`n(Out-GridView not available; showing tables instead)" -ForegroundColor Yellow } # ========================= # Block 6 - Cleanup # ========================= if (Test-Path $TempXml) { Remove-Item $TempXml -Force -ErrorAction SilentlyContinue Write-Host "Temporary CLIXML removed: $TempXml" }