Las políticas de contraseñas son las mejores 😀 Aunque a veces conducen a cierres de cuentas cuando alguien se olvida de cerrar la sesión en algún lugar de la red. Podría ser la sesión de TS que utilizan una vez al trimestre para la presentación de informes o tal vez usted sabe la sensación cuando RDP a un servidor sólo para encontrar que está bloqueado por otros 2 administradores que se olvidó de cerrar la sesión cuando se fueron. (No porque esto nunca sucede… todos usamos PowerShell…) De todos modos, esto me hizo buscar una sesión de usuario en algún lugar de la red. Lo peor es cuando mi propia contraseña caduca. Odio cuando mi cuenta termina bloqueada. Por lo tanto, hice una regla para comprobar todos los servidores antes de cambiar la contraseña. Hay múltiples maneras de hacer esto, pero, por supuesto, tiendo a ir la ruta de PowerShell.
Investigación
El método original que utilicé es de la galería de TechNet
En resumen: Get-WmiObject -Class Win32_process
Esto básicamente encuentra todos los usuarios únicos que ejecutan procesos en la máquina. Esto es genial porque encuentra todo, incluso las cosas que se ejecutan como un servicio, pero no estoy convencido de que es la manera más eficiente.
Comprobando con google encuentro un montón de maneras creativas para comprobar quién está conectado a su caja.
peetersonline.nl/2008/11/oneliner-get-logged-on-users-with-powershell/ me dio la idea de comprobar Win32_LoggedOnUser que parece obvio.
Esto se ve muy bien y parece que también funciona con Get-CimInstance aunque la salida es un poco diferente.
aprender-powershell.net/…/Quick-hit-find-currently-logged-on-users/ tomó un enfoque un poco más de la vieja escuela que me gusta porque es un poco áspero y me obliga a jugar con mi parsing basado en plantillas.
No estoy muy seguro de qué método es más rápido, así que por qué no intentar implementar los 3 en un módulo y probarlo.
Bocetos
Siempre es una buena idea comenzar haciendo un boceto de lo que estás tratando de lograr.
Pseudo code:Get-ActiveUser -ComputerName -Method Wanted output:Username ComputerName-------- ------------TestUser1 Svr3TestUser3 Svr3DonaldDuck Client2
Ahora tengo toda la información que necesito para configurar el repositorio de GitHub.
github.com/mrhvid/Get-ActiveUser
Code
En primer lugar los parámetros que me interesan son ComputerName y Method.
Param ( # Computer name, IP, Hostname ] $ComputerName, # Choose method, WMI, CIM or Query $Method )
Ya tengo 3 posibles Methods en mente así que pongo ValidateSet con las 3 posibilidades. Entonces no tengo que preocuparse de esa entrada más tarde.
Process { switch ($Method) { 'WMI' { } 'CIM' { } 'Query' { } } }
En la parte de Proceso de mi función simplemente uso un interruptor para los 3 métodos diferentes que permití en el Parámetro.
Ahora es básico rellenar los espacios en blanco.
WMI
Mi antigua solución es sencilla y funciona bien.
$WMI = Get-WmiObject -Class Win32_Process -ComputerName $ComputerName -ErrorAction Stop$ProcessUsers = $WMI.getowner().user | Select-Object -Unique
Pero ahora que he encontrado Win32_LoggedOnUser me parece mal hacerlo así. Veamos la nueva idea en su lugar.
Estos son todos los datos correctos pero parece que están en un formato de cadena así que tendré que hacer una pequeña manipulación. Esto se puede hacer de un millón de maneras.
function Get-MyLoggedOnUsers { param($Computer) Get-WmiObject Win32_LoggedOnUser -ComputerName $Computer | Select Antecedent -Unique | %{"{0}{1}" -f $_.Antecedent.ToString().Split('"'), $_.Antecedent.ToString().Split('"')} }
El mencionado one-liner de Peter no me pareció muy fácil de leer, lo cual está bien para un one-liner, pero me gustaría que fuera un poco más legible si es posible.
$WMI = (Get-WmiObject Win32_LoggedOnUser).Antecedent$ActiveUsers = @()foreach($User in $WMI) { $StartOfUsername = $User.LastIndexOf('=') + 2 $EndOfUsername = $User.Length - $User.LastIndexOf('=') -3 $ActiveUsers += $User.Substring($StartOfUsername,$EndOfUsername)}
Esto parece correcto 🙂 Guardaré la salida en la variable $ActiveUsers y haré lo mismo para CIM y Query.
CIM
Probemos con CIM.
Esto parece mucho más estructurado.
CIM acaba siendo un one-liner fácil de entender 😀
$ActiveUsers = (Get-CimInstance Win32_LoggedOnUser -ComputerName $ComputerName).antecedent.name | Select-Object -Unique
Query
Usando el buen Query.exe me ha resultado muy útil el análisis sintáctico basado en plantillas del que hablábamos antes.
$Template = @' USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME>{USER*:jonas} console 1 Active 1+00:27 24-08-2015 22:22 {USER*:test} 2 Disc 1+00:27 25-08-2015 08:26'@$Query = query.exe user$ActiveUsers = $Query | ConvertFrom-String -TemplateContent $Template | Select-Object -ExpandProperty User
Salida
Ahora sólo necesito formatear y dar salida a los usuarios de una forma bonita. Quiero objetos limpios con ComputerName y UserName.
# Create nice output format$UsersComputersToOutput = @()foreach($User in $ActiveUsers) { $UsersComputersToOutput += New-Object psobject -Property @{ ComputerName=$ComputerName; UserName=$User } }}# output data$UsersComputersToOutput
Testing
Ahora tengo un problema. No puedo probar esto ya que no tengo un montón de servidores de prueba a mi disposición. Todas mis pruebas se han hecho contra mi propia caja de Windows 10. Es parece que la consulta es mucho más rápido que se ejecuta localmente, pero WMI / CIM podría dar una visión más completa de lo que los servicios se están ejecutando.
Tengo un montón de cuentas de servicio estándar que se ejecuta que podría ser bueno para eliminar de la salida. Además, para que esto sea útil tendremos que ejecutarlo en muchas máquinas.
La combinación de Get-ActiveUser con Start-Multithread del post de la semana pasada parece funcionar como se pretendía.
Start-Multithread -Script { param($C) Get-ActiveUser -ComputerName $C -Method Query } -ComputerName ::1,Localhost | Out-GridView
La canalización de lo anterior a Out-GridView es probablemente mi forma favorita de lograr algo realmente útil.
Ahora tenemos todos los datos en una forma agradable de búsqueda y es realmente fácil de comprobar si su usuario está conectado en alguna máquina al azar. También es una manera fácil de comprobar los usuarios rouge en su red.
Publicación y retroalimentación
El código se publica en PowerShellGallery.
Por favor, ayúdame a probarlo para mí. Me encantaría saber si esto funciona en el mundo real 🙂
# To install Get-ActiveUserInstall-Module Get-ActiveUser#To install Start-MultithreadInstall-Module Start-Multithread
Esto debería funcionar cuando se tiene WMF 5 + instalado y en Windows 10 fuera de la caja.