Déléguer la gestion des sessions RDP

Déléguer la gestion des sessions RDP
Dans l'organisation où je travaille, le télétravail était fondamentalement interdit. C'était le cas jusqu'à la semaine dernière. Maintenant, nous avons dû mettre en place une solution en urgence. Du côté de l'entreprise, cela implique l'adaptation des processus au nouveau format de travail, de notre côté — PKI avec codes PIN et jetons, VPN, journalisation détaillée et bien d'autres choses encore.
En plus de cela, je travaillais sur la configuration de l'infrastructure de bureaux à distance, aka le service de terminaux. Nous avons plusieurs déploiements RDS dans différents centres de données. L'une des tâches était de permettre à mes collègues des départements adjacents en informatique de se connecter aux sessions utilisateurs en mode interactif. Comme vous le savez, pour cela, il existe un mécanisme standard de RDS Shadow et la manière la plus simple de le déléguer est de donner des droits d'administrateur local sur les serveurs RDS.
Je respecte et apprécie mes collègues, mais je suis très réticent à accorder des droits d'administrateur. 🙂 Ceux qui partagent mon avis, je vous invite à passer à l'étape suivante.

Eh bien, la tâche est claire, maintenant — au travail.

Étape 1

Créons un groupe de sécurité dans Active Directory RDP_Operators et ajoutons-y les comptes des utilisateurs auxquels nous souhaitons déléguer des droits :

$Users = @(
    "UserLogin1",
    "UserLogin2",
    "UserLogin3"
)
$Group = "RDP_Operators"
New-ADGroup -Name $Group -GroupCategory Security -GroupScope DomainLocal
Add-ADGroupMember -Identity $Group -Members $Users

Si vous avez plusieurs sites AD, il faut attendre que cela soit répliqué sur tous les contrôleurs de domaine avant de passer à l'étape suivante. Cela prend généralement moins de 15 minutes.

Étape 2

Donnerons au groupe les droits de gestion des sessions de terminal sur chacun des serveurs RDSH :

Set-RDSPermissions.ps1

$Group = "RDP_Operators"
$Servers = @(
    "RDSHost01",
    "RDSHost02",
    "RDSHost03"
)
ForEach ($Server in $Servers) {
    #Déleguer le droit sur les sessions d'ombre
    $WMIHandles = Get-WmiObject `
        -Class "Win32_TSPermissionsSetting" `
        -Namespace "rootCIMV2terminalservices" `
        -ComputerName $Server `
        -Authentication PacketPrivacy `
        -Impersonation Impersonate
    ForEach($WMIHandle in $WMIHandles)
    {
        If ($WMIHandle.TerminalName -eq "RDP-Tcp")
        {
        $retVal = $WMIHandle.AddAccount($Group, 2)
        $opstatus = "réussi"
        If ($retVal.ReturnValue -ne 0) {
            $opstatus = "erreur"
        }
        Write-Host ("Délégation des droits de connexion d'ombre au groupe " +
            $Group + " sur le serveur " + $Server + ": " + $opstatus + "`r`n")
        }
    }
}

Étape 3

Ajoutons le groupe au groupe local Utilisateurs de bureau à distance sur chacun des serveurs RDSH. Si vos serveurs sont regroupés en collections de sessions, faites cela au niveau de la collection :

$Group = "RDP_Operators"
$CollectionName = "MyRDSCollection"
[String[]]$CurrentCollectionGroups = @(Get-RDSessionCollectionConfiguration -CollectionName $CollectionName -UserGroup).UserGroup
Set-RDSessionCollectionConfiguration -CollectionName $CollectionName -UserGroup ($CurrentCollectionGroups + $Group)

Pour les serveurs individuels, nous utilisons la stratégie de groupe, en attendant qu'elle soit appliquée sur les serveurs. Ceux qui n'ont pas envie d'attendre peuvent forcer le processus avec le bon vieux gpupdate, de préférence de manière centralisée.

Étape 4

Préparons un script PS pour les « gestionnaires » :

RDSManagement.ps1

$Servers = @(
    "RDSHost01",
    "RDSHost02",
    "RDSHost03"
)

function Invoke-RDPSessionLogoff {
    Param(
        [parameter(Mandatory=$True, Position=0)][String]$ComputerName,
        [parameter(Mandatory=$true, Position=1)][String]$SessionID
    )
    $ErrorActionPreference = "Stop"
    logoff $SessionID /server:$ComputerName /v 2>&1
}

function Invoke-RDPShadowSession {
    Param(
        [parameter(Mandatory=$True, Position=0)][String]$ComputerName,
        [parameter(Mandatory=$true, Position=1)][String]$SessionID
    )
    $ErrorActionPreference = "Stop"
    mstsc /shadow:$SessionID /v:$ComputerName /control 2>&1
}

Function Get-LoggedOnUser {
    Param(
        [parameter(Mandatory=$True, Position=0)][String]$ComputerName="localhost"
    )
    $ErrorActionPreference = "Stop"
    Test-Connection $ComputerName -Count 1 | Out-Null
    quser /server:$ComputerName 2>&1 | Select-Object -Skip 1 | ForEach-Object {
        $CurrentLine = $_.Trim() -Replace "s+"," " -Split "s"
        $HashProps = @{
            UserName = $CurrentLine[0]
            ComputerName = $ComputerName
        }
        If ($CurrentLine[2] -eq "Disc") {
            $HashProps.SessionName = $null
            $HashProps.Id = $CurrentLine[1]
            $HashProps.State = $CurrentLine[2]
            $HashProps.IdleTime = $CurrentLine[3]
            $HashProps.LogonTime = $CurrentLine[4..6] -join " "
            $HashProps.LogonTime = $CurrentLine[4..($CurrentLine.GetUpperBound(0))] -join " "
        }
        else {
            $HashProps.SessionName = $CurrentLine[1]
            $HashProps.Id = $CurrentLine[2]
            $HashProps.State = $CurrentLine[3]
            $HashProps.IdleTime = $CurrentLine[4]
            $HashProps.LogonTime = $CurrentLine[5..($CurrentLine.GetUpperBound(0))] -join " "
        }
        New-Object -TypeName PSCustomObject -Property $HashProps |
        Select-Object -Property UserName, ComputerName, SessionName, Id, State, IdleTime, LogonTime
    }
}

$UserLogin = Read-Host -Prompt "Entrez le nom d'utilisateur"
Write-Host "Recherche des sessions RDP de l'utilisateur sur les serveurs..."
$SessionList = @()
ForEach ($Server in $Servers) {
    $TargetSession = $null
    Write-Host "  Interrogation du serveur $Server"
    Try {
        $TargetSession = Get-LoggedOnUser -ComputerName $Server | Where-Object {$_.UserName -eq $UserLogin}
    }
    Catch {
        Write-Host "Erreur: " $Error[0].Exception.Message -ForegroundColor Red
        Continue
    }
    If ($TargetSession) {
        Write-Host "    Session trouvée avec l'ID $($TargetSession.ID) sur le serveur $Server" -ForegroundColor Yellow
        Write-Host "    Que voulez-vous faire?"
        Write-Host "      1 - se connecter à la session"
        Write-Host "      2 - terminer la session"
        Write-Host "      0 - rien"
        $Action = Read-Host -Prompt "Entrez l'action"
        If ($Action -eq "1") {
            Invoke-RDPShadowSession -ComputerName $Server -SessionID $TargetSession.ID
        }
        ElseIf ($Action -eq "2") {
            Invoke-RDPSessionLogoff -ComputerName $Server -SessionID $TargetSession.ID
        }
        Break
    }
    Else {
        Write-Host "    Aucune session trouvée"
    }
}

Pour faciliter l'exécution du script PS, créons un wrapper sous forme de fichier cmd avec le même nom que le script PS :

RDSManagement.cmd

@ECHO OFF
powershell -NoLogo -ExecutionPolicy Bypass -File "%~d0%~p0%~n0.ps1" %*

Nous plaçons les deux fichiers dans un dossier accessible aux "gestionnaires" et leur demandons de se reconnecter. Maintenant, en lançant le fichier cmd, ils pourront se connecter aux sessions d'autres utilisateurs en mode RDS Shadow et les déconnecter de force (ce qui est utile lorsque l'utilisateur ne peut pas finir lui-même une session "bloquée").

Cela ressemble à peu près à ceci :

Pour le "gestionnaire"Déléguer la gestion des sessions RDP

Pour l'utilisateurDéléguer la gestion des sessions RDP

Quelques remarques en conclusion

Nuance 1. Si la session de l'utilisateur à laquelle nous tentons d'accéder a été démarrée avant que le script Set-RDSPermissions.ps1 ne soit exécuté sur le serveur, le "gestionnaire" recevra un message d'erreur d'accès. La solution ici est évidente : attendre que l'utilisateur géré se reconnecte.

Nuance 2. Après quelques jours de travail avec RDP Shadow, nous avons remarqué un bug ou une fonctionnalité intéressante : après la fin de la session d'ombre sur l'utilisateur auquel nous étions connectés, la barre de langue disparaît de la zone de notification, et pour la récupérer, l'utilisateur doit se reconnecter. Il s'avère que nous ne sommes pas seuls : un, deux, trois.

C'est tout. Je vous souhaite santé à vous et à vos serveurs. Comme toujours, j'attends vos retours dans les commentaires et vous prie de participer à un petit sondage ci-dessous.

Sources

Seuls les utilisateurs enregistrés peuvent participer au sondage. Connectez-vous, s'il vous plaît.

Quels outils utilisez-vous ?

  • 8,1%AMMYY Admin5

  • 17,7%AnyDesk11

  • 9,7%DameWare6

  • 24,2%Radmin15

  • 14,5%RDS Shadow9

  • 1,6%Assistance rapide / Assistance à distance Windows1

  • 38,7%TeamViewer24

  • 32,3%VNC20

  • 32,3%autre20

  • 3,2%LiteManager2

62 utilisateurs ont voté. 22 utilisateurs se sont abstenus.

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster