|
Sistemas Operativos: AjpdSoft Información Usuarios Terminal Server
Hemos colocado una nueva descarga de nuestra aplicación "AjpdSoft Información Usuarios Terminal Server". Con esta aplicación podrás saber qué usuarios hay conectados a los servidores de Terminal Server, en qué servidor está cada usuario, hora de inicio de sesión, número de veces que se ha conectado, denegar/permitir acceso al servidor, establecer un servidor de terminal server como preferido, hacer control remoto automáticamente a un usuario, etc. Imaginemos esta situación y la problemática que conlleva: Desde que nuestra empresa empezó a crecer en volumen de usuarios tuvimos que ir aumentando proporcionalmente el número de servidores de Terminal Server. Actualmente contamos con 4 servidores con Windows 2003. El problema surgió a partir de la adquisición del segundo servidor. Actualmente tenemos 250 usuarios conectados a los tres servidores de Terminal Server. Nuestros técnicos informáticos, cuando tienen que hacer control remoto a algún usuario que haya conectado a algún servidor de terminal server, a veces les es casi imposible saber en qué servidor está el usuario al que le tienen que hacer control remoto. Para averiguar en qué servidor está el usuario utlizaban varios métodos:
Tras analizar la problemática, nuestros desarrolladores informáticos, junto con nuestros administradores de sistemas se pusieron manos a la obra, para intentar solucionar este problema. La solución a este problema requiere una parte de desarrollo y otra de administración de sistemas. En primer lugar desarrollaron un script que se ejecuta al inicio de cada sesión de Terminal Server. Este script (desarrollado en Delphi) realiza las siguientes tareas (entre otras):
Evidentemente, de las tareas que realiza el script de inicio de sesión (pulsa aquí para ver un manual sobre cómo realizar un script para inicio de sesión de Terminal Server), la que comentaremos en este artículo es la última (marcada en negrita). El código en Delphi 6 del script para realizar esta tarea es el siguiente: program inicioSesion; {$APPTYPE CONSOLE} uses SysUtils, inifiles, Dialogs, windows, Classes, shellapi, Controls; function obtenerDirectorioWindows : TFileName; var WinDir: array [0..MAX_PATH-1] of char; begin SetString(Result, WinDir, GetWindowsDirectory(WinDir, MAX_PATH)); end; function obtenerDirectorioSistema : TFileName; var SysDir: array [0..MAX_PATH-1] of char; begin SetString(Result, SysDir, GetSystemDirectory(SysDir, MAX_PATH)); end; function ejecutarEsperar (aplicacion: String; parametros : string): Cardinal; var StartInfo: TStartupInfo; ProcInfo: TProcessInformation; begin Result := 0; FillChar(StartInfo, SizeOf(StartInfo), 0); StartInfo.cb := SizeOf(StartInfo); if CreateProcess( PChar(aplicacion), PChar(parametros), nil, nil, false, 0, nil, nil, StartInfo, ProcInfo) then Result := ProcInfo.hProcess; end; function ejecutarFichero (fichero, parametros : string) : boolean; var resEj : THandle; begin resEj := 0; resEj := ShellExecute(resEj, 'open', PChar(fichero), PChar(parametros), nil, SW_SHOWNORMAL); if resEj < 32 then begin result := false; end else begin result := true; end; end; function obtenerVariableEntorno (variable : string) : String; var Env : PChar; valorVariable : string; begin Result := ''; Env := GetEnvironmentStrings; While Env^ <> #0 do begin valorVariable := StrPas(Env); if Pos (variable, valorVariable) = 1 then begin Result := copy (valorVariable, length(variable) + 1, length(valorVariable)); exit; end; Inc(Env, StrLen(Env) + 1); end; end; procedure cerrarSesion; var rl, flgs : Cardinal; hToken : Cardinal; tkp : TOKEN_PRIVILEGES; begin flgs := 0; flgs := (flgs and (not (EWX_REBOOT or EWX_SHUTDOWN or EWX_POWEROFF))) or EWX_LOGOFF; if Win32Platform = VER_PLATFORM_WIN32_NT then begin if not OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) then //silenciosa else begin if LookupPrivilegeValue(nil, 'SeShutdownPrivilege', tkp.Privileges[0].Luid) then begin tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED; tkp.PrivilegeCount := 1; AdjustTokenPrivileges(hToken, False, tkp, 0, nil, rl); if GetLastError <> ERROR_SUCCESS then Writeln('Se ha producido un error al intentar ajustar los privilegios.'); end; end; end; // else begin ExitWindowsEx(flgs, 0); // end; end; var rutaPerfil : string; nombreServidor : string; nombreUsuario : string; nombreEquipoCliente : string; numConexiones : integer; avisarUsuario : Boolean; nombreServidorPref : string; mensaje : string; permitirInicio : Boolean; cerrarSesionUsuario : Boolean; iniciarSTS : Boolean; controlRemoto : Boolean; usuAdministrador : Boolean; usuControlRemoto : string; listaFichero : TStringList; idSesion : string; numProceso : Cardinal; const docInfo = '//servidor/netlogon/info.ini'; begin try //comprobamos si le corresponde iniciar sesión en este servidor nombreServidor := obtenerVariableEntorno ('COMPUTERNAME='); nombreUsuario := obtenerVariableEntorno ('USERNAME='); with tinifile.create (docInfo) do try nombreServidorPref := ReadString (nombreUsuario, 'Servidor preferido', ''); avisarUsuario := readBool (nombreUsuario, 'Mostrar aviso', false); permitirInicio := readBool (nombreUsuario, 'Permitir inicio sesión', true); cerrarSesionUsuario := readBool (nombreUsuario, 'Cerrar sesión', false); finally free; end; if not permitirInicio then begin if avisarUsuario then MessageDlg('Atención: no tiene permiso para inciar sesión. Consulte ' + 'con el departamento de Nuevas Tecnologías. ' + 'Pulse Aceptar para cerrar la sesión.', mtWarning, [mbok], 0); cerrarSesion; end; if avisarUsuario and (AnsiUpperCase (nombreServidor) <> AnsiUpperCase (nombreServidorPref)) then begin if cerrarSesionUsuario then mensaje := 'Atención: su servidor por defecto es [' + nombreServidorPref + ']. Se ha conectado a [' + nombreServidor + '].' + chr(13) + chr(13) + chr(13) + 'Pulse Aceptar para cerrar la sesión.' else mensaje := 'Atención: su servidor por defecto es [' + nombreServidorPref + ']. Se ha conectado a [' + nombreServidor + '].'; MessageDlg(mensaje, mtWarning, [mbok], 0); if cerrarSesionUsuario then begin cerrarSesion; end; end; //***** FIN comprobamos si le corresponde iniciar sesión en este servidor rutaPerfil := obtenerVariableEntorno ('USERPROFILE='); //*******PARA GUARDAR EN QUÉ SERVIDOR ESTÁ CADA USUARIO ******* nombreEquipoCliente := obtenerVariableEntorno ('CLIENTNAME='); //escribimos en info.ini los datos del usuario with tinifile.create (docInfo) do try numConexiones := ReadInteger (nombreUsuario, 'Nº Conexiones', 0); numConexiones := numConexiones + 1; writeString (nombreUsuario, 'Servidor', nombreServidor); writeString (nombreUsuario, 'Equipo cliente', nombreEquipoCliente); writeString (nombreUsuario, 'Hora Inicio sesion', datetimetostr(now)); WriteInteger (nombreUsuario, 'Nº Conexiones', numConexiones); finally free; end; //*******FIN PARA GUARDAR EN QUÉ SERVIDOR ESTÁ CADA USUARIO ******* //Iniciar Administrador de servicios de Terminal Server //Control remoto with tinifile.create (docInfo) do try iniciarSTS := ReadBool (nombreUsuario, 'Iniciar servicios TS', false); controlRemoto := ReadBool (nombreUsuario, 'Control remoto', false); usuAdministrador := ReadBool (nombreUsuario, 'Administrador', false); usuControlRemoto := ReadString (nombreUsuario, 'Usuario control remoto', ''); finally free; end; if (usuAdministrador = true) and (usuControlRemoto <> '') and (controlRemoto = true) then begin with tinifile.create (docInfo) do try WriteString (nombreUsuario, 'Usuario control remoto', ''); finally free; end; numProceso := ejecutarEsperar(obtenerDirectorioSistema + '/cmd.exe', '/c query user ' + usuControlRemoto + ' > C:/resultado_query.txt'); if numProceso <> 0 then WaitForSingleObject(numProceso, INFINITE); if FileExists('C:/resultado_query.txt') then begin listaFichero := TStringList.Create; listaFichero.LoadFromFile('C:/resultado_query.txt'); if listaFichero.Count > 1 then begin if MessageDlg('¿Desea realizar control remoto al usuario [' + usuControlRemoto + ']?' + chr(13) + chr(13) + ' Para cerrar el control remoto no olvide pulsar "Control + *".', mtconfirmation, [mbyes, mbno], 0) = mryes then begin idSesion := trim (copy (listaFichero.Strings[1], 23, 19)); ejecutarFichero ('cmd.exe', ' /c shadow ' + idSesion); end; end else MessageDlg('El usuario [' + usuControlRemoto + '] no tiene sesión abierta en el servidor [' + nombreServidor + '].', mtInformation, [mbok], 0); DeleteFile(pchar('C:/resultado_query.txt')); end; end; if iniciarSTS then ejecutarFichero ('tsadmin.exe', ''); //*******FIN Iniciar Administrador de servicios de Terminal Server //control remoto except end; end. Con el script anterior, conseguiremos guardar la información necesaria para saber en qué servidor está conectado un usuario actuamente. También nos servirá para realizar control remoto, si así lo hemos indicado en la aplicación que a continuación os explicaremos. Para realizar el control remoto automático al usuario hemos utilizado dos comandos de Windows 2000/2003: query user nombre_usuario > ficherodestino este comando devuelve en "ficherodestino" los datos del usuario "nombre_usuario" si ha iniciado sesión (id de sesión, tiempo de inactividad, etc), necesarios para el siguiente comando, el que hace el control remoto: shadow id_sesion Este comando es el que realiza el control remoto al id de sesión pasado como parámetro. Para poder ejecutar correctamente estos dos comandos, nuestros desarrolladores tuvieron que realizar una función que ejecutara comandos de MS-DOS y se le pudieran pasar parámetros. También era necesario que la función que ejecutara el comando "query" esperara a que este terminara, de lo contrario funcionaba sólo a veces. En resumen, lo que se ideó para ejecutar estos comandos desde Delphi en Windows 2003 (al iniciarse la sesión del usuario) fue:
Tras realizar el script de inicio de sesión, desarrollamos la aplicación que administraría el fichero .ini que genera el script de inicio de sesión. Donde se guardan todos los datos de los usuarios. Dicho fichero .ini tiene la siguiente estructura:
La aplicación que permite leer y administrar el contenido de este fichero tiene el siguiente código fuente: unit UnidadMenuPrincipal; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ExtCtrls, Buttons, inifiles, TrayIcon, ActnList, Menus, ImgList, registry, shellapi; type TformMenuPrincipal = class(TForm) tab: TPageControl; tabBuscar: TTabSheet; tabModificar: TTabSheet; GroupBox1: TGroupBox; Label1: TLabel; txtUsuario: TComboBox; GroupBox2: TGroupBox; txtDatos: TMemo; GroupBox3: TGroupBox; Label2: TLabel; txtModUsuario: TComboBox; Label3: TLabel; Label4: TLabel; Label6: TLabel; txtModServidorPref: TComboBox; txtModNumConexiones: TEdit; txtModNombreCompleto: TEdit; bModificar: TBitBtn; bEliminar: TBitBtn; Panel1: TPanel; opPermitirInicioSesion: TCheckBox; opMostrarAviso: TCheckBox; opCerrarSesionSNPref: TCheckBox; bObtener: TBitBtn; tMin: TTrayIcon; bMinimizar: TBitBtn; bCerrar: TBitBtn; PopupMenu1: TPopupMenu; Mostrar1: TMenuItem; N1: TMenuItem; Cerrar1: TMenuItem; listaAcciones: TActionList; actCerrar: TAction; actMostrar: TAction; actMinimizar: TAction; Buscar1: TMenuItem; ImageList1: TImageList; actObtener: TAction; actGuardar: TAction; actEliminar: TAction; actBuscar: TAction; BitBtn1: TBitBtn; actPasarDatos: TAction; be: TStatusBar; tabConfiguracion: TTabSheet; GroupBox4: TGroupBox; opIniciarMinimizada: TCheckBox; opIniciarWindows: TCheckBox; Label5: TLabel; txtFichero: TEdit; bSelFic: TBitBtn; dlAbrir: TOpenDialog; BitBtn2: TBitBtn; actIniciarTerminalServer: TAction; txtUsuarioAdmin: TEdit; Label7: TLabel; Label8: TLabel; txtDominio: TEdit; opIniciarAdmServicios: TCheckBox; opControlRemoto: TCheckBox; GroupBox5: TGroupBox; bNoPermitirTodos: TBitBtn; bPermitirTodos: TBitBtn; procedure FormCreate(Sender: TObject); procedure txtUsuarioKeyPress(Sender: TObject; var Key: Char); procedure actCerrarExecute(Sender: TObject); procedure actMostrarExecute(Sender: TObject); procedure actMinimizarExecute(Sender: TObject); procedure actObtenerExecute(Sender: TObject); procedure actGuardarExecute(Sender: TObject); procedure actEliminarExecute(Sender: TObject); procedure actBuscarExecute(Sender: TObject); procedure actPasarDatosExecute(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure bSelFicClick(Sender: TObject); procedure actIniciarTerminalServerExecute(Sender: TObject); private { Private declarations } public { Public declarations } end; var formMenuPrincipal: TformMenuPrincipal; nombreUsuario : string; nombreServidor : string; nombreEquipoCliente : string; numConexiones : integer; horaInicio : string; nombreCompleto : string; nombreServidorPreferido : string; PermitirInicioSesion : boolean; MostrarAviso : boolean; CerrarSesionSNPref : boolean; vtServiciosTS : Boolean; vtControlRemoto : Boolean; vtUsuAdministrador : Boolean; implementation {$R *.dfm} procedure ejecutarFichero (fichero, parametros : string); var resEj : THandle; begin resEj := 0; resEj := ShellExecute(resEj, 'open', PChar(fichero), PChar(parametros), nil, SW_SHOWNORMAL); if resEj < 32 then begin RaiseLastWin32Error; end else begin //'El fichero se ha ejecutado correctamente'; end; end; procedure quitarEjecutarInicio (); var reg: TRegistry; begin reg := TRegistry.Create; reg.RootKey := HKEY_LOCAL_MACHINE; reg.OpenKey('Software/Microsoft/Windows/CurrentVersion/Run', false); reg.DeleteValue(Application.Title); reg.CloseKey; reg.Free; end; procedure ejecutarInicio (); var reg : tregistry; begin Reg := TRegistry.Create(KEY_WRITE); try Reg.RootKey := HKEY_LOCAL_MACHINE; if Reg.OpenKey('/Software/Microsoft/Windows/CurrentVersion/Run', True) then begin try Reg.WriteString(Application.Title, ExtractFilePath(ParamStr(0)) + ExtractFileName(ParamStr(0))); except Reg.CloseKey; raise; end; end; Reg.CloseKey; finally Reg.Free; end; end; function listarClavesINI (fichero : string) : TStringList; var lista : TStringList; ltFichero : TStringList; i : integer; linea : string; nombreClave : string; begin lista := TStringList.Create; if FileExists(fichero) then begin ltFichero := TStringList.Create; ltFichero.LoadFromFile(fichero); for i := 0 to ltFichero.Count - 1 do begin linea := trim(ltFichero.Strings[i]); if pos('[', linea) = 1 then begin nombreClave := copy(linea, pos('[', linea) + 1, pos(']', linea) - 2); lista.Add(nombreClave); end; end; end; result := lista; end; function listarServidores (fichero : string) : TStringList; var lista : TStringList; ltClaves : TStringList; i : integer; servidorOb : string; begin lista := TStringList.Create; lista.Sorted := true; lista.Duplicates := dupIgnore; if FileExists(fichero) then begin ltClaves := listarClavesINI (fichero); with tinifile.create (fichero) do begin try for i := 0 to ltClaves.Count - 1 do begin servidorOb := ReadString(ltClaves.Strings[i], 'Servidor', ''); lista.Add(servidorOb); end; finally free; end; end; end; result := lista; end; procedure TformMenuPrincipal.FormCreate(Sender: TObject); var docInfo : string; begin with tinifile.create (changefileext(paramstr(0), '.ini')) do begin try opIniciarMinimizada.Checked := ReadBool ('Inicio', 'Minimizada', false); opIniciarWindows.Checked := ReadBool ('Inicio', 'Windows', false); opIniciarAdmServicios.Checked := ReadBool ('Inicio', 'Iniciar servicios TS', false); opControlRemoto.Checked := ReadBool ('Inicio', 'Control remoto', false); txtFichero.Text := ReadString ('Datos', 'Ubicación fichero INI', ''); txtUsuarioAdmin.Text := ReadString ('Inicio', 'Administrador', ''); txtDominio.Text := ReadString ('Datos', 'Dominio', ''); finally free; end; end; docInfo := txtFichero.Text; txtUsuario.Items := listarClavesINI (docInfo); txtModServidorPref.Items := listarServidores(docInfo); txtModUsuario.Items := txtUsuario.Items; be.Panels[1].Text := inttostr(txtUsuario.Items.Count) + ' usuarios'; if opIniciarMinimizada.Checked then actMinimizarExecute(Self); tabBuscar.Show; end; procedure TformMenuPrincipal.txtUsuarioKeyPress(Sender: TObject; var Key: Char); begin if Key = #13 then actObtenerExecute(Self); end; procedure TformMenuPrincipal.actCerrarExecute(Sender: TObject); begin close; end; procedure TformMenuPrincipal.actMostrarExecute(Sender: TObject); begin show; WindowState := wsNormal; actMinimizar.Enabled := true; actMostrar.Enabled := false; tMin.Hide; end; procedure TformMenuPrincipal.actMinimizarExecute(Sender: TObject); begin actMinimizar.Enabled := false; actMostrar.Enabled := true; Hide; Application.ShowMainForm := False; tMin.Hint := Application.Title; tMin.Show; end; procedure TformMenuPrincipal.actObtenerExecute(Sender: TObject); var docInfo : string; begin txtDatos.Clear; docInfo := txtFichero.Text; if FileExists(docInfo) then begin nombreUsuario := txtUsuario.Text; if nombreUsuario <> '' then begin with tinifile.create (docInfo) do try numConexiones := ReadInteger (nombreUsuario, 'Nº Conexiones', 0); nombreServidor := readString (nombreUsuario, 'Servidor', ''); nombreEquipoCliente := ReadString (nombreUsuario, 'Equipo cliente', ''); horaInicio := ReadString (nombreUsuario, 'Hora Inicio sesion', ''); nombreCompleto := ReadString (nombreUsuario, 'Nombre completo', ''); nombreServidorPreferido := ReadString (nombreUsuario, 'Servidor preferido', ''); PermitirInicioSesion := readBool (nombreUsuario, 'Permitir inicio sesión', true); MostrarAviso := readBool (nombreUsuario, 'Mostrar aviso', false); CerrarSesionSNPref := readBool (nombreUsuario, 'Cerrar sesión', false); vtServiciosTS := ReadBool (nombreUsuario, 'Iniciar servicios TS', false); vtControlRemoto := ReadBool (nombreUsuario, 'Control remoto', false); vtUsuAdministrador := ReadBool (nombreUsuario, 'Administrador', false); txtDatos.Lines.Add('Servidor actual: ' + nombreServidor); txtDatos.Lines.Add('Servidor preferido: ' + nombreServidorPreferido); txtDatos.Lines.Add('Nº conexiones: ' + IntToStr(numConexiones)); txtDatos.Lines.Add('Equipo cliente: ' + nombreEquipoCliente); txtDatos.Lines.Add('Nombre completo: ' + nombreCompleto); txtDatos.Lines.Add('Inicio sesión: ' + horaInicio); if PermitirInicioSesion then txtDatos.Lines.Add('Permitir inicio de sesión: Sí') else txtDatos.Lines.Add('Permitir inicio de sesión: No'); if MostrarAviso then txtDatos.Lines.Add('Mostrar aviso si no es su servidor: Sí') else txtDatos.Lines.Add('Mostrar aviso si no es su servidor: No'); if CerrarSesionSNPref then txtDatos.Lines.Add('Cerrar sesión si no es su servidor: Sí') else txtDatos.Lines.Add('Cerrar sesión si no es su servidor: No'); if vtUsuAdministrador then txtDatos.Lines.Add('Administrador: Sí') else txtDatos.Lines.Add('Administrador: No'); if vtServiciosTS then txtDatos.Lines.Add('Iniciar administrador Servicios TS: Sí') else txtDatos.Lines.Add('Iniciar administrador Servicios TS: No'); if vtControlRemoto then txtDatos.Lines.Add('Hacer control remoto: Sí') else txtDatos.Lines.Add('Hacer control remoto: No'); finally free; end; end else begin MessageDlg('Debe indicar el nombre de usuario a consultar.', mtInformation, [mbok], 0); txtUsuario.SetFocus; end; end else MessageDlg('El fichero de información: ' + chr(13) + chr(13) + docInfo + chr(13) + chr(13) + ' no existe o no es accesible.', mtWarning, [mbok], 0); end; procedure TformMenuPrincipal.actGuardarExecute(Sender: TObject); var nombreUsuario : string; docInfo : string; begin docInfo := txtFichero.Text; if FileExists(docInfo) then begin nombreUsuario := txtUsuario.Text; if nombreUsuario <> '' then begin with tinifile.create (docInfo) do try WriteInteger (nombreUsuario, 'Nº Conexiones', strtoint(txtModNumConexiones.Text)); WriteString (nombreUsuario, 'Nombre completo', txtModNombreCompleto.Text); WriteString (nombreUsuario, 'Servidor preferido', txtModServidorPref.Text); WriteBool (nombreUsuario, 'Permitir inicio sesión', opPermitirInicioSesion.Checked); WriteBool (nombreUsuario, 'Mostrar aviso', opMostrarAviso.Checked); WriteBool (nombreUsuario, 'Cerrar sesión', opCerrarSesionSNPref.Checked); MessageDlg('Datos guardados correctamente.', mtInformation, [mbok], 0); finally free; end; end else begin MessageDlg('Debe indicar el nombre de usuario a consultar.', mtInformation, [mbok], 0); txtUsuario.SetFocus; end; end else MessageDlg('El fichero de información: ' + chr(13) + chr(13) + docInfo + chr(13) + chr(13) + ' no existe o no es accesible.', mtWarning, [mbok], 0); end; procedure TformMenuPrincipal.actEliminarExecute(Sender: TObject); begin // end; procedure TformMenuPrincipal.actBuscarExecute(Sender: TObject); begin actMostrarExecute(Self); tabBuscar.Show; txtUsuario.SetFocus; txtUsuario.SelectAll; end; procedure TformMenuPrincipal.actPasarDatosExecute(Sender: TObject); begin txtModUsuario.Text := nombreUsuario; txtModServidorPref.Text := nombreServidorPreferido; txtModNombreCompleto.Text := nombreCompleto; txtModNumConexiones.Text := inttostr(numConexiones); opPermitirInicioSesion.Checked := PermitirInicioSesion; opMostrarAviso.Checked := MostrarAviso; opCerrarSesionSNPref.Checked := CerrarSesionSNPref; tabModificar.Show; txtModServidorPref.SetFocus; end; procedure TformMenuPrincipal.FormClose(Sender: TObject; var Action: TCloseAction); begin with tinifile.create (changefileext(paramstr(0), '.ini')) do begin try WriteBool ('Inicio', 'Minimizada', opIniciarMinimizada.Checked); WriteBool ('Inicio', 'Windows', opIniciarWindows.Checked); WriteBool ('Inicio', 'Iniciar servicios TS', opIniciarAdmServicios.Checked); WriteBool ('Inicio', 'Control remoto', opControlRemoto.Checked); WriteString ('Inicio', 'Administrador', txtUsuarioAdmin.Text); WriteString ('Datos', 'Ubicación fichero INI', txtFichero.Text); WriteString ('Datos', 'Dominio', txtDominio.Text); finally free; end; end; //para el usuario administrador if FileExists(txtFichero.Text) then begin with tinifile.create (txtFichero.Text) do begin try WriteBool (txtUsuarioAdmin.Text, 'Iniciar servicios TS', opIniciarAdmServicios.Checked); WriteBool (txtUsuarioAdmin.Text, 'Control remoto', opControlRemoto.Checked); WriteBool (txtUsuarioAdmin.Text, 'Administrador', true); WriteString (txtUsuarioAdmin.Text, 'Usuario control remoto', nombreUsuario); finally free; end; end; end; if opIniciarWindows.Checked then ejecutarInicio else quitarEjecutarInicio; end; procedure TformMenuPrincipal.bSelFicClick(Sender: TObject); begin if dlAbrir.Execute then txtFichero.Text := dlAbrir.FileName; end; procedure TformMenuPrincipal.actIniciarTerminalServerExecute( Sender: TObject); var rutaFicheroConexion : string; contenido : TStringList; begin rutaFicheroConexion := ExtractFilePath (Application.ExeName) + 'conexion.rdp'; contenido := TStringList.Create; contenido.Add ('screen mode id:i:2'); //contenido.Add ('desktopwidth:i:800'); //contenido.Add ('desktopheight:i:600'); contenido.Add ('session bpp:i:8'); contenido.Add ('winposstr:s:0,1,0,0,800,566'); contenido.Add ('full address:s:' + nombreServidor); contenido.Add ('compression:i:1'); contenido.Add ('keyboardhook:i:2'); contenido.Add ('audiomode:i:2'); contenido.Add ('redirectdrives:i:0'); contenido.Add ('redirectprinters:i:1'); contenido.Add ('redirectcomports:i:0'); contenido.Add ('redirectsmartcards:i:1'); contenido.Add ('displayconnectionbar:i:1'); contenido.Add ('autoreconnection enabled:i:1'); contenido.Add ('username:s:' + txtUsuarioAdmin.Text); contenido.Add ('domain:s:' + txtDominio.Text); contenido.Add ('alternate shell:s:'); contenido.Add ('shell working directory:s:'); contenido.Add ('disable wallpaper:i:1'); contenido.Add ('disable full window drag:i:1'); contenido.Add ('disable menu anims:i:1'); contenido.Add ('disable themes:i:1'); contenido.Add ('disable cursor setting:i:0'); contenido.Add ('bitmapcachepersistenable:i:1'); contenido.SaveToFile(rutaFicheroConexion); with tinifile.create (txtFichero.Text) do begin try WriteBool (txtUsuarioAdmin.Text, 'Iniciar servicios TS', opIniciarAdmServicios.Checked); WriteBool (txtUsuarioAdmin.Text, 'Control remoto', opControlRemoto.Checked); WriteBool (txtUsuarioAdmin.Text, 'Administrador', true); WriteString (txtUsuarioAdmin.Text, 'Usuario control remoto', nombreUsuario); finally free; end; end; ejecutarFichero ('mstsc.exe', '"' + rutaFicheroConexion + '"'); end; end. La aplicación funcionando tiene este aspecto:
La aplicación permite minimizarse en la barra de notificación de Windows, de esta forma podrá permanecer siempre abierta y no ocupará espacio en la barra de tareas: Desde esta aplicación podremos realizar control remoto a un usuario de Terminal Server, para ello obtendremos los datos del usuario en cuestión y pulsaremos "Iniciar sesión": Se abrirá una conexión con el servidor de Terminal Server al que esté conectado el usuario, con las credenciales del usuario que hayamos indicado en la pestaña "Configuración" como administrador. Si el usuario no ha iniciado sesión en el servidor en cuestión o se ha desconectado el script de inicio de sesión mostrará un mensaje como este:
Si el usuario está conectado mostrará una confirmación para realizar el control remoto:
Si pulsamos "Sí" se realizará control remoto al usuario directamente.
Con esta aplicación se cumplen los objetivos marcados por los desarrolladores y administradores de AjpdSoft. Pues hemos conseguido agilizar y automatizar un proceso que antes era, en ocasiones, traumático para el usuario. Sobre todo ante la pregunta "¿me podría decir a qué servidor se conecta?", la respuesta de los usuarios solía ser "no sé de qué me hablas, ¿cómo lo miro?". Evidentemente esto redundaba en una pérdida de tiempo por parte del usuario y por nuestra parte.
Por supuesto, como cualquier proyecto, se puede mejorar. Os indicamos algunas de las mejoras que estamos planteando a nuestros desarrolladores:
Esta aplicación y el código fuente está disponible de forma totalmente gratuita (freeware) en nuestra web. Para descargarla deberá ser usuario registrado, si aún no lo es pulse aquí para registrarse: AjpdSoft Información Usuarios Terminal Server
La aplicación que complementa a esta: Realizar script para inicio de sesión de usuarios de Terminal Server Anuncios
Enviado el Lunes, 18 junio a las 12:42:36 por ajpdsoft
|
|