Exporter la liste des applications RD Web et leurs droits d’accès : scripts PowerShell, méthodes et bonnes pratiques

Besoin d’un inventaire fiable des RemoteApps exposées dans RD Web, avec les groupes et utilisateurs autorisés ? Voici des scripts PowerShell prêts à l’emploi, des méthodes alternatives et toutes les bonnes pratiques pour un export exploitable et automatisable.

Sommaire

Vue d’ensemble de la question

Un administrateur RDS souhaite :

  • Télécharger / exporter la liste complète des applications publiées via Remote Desktop Web Access (RD Web).
  • Inclure pour chaque application les utilisateurs ou groupes autorisés (droits d’accès).

Réponse & solutions

ApprochePrincipeÉtapes / commandes clésAvantagesLimites
Aucune fonction “Exporter” intégréeL’interface graphique de RD Web ne propose pas de bouton d’export.Oblige à passer par des méthodes alternatives.
Rapports de “User Access Logging” (UAL) ou “Accounting”Activer la journalisation côté RD Connection Broker ou RD Gateway pour récupérer l’historique des connexions.Activer la journalisation dans les rôles concernés (UAL, journaux événement, NPS/IIS pour RD Gateway). Générer un export ad hoc en CSV via les consoles d’administration ou PowerShell (selon le rôle déployé). Exemples utiles (complément d’inventaire) : # Sessions en cours sur l’environnement RDS Get-RDUserSession | Select UserName, HostServer, SessionState, ApplicationType, ApplicationNameFacile à générer ; donne la réalité des connexions (qui s’est effectivement connecté).N’affiche pas directement la liste des applications ni les droits d’accès statiques ; se limite aux sessions déjà établies.
PowerShell RDS cmdlets (méthode recommandée pour un export structuré)Interroger le Broker pour lister :
• les collections
• les RemoteApps publiées
• les groupes/utilisateurs affectés
# Lister les RemoteApps de la collection "AppsProd" $apps = Get-RDRemoteApp -CollectionName "AppsProd" # Pour chaque RemoteApp, extraire le champ 'UserGroups' $report = foreach ($app in $apps) { [PSCustomObject]@{ Collection = $app.CollectionName RemoteApp = $app.Alias UserGroups = ($app.UserGroups -join ';') } } # Exporter en CSV $report | Export-Csv "RDWeb-Apps-Access.csv" -NoTypeInformation• Résultat exhaustif (applications et droits).
• Automatisable par tâche planifiée.
• Sortie .csv directement exploitable (Excel, Power BI, etc.).
Demande des droits d’admin sur le Connection Broker et le module RemoteDesktop PowerShell.
WMI / CIMInterroger des classes d’instrumentation pour lister RemoteApps et ACL.Pratique quand les cmdlets RDS ne sont pas disponibles. Découverte des classes : Get-CimClass -Namespace root\cimv2 -ClassName *RDS* | Select-Object CimClassNameGrande souplesse.Syntaxe plus complexe ; dépend de la version Windows Server.

Prérequis et périmètre

  • Rôle RD Connection Broker en place (en haute dispo si nécessaire).
  • Module PowerShell RemoteDesktop disponible (présent sur les serveurs RDS ; sur un poste d’admin, installer les RSAT Remote Desktop Services Tools).
  • Compte disposant des droits d’administration RDS (administrateur local du Broker ou membre des groupes d’administration RDS).
  • Exécution depuis le Broker, ou à distance en précisant -ConnectionBroker et en veillant à l’ouverture de WinRM/pare-feu.

Script express pour un export CSV des RemoteApps et droits

Ce script convient si vous n’avez qu’une collection ou si vous connaissez déjà son nom.

# Paramètres
$collection = "AppsProd"
$exportPath = "C:\Exports\RDWeb-Apps-Access.csv"

# Récupérer les RemoteApps de la collection

$apps = Get-RDRemoteApp -CollectionName $collection

# Construire le rapport

$report = foreach ($app in $apps) {
[PSCustomObject]@{
Collection   = $app.CollectionName
RemoteApp    = $app.Alias
DisplayName  = $app.DisplayName
FilePath     = $app.FilePath
ShowInRDWeb  = $app.ShowInWebAccess
UserGroups   = ($app.UserGroups -join ';')
}
}

# Export CSV

$null = New-Item -ItemType Directory -Path (Split-Path $exportPath) -Force -ErrorAction SilentlyContinue
$report | Export-Csv $exportPath -NoTypeInformation -Encoding UTF8
Write-Host "Export terminé: $exportPath"

Export multi‑collections avec héritage des droits

Dans RDS, l’accès peut être défini au niveau collection et/ou affiné au niveau RemoteApp. Lorsqu’une RemoteApp n’a pas de UserGroups explicite, elle hérite généralement du groupe d’accès de la collection. Le script ci‑dessous gère cet héritage et signale où le droit est défini.

# Paramètres
$broker     = "rds-broker.contoso.local"  # FQDN du Connection Broker (obligatoire si exécution distante)
$exportAll  = "C:\Exports\RDWeb-Apps-Access-All.csv"
$exportWeb  = "C:\Exports\RDWeb-Apps-Access-Visible.csv"  # uniquement ce qui est visible dans RD Web

# Lister toutes les collections
$collections = Get-RDSessionCollection -ConnectionBroker $broker

$rows = foreach ($coll in $collections) {

  # Récupérer la config de la collection (pour l'héritage des droits)
  $collCfg = Get-RDSessionCollectionConfiguration `
               -CollectionName $coll.CollectionName `
               -ConnectionBroker $broker `
               -UserGroup
  $collGroups = @($collCfg.UserGroup)  # peut être vide

  # Lister les RemoteApps de la collection
  $apps = Get-RDRemoteApp -ConnectionBroker $broker -CollectionName $coll.CollectionName

  foreach ($app in $apps) {
    $hasAppLevel = ($app.UserGroups -and $app.UserGroups.Count -gt 0)
    $effectiveGroups = if ($hasAppLevel) { $app.UserGroups } else { $collGroups }

    [PSCustomObject]@{
      Collection      = $coll.CollectionName
      RemoteApp       = $app.Alias
      DisplayName     = $app.DisplayName
      FilePath        = $app.FilePath
      ShowInRDWeb     = [bool]$app.ShowInWebAccess
      AccessDefinedAt = if ($hasAppLevel) { "RemoteApp" } else { "Collection" }
      UserGroups      = ($effectiveGroups -join ';')
    }
  }
}

# Exports
$rows | Export-Csv $exportAll -NoTypeInformation -Encoding UTF8
$rows | Where-Object { $_.ShowInRDWeb } |
  Export-Csv $exportWeb -NoTypeInformation -Encoding UTF8

Write-Host "Exports créés:"
Write-Host " - Complet : $exportAll"
Write-Host " - RD Web  : $exportWeb"

Astuce

  • Si vous ne gérez que les applications affichées dans RD Web, travaillez directement avec la variante filtrée ShowInRDWeb -eq $true.
  • Pour les déploiements en haute disponibilité du Broker, utilisez le nom d’équilibreur ou le FQDN virtuel.

Filtrer par utilisateur ou groupe

Deux scénarios fréquents : “quelles applis pour ce groupe ?” et “à quoi cet utilisateur a‑t‑il accès ?”. Les RemoteApps stockent des groupes; pour un utilisateur il faut donc comparer ses appartenances de groupe.

Filtrer par groupe AD

$group = "CONTOSO\Grp_RDS_Finance"

$apps = Get-RDRemoteApp -CollectionName "AppsProd"
$report = foreach ($app in $apps) {
$allowed = @($app.UserGroups)
if (-not $allowed -or $allowed.Count -eq 0) {
# hérite de la collection, récupérer le groupe de la collection
$collCfg = Get-RDSessionCollectionConfiguration -CollectionName "AppsProd" -UserGroup
$allowed = @($collCfg.UserGroup)
}
if ($allowed -contains $group) {
[PSCustomObject]@{ RemoteApp = $app.DisplayName; Collection = $app.CollectionName }
}
}
$report | Export-Csv "C:\Exports\Apps-pour-groupe.csv" -NoTypeInformation

Filtrer par utilisateur AD (avec expansion des groupes)

Cette variante requiert le module ActiveDirectory pour interroger l’appartenance aux groupes.

Import-Module ActiveDirectory

$userUpnOrSam = "[jdupont@contoso.com](mailto:jdupont@contoso.com)"   # ou "CONTOSO\jdupont"
$adUser = Get-ADUser $userUpnOrSam
$userGroups = (Get-ADPrincipalGroupMembership $adUser).SamAccountName

# Construire un préfixe "CONTOSO" cohérent pour comparer avec UserGroups

$domainNetbios = ($adUser.DistinguishedName -split ',')[-1] -replace '^DC=', ''

# Selon votre environnement, vous pouvez imposer: $domainNetbios = "CONTOSO"

$qualifiedUserGroups = $userGroups | ForEach-Object { "$domainNetbios$_" }

$broker      = "rds-broker.contoso.local"
$collections = Get-RDSessionCollection -ConnectionBroker $broker

$visibleForUser = foreach ($coll in $collections) {
$collCfg = Get-RDSessionCollectionConfiguration -CollectionName $coll.CollectionName -ConnectionBroker $broker -UserGroup
$collAllowed = @($collCfg.UserGroup)

$apps = Get-RDRemoteApp -ConnectionBroker $broker -CollectionName $coll.CollectionName
foreach ($app in $apps) {
$allowed = if ($app.UserGroups -and $app.UserGroups.Count -gt 0) { @($app.UserGroups) } else { @($collAllowed) }
if ($allowed.Count -gt 0 -and ($allowed | Where-Object { $qualifiedUserGroups -contains $_ })) {
[PSCustomObject]@{
User        = $userUpnOrSam
Collection  = $coll.CollectionName
RemoteApp   = $app.DisplayName
ShowInRDWeb = $app.ShowInWebAccess
}
}
}
}

$visibleForUser | Export-Csv "C:\Exports\Apps-pour-$($adUser.SamAccountName).csv" -NoTypeInformation -Encoding UTF8

Export détaillé “user‑level” en développant les groupes

Pour des audits fins (conformité, recertification), on peut étendre chaque groupe aux utilisateurs membres afin d’obtenir un mapping Application → Utilisateur.

Import-Module ActiveDirectory

$broker       = "rds-broker.contoso.local"
$exportGroups = "C:\Exports\RDWeb-Apps-Access-Groups.csv"
$exportUsers  = "C:\Exports\RDWeb-Apps-Access-Users.csv"

$collections = Get-RDSessionCollection -ConnectionBroker $broker

# 1) Export au niveau groupes (référence)

$groupRows = foreach ($coll in $collections) {
$collCfg = Get-RDSessionCollectionConfiguration -CollectionName $coll.CollectionName -ConnectionBroker $broker -UserGroup
$collGroups = @($collCfg.UserGroup)

$apps = Get-RDRemoteApp -ConnectionBroker $broker -CollectionName $coll.CollectionName
foreach ($app in $apps) {
$hasAppLevel = ($app.UserGroups -and $app.UserGroups.Count -gt 0)
$effective = if ($hasAppLevel) { $app.UserGroups } else { $collGroups }
foreach ($g in $effective) {
[PSCustomObject]@{
Collection      = $coll.CollectionName
RemoteApp       = $app.DisplayName
AccessDefinedAt = if ($hasAppLevel) { "RemoteApp" } else { "Collection" }
Group           = $g
}
}
}
}
$groupRows | Export-Csv $exportGroups -NoTypeInformation -Encoding UTF8

# 2) Expansion en utilisateurs (peut être long sur de très grands groupes)

$userRows = foreach ($row in $groupRows) {
try {
$members = Get-ADGroupMember -Identity $row.Group -Recursive -ErrorAction Stop |
Where-Object { $*.ObjectClass -eq 'user' }
foreach ($m in $members) {
$u = Get-ADUser $m.SamAccountName -Properties DisplayName, UserPrincipalName
[PSCustomObject]@{
Collection = $row.Collection
RemoteApp  = $row.RemoteApp
Group      = $row.Group
UserSam    = $u.SamAccountName
UserUPN    = $u.UserPrincipalName
UserName   = $u.DisplayName
}
}
} catch {
[PSCustomObject]@{
Collection = $row.Collection
RemoteApp  = $row.RemoteApp
Group      = $row.Group
UserSam    = $null
UserUPN    = $null
UserName   = "ERREUR: $($*.Exception.Message)"
}
}
}

$userRows | Export-Csv $exportUsers -NoTypeInformation -Encoding UTF8

Write-Host "Exports:"
Write-Host " - Groupes : $exportGroups"
Write-Host " - Utilisateurs (expansion) : $exportUsers"

Attention performance : l’expansion récursive de groupes très volumineux peut durer plusieurs minutes et solliciter fortement les contrôleurs de domaine. Planifiez cette tâche la nuit et, si besoin, filtrez les collections ou RemoteApps critiques.

Validation rapide de l’export

  • Ouvrir le CSV dans Excel, vérifier l’absence de doublons évidents (RemoteApp + Group).
  • Contrôler quelques applications au hasard dans la console RDS pour confirmer la concordance des groupes.
  • Tester un utilisateur via une session RD Web : l’utilisateur voit‑il bien les RemoteApps attendues ?

Journalisation des connexions et compléments d’inventaire

Un export des droits complète utilement un export des usages.

  • Sessions en cours : Get-RDUserSession | Select UserName, HostServer, SessionState, ApplicationType, ApplicationName
  • Historique de connexions : selon vos rôles, exploitez les journaux Windows (Session Host, Broker), la fonctionnalité User Access Logging et, pour RD Gateway, les logs NPS/IIS ou la base d’accounting configurée. Exportez ensuite en CSV pour croiser avec vos droits.

Automatisation et intégration

  • Tâche planifiée : créez une tâche quotidienne sous un compte de service autorisé. # Exemple d’action Task Scheduler powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\Export-RDWebApps.ps1"
  • Partage sécurisé : déposez les CSV dans un dossier réseau avec ACL restrictives, puis ingérez‑les dans Power BI/Excel.
  • Notification : ajoutez un envoi e‑mail automatique avec Send-MailMessage ou votre solution d’alerte interne.

Bonnes pratiques et points d’attention

  • Préciser le Broker : sur un poste d’admin, utilisez systématiquement -ConnectionBroker.
  • Haute disponibilité : visez le FQDN virtuel du Broker pour éviter une dépendance à un seul nœud.
  • Héritage des droits : une RemoteApp sans UserGroups explicite hérite du groupe de la collection ; signalez‑le dans l’export (AccessDefinedAt).
  • Visibilité RD Web : le champ ShowInWebAccess permet de n’exporter que ce qui est affiché dans RD Web.
  • Noms de groupes : standardisez le format DOMAINE\Groupe pour simplifier les comparaisons.
  • Protection des exports : les CSV contiennent des informations sensibles ; stockez‑les chiffrés et limitez la diffusion.
  • Traçabilité : datez le fichier (yyyyMMdd) et signez le script si votre politique d’exécution l’exige.

Outils tiers

Des solutions d’observabilité RDS proposent des rapports prêts à l’emploi (accès, usage, tendance). Elles peuvent accélérer les audits récurrents, au prix de licences supplémentaires. Les scripts ci‑dessus restent néanmoins la base la plus contrôlable et industrialisable.

Résolution des erreurs fréquentes

SymptômeCause probablePiste de résolution
Get-RDRemoteApp : The term is not recognizedModule RemoteDesktop absent.Exécuter depuis un serveur RDS ou installer les outils RSAT RDS sur le poste d’admin.
Cannot connect to the Connection BrokerBroker incorrect, pare-feu WinRM, DNS/FQDN.Spécifier -ConnectionBroker, vérifier la résolution DNS, l’ouverture TCP 5985/5986 et l’accès du compte.
CSV vide pour certaines applisUserGroups non défini au niveau RemoteApp.Gérer l’héritage : lire UserGroup au niveau collection via Get-RDSessionCollectionConfiguration -UserGroup.
Temps d’exécution très long lors de l’expansion utilisateursGroupes AD volumineux ou imbriqués.Limiter le périmètre, planifier hors‑prod, ou éviter l’expansion si non nécessaire.

FAQ

Pourquoi une RemoteApp n’apparaît pas dans RD Web alors qu’elle est publiée ?
Vérifiez le paramètre ShowInWebAccess. Si false, l’application reste accessible via fichiers .rdp, mais n’est pas listée dans le portail RD Web.

Peut‑on exporter depuis l’interface RD Web ?
Non. Il n’y a pas de bouton d’export natif ; passez par PowerShell ou l’API d’administration.

Les droits doivent‑ils être mis sur la RemoteApp ou la collection ?
Dans la plupart des cas, appliquez les groupes au niveau collection pour la cohérence, et utilisez le niveau RemoteApp pour les exceptions. Le script gère cet héritage.

Comment gérer plusieurs forêts AD ?
Utilisez des noms qualifiés DOMAINE\Groupe et, pour l’expansion, ciblez le bon contrôleur avec -Server dans les cmdlets AD. Vérifiez les relations d’approbation.

Résumé opérationnel

  • Pas d’export natif dans RD Web ; la voie royale est PowerShell RemoteDesktop.
  • Get-RDRemoteApp + gestion de l’héritage collection → export CSV exhaustif et industrialisable.
  • Complétez par la journalisation pour l’usage réel et par une expansion utilisateur si votre audit l’exige.

Exemples prêts à copier

Export simple d’une collection

$apps = Get-RDRemoteApp -CollectionName "AppsProd"
$report = foreach ($app in $apps) {
  [PSCustomObject]@{
    Collection    = $app.CollectionName
    RemoteApp     = $app.Alias
    UserGroups    = ($app.UserGroups -join ';')
  }
}
$report | Export-Csv "RDWeb-Apps-Access.csv" -NoTypeInformation

Export multi‑collections avec héritage

$broker = "rds-broker.contoso.local"
$collections = Get-RDSessionCollection -ConnectionBroker $broker
$rows = foreach ($coll in $collections) {
  $collCfg = Get-RDSessionCollectionConfiguration -CollectionName $coll.CollectionName -ConnectionBroker $broker -UserGroup
  $apps = Get-RDRemoteApp -ConnectionBroker $broker -CollectionName $coll.CollectionName
  foreach ($app in $apps) {
    $hasAppLevel = ($app.UserGroups -and $app.UserGroups.Count -gt 0)
    $effective = if ($hasAppLevel) { $app.UserGroups } else { @($collCfg.UserGroup) }
    [PSCustomObject]@{
      Collection      = $coll.CollectionName
      RemoteApp       = $app.Alias
      DisplayName     = $app.DisplayName
      AccessDefinedAt = if ($hasAppLevel) { "RemoteApp" } else { "Collection" }
      UserGroups      = ($effective -join ';')
    }
  }
}
$rows | Export-Csv "RDWeb-Apps-Access-All.csv" -NoTypeInformation -Encoding UTF8

Filtrer par utilisateur précis

Import-Module ActiveDirectory
$user  = "CONTOSO\jdupont"
$u     = Get-ADUser $user
$grps  = (Get-ADPrincipalGroupMembership $u).SamAccountName | ForEach-Object { "CONTOSO\$_" }

$apps = Get-RDRemoteApp -CollectionName "AppsProd"
$collCfg = Get-RDSessionCollectionConfiguration -CollectionName "AppsProd" -UserGroup

$report = foreach ($app in $apps) {
$allowed = if ($app.UserGroups) { $app.UserGroups } else { @($collCfg.UserGroup) }
if ($allowed | Where-Object { $grps -contains $_ }) {
[PSCustomObject]@{ RemoteApp = $app.DisplayName; Collection = $app.CollectionName }
}
}
$report | Export-Csv "AppsPour-jdupont.csv" -NoTypeInformation

Lister les sessions en cours

Get-RDUserSession | Select UserName, HostServer, ApplicationType, ApplicationName

Sécurité et conformité

  • Vérifiez la conformité au RGPD/à la politique interne : un export de droits d’accès est une donnée sensible.
  • Chiffrez les emplacements de dépôt, journalisez les accès aux rapports et définissez une rétention.
  • Ne diffusez que le strict nécessaire aux équipes concernées.

Conclusion

Il n’existe pas de bouton natif pour exporter la liste des RemoteApps et leurs droits dans RD Web. La méthode la plus complète, pérenne et automatisable consiste à s’appuyer sur PowerShell : interroger le Broker, gérer l’héritage des droits collection/RemoteApp, puis exporter en CSV. En complément, les journaux de connexion et, le cas échéant, l’expansion des groupes au niveau utilisateur offrent une vision d’ensemble droits + usages indispensable à la gouvernance d’accès.

Scripts fournis : export simple, export multi‑collections avec héritage, filtrage par groupe/utilisateur, expansion utilisateur, sessions en cours. Leur mise en tâche planifiée vous donnera un reporting à jour, exploitable dans Excel/Power BI et prêt pour vos audits périodiques.


En résumé : pas d’export natif, mais des cmdlets RDS fiables ; un CSV propre, un héritage correctement géré et une automatisation bien pensée suffisent pour obtenir un inventaire exhaustif des applications RD Web et de leurs droits d’accès.

Sommaire