Делегираме управлението на RDP сесии

Делегираме управлението на RDP сесии
В организация, в която работя, дистанционната работа е забранена принципно. Сега. До миналата седмица. Сега се наложи да внедрим решение спешно. От бизнеса — адаптиране на процесите към новия формат на работа, от нас — PKI с ПИН кодове и токени, VPN, детайлно логване и много други.
Освен всичко друго, се занимавах със настройката на инфраструктурата за дистанционни работни станции aka службата по терминали. Имаме няколко RDS разгръщания в различни ЦОД. Една от задачите беше да се даде възможност на колеги от съседни IT отдели да се свързват с потребителските сесии в интерактивен режим. Както е известно, за това има вграден механизъм RDS Shadow и най-простият начин да го делегираме — е да предоставим права на локален администратор на RDS сървърите.
Уважавам и ценя колегите си, но съм много стиснат по отношение на раздаването на админски права. 🙂 Тези, които са съгласни с мен, моля, под кат.

Каквото и да е, задачата е ясна, сега — към работата.

Стъпка 1

Ще създадем в Active Directory група за сигурност RDP_Operators и ще включим в нея учетните записи на тези потребители, на които искаме да делегираме правата:

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

Ако имате няколко AD сайта, преди да преминете към следващата стъпка, трябва да изчакате, докато бъде репликирана на всички контролери на домейна. Обикновено отнема не повече от 15 минути.

Стъпка 2

Ще предоставим на групата права за управление на терминалните сесии на всеки от 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")
        }
    }
}

Стъпка 3

Добавяме групата в локалната група Потребители на дистанционни работни станции на всеки от RDSH сървърите. Ако имате сървъри, обединени в колекции от сесии, тогава правим това на ниво колекция:

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

За единични сървъри използваме груповата политика, изчаквайки прилагането ѝ върху сървърите. Тези, които не желаят да чакат, могат да ускореят процеса с добре познатото gpupdate, най-добре централизирано.

Стъпка 4

Нека подготвим такъв PS-скрипт за „управляващите“:

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 "    не са намерени сесии"
    }
}

За удобство при стартиране на PS-скрипта, ще създадем обвивка под формата на cmd файл с име, съвпадащо с името на PS-скрипта:

RDSManagement.cmd

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

Слагаме двата файла в папка, която ще бъде достъпна за «управляващите» и им молим да влязат отново. Сега, като стартират cmd-файла, те ще могат да се свързват със сесиите на други потребители в режим RDS Shadow и да ги разлогинират принудително (полезно е, когато потребителят не може сам да завърши «зависнала» сесия).

Изглежда това по следния начин:

За «управляващия»Делегираме управлението на RDP сесии

За потребителяДелегираме управлението на RDP сесии

Няколко бележки накрая

Нюанс 1. Ако сесията на потребителя, към която се опитваме да получим достъп, е била стартирана преди скриптът Set-RDSPermissions.ps1 да е изпълнен на сървъра, «управляващият» ще получи грешка на достъпа. Решението е очевидно: да изчакаме, докато управляваният потребител влезе отново.

Нюанс 2. След няколко дни работа с RDP Shadow забелязахме интересен бъг или функция: след завършване на сесията на потребителя, към когото се свързвахме, езиковата лента в трейа изчезва и потребителят трябва да влезе отново, за да я възстанови. Оказа се, че не сме единствени: раз, два, три.

На това всичко. Желая здраве на вас и вашите сървъри. Както винаги, очаквам обратна връзка в коментарите и ви моля да попълните малка анкета по-долу.

Източници

Само регистрирани потребители могат да участват в анкетата. Влезте, моля.

С какво се ползвате?

  • 8,1%AMMYY Admin5

  • 17,7%AnyDesk11

  • 9,7%DameWare6

  • 24,2%Radmin15

  • 14,5%RDS Shadow9

  • 1,6%Quick Assist / Windows Remote Assistance1

  • 38,7%TeamViewer24

  • 32,3%VNC20

  • 32,3%друго20

  • 3,2%LiteManager2

Гласували са 62 потребители. Въздържали са се 22 потребители.

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster