In de organisatie waar ik werk, is thuiswerken in principe verboden. Dat was tot vorige week. Nu moesten we snel een oplossing implementeren. Van het bedrijfsleven ā de aanpassing van processen aan het nieuwe werkformaat, van onze kant ā PKI met pincode's en tokens, VPN, gedetailleerde logging en nog veel meer.
Naast al het andere was ik bezig met de configuratie van de infrastructuur voor remote desktops, oftewel terminalservices. We hebben meerdere RDS-implementaties in verschillende datacenters. Een van de taken was om collega's uit aanverwante IT-afdelingen de mogelijkheid te geven om interactief verbinding te maken met gebruikerssessies. Zoals bekend is er een standaardmechanisme voor RDS Shadow en de eenvoudigste manier om dit te delegeren is door lokale administratorrechten op de RDS-servers te geven.
Ik respecteer en waardeer mijn collega's, maar ben heel terughoudend met het toekennen van adminrechten. š Degenen die het met me eens zijn, vraag ik onder de kat.
Welnu, de taak is duidelijk, nu ā aan de slag.
Stap 1
Laten we in Active Directory een beveiligingsgroep aanmaken RDP_Operators en toevoegen aan deze groep de accounts van de gebruikers aan wie we rechten willen delegeren:
$Users = @(
"UserLogin1",
"UserLogin2",
"UserLogin3"
)
$Group = "RDP_Operators"
New-ADGroup -Name $Group -GroupCategory Security -GroupScope DomainLocal
Add-ADGroupMember -Identity $Group -Members $Users
Als u meerdere AD-sites heeft, moet u wachten totdat deze is gerepliceerd naar alle domeincontrollers voordat u doorgaat naar de volgende stap. Dit duurt meestal niet langer dan 15 minuten.
Stap 2
Laten we de groep rechten geven om terminalsessies te beheren op elk van de RDSH-servers:
Set-RDSPermissions.ps1
$Group = "RDP_Operators"
$Servers = @(
"RDSHost01",
"RDSHost02",
"RDSHost03"
)
ForEach ($Server in $Servers) {
# Delegeren van recht op shadow sessies
$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 = "succesvol"
If ($retVal.ReturnValue -ne 0) {
$opstatus = "fout"
}
Write-Host ("Rechten voor shadow verbinding delegeert aan groep " +
$Group + " op server " + $Server + ": " + $opstatus + "`r`n")
}
}
}
Stap 3
Laten we de groep toevoegen aan de lokale groep Remote Desktop Users op elk van de RDSH-servers. Als uw servers zijn samengevoegd in sessiecollecties, doe dit dan op het niveau van de collectie:
$Group = "RDP_Operators"
$CollectionName = "MyRDSCollection"
[String[]]$CurrentCollectionGroups = @(Get-RDSessionCollectionConfiguration -CollectionName $CollectionName -UserGroup).UserGroup
Set-RDSessionCollectionConfiguration -CollectionName $CollectionName -UserGroup ($CurrentCollectionGroups + $Group)
Voor enkele servers gebruiken we , wachtend tot het toegepast is op de servers. Degenen die niet willen wachten, kunnen het proces forceren met de oude vertrouwde gpupdate, bij voorkeur .
Stap 4
Laten we voor de 'beheerders' een PS-script voorbereiden:
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 "Voer de gebruikerslogin in"
Write-Host "Zoeken naar RDP-sessies voor de gebruiker op servers..."
$SessionList = @()
ForEach ($Server in $Servers) {
$TargetSession = $null
Write-Host " Server $Server aan het peilen"
Try {
$TargetSession = Get-LoggedOnUser -ComputerName $Server | Where-Object {$_.UserName -eq $UserLogin}
}
Catch {
Write-Host "Fout: " $Error[0].Exception.Message -ForegroundColor Red
Continue
}
If ($TargetSession) {
Write-Host " Sessie met ID $($TargetSession.ID) gevonden op server $Server" -ForegroundColor Yellow
Write-Host " Wat willen we doen?"
Write-Host " 1 - verbind met sessie"
Write-Host " 2 - beƫindig sessie"
Write-Host " 0 - niets"
$Action = Read-Host -Prompt "Voer actie in"
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 " Geen sessies gevonden"
}
}
Om de PS-script eenvoudig uit te voeren, maken we een wrapper in de vorm van een cmd-bestand met dezelfde naam als het PS-script:
RDSManagement.cmd
@ECHO OFF
powershell -NoLogo -ExecutionPolicy Bypass -File "%~d0%~p0%~n0.ps1" %*
Plaats beide bestanden in een map die beschikbaar is voor de 'beheerders' en vraag hen om opnieuw in te loggen. Nu kunnen ze, door het cmd-bestand uit te voeren, verbinding maken met de sessies van andere gebruikers in RDS Shadow-modus en hen gedwongen afmelden (dit kan nuttig zijn wanneer een gebruiker zijn 'vastgelopen' sessie niet zelf kan beƫindigen).
Dit ziet er ongeveer zo uit:
Voor de 'beheerder'
Voor de gebruiker
Enkele laatste opmerkingen
Nuance 1. Als de sessie van de gebruiker, waarmee we proberen verbinding te maken, was gestart voordat het script Set-RDSPermissions.ps1 op de server werd uitgevoerd, zal de 'beheerder' een toegangs foutmelding krijgen. De oplossing is hier voor de hand liggend: wachten tot de beheerde gebruiker opnieuw inlogt.
Nuance 2. Na enkele dagen werken met RDP Shadow hebben we een interessante bug of functie ontdekt: na het beƫindigen van de schaduw sessie verdwijnt de taalbalk in de tray van de gebruiker waarmee we verbinding maakten en om deze terug te krijgen, moet de gebruiker opnieuw inloggen. Blijkbaar zijn we niet de enigen hierin: , , .
Dat is alles. Ik wens u en uw servers gezondheid. Zoals altijd kijk ik uit naar uw feedback in de opmerkingen en vraag ik u om een korte enquĆŖte hieronder in te vullen.
Bronnen
Alleen geregistreerde gebruikers kunnen deelnemen aan de enquĆŖte. , alstublieft.
Waar maak je gebruik van?
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%ander20
3,2%LiteManager2
62 gebruikers gestemd. 22 gebruikers hebben zich onthouden.
Bron: habr.com
