Tiện ích kết nối bóng người của người không phải quản trị viên với phiên người dùng RDP trong WinServer 2012R2

Проблема в период карантинной работы предприятия стала следующей: действительно нужно минимизировать количество посещений кабинетов специалистами, обслуживающими и консультирующими по прикладному ПО, да и сказать откровенно, пользователи частенько злоупотребляют помощью специалистов не желая вникать в сам вопрос, мол «придут — помогут — сделают, а я пока покурю/попью кофе и т.п.». Консультация по телефону при совместном доступе к серверу эффективнее, если просматривать удаленный экран.

Tiện ích kết nối bóng người của người không phải quản trị viên với phiên người dùng RDP trong WinServer 2012R2

Уже после «изобретения» нашего велосипеда подвернулась вменяемая информация на тему статьи: RDS Shadow – теневое подключение к RDP сессиям пользователей в Windows Server 2012 R2 hoặc Режим shadow непривилегированного пользователя в windows server hoặc Ủy quyền quản lý các phiên RDP. Все они подразумевают применение консоли, даже с элементами простого диалога.

Вся изложенная ниже информация предназначена для тех, кто нормально переносит ненормальные извращения для получения нужного результата, изобретая ненужные способы.
Чтобы «не тянуть кота за хвост», начну с последнего: велосипед работает у обычного пользователя с помощью утилиты AdmiLink, за что ее автору и спасибо.

I. Консоль и shadow RDP.

Так как использование с админскими правами консоли Server Manager -> QuickSessionCollection -> щелкнув по сессии интересующего пользователя, выбрав в контекстном меню Shadow (Теневая копия) для персонала, инструктирующего по работе с ПО, — не вариант, был рассмотрен другой «деревянный» способ, а именно:

1. Узнаем RDP id сессии:

query user | findstr Administrator

hoặc:

qwinsta | findstr Administrator 

Причем "| findstr Administrator" было удобно только когда ты знаешь, что именно Quản trị тебе нужен, либо использовать только первую часть для лицезрения всех залогинившихся на сервере.

Tiện ích kết nối bóng người của người không phải quản trị viên với phiên người dùng RDP trong WinServer 2012R2

2. Подключаемся к этой сессии, при условии что в доменных групповых политиках параметр «Устанавливает правила удаленного управления для пользовательских сеансов служб удаленных рабочих столов» выбран параметр как минимум «Наблюдение за сеансом с разрешения пользователя» (hơn):

mstsc /shadow:127

Прошу обратить внимание что в списке будут только логины пользователей.

Повторюсь что без админских прав вы получите следующее:

Tiện ích kết nối bóng người của người không phải quản trị viên với phiên người dùng RDP trong WinServer 2012R2

Но для предварительной отладки программы, о которой пойдет речь, я использовал учетку с правами администратора.

II. Программа

Итак постановка задачи: создание некого простого графического интерфейса для подключения к теневому сенсу пользователя с его разрешения, отправка сообщения пользователю. Среда программирования выбрана Lazarus.

1. Получаем полный доменный список пользователей «логин» — «полное имя» у админа, либо опять таки через консоль:

wmic useraccount get Name,FullName 

никто не запрещает даже так:

wmic useraccount get Name,FullName > c:testusername.txt

Скажу сразу, что именно у Lazarus оказалось проблема с обработкой этого файла, так как по умолчанию его кодировка UCS-2, поэтому пришлось просто преобразовать вручную в обычный UTF-8. В структуре файла много табуляций, вернее множество пробелов, которые было решено все-таки программно обработать, рано или поздно задачка с кодировкой будет решена, и файл будет программно обновляться.

Итак, в задумке папка, доступная для пользователей программы, например c:test, в которой будет 2 файла: первый с login и fullname, второй с id_rdp и login пользователей. Далее эти данные обрабатываем как можем:).

А пока для ассоциирования со списком сессий переносим это (login и fullname) содержимое в массив:

procedure Tf_rdp.UserF2Array;
var 
  F:TextFile;   i:integer;   f1, line1:String;   fL: TStringList;
begin //f_d глобальный путь к размещению файлов 
f1:=f_d+'user_name.txt';     //задача считать в массив содержимое файла
fL := TStringList.Create; // строку подвергнем метамарфозам с разделителями
fL.Delimiter := '|'; fL.StrictDelimiter := True;
AssignFile(F,f1); 
try // Открыть файл для чтения
  reset(F); ReadLn(F,line1);
  i:=0;
while not eof(F) do // Считываем строки, пока не закончится файл
begin
ReadLn(F,line1);
line1:= StringReplace(line1, '  ', '|',[]); //заменяем первый попавш.2пробела разделителем |
// удаляем все двойные пробелы
while pos('  ',line1)>0 do line1:= StringReplace(line1, '  ', ' ', [rfReplaceAll]);
begin
if (pos('|',line1)>0) then
begin //если разделитель существует заносим его в массив
fL.DelimitedText :=line1; // разбиваем на столбцы
if (fL[0]<>'') then //если учетка имеет имя
begin //вносим ее в массив
 inc(i); // избавляемся от возможных одиночных пробелов в логине
 fam[0,i]:=StringReplace(fL[1],' ','',[rfReplaceall, rfIgnoreCase]);
 fam[1,i]:=fL[0];
 end;end;end;end; // Готово. Закрываем файл.
 CloseFile(F);
 Fl.Free;
 except
 on E: EInOutError do  ShowMessage('Ошибка обработки файла. Детали: '+E.Message);
 end;end;

Прошу извинения за «много кода», следующие пункты будут лаконичнее.

2. Аналогично методом из предыдущего пункта считываем результат обработки списка в элемент StringGrid, при этом приведу «значимый» кусок кода:

2.1 Получаем актуальный список RDP сессий в файл:

f1:=f_d+'user.txt';
cmdline:='/c query user >'+ f1;
if ShellExecute(0,nil, PChar('cmd'),PChar(cmdline),nil,1)=0 then;
Sleep(500); // можно и подольше ждать пока файл для чтения создается

2.2 Обрабатываем файл (указан только значимые строки кода):

StringGrid1.Cells[0,i]:=fL[1]; StringGrid1.Cells[2,i]:=fL[3]; //кидаем в цикле в StringGrid1
login1:=StringReplace(fL[1],' ','',[rfReplaceall, rfIgnoreCase]); //убираем из логина пробелы
if (SearchArr(login1)>=0) then //ищем в массиве из п1. логин и записываем в таблицу ФИО
StringGrid1.Cells[1,i]:=fam[1,SearchArr(login1)]
else StringGrid1.Cells[1,i]:='+'; // либо записываем плюсик:)
.... //в зависимости от выбора пользователя сортируем и форматируем по данным
if (b_id.Checked=true) then SortGrid(0) else SortGrid(1);
StringGrid1.AutoSizeColumn(0);StringGrid1.AutoSizeColumn(1); StringGrid1.AutoSizeColumn(2);  

3. Непосредственно само подключение при клике на строку с пользователем и номером его сеанса:

  id:=(StringGrid1.Row);// узнаем номер строки  IntToStr(StringGrid1.Row)
  ids:=StringGrid1.Cells[2,id]; //получаем идентификатор rdp
  cmdline:='/c mstsc /shadow:'+ ids; //и подключаемся....
 if (b_rdp.Checked=True) then  if ShellExecute(0,nil, PChar('cmd'),PChar(cmdline),nil,1) =0 then;       

4. Сделано еще пару украшательств типа сортировки по клику на radiobutton, и сообщения пользователю, либо всем пользователям.

Tiện ích kết nối bóng người của người không phải quản trị viên với phiên người dùng RDP trong WinServer 2012R2

→ Полный исходный код можно увидеть đây

III. Применение AdminLink — что я увидел:

AdminLink действительно генерирует ярлык, в котором ссылается на расположение утилиты admilaunch.exe, и личной копией утилиты запуска AdmiRun.Exe которая находится в папке пользователя, например vasya, loại hình C:UsersvasyaWINDOWS. В общем, не все так плохо: с правами доступа к файлу ярлыка и другими, для очищения собственной админской совести, можно поиграться.

Nguồn: www.habr.com

Thêm một lời nhận xét