Deleguj zarządzanie sesjami RDP

Deleguj zarządzanie sesjami RDP
W organizacji, w której pracuję, praca zdalna jest co do zasady zabroniona. Był. Do zeszłego tygodnia. Teraz musiałem pilnie wdrożyć rozwiązanie. Od biznesu - dostosowanie procesów do nowego formatu pracy, od nas - PKI z kodami PIN i tokenami, VPN, szczegółowe logowanie i wiele więcej.
Między innymi brałem udział w tworzeniu infrastruktury pulpitu zdalnego, czyli usług terminalowych. Mamy kilka wdrożeń RDS w różnych centrach danych. Jednym z celów było umożliwienie współpracownikom z powiązanych działów IT interaktywnego łączenia się z sesjami użytkowników. Jak wiesz, istnieje do tego zwykły mechanizm RDS Shadow, a najłatwiejszym sposobem delegowania jest nadanie uprawnień lokalnego administratora na serwerach RDS.
Szanuję i doceniam moich kolegów, ale jestem bardzo zachłanny na dystrybucję praw administratora. 🙂 Tych, którzy się ze mną zgadzają, proszę pod kat.

Cóż, zadanie jest teraz jasne - do biznesu.

Krok 1

Utwórz grupę zabezpieczeń w usłudze Active Directory RDP_Operatorzy i uwzględnić w nim konta tych użytkowników, którym chcemy przekazać uprawnienia:

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

Jeśli masz wiele witryn AD, przed przejściem do następnego kroku musisz poczekać, aż zostanie zreplikowany na wszystkich kontrolerach domeny. Zwykle zajmuje to nie więcej niż 15 minut.

Krok 2

Nadajmy grupie uprawnienia do zarządzania sesjami terminalowymi na każdym z serwerów RDSH:

Set-RDSPermissions.ps1

$Group = "RDP_Operators"
$Servers = @(
    "RDSHost01",
    "RDSHost02",
    "RDSHost03"
)
ForEach ($Server in $Servers) {
    #Делегируем право на теневые сессии
    $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 = "успешно"
        If ($retVal.ReturnValue -ne 0) {
            $opstatus = "ошибка"
        }
        Write-Host ("Делегирование прав на теневое подключение группе " +
            $Group + " на сервере " + $Server + ": " + $opstatus + "`r`n")
        }
    }
}

Krok 3

Dodaj grupę do grupy lokalnej Użytkownicy Pulpitu Zdalnego na każdym z serwerów RDSH. Jeśli Twoje serwery są połączone w kolekcje sesji, robimy to na poziomie kolekcji:

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

W przypadku pojedynczych serwerów użyj Zasady grupy, czekając na zastosowanie go na serwerach. Dla tych, którzy są zbyt leniwi, by czekać, możesz wymusić proces za pomocą starego dobrego gpupdate, najlepiej centralnie.

Krok 4

Przygotujmy następujący skrypt PS dla „menedżerów”:

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 "Введите логин пользователя"
Write-Host "Поиск RDP-сессий пользователя на серверах..."
$SessionList = @()
ForEach ($Server in $Servers) {
    $TargetSession = $null
    Write-Host "  Опрос сервера $Server"
    Try {
        $TargetSession = Get-LoggedOnUser -ComputerName $Server | Where-Object {$_.UserName -eq $UserLogin}
    }
    Catch {
        Write-Host "Ошибка: " $Error[0].Exception.Message -ForegroundColor Red
        Continue
    }
    If ($TargetSession) {
        Write-Host "    Найдена сессия с ID $($TargetSession.ID) на сервере $Server" -ForegroundColor Yellow
        Write-Host "    Что будем делать?"
        Write-Host "      1 - подключиться к сессии"
        Write-Host "      2 - завершить сессию"
        Write-Host "      0 - ничего"
        $Action = Read-Host -Prompt "Введите действие"
        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 "    сессий не найдено"
    }
}

Aby ułatwić uruchamianie skryptu PS, wykonamy dla niego powłokę w postaci pliku cmd o takiej samej nazwie jak skrypt PS:

RDSManagement.cmd

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

Oba pliki umieszczamy w folderze, który będzie dostępny dla „menadżerów” i prosimy o ponowne zalogowanie. Teraz, uruchamiając plik cmd, będą mogli łączyć się z sesjami innych użytkowników w trybie RDS Shadow i wymusić na nich wylogowanie (przydatne, gdy użytkownik nie może samodzielnie zakończyć „zawieszonej” sesji).

Wygląda to mniej więcej tak:

Dla „kierownika”Deleguj zarządzanie sesjami RDP

Dla użytkownikaDeleguj zarządzanie sesjami RDP

Kilka ostatnich uwag

Niuans 1. Jeżeli sesja użytkownika, nad którym próbujemy przejąć kontrolę, została uruchomiona przed wykonaniem skryptu Set-RDSPermissions.ps1 na serwerze, wówczas „menedżer” otrzyma błąd dostępu. Rozwiązanie tutaj jest oczywiste: poczekaj, aż zarządzany użytkownik ponownie się zaloguje.

Niuans 2. Po kilku dniach pracy z RDP Shadow zauważyliśmy ciekawy błąd lub funkcję: po zakończeniu sesji shadow, użytkownik, z którym się połączył, znika w zasobniku z paskiem języka, a aby go przywrócić, użytkownik musi ponownie Zaloguj sie. Jak się okazuje, nie jesteśmy sami: czas, два, trzy.

To wszystko. Życzę zdrowia Tobie i Twoim serwerom. Jak zawsze czekam na Wasze opinie w komentarzach i proszę o wypełnienie krótkiej ankiety poniżej.

Źródła informacji

W ankiecie mogą brać udział tylko zarejestrowani użytkownicy. Zaloguj się, Proszę.

Czego używasz?

  • 8,1%Administrator AMMYY5

  • 17,7%Dowolne biurko11

  • 9,7%DameWare6

  • 24,2%Radmin15

  • 14,5%RDS Shadow9

  • 1,6%Szybka pomoc / Pomoc zdalna systemu Windows1

  • 38,7%TeamViewer24

  • 32,3%VNC20

  • 32,3%inne20

  • 3,2%LiteManager2

Głosowało 62 użytkowników. 22 użytkowników wstrzymało się od głosu.

Źródło: www.habr.com

Dodaj komentarz