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.
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
Approche | Principe | Étapes / commandes clés | Avantages | Limites |
---|---|---|---|---|
Aucune fonction “Exporter” intégrée | L’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, ApplicationName | Facile à 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 / CIM | Interroger 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 CimClassName | Grande 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ôme | Cause probable | Piste de résolution |
---|---|---|
Get-RDRemoteApp : The term is not recognized | Module RemoteDesktop absent. | Exécuter depuis un serveur RDS ou installer les outils RSAT RDS sur le poste d’admin. |
Cannot connect to the Connection Broker | Broker 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 applis | UserGroups 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 utilisateurs | Groupes 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.