私が働いている組織ではリモートワークが原則禁止となっています。 だった。 先週までは。 今、私たちは早急に解決策を導入する必要がありました。 ビジネスからはプロセスを新しい作業形式に適応させ、私たちからは PIN コードとトークンを使用した PKI、VPN、詳細なログなどを提供します。
とりわけ、私はリモート デスクトップ インフラストラクチャ、別名ターミナル サービスをセットアップしていました。 当社では、さまざまなデータセンターに複数の RDS を導入しています。 目標の XNUMX つは、関連する IT 部門の同僚がユーザー セッションに対話的に接続できるようにすることでした。 ご存知のとおり、これには標準の RDS シャドウ メカニズムがあり、これを委任する最も簡単な方法は、RDS サーバーのローカル管理者権限を与えることです。
私は同僚を尊敬し、大切にしていますが、管理者権限を与えることに関しては非常に貪欲です。 🙂 共感していただける方はフォローお願いします。
さて、課題は明確です。さあ、本題に取り掛かりましょう。
ステップ1
Active Directory にセキュリティ グループを作成しましょう RDP_オペレーター その中に、権限を委任したいユーザーのアカウントを含めます。
$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)
私たちが使用する単一サーバーの場合
ステップ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 スクリプトを実行しやすくするために、PS スクリプトと同じ名前の cmd ファイルの形式でそのシェルを作成します。
RDSManagement.cmd
@ECHO OFF
powershell -NoLogo -ExecutionPolicy Bypass -File "%~d0%~p0%~n0.ps1" %*
両方のファイルを「マネージャー」がアクセスできるフォルダーに置き、再ログインを求めます。 これで、cmd ファイルを実行することで、RDS シャドウ モードで他のユーザーのセッションに接続し、強制的にログアウトできるようになります (これは、ユーザーが「ハング」セッションを独自に終了できない場合に便利です)。
それはこのように見えます:
「マネージャー」にとっては
ユーザーにとって
最後にいくつかのコメント
ニュアンス1。 Set-RDSPermissions.ps1 スクリプトがサーバー上で実行される前に、制御を取得しようとしているユーザー セッションが起動された場合、「マネージャー」はアクセス エラーを受け取ります。 ここでの解決策は明らかです。管理対象ユーザーがログインするまで待ちます。
ニュアンス2。 RDP Shadow を数日間使用した後、興味深いバグまたは機能に気づきました。シャドウ セッションの終了後、接続しているユーザーのトレイの言語バーが消えます。言語バーを元に戻すには、ユーザーは言語バーを再表示する必要があります。 -ログイン。 結局のところ、私たちは一人ではありません。
それだけです。 あなたとあなたのサーバーの健康を祈っています。 いつものように、コメント欄でのフィードバックを楽しみにしています。また、以下の簡単なアンケートにご協力ください。
ソース
RDS Shadow – Windows Server 2016 / 2012 R2 の RDP ユーザー セッションへのシャドウ接続 Windows Server 2012 のシャドーイング – 管理者以外への権限の委任 Get-LoggedOnUser リモート システム上のログオン ユーザーの情報を収集します PowerShell PS1 スクリプトを開始する最良の方法 ドメイン ユーザーをローカル セキュリティ グループに追加する GPMC – OU 内のすべてのコンピューターに gpupdate を強制する
登録ユーザーのみがアンケートに参加できます。
あなたは何を使うのですか?
-
視聴者の38%がアミー管理者5
-
視聴者の38%がエニーデスク11
-
視聴者の38%がダメウェア6
-
視聴者の38%がラドミン15
-
視聴者の38%がRDSシャドウ9
-
視聴者の38%がクイックアシスト / Windows リモート アシスタンス1
-
視聴者の38%がTeamViewer24
-
視聴者の38%がVNC20
-
視聴者の38%がその他20
-
視聴者の38%がLiteManager2
62 人のユーザーが投票しました。 22名のユーザーが棄権した。
出所: habr.com