В организацията, в която работя, работата от разстояние беше забранена принципно. Беше. До миналата седмица. Сега беше необходимо спешно да внедрим решение. От бизнеса – адаптация на процесите към новия формат на работа, от наша страна – PKI с ПИН кодове и токени, VPN, детайлно логване и много други.
Освен всичко друго, занимавах се с настройка на инфраструктурата за отдалечени работни станции, aka терминални услуги. Имаме няколко RDS внедрения в различни ЦОД. Една от задачите беше да предоставим на колегите от сродните ИТ отдели възможност да се свързват с потребителските сесии в интерактивен режим. Както е известно, за това има вграден механизъм 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 и да ги разлогват принудително (полезно е, когато потребителят не може сам да завърши «висналата» сесия).
Изглежда това по следния начин:
За «управляващия»
За потребителя
Няколко забележки накрая
Нюанс 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
