tengo dos scripts
Administrador remoto:
# Cargar las librerías necesarias para trabajar con Forms
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing


# Definir la función DestroyIcon de la API de Windows
Add-Type @"
using System;
using System.Runtime.InteropServices;

public class User32 {
    [DllImport("user32.dll")]
    public static extern bool DestroyIcon(IntPtr hIcon);
}
"@

#***************************************************************************************
$ImagenBytes = [Convert]::FromBase64String('cadena')

# Crear un MemoryStream y cargar la imagen
$ms = New-Object System.IO.MemoryStream(,$ImagenBytes)
$image = [System.Drawing.Image]::FromStream($ms)

# Crear un Bitmap y un Icono
$bitmap = New-Object System.Drawing.Bitmap($image)
$iconHandle = $bitmap.GetHicon()
$icon = [System.Drawing.Icon]::FromHandle($iconHandle)

# No liberar el icono aquí, lo haremos más tarde
# Liberar recursos de la imagen y el bitmap
$image.Dispose()
$bitmap.Dispose()


#***************************************************************************************
#Variables
$Global:puerto=4430

# Función para cargar la lista de servidores desde un archivo
function Load-ServerList {
    $serverList = @()
    if (Test-Path "servers.txt") {
        Get-Content "servers.txt" | ForEach-Object {
            if ($_ -match "(\d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2}) - (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - (.+)") {
                $matches = $matches
                $serverList += [PSCustomObject]@{
                    DateTime = $matches[1]
                    IP = $matches[2]
                    Description = $matches[3]
                }
            }
        }
    }
    return $serverList
}

# Crear el formulario de selección de servidor
$serverSelectionForm = New-Object System.Windows.Forms.Form
$serverSelectionForm.Text = "Seleccionar Servidor"
$serverSelectionForm.Size = New-Object System.Drawing.Size(400, 300)
$serverSelectionForm.StartPosition = "CenterScreen"
$serverSelectionForm.Icon = $icon
$serverListBox = New-Object System.Windows.Forms.ListBox
$serverListBox.Location = New-Object System.Drawing.Point(10, 10)
$serverListBox.Size = New-Object System.Drawing.Size(360, 200)
$serverSelectionForm.Controls.Add($serverListBox)

$connectButton = New-Object System.Windows.Forms.Button
$connectButton.Location = New-Object System.Drawing.Point(150, 220)
$connectButton.Size = New-Object System.Drawing.Size(100, 30)
$connectButton.Text = "Conectar"
$serverSelectionForm.Controls.Add($connectButton)
# Evento del botón Conectar
$connectButton.Add_Click({
    if ($serverListBox.SelectedItem) {
        $global:selectedServer = $servers[$serverListBox.SelectedIndex]
        $serverSelectionForm.Close()
        [User32]::DestroyIcon($iconHandle)
 
        # Cargar el directorio inicial (por ejemplo, el directorio de usuario)
        Update-FileList -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -path $env:USERPROFILE
        # Cargar procesos y servicios iniciales
        Refrescar-Procesos
        Refrescar-Servicios
        # Mostrar el formulario
        
        $form.ShowDialog()
        # Evento Conectar
        $listBox.Tag = $initialPath
        
    } else {
        [System.Windows.Forms.MessageBox]::Show("Por favor, seleccione un servidor.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
})

# Cargar la lista de servidores
$servers = Load-ServerList
foreach ($server in $servers) {
    $serverListBox.Items.Add("$($server.DateTime) - $($server.IP) - $($server.Description)")
}
# Mostrar el formulario de selección de servidor
$serverSelectionForm.ShowDialog()

# Crear una ventana principal
$form = New-Object System.Windows.Forms.Form
$form.Text = "Administrador de Equipos Remotos - $($global:selectedServer.IP)"
$form.Size = New-Object System.Drawing.Size(800, 700)
$form.StartPosition = "CenterScreen"
$form.FormBorderStyle = 'FixedDialog'
$form.ControlBox = $false


#*************************************************************************************
#Control de pestañas
$tabControl = New-Object System.Windows.Forms.TabControl
$tabControl.Location = New-Object System.Drawing.Point(0, 0)
$tabControl.Size = New-Object System.Drawing.Size(800, 700)

#Definir pestañas
$TabFiles = New-Object System.Windows.Forms.TabPage
$TabFiles.Text = "Archivos"

$tabPageProcesos = New-Object System.Windows.Forms.TabPage
$tabPageProcesos.Text = "Procesos"
$tabPageProcesos.Add_Enter({
    Refrescar-Procesos
})

$tabPageServicios = New-Object System.Windows.Forms.TabPage
$tabPageServicios.Text = "Servicios"
$tabPageServicios.Add_Enter({
    Refrescar-Servicios
})

#Agregar las pestañas al form
$tabControl.TabPages.Add($TabFiles)
$tabControl.TabPages.Add($tabPageProcesos)
$tabControl.TabPages.Add($tabPageServicios)

#Agregar el control al form
$form.Controls.Add($tabControl)

# Pestaña de Procesos
$txtBusquedaProcesos = New-Object System.Windows.Forms.TextBox
$txtBusquedaProcesos.Location = New-Object System.Drawing.Point(10, 10)
$txtBusquedaProcesos.Size = New-Object System.Drawing.Size(200, 20)
$tabPageProcesos.Controls.Add($txtBusquedaProcesos)

$btnBuscarProcesos = New-Object System.Windows.Forms.Button
$btnBuscarProcesos.Location = New-Object System.Drawing.Point(220, 10)
$btnBuscarProcesos.Size = New-Object System.Drawing.Size(80, 23)
$btnBuscarProcesos.Text = "Buscar"
$tabPageProcesos.Controls.Add($btnBuscarProcesos)

$btnMatarProcesos = New-Object System.Windows.Forms.Button
$btnMatarProcesos.Location = New-Object System.Drawing.Point(10, 530)
$btnMatarProcesos.Size = New-Object System.Drawing.Size(150, 23)
$btnMatarProcesos.Text = "Terminar proceso"
$tabPageProcesos.Controls.Add($btnMatarProcesos)
$btnMatarProcesos.Add_Click({ 
     terminar-proceso
})

$dataGridProcesos = New-Object System.Windows.Forms.DataGridView
$dataGridProcesos.Location = New-Object System.Drawing.Point(10, 40)
$dataGridProcesos.Size = New-Object System.Drawing.Size(770, 480)
$dataGridProcesos.AutoSizeColumnsMode = [System.Windows.Forms.DataGridViewAutoSizeColumnsMode]::Fill
$dataGridProcesos.ReadOnly = $true
$dataGridProcesos.AllowUserToAddRows = $false
$dataGridProcesos.SelectionMode = "FullRowSelect"
$tabPageProcesos.Controls.Add($dataGridProcesos)

# Pestaña de Servicios
$txtBusquedaServicios = New-Object System.Windows.Forms.TextBox
$txtBusquedaServicios.Location = New-Object System.Drawing.Point(10, 10)
$txtBusquedaServicios.Size = New-Object System.Drawing.Size(200, 20)
$tabPageServicios.Controls.Add($txtBusquedaServicios)

$btnBuscarServicios = New-Object System.Windows.Forms.Button
$btnBuscarServicios.Location = New-Object System.Drawing.Point(220, 10)
$btnBuscarServicios.Size = New-Object System.Drawing.Size(80, 23)
$btnBuscarServicios.Text = "Buscar"
$tabPageServicios.Controls.Add($btnBuscarServicios)

$btnExcluirMicrosoft = New-Object System.Windows.Forms.Button
$btnExcluirMicrosoft.Location = New-Object System.Drawing.Point(310, 10)
$btnExcluirMicrosoft.Size = New-Object System.Drawing.Size(200, 23)
$btnExcluirMicrosoft.Text = "Excluir servicios de Microsoft"
$tabPageServicios.Controls.Add($btnExcluirMicrosoft)

$dataGridServicios = New-Object System.Windows.Forms.DataGridView
$dataGridServicios.Location = New-Object System.Drawing.Point(10, 40)
$dataGridServicios.Size = New-Object System.Drawing.Size(770, 480)
$dataGridServicios.AutoSizeColumnsMode = [System.Windows.Forms.DataGridViewAutoSizeColumnsMode]::Fill
$dataGridServicios.ReadOnly = $true
$dataGridServicios.AllowUserToAddRows = $false
$dataGridServicios.SelectionMode = "FullRowSelect"
$tabPageServicios.Controls.Add($dataGridServicios)

$btnRefrescarServicios = New-Object System.Windows.Forms.Button
$btnRefrescarServicios.Location = New-Object System.Drawing.Point(10, 530)
$btnRefrescarServicios.Size = New-Object System.Drawing.Size(120, 23)
$btnRefrescarServicios.Text = "Refrescar Servicios"
$tabPageServicios.Controls.Add($btnRefrescarServicios)

$btnIniciarServicio = New-Object System.Windows.Forms.Button
$btnIniciarServicio.Location = New-Object System.Drawing.Point(140, 530)
$btnIniciarServicio.Size = New-Object System.Drawing.Size(80, 23)
$btnIniciarServicio.Text = "Iniciar"
$tabPageServicios.Controls.Add($btnIniciarServicio)
$btnIniciarServicio.Add_Click({ 
     Iniciar-Servicios
})


$btnDetenerServicio = New-Object System.Windows.Forms.Button
$btnDetenerServicio.Location = New-Object System.Drawing.Point(230, 530)
$btnDetenerServicio.Size = New-Object System.Drawing.Size(80, 23)
$btnDetenerServicio.Text = "Detener"
$tabPageServicios.Controls.Add($btnDetenerServicio)
$btnDetenerServicio.Add_Click({ 
     Detener-Servicios 
})

$btnReiniciarServicio = New-Object System.Windows.Forms.Button
$btnReiniciarServicio.Location = New-Object System.Drawing.Point(320, 530)
$btnReiniciarServicio.Size = New-Object System.Drawing.Size(80, 23)
$btnReiniciarServicio.Text = "Reiniciar"
$tabPageServicios.Controls.Add($btnReiniciarServicio)
$btnReiniciarServicio.Add_Click({ 
     reiniciar-Servicios 
})
# Función para refrescar la lista de procesos
function Refrescar-Procesos {
    param (
        [string]$filtro = ""
    )
    $command = "GET_PROCESSES|$filtro"
    $procesos = Send-RemoteCommand -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -command $command

    if ($procesos) {
        $dataGridProcesos.DataSource = [System.Collections.ArrayList]@($procesos)
        $dataGridProcesos.Refresh()
    }
}

# Función para refrescar la lista de servicios
function Refrescar-Servicios {
    param (
        [string]$filtro = ""
    )
    $command = "GET_SERVICES|$filtro|$global:excluirMicrosoft"
    $servicios = Send-RemoteCommand -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -command $command

    if ($servicios) {
        $dataGridServicios.DataSource = [System.Collections.ArrayList]@($servicios)
        $dataGridServicios.Refresh()
    }
}

# Función para detener un servicio
function Detener-Servicios {
    $selectedService = $dataGridServicios.SelectedRows[0].Cells["Name"].Value
    if ($selectedService) {
        $command = "STOP_SERVICE|$selectedService"
        $response = Send-RemoteCommand -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -command $command

        if ($response.success) {
            [System.Windows.Forms.MessageBox]::Show("Servicio detenido exitosamente.", "Éxito", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
            Refrescar-Servicios
        } else {
            [System.Windows.Forms.MessageBox]::Show("Error al detener el servicio: $($response.message)", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    } else {
        [System.Windows.Forms.MessageBox]::Show("Por favor, selecciona un servicio para detener.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
}

# Función para iniciar servicio
function Iniciar-Servicios {
    $selectedService = $dataGridServicios.SelectedRows[0].Cells["Name"].Value
    if ($selectedService) {
        $command = "START_SERVICE|$selectedService"
        $response = Send-RemoteCommand -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -command $command

        if ($response.success) {
            [System.Windows.Forms.MessageBox]::Show("Servicio iniciado exitosamente.", "Éxito", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
            Refrescar-Servicios
        } else {
            [System.Windows.Forms.MessageBox]::Show("Error al iniciar el servicio: $($response.message)", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    } else {
        [System.Windows.Forms.MessageBox]::Show("Por favor, selecciona un servicio para iniciar.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
}

# Función para matar proceso
function terminar-proceso {
    $procesoseleccionado = $dataGridProcesos.SelectedRows[0].Cells["id"].Value 
    if ($procesoseleccionado) {
        $command = "TERMINATE_PROCESS|$procesoseleccionado"
        $response = Send-RemoteCommand -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -command $command

        if ($response.success) {
            [System.Windows.Forms.MessageBox]::Show("Proceso detenido exitosamente.", "Éxito", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
            Refrescar-Procesos
        } else {
            [System.Windows.Forms.MessageBox]::Show("Error al detener el proceso: $($response.message)", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    } else {
        [System.Windows.Forms.MessageBox]::Show("Por favor, selecciona un proceso para detener.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
}

# Función para iniciar servicio
function reiniciar-Servicios {
    $selectedService = $dataGridServicios.SelectedRows[0].Cells["Name"].Value
    if ($selectedService) {
        $command = "RESTART_SERVICE|$selectedService"
        $response = Send-RemoteCommand -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -command $command

        if ($response.success) {
            [System.Windows.Forms.MessageBox]::Show("Servicio detenido exitosamente.", "Éxito", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
            Refrescar-Servicios
        } else {
            [System.Windows.Forms.MessageBox]::Show("Error al detener el servicio: $($response.message)", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    } else {
        [System.Windows.Forms.MessageBox]::Show("Por favor, selecciona un servicio para detener.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
}

# Eventos
$btnRefrescarServicios.Add_Click({ 
    $global:excluirMicrosoft = $false
    $btnExcluirMicrosoft.Text = "Excluir servicios de Microsoft"
    Refrescar-Servicios 
})

$btnBuscarProcesos.Add_Click({ Refrescar-Procesos -filtro $txtBusquedaProcesos.Text })
$btnBuscarServicios.Add_Click({ Refrescar-Servicios -filtro $txtBusquedaServicios.Text })

$btnExcluirMicrosoft.Add_Click({
    $global:excluirMicrosoft = -not $global:excluirMicrosoft
    if ($global:excluirMicrosoft) {
        $btnExcluirMicrosoft.Text = "Mostrar todos los servicios"
    } else {
        $btnExcluirMicrosoft.Text = "Excluir servicios de Microsoft"
    }
    Refrescar-Servicios
})

#*************************************************************************************


# Crear un control de lista para mostrar los archivos y carpetas
$listBox = New-Object System.Windows.Forms.ListBox
$listBox.Size = New-Object System.Drawing.Size(750, 240)
$listBox.Location = New-Object System.Drawing.Point(20, 20)
$TabFiles.Controls.Add($listBox)

$txtComando = New-Object System.Windows.Forms.TextBox
$txtComando.Location = New-Object System.Drawing.Point(20, 320)
$txtComando.Size = New-Object System.Drawing.Size(750, 20)
$txtComando.Font = New-Object System.Drawing.Font("Consolas", 10)
$TabFiles.Controls.Add($txtComando)

$txtSalida = New-Object System.Windows.Forms.RichTextBox
$txtSalida.Location = New-Object System.Drawing.Point(20, 350)
$txtSalida.Size = New-Object System.Drawing.Size(750, 270)
$txtSalida.Multiline = $true
$txtSalida.ScrollBars = "Vertical"
#$txtSalida.Font = New-Object System.Drawing.Font("Consolas", 8)
$txtSalida.BackColor = [System.Drawing.Color]::Blue  # Fondo azul
$txtSalida.ForeColor = [System.Drawing.Color]::White  # Texto blanco
$txtSalida.Rtf = "{\rtf1\ansi\deff0{\fonttbl{\f0 Consolas;}}{\f0\fs20\sl240\slmult1}}"
$txtSalida.ReadOnly = $true
$TabFiles.Controls.Add($txtSalida)

# Función para ejecutar comandos PowerShell remotos
function Execute-RemoteCommand {
    param (
        [string]$command
    )
    try {
        $commandToSend = "EXECUTE_COMMAND|$command"
        $response = Send-RemoteCommand -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -command $commandToSend
        
        if ($response.success) {
            $txtSalida.Clear()
            $txtSalida.AppendText(">> $command`r`n")
            $txtSalida.AppendText($response.output + "`r`n`r`n")
        } else {
            $txtSalida.AppendText("Error: $($response.message)`r`n`r`n")
        }
    } catch {
        $txtSalida.AppendText("Error de ejecución: $($_.Exception.Message)`r`n`r`n")
    }
}

# Evento del botón Enviar
#$btnEnviarComando.Add_Click({
#    if ($txtComando.Text.Trim()) {
#        Execute-RemoteCommand -command $txtComando.Text.Trim()
#        $txtComando.Clear()
#    }
#})

# Evento para manejar la tecla Enter en el TextBox de comandos
$txtComando.Add_KeyDown({
    param($sender, $e)
    if ($e.KeyCode -eq [System.Windows.Forms.Keys]::Enter) {
        if ($txtComando.Text.Trim()) {
            Execute-RemoteCommand -command $txtComando.Text.Trim()
            $txtComando.Clear()
        }
        $e.SuppressKeyPress = $true
    }
})

# Crear botones para las diferentes acciones
#$btnEnviarComando = New-Object System.Windows.Forms.Button
#$btnEnviarComando.Location = New-Object System.Drawing.Point(680, 320)
#$btnEnviarComando.Size = New-Object System.Drawing.Size(90, 23)
#$btnEnviarComando.Text = "Enviar"
#$TabFiles.Controls.Add($btnEnviarComando)

$buttonDownload = New-Object System.Windows.Forms.Button
$buttonDownload.Text = "Descargar"
$buttonDownload.Size = New-Object System.Drawing.Size(100, 30)
$buttonDownload.Location = New-Object System.Drawing.Point(10, 270)
$TabFiles.Controls.Add($buttonDownload)

$buttonDelete = New-Object System.Windows.Forms.Button
$buttonDelete.Text = "Eliminar"
$buttonDelete.Size = New-Object System.Drawing.Size(100, 30)
$buttonDelete.Location = New-Object System.Drawing.Point(120, 270)
$TabFiles.Controls.Add($buttonDelete)

$buttonCopy = New-Object System.Windows.Forms.Button
$buttonCopy.Text = "Copiar"
$buttonCopy.Size = New-Object System.Drawing.Size(100, 30)
$buttonCopy.Location = New-Object System.Drawing.Point(230, 270)
$TabFiles.Controls.Add($buttonCopy)

$buttonMove = New-Object System.Windows.Forms.Button
$buttonMove.Text = "Mover"
$buttonMove.Size = New-Object System.Drawing.Size(100, 30)
$buttonMove.Location = New-Object System.Drawing.Point(340, 270)
$TabFiles.Controls.Add($buttonMove)

$buttonUpload = New-Object System.Windows.Forms.Button
$buttonUpload.Text = "Subir"
$buttonUpload.Size = New-Object System.Drawing.Size(100, 30)
$buttonUpload.Location = New-Object System.Drawing.Point(450, 270)
$TabFiles.Controls.Add($buttonUpload)

$buttonSalir = New-Object System.Windows.Forms.Button
$buttonSalir.Text = "Salir"
$buttonSalir.Size = New-Object System.Drawing.Size(100, 30)
$buttonSalir.Location = New-Object System.Drawing.Point(560, 270)
$TabFiles.Controls.Add($buttonSalir)

$buttonSalir.Add_Click({
    $form.Hide()  # Ocultar el formulario principal en lugar de cerrarlo
#    $serverSelectionForm.Show()  # Mostrar el formulario de selección de servidor
})

$buttonRDP = New-Object System.Windows.Forms.Button
$buttonRDP.Text = "Escritorio Remoto"
$buttonRDP.Size = New-Object System.Drawing.Size(100, 30)
$buttonRDP.Location = New-Object System.Drawing.Point(670, 270)
$TabFiles.Controls.Add($buttonRDP)

$buttonRDP.Add_Click({
    
    Start-Process "mstsc.exe" -ArgumentList "/v:$($global:selectedServer.IP) /f"
})

#Controlar el cierre del formulario
$form.Add_FormClosing({
    # Ocultar el formulario en lugar de cerrarlo
    $form.Hide()  # Oculta el formulario
#    $serverSelectionForm.Show()  # Muestra el formulario de selección de servidor
    # Cancelar el cierre del formulario principal
    $_.Cancel = $true  # Esto cancela el cierre del formulario
})


# Funcion para subir archivos
$buttonUpload.Add_Click({
    $openFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $openFileDialog.Title = "Seleccionar archivo para subir"
    if ($openFileDialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
        $localPath = $openFileDialog.FileName
        $remotePath = $listBox.SelectedItem
        if (-not $remotePath) {
            [System.Windows.Forms.MessageBox]::Show("Por favor, selecciona una carpeta de destino en el servidor.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
            return
        }
        $remoteFilePath = Join-Path -Path $remotePath -ChildPath (Split-Path -Leaf $localPath)
        $fileContent = [System.IO.File]::ReadAllBytes($localPath)
        $fileContentBase64 = [System.Convert]::ToBase64String($fileContent)
        $command = "UPLOAD_FILE|$remoteFilePath|$fileContentBase64"
        $response = Send-RemoteCommand -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -command $command
        if ($response.success) {
            [System.Windows.Forms.MessageBox]::Show("Archivo subido exitosamente.", "Éxito", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
            Update-FileList -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -path $remotePath
        } else {
            [System.Windows.Forms.MessageBox]::Show("Error al subir el archivo: $($response.message)", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    }
})

# Función para enviar comandos al servidor remoto
function Send-RemoteCommand {
    param (
        [string]$remoteServer,
        [int]$remotePort,
        [string]$command
    )
    try {
        $client = New-Object System.Net.Sockets.TcpClient($remoteServer, $remotePort)
        $stream = $client.GetStream()
        $writer = New-Object System.IO.StreamWriter($stream)
        $reader = New-Object System.IO.StreamReader($stream)

        Write-Host "Enviando comando: $($command.Substring(0, [Math]::Min(100, $command.Length)))..."
        $writer.WriteLine($command)
        $writer.Flush()

        $response = $reader.ReadToEnd()
        Write-Host "Respuesta recibida: $response"

        $reader.Close()
        $writer.Close()
        $stream.Close()
        $client.Close()

        return $response | ConvertFrom-Json
    } catch {
        Write-Host "Error de conexión: $($_.Exception.Message)" -ForegroundColor Red
        [System.Windows.Forms.MessageBox]::Show("Error de conexión: $($_.Exception.Message)", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        return $null
    }
}

# Función para actualizar la lista de archivos
function Update-FileList {
    param (
        [string]$remoteServer,
        [int]$remotePort,
        [string]$path
    )
    $command = "LIST_FILES|$path"
    $response = Send-RemoteCommand -remoteServer $remoteServer -remotePort $remotePort -command $command
    if ($response -and $response.success -and $response.files) {
        $listBox.Items.Clear()
        
        # Agregar '..' al inicio de la lista si no estamos en la raíz
        if ($path -ne [System.IO.Path]::GetPathRoot($path)) {
            $listBox.Items.Add('..')
        }
        
        foreach ($file in $response.files) {
            $listBox.Items.Add($file)
        }
    } else {
        [System.Windows.Forms.MessageBox]::Show("No se pudieron obtener los archivos.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
}




# Función para descargar un archivo
$buttonDownload.Add_Click({
    $selectedFile = $listBox.SelectedItem
    if ($selectedFile) {
        $saveFileDialog = New-Object System.Windows.Forms.SaveFileDialog
        $saveFileDialog.FileName = [System.IO.Path]::GetFileName($selectedFile)
        
        if ($saveFileDialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
            $localPath = $saveFileDialog.FileName
            $command = "DOWNLOAD_FILE|$selectedFile"
            $response = Send-RemoteCommand -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -command $command
            
            if ($response.success) {
                $fileContentBase64 = $response.fileContent
                $fileContent = [System.Convert]::FromBase64String($fileContentBase64)
                [System.IO.File]::WriteAllBytes($localPath, $fileContent)
                [System.Windows.Forms.MessageBox]::Show("Archivo descargado exitosamente.", "Éxito", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
            } else {
                [System.Windows.Forms.MessageBox]::Show("Error al descargar el archivo: $($response.message)", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
            }
        }
    } else {
        [System.Windows.Forms.MessageBox]::Show("Por favor selecciona un archivo para descargar.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
})

# Función para eliminar un archivo
$buttonDelete.Add_Click({
    $selectedFile = $listBox.SelectedItem
    if ($selectedFile) {
        $command = "DELETE_FILE|$selectedFile"
        $response = Send-RemoteCommand -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -command $command
        if ($response.success) {
            [System.Windows.Forms.MessageBox]::Show($response.message, "Éxito", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
            Update-FileList -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -path (Split-Path -Parent $selectedFile)
        } else {
            [System.Windows.Forms.MessageBox]::Show($response.message, "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    } else {
        [System.Windows.Forms.MessageBox]::Show("Por favor selecciona un archivo para eliminar.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
})

# Función para copiar un archivo
$buttonCopy.Add_Click({
    $selectedFile = $listBox.SelectedItem
    if ($selectedFile) {
        $folderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog
        if ($folderBrowser.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
            $destination = Join-Path -Path $folderBrowser.SelectedPath -ChildPath (Split-Path -Leaf $selectedFile)
            $command = "COPY_FILE|$selectedFile|$destination"
            $response = Send-RemoteCommand -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -command $command
            [System.Windows.Forms.MessageBox]::Show($response.message, "Resultado", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
        }
    } else {
        [System.Windows.Forms.MessageBox]::Show("Por favor selecciona un archivo para copiar.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
})

# Función para mover un archivo
$buttonMove.Add_Click({
    $selectedFile = $listBox.SelectedItem
    if ($selectedFile) {
        $folderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog
        if ($folderBrowser.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
            $destination = Join-Path -Path $folderBrowser.SelectedPath -ChildPath (Split-Path -Leaf $selectedFile)
            $command = "MOVE_FILE|$selectedFile|$destination"
            $response = Send-RemoteCommand -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -command $command
            [System.Windows.Forms.MessageBox]::Show($response.message, "Resultado", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
            Update-FileList -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -path (Split-Path -Parent $selectedFile)
        }
    } else {
        [System.Windows.Forms.MessageBox]::Show("Por favor selecciona un archivo para mover.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
})

# Evento para manejar el doble clic en el ListBox
$listBox.Add_DoubleClick({
    $selectedItem = $listBox.SelectedItem
    if ($selectedItem) {
        if ($selectedItem -eq '..') {
            # Subir un nivel de directorio
            $currentPath = $listBox.Tag # Asumimos que guardamos la ruta actual en la propiedad Tag del ListBox
            $parentPath = [System.IO.Path]::GetDirectoryName($currentPath)
            Update-FileList -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -path $parentPath
            $listBox.Tag = $parentPath
        } elseif (Test-Path $selectedItem -PathType Container) {
            # Si es un directorio, actualizar la lista de archivos
            Update-FileList -remoteServer $global:selectedServer.IP -remotePort $Global:puerto -path $selectedItem
            $listBox.Tag = $selectedItem
        } else {
            # Si es un archivo, mostrar un mensaje
            [System.Windows.Forms.MessageBox]::Show("Seleccionaste el archivo: $selectedItem", "Información", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
        }
    }
})

$serverSelectionForm.ShowDialog()

y el aente:
# Importar los ensamblados necesarios para System.Net
Add-Type -AssemblyName System.Net


$port = 4430
$endpoint = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Any, $port)
$listener = New-Object System.Net.Sockets.TcpListener $endpoint
$listener.Start()

Write-Host "Escuchando en el puerto $port..."

while ($true) {
    $client = $listener.AcceptTcpClient()
    $stream = $client.GetStream()
    $reader = New-Object System.IO.StreamReader($stream)
    $writer = New-Object System.IO.StreamWriter($stream)

    $command = $reader.ReadLine()
    Write-Host "Comando recibido: $($command.Substring(0, [Math]::Min(100, $command.Length)))..."

    $parts = $command -split '\|'
    $action = $parts[0]

    switch ($action) {
            "EXECUTE_COMMAND" {
                $commandToExecute = $parts[1]
                try {
                    $output = Invoke-Expression $commandToExecute | Out-String
                    $response = @{
                        success = $true
                        output = $output
                    } | ConvertTo-Json
                } catch {
                    $response = @{
                        success = $false
                        message = $_.Exception.Message
                    } | ConvertTo-Json
                }
                $writer.WriteLine($response)
                $writer.Flush()
            }
            "UPLOAD_FILE" {
            $remoteFilePath = $parts[1]
            $fileContentBase64 = $parts[2]
            try {
                $fileContent = [System.Convert]::FromBase64String($fileContentBase64)
                [System.IO.File]::WriteAllBytes($remoteFilePath, $fileContent)
                $response = @{
                    success = $true
                    message = "Archivo subido exitosamente."
                } | ConvertTo-Json -Compress
            } catch {
                $response = @{
                    success = $false
                    message = $_.Exception.Message
                } | ConvertTo-Json -Compress
            }
            Write-Host "Enviando respuesta: $response"
            $writer.WriteLine($response)
            $writer.Flush()
        }
        "LIST_FILES" {
            $directoryPath = $parts[1]
            try {
                if (Test-Path $directoryPath) {
                    $files = Get-ChildItem -Path $directoryPath | Select-Object -ExpandProperty FullName
                    $response = @{
                        success = $true
                        files = @($files)
                        currentPath = $directoryPath
                    } | ConvertTo-Json -Compress
                } else {
                    $response = @{
                        success = $false
                        message = 'Directorio no encontrado'
                    } | ConvertTo-Json -Compress
                }
            } catch {
                $response = @{
                    success = $false
                    message = $_.Exception.Message
                } | ConvertTo-Json -Compress
            }
            Write-Host "Enviando respuesta: $response"
            $writer.WriteLine($response)
            $writer.Flush()
        }
        "DELETE_FILE" {
            $filePath = $parts[1]
            try {
                Remove-Item -Path $filePath -Force
                $response = @{success=$true; message='Archivo eliminado.'} | ConvertTo-Json -Compress
            } catch {
                $response = @{success=$false; message=$_.Exception.Message} | ConvertTo-Json -Compress
            }
            Write-Host "Enviando respuesta: $response"
            $writer.WriteLine($response)
        }
        "COPY_FILE" {
            $sourcePath = $parts[1]
            $destinationPath = $parts[2]
            try {
                Copy-Item -Path $sourcePath -Destination $destinationPath
                $response = @{success=$true; message='Archivo copiado.'} | ConvertTo-Json -Compress
            } catch {
                $response = @{success=$false; message=$_.Exception.Message} | ConvertTo-Json -Compress
            }
            Write-Host "Enviando respuesta: $response"
            $writer.WriteLine($response)
        }
        "MOVE_FILE" {
            $sourcePath = $parts[1]
            $destinationPath = $parts[2]
            try {
                Move-Item -Path $sourcePath -Destination $destinationPath
                $response = @{success=$true; message='Archivo movido.'} | ConvertTo-Json -Compress
            } catch {
                $response = @{success=$false; message=$_.Exception.Message} | ConvertTo-Json -Compress
            }
            Write-Host "Enviando respuesta: $response"
            $writer.WriteLine($response)
        }
        "DOWNLOAD_FILE" {
            $remoteFilePath = $parts[1]
            try {
                if (Test-Path $remoteFilePath) {
                    $fileContent = [System.IO.File]::ReadAllBytes($remoteFilePath)
                    $fileContentBase64 = [System.Convert]::ToBase64String($fileContent)
                    $response = @{
                        success = $true
                        fileContent = $fileContentBase64
                        fileName = [System.IO.Path]::GetFileName($remoteFilePath)
                    } | ConvertTo-Json -Compress
                } else {
                    $response = @{
                        success = $false
                        message = "El archivo no existe."
                    } | ConvertTo-Json -Compress
                }
                $writer.WriteLine($response)
                $writer.Flush()
            } catch {
                $response = @{
                    success = $false
                    message = $_.Exception.Message
                } | ConvertTo-Json -Compress
                $writer.WriteLine($response)
                $writer.Flush()
            }
        }"GET_PROCESSES" {
            $filtro = $parts[1]
            $procesos = Get-Process | ForEach-Object {
                [PSCustomObject]@{
                    Id = $_.Id
                    Name = $_.Name
                    CPU = $_.CPU
                    "Memory (MB)" = [math]::Round($_.WorkingSet64 / 1MB, 2)
                }
            } | Sort-Object Name

            if ($filtro) {
                $procesos = $procesos | Where-Object { $_.Name -like "*$filtro*" -or $_.Id -like "*$filtro*" }
            }

            $writer.WriteLine(($procesos | ConvertTo-Json))
        }
        "GET_SERVICES" {
            $filtro = $parts[1]
            $excluirMicrosoft = [System.Convert]::ToBoolean($parts[2])
            $servicios = Get-CimInstance -ClassName Win32_Service | Select-Object Name, DisplayName, State, StartMode, @{Name="CompanyName";Expression={ $_.PathName | ForEach-Object { (Get-ItemProperty $_).VersionInfo.CompanyName }}} | Sort-Object DisplayName

            if ($filtro) {
                $servicios = $servicios | Where-Object { $_.Name -like "*$filtro*" -or $_.DisplayName -like "*$filtro*" }
            }

            if ($excluirMicrosoft) {
                $servicios = $servicios | Where-Object { $_.CompanyName -notlike "*Microsoft*" }
            }

            $writer.WriteLine(($servicios | ConvertTo-Json))
        }
       "TERMINATE_PROCESS" {
            $processId = $parts[1]
            try {
                Stop-Process -Id $processId -Force
                $response = @{
                    success = $true
                    message = "Proceso terminado"
                } | ConvertTo-Json
            } catch {
                $response = @{
                    success = $false
                    message = $_.Exception.Message
                } | ConvertTo-Json
            }
            # Enviar siempre la respuesta en formato JSON
            $writer.WriteLine($response)
            $writer.Flush()
        }
        "START_SERVICE" {
            $serviceName = $parts[1]
            try {
                $service = Get-Service -Name $serviceName -ErrorAction Stop
                if ($service.Status -eq 'Stopped') {
                    Start-Service -Name $serviceName -ErrorAction Stop
                    $response = @{
                        success = $true
                        message = "Servicio '$serviceName' iniciado exitosamente."
                    } | ConvertTo-Json
                } else {
                    $response = @{
                        success = $false
                        message = "El servicio '$serviceName' está en ejecución."
                    } | ConvertTo-Json
                }
            } catch {
                $response = @{
                    success = $false
                    message = "Error al iniciar el servicio '$serviceName': $($_.Exception.Message)"
                } | ConvertTo-Json
            }
            $writer.WriteLine($response)
            $writer.Flush()
        }
        "STOP_SERVICE" {
            $serviceName = $parts[1]
            try {
                $service = Get-Service -Name $serviceName -ErrorAction Stop
                if ($service.Status -eq 'Running') {
                    Stop-Service -Name $serviceName -Force -ErrorAction Stop
                    $response = @{
                        success = $true
                        message = "Servicio '$serviceName' detenido exitosamente."
                    } | ConvertTo-Json
                } else {
                    $response = @{
                        success = $false
                        message = "El servicio '$serviceName' no está en ejecución."
                    } | ConvertTo-Json
                }
            } catch {
                $response = @{
                    success = $false
                    message = "Error al detener el servicio '$serviceName': $($_.Exception.Message)"
                } | ConvertTo-Json
            }
            $writer.WriteLine($response)
            $writer.Flush()
        }
        "RESTART_SERVICE" {
            $serviceName = $parts[1]
            try {
                $service = Get-Service -Name $serviceName -ErrorAction Stop
                
                    Restart-Service -Name $serviceName -Force -ErrorAction Stop
                    $response = @{
                        success = $true
                        message = "Servicio '$serviceName' detenido exitosamente."
                    } | ConvertTo-Json
                 
            } catch {
                $response = @{
                    success = $false
                    message = "Error al detener el servicio '$serviceName': $($_.Exception.Message)"
                } | ConvertTo-Json
            }
            $writer.WriteLine($response)
            $writer.Flush()
        }
        default {
            $response = @{success=$false; message='Comando no reconocido'} | ConvertTo-Json -Compress
            Write-Host "Enviando respuesta: $response"
            $writer.WriteLine($response)
        }
    }

    $writer.Flush()
    $client.Close()
}

$listener.Stop()

Quiero que el agente pueda registrarse en el archivo que lee el administrador remoto (servers.txt) donde colocan esta información: 10/07/2024 15:16:35 - 192.168.64.200 - AD