Betrieb von RDP-Sitzungen delegieren

Betrieb von RDP-Sitzungen delegieren
In der Organisation, in der ich arbeite, ist Homeoffice prinzipiell verboten. War es zumindest. Bis letzte Woche. Jetzt mussten wir hastig eine Lösung einfĂŒhren. Von der GeschĂ€ftsleitung — Anpassung der Prozesse an das neue Arbeitsformat, von uns — PKI mit PIN-Codes und Tokens, VPN, detaillierte Protokollierung und vieles mehr.
Neben allem anderen habe ich die Infrastruktur fĂŒr Remote-Desktops aka Terminaldienste eingerichtet. Wir haben mehrere RDS-Bereitstellungen in verschiedenen Rechenzentren. Eine der Aufgaben war es, Kollegen aus angrenzenden IT-Abteilungen die Möglichkeit zu geben, sich interaktiv mit Nutzersitzungen zu verbinden. Wie bekannt ist, gibt es dafĂŒr den integrierten Mechanismus RDS Shadow und die einfachste Möglichkeit, ihn zu delegieren — die Rechte des lokalen Administrators auf den RDS-Servern zu vergeben.
Ich respektiere und schĂ€tze meine Kollegen, bin aber sehr sparsam bei der Vergabe von Administratorrechten. 🙂 Diejenigen, die mir zustimmen, bitte unter dem Cut.

Nun, die Aufgabe ist klar, jetzt — zur Sache.

Schritt 1

Erstellen wir in Active Directory eine Gruppe fĂŒr Sicherheitszwecke. RDP_Operators und fĂŒgen wir die Konten der Benutzer hinzu, denen wir Rechte delegieren möchten:

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

Wenn Sie mehrere AD-Standorte haben, mĂŒssen Sie warten, bis dies auf alle DomĂ€nencontroller repliziert wurde, bevor Sie zum nĂ€chsten Schritt ĂŒbergehen. In der Regel dauert dies nicht lĂ€nger als 15 Minuten.

Schritt 2

Geben wir der Gruppe die Berechtigungen zur Verwaltung von Terminalsitzungen auf jedem der RDSH-Server:

Set-RDSPermissions.ps1

$Group = "RDP_Operators"
$Servers = @(
    "RDSHost01",
    "RDSHost02",
    "RDSHost03"
)
ForEach ($Server in $Servers) {
    #Recht auf Schatten-Sitzungen delegieren
    $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 = "erfolgreich"
        If ($retVal.ReturnValue -ne 0) {
            $opstatus = "Fehler"
        }
        Write-Host ("Rechte fĂŒr die Schattenverbindung an die Gruppe " +
            $Group + " auf dem Server " + $Server + ": " + $opstatus + "`r`n")
        }
    }
}

Schritt 3

FĂŒgen wir die Gruppe zur lokalen Gruppe hinzu. Benutzer der Remote-Desktop auf jedem der RDSH-Server. Wenn Ihre Server in Sitzungs-Sammlungen zusammengeschlossen sind, machen wir das auf der Ebene der Sammlung:

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

FĂŒr Einzelserver verwenden wir Gruppenrichtlinien, wĂ€hrend wir darauf warten, dass sie auf den Servern angewendet wird. Diejenigen, die nicht warten möchten, können den Prozess mit dem altbekannten gpupdate forcieren, vorzugsweise zentralisiert.

Schritt 4

Wir bereiten fĂŒr die "Verwalter" folgendes PS-Skript vor:

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 "Geben Sie den Benutzernamen ein"
Write-Host "Suche nach RDP-Sitzungen des Benutzers auf den Servern..."
$SessionList = @()
ForEach ($Server in $Servers) {
    $TargetSession = $null
    Write-Host "  Abfrage des Servers $Server"
    Try {
        $TargetSession = Get-LoggedOnUser -ComputerName $Server | Where-Object {$_.UserName -eq $UserLogin}
    }
    Catch {
        Write-Host "Fehler: " $Error[0].Exception.Message -ForegroundColor Red
        Continue
    }
    If ($TargetSession) {
        Write-Host "    Sitzung mit ID $($TargetSession.ID) auf Server $Server gefunden" -ForegroundColor Yellow
        Write-Host "    Was möchten Sie tun?"
        Write-Host "      1 - Verbindung zur Sitzung herstellen"
        Write-Host "      2 - Sitzung beenden"
        Write-Host "      0 - nichts"
        $Action = Read-Host -Prompt "Geben Sie die Aktion ein"
        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 "    Keine Sitzungen gefunden"
    }
}

Um das PS-Skript bequem auszufĂŒhren, erstellen wir fĂŒr es eine Shell in Form einer cmd-Datei mit demselben Namen wie das PS-Skript:

RDSManagement.cmd

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

Wir legen beide Dateien in einen Ordner, der fĂŒr die „Verwalter“ zugĂ€nglich ist, und bitten sie, sich erneut anzumelden. Nun können sie durch AusfĂŒhrung der CMD-Datei auf die Sitzungen anderer Benutzer im RDS Shadow-Modus zugreifen und diese zwangsweise abmelden (was nĂŒtzlich sein kann, wenn ein Benutzer die „hĂ€ngende“ Sitzung nicht selbst beenden kann).

So sieht es ungefÀhr aus:

FĂŒr den „Verwalter“Betrieb von RDP-Sitzungen delegieren

FĂŒr den BenutzerBetrieb von RDP-Sitzungen delegieren

Ein paar abschließende Anmerkungen

Hinweis 1. Wenn die Sitzung des Benutzers, dessen Kontrolle wir ĂŒbernehmen möchten, gestartet wurde, bevor das Script Set-RDSPermissions.ps1 auf dem Server ausgefĂŒhrt wurde, erhĂ€lt der „Verwalter“ einen Zugriffsfehler. Die Lösung liegt auf der Hand: Warten, bis der verwaltete Benutzer sich erneut anmeldet.

Hinweis 2. Nach mehreren Tagen Arbeit mit RDP Shadow haben wir einen interessanten Bug oder ein Feature festgestellt: Nach dem Beenden der Schatten-Sitzung beim Benutzer, mit dem wir verbunden waren, verschwindet die Sprachleiste im Tray, und um sie zurĂŒckzubekommen, muss der Benutzer sich erneut anmelden. Wie sich herausstellte, sind wir damit nicht allein: eins, zwei, drei.

Das ist alles. Ich wĂŒnsche Ihnen und Ihren Servern Gesundheit. Wie immer freue ich mich auf Ihr Feedback in den Kommentaren und bitte Sie, an der kleinen Umfrage unten teilzunehmen.

Quellen

Nur registrierte Benutzer können an der Umfrage teilnehmen. Bitte einloggen.

Was verwenden Sie?

  • 8,1%AMMYY Admin5

  • 17,7%AnyDesk11

  • 9,7%DameWare6

  • 24,2%Radmin15

  • 14,5%RDS Shadow9

  • 1,6%Schnelle Hilfe / Windows Remote Assistance1

  • 38,7%TeamViewer24

  • 32,3%VNC20

  • 32,3%andere20

  • 3,2%LiteManager2

62 Benutzer haben abgestimmt. 22 Benutzer haben sich enthalten.

Quelle: habr.com

60GB SSD 8Gb DDR4