Qué vas a conseguir
Usar PowerShell remoto como herramienta diaria de operaciones: saber qué tiene que estar en su sitio para que funcione, lanzar un comando contra cien servidores y quedarte con los resultados y con la lista de los que fallaron, trabajar en una sesión interactiva, resolver el "acceso denegado" al recurso compartido desde dentro de la sesión, dar a soporte solo los comandos que necesita y diagnosticar los servidores que responden WinRM cannot complete the operation o Access is denied.
Antes de empezar
- Windows PowerShell 5.1 o PowerShell 7 en tu equipo de administración, en el dominio
contoso.local. - Una cuenta de administración (
CONTOSO\adm-lmartin, no tu cuenta de correo) que sea administrador local en los servidores, normalmente por un grupo comoGG-Admins-Servidores. - El módulo ActiveDirectory de RSAT para consultar equipos y SPN.
- La guía del script de inventario remoto explica el bucle con
try/catch; aquí se pasa a la ejecución en paralelo.
1. WinRM en dos minutos
PowerShell remoto viaja por WinRM, la implementación de Microsoft de WS-Management:
- 5985/TCP para HTTP y 5986/TCP para HTTPS. En el dominio, HTTP no viaja en claro: Kerberos cifra el contenido después de autenticar.
- En Windows Server viene activo de serie. En Windows 11,
Enable-PSRemoting -Forcearranca el servicio, crea el agente de escucha y abre el firewall. Si la red del equipo es Pública, falla salvo con-SkipNetworkProfileCheck, que solo abre a la subred local. - Para muchos equipos, una GPO: Configuración del equipo › Plantillas administrativas › Componentes de Windows › Administración remota de Windows (WinRM) › Servicio WinRM › Permitir la administración remota del servidor a través de WinRM, el servicio WinRM en automático y la regla de firewall Administración remota de Windows (HTTP de entrada) limitada a la red de administración.
Test-NetConnection srv-app07 -Port 5985 | Select-Object ComputerName, TcpTestSucceededComputerName TcpTestSucceeded------------ ----------------srv-app07 TrueTest-WSMan srv-app07wsmid : http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsdProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsdProductVendor : Microsoft CorporationProductVersion : OS: 0.0.0 SP: 0.0 Stack: 3.0Test-WSMan contesta sin autenticar: confirma red, firewall y servicio, no permisos.
Fuera del dominio (un servidor en grupo de trabajo, una DMZ, o cuando escribes una IP), Kerberos no sirve y entra NTLM. Entonces hace falta HTTPS o añadir el destino a TrustedHosts en tu equipo, y pasar -Credential siempre:
Set-Item WSMan:\localhost\Client\TrustedHosts -Value 'srv-dmz01' -Concatenate -ForceGet-Item WSMan:\localhost\Client\TrustedHosts | Select-Object ValueTrustedHosts no hace "de confianza" a nadie: solo calla el aviso de que no se puede comprobar la identidad del servidor. Nunca *, y nunca para equipos del dominio, que deben ir por nombre y Kerberos. Para la DMZ, mejor un agente de escucha HTTPS en 5986 con un certificado de la CA interna.
2. Invoke-Command contra muchos equipos
Si -ComputerName recibe la lista entera, PowerShell abre las conexiones en paralelo, 32 a la vez por defecto (-ThrottleLimit). Cada resultado llega con la propiedad PSComputerName, y los equipos que fallan van a la variable de errores en lugar de parar el comando:
$servidores = (Get-ADComputer -Filter 'OperatingSystem -like "*Server*"' -SearchBase 'OU=Servidores,DC=contoso,DC=local').DNSHostName$servicio = 'Spooler'$r = Invoke-Command -ComputerName $servidores -ThrottleLimit 64 -ErrorAction SilentlyContinue -ErrorVariable fallos -ScriptBlock { $s = Get-Service -Name $using:servicio [pscustomobject]@{ Estado = $s.Status; Inicio = $s.StartType; Arranque = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime }}$r | Select-Object PSComputerName, Estado, Inicio, Arranque | Export-Csv C:\Temp\spooler.csv -NoTypeInformation -Delimiter ';' -Encoding UTF8$fallos | ForEach-Object { [pscustomobject]@{ Equipo = $_.TargetObject; Error = $_.FullyQualifiedErrorId } } | Format-Table -AutoSizeEquipo Error------ -----srv-app07.contoso.local WinRMOperationTimeout,PSSessionStateBrokensrv-app09.contoso.local CannotConnect,PSSessionStateBrokensrv-app11.contoso.local AccessDenied,PSSessionStateBroken$using:serviciolleva una variable local al bloque remoto. Sin$using:llega vacía.-ErrorVariable fallos(sin$) guarda los errores de conexión con el equipo enTargetObject. Ese CSV de fallos es tan importante como el de resultados: dice qué equipos no sabes cómo están.- Para trabajos largos,
-AsJobdevuelve el control yReceive-Jobrecoge después. - Si vas a lanzar varios comandos seguidos, abre las sesiones una vez:
$ses = New-PSSession -ComputerName $servidores, despuésInvoke-Command -Session $ses ...y al finalRemove-PSSession $ses.
3. Enter-PSSession: una consola en el servidor
Enter-PSSession -ComputerName srv-app07[srv-app07]: PS C:\Users\adm-lmartin\Documents> Get-Service W3SVC | Restart-Service -PassThruStatus Name DisplayName------ ---- -----------Running W3SVC World Wide Web Publishing Service[srv-app07]: PS C:\Users\adm-lmartin\Documents> exit- Todo corre en el servidor, sin escritorio: nada que abra una ventana ni que pregunte de forma interactiva (instaladores con asistente,
notepad). - Para llevar un archivo, sin carpetas compartidas:
Copy-Item C:\Temp\parche.msu -Destination C:\Temp -ToSession (New-PSSession srv-app07).
4. El segundo salto
Dentro de la sesión en srv-app07, Get-ChildItem \\srv-ficheros\Software$ da Access is denied. No es un permiso que falte: con Kerberos, srv-app07 sabe quién eres pero no tiene tus credenciales para presentarlas a un tercer equipo. Es el segundo salto. Las salidas, de mejor a peor:
- Evitarlo: copiar el archivo al servidor antes con
Copy-Item -ToSession, o lanzar el trabajo desde el equipo que tiene los datos. - Pasar la credencial explícitamente para ese acceso:
Invoke-Command srv-app07 { New-PSDrive -Name S -PSProvider FileSystem -Root \\srv-ficheros\Software$ -Credential $using:cred }, con$cred = Get-Credentialen tu equipo. - Delegación restringida basada en recursos (Kerberos, sin guardar contraseñas), configurada en el destino:
Set-ADComputer srv-ficheros -PrincipalsAllowedToDelegateToAccount (Get-ADComputer srv-app07). Sirve para SMB, no para encadenar otra sesión de WinRM. Si ya se intentó antes,klist purge -li 0x3e7ensrv-app07o esperar 15 minutos. - CredSSP: envía tu credencial al servidor y la deja allí; si ese servidor está comprometido, tu cuenta también. Solo de forma puntual, hacia un servidor concreto (
Enable-WSManCredSSP -Role Client -DelegateComputer srv-app07.contoso.localy-Role Serveren el destino) y deshaciéndolo al terminar conDisable-WSManCredSSP.
La delegación sin restricciones (Confiar en este equipo para la delegación a cualquier servicio) también "funciona" y es la peor opción: cualquier servicio de ese equipo puede usar tu identidad en cualquier sitio.
5. JEA: solo los comandos que hacen falta
Just Enough Administration crea un punto de conexión propio donde un grupo solo ve unos comandos concretos, y ejecuta con una cuenta virtual que es administradora local mientras dura la sesión. Ejemplo: que Soporte N1 pueda reiniciar la cola de impresión e IIS sin ser administrador del servidor.
$mod = 'C:\Program Files\WindowsPowerShell\Modules\JEASoporte'New-Item -ItemType Directory -Path "$mod\RoleCapabilities" -Force | Out-NullNew-ModuleManifest -Path "$mod\JEASoporte.psd1"New-PSRoleCapabilityFile -Path "$mod\RoleCapabilities\ReinicioServicios.psrc" -VisibleCmdlets 'Get-Service', @{ Name = 'Restart-Service'; Parameters = @{ Name = 'Name'; ValidateSet = 'Spooler', 'W3SVC' } }New-PSSessionConfigurationFile -Path C:\Temp\Soporte.pssc -SessionType RestrictedRemoteServer -RunAsVirtualAccount -TranscriptDirectory 'C:\JEA\Transcripciones' -RoleDefinitions @{ 'CONTOSO\GG-Soporte-N1' = @{ RoleCapabilities = 'ReinicioServicios' } }Test-PSSessionConfigurationFile C:\Temp\Soporte.psscTrueRegister-PSSessionConfiguration -Name Soporte -Path C:\Temp\Soporte.psscDesde soporte: Enter-PSSession srv-app07 -ConfigurationName Soporte. Get-PSSessionCapability -ConfigurationName Soporte -Username CONTOSO\jperez muestra qué comandos verá cada persona antes de que pruebe. JEA también resuelve el acceso de quien no es administrador, que en el punto de conexión por defecto recibe acceso denegado.
6. Registro: quién hizo qué
- Transcripciones:
Start-Transcript -Path \\srv-gestion\Transcripciones$\$env:USERNAME-$(Get-Date -Format yyyyMMdd-HHmm).txtal empezar un cambio, o la directiva Activar la transcripción de PowerShell con una carpeta central donde los usuarios pueden escribir pero no leer. JEA las guarda enTranscriptDirectory. - Registro de bloques de script: evento 4104 en Microsoft-Windows-PowerShell/Operational del servidor, con el código que se ejecutó en remoto. Se activa por GPO, como en la guía de GPO de seguridad.
- Conexiones: Microsoft-Windows-WinRM/Operational en el destino, y en Seguridad el evento 4624 de tipo de inicio de sesión 3 con tu cuenta de administración.
7. El ticket: "WinRM cannot complete the operation / Access is denied en algunos servidores"
Jueves, 10:20. El script de comprobación del punto 2 funciona en 58 de 63 servidores. Los cinco restantes:
- srv-app07, WinRMOperationTimeout: el mensaje completo dice WinRM cannot complete the operation... a firewall exception for the WinRM service is enabled.... El puerto no responde. Por consola remota o la consola del hipervisor,
Get-NetConnectionProfiledaNetworkCategory : Public: al arrancar no encontró un controlador de dominio y la regla de firewall del perfil Dominio no aplica.Restart-Service NlaSvc -Forcelo devuelve aDomainAuthenticated; para que no se repita, se revisa por qué arranca sin ver el dominio (DNS de la tarjeta, orden de arranque frente a los controladores). - srv-app09, CannotConnect:
sc.exe \\srv-app09 query winrmdaSTATE : 1 STOPPED. Alguien lo paró y quedó en manual.sc.exe \\srv-app09 config winrm start= delayed-autoysc.exe \\srv-app09 start winrm; la GPO del punto 1 evita que vuelva a pasar. - srv-app11, AccessDenied: red y servicio bien, la cuenta no es administradora local. El servidor se movió a una OU donde no llega la GPO que añade
GG-Admins-Servidoresa Administradores. Se corrige la OU o el vínculo; no se añade tu cuenta a mano. - 10.0.30.25, por IP: The WinRM client cannot process the request... the destination machine must be added to the TrustedHosts configuration setting. Con IP no hay Kerberos. Se cambia la lista para usar el nombre DNS (
Resolve-DnsName 10.0.30.25dasrv-app14.contoso.local), no se toca TrustedHosts. - srv-app12, error 0x80090322 con Kerberos:
setspn -Q HTTP/srv-app12*muestra el SPNHTTP/srv-app12.contoso.localregistrado en la cuentasvc-intranet(una aplicación de IIS con autenticación Kerberos), así que el vale se cifra para la cuenta equivocada. Con el responsable de la aplicación, el SPN pasa a un nombre propio de la web (HTTP/intranet.contoso.local) y WinRM vuelve a usar el del equipo.
Un sexto caso que aparece en servidores fuera del dominio: con una cuenta local que es administradora, el acceso se deniega igualmente porque UAC filtra el token de las cuentas locales en conexiones de red. No se resuelve poniendo LocalAccountTokenFilterPolicy a 1 en todos los equipos (la base de seguridad de Microsoft lo mantiene filtrado a propósito para frenar el movimiento lateral): cuenta de dominio, o JEA, o como mucho una excepción documentada en ese servidor.
En el ticket: cada servidor con su error, la causa, el cambio y la repetición del comando con 63 de 63.
Siguientes pasos
- El informe semanal de Active Directory es la otra guía de este tema: se programa con una gMSA y se puede combinar con la consulta remota de este artículo.
- Para que WinRM, el firewall y el grupo de administradores lleguen igual a todos los servidores, la guía de GPO de seguridad explica el despliegue con piloto.
- Las cuentas de servicio sin contraseña que caduca están en la guía de gMSA y tareas programadas.
¿Falta algo o en tu entorno es distinto? Escríbeme y lo corrijo.
Tech Career Lab · newsletter
¿Te ha servido? Cada dos semanas envío una idea práctica para perfiles IT: LinkedIn, proyectos, networking y procesos de selección.
Apúntate y llévate las 33 ideas →