Docker ps – objetizando las respuestas

El titulo alternativo era “Dale docker, devolveme un objeto en vez de un montón de caracteres con un formato horrible, estamos en 2019!” pero me parecía demasiado largo.

Este ultimo tiempo estuve intentando migrar a un rol un poco mas divertido, mas dinámico, a lo que creo que es el siguiente paso para un administrador. DevOps.
La palabra resuena mucho por todos lados, todas las empresas quieren dinamismo, escalabilidad, resiliencia, o minimamente poder decir que tienen un equipo “cloud”.

Pero hoy no vengo a hablar de DevOps, ni de corporaciones, ni de laburo. Hoy me desperté con ganas de compartir una cosita muy muy chiquita que me llevó unas cuantas horas para armar (y probar, y putear, y aprender), que probablemente pueda ayudar a cualquier otra persona que empiece a meterse en estas tecnologías tan divertidas y novedosas

Cuestión que estaba haciendo un cursito de Docker en udemy, levantando containers a lo pavote, redirigiendo puertos, apuntando storage, un quilombo bárbaro. Súper súper divertido, todo muy dinámico, hasta que quise ordenar el output de docker ps -a y me di cuenta de lo malacostumbrado que me tiene Powershell.

horrorosos strings 🙁

Cuando uso cualquier cmdlet (get-sarasa) recibo un objeto como respuesta. Un hermoso objeto con propiedades, que puedo usar para filtrar, para ordenar, para listar, para re-usar, todo de manera ordenada, bella y hermosa <3.
Lamentablemente con docker no es el caso 🙁
Como toda herramienta con base linuxera, la respuesta viene en strings, cadenas de caracteres sin inteligencia propia, que un administrador experimentado probablemente sepa parsear muy fácil y rápido con algún comandito sencillo y 100% desconocido para mi (porque soy un windows boy y no tengo los huevos para migrar por ahora) ASI QUE se me ocurrió armar una función sencillita y rápida para dejar de sufrir y poder matar containers sin tener que escribir mucho 😀

Asi que les presento ConvertFrom-DockerPS.

function ConvertFrom-DockerPS {
<#
.SYNOPSIS
Parses docker ps output to make it more readable
.DESCRIPTION
Pipe the results of Docker ps to this function and get the results in a nice, more powershelly format
.PARAMETER
.EXAMPLE
docker ps | ConvertFrom-DockerPS | select names, image, "container id", created # Get all running containers
docker ps -a | ConvertFrom-DockerPS | where {$_.status -like "exited*"} | docker # Get all closed containers
docker ps -a | ConvertFrom-DockerPS | where {$_.status -like "exited*"} | foreach { docker rm $_.'CONTAINER ID' } # remove all stopped containers
.NOTES
The core of the code was taken from https://www.reddit.com/r/PowerShell/comments/8p09mb/how_to_loop_through_docker_ps_a_with_powershell/ so
credits go to reddit user /u/Lee_Dailey (https://www.reddit.com/user/Lee_Dailey/), a great contributor on the powershell subreddit [grin]
I've also (forcefully) learned the how's and why's of using advanced functions, and the massive value of the ISE (which i will never use again, heh)
Thank you fellow admin for reading this ramblings, and party on!
#>
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$true)]$adentro
)
begin{
#Declare the $final helper object
$final=@()
}
process{
$InStuff = $adentro.Split("`n").Trim("`r")
$OutStuff = $InStuff -replace '\s{23,}', ',,' -replace '\s{2,}', ','
#Added this to mitigate an issue with formatting on the ugly header
if ($OutStuff -like "*IMAGE,COMMAND,*") { $OutStuff= $OutStuff.replace(',,',',')}
$final+=$OutStuff
}
end{
#Convert it all to CSV and send it back
$final | ConvertFrom-Csv
}
}
Bello bello objeto 😀

Y ahora los dejo, que estoy súper manija con este curso, si tienen la oportunidad chusmeenlo, que esta muy bien explicado y tiene ejercicios concretos, una plataforma online para poder hacer (casi) todo sin instalar nada, y honestamente creo que el futuro de la administración de sistemas viene por este lado.

Hasta la próxima!

Tenemos PowerShell 5.0!

Finalmente, después de mil vueltas, los muchachos del equipo de PowerShell largaron el Windows Management Framework 5.0, que incluye Powershell 5, PowerShell Desired State Configuration (DSC), Windows Remote Management (WinRM) y Windows Management Instrumentation (WMI).

Continua leyendo “Tenemos PowerShell 5.0!” »

Que hay de nuevo en Powershell 5.0

Hola de nuevo!

Ayer les adelanté la salida de Powershell 5.0. Hoy vengo a comentarles algunas de las novedades más interesantes que nos va a traer esta actualización.

Entre ellas:

  • Write-Information, un cmdlet nuevo que permite especificar como Powershell maneja la información estructurada en un comando en particular.
    Format-Table ahora alinea las columnas automáticamente evaluando los primeros 300ms de datos que recibe.
  • ConverFrom-String, un cmdlet nuevo usado para extraer y parsear estructuras de objetos basándose en contenidos de texto (Excelente para usar con comandos legacy, por ejemplo ipconfig).
  • Un nuevo módulo Microsoft.Powershell.Archive, el cual incluye nuevos cmdlets que permiten comprimir , extraer y modificar archivos y carpetas en ZIPs.
  • Un nuevo módulo, PackageManagement, que permite descubrir e instalar paquetes de software de internet (Como un apt-get para Windows :D).
  • Actualizaciones sobre los cmdlets New-Item, Remove-Item y Get-ChildItem para soportar la creación y administración de SymLinks. Por fin!
  • Get-ChildItem ahora soporta un nuevo parámetro, -Depth, con el cual podremos especificar qué tan profundo queremos que vaya la recursividad (con -Recurse).
  • Get-Clipboard y Set-Clipboard se agregaron al módulo Microsoft.Powershell.Utility, para mejorar el soporte de transferencia de contenido de y hacia las sesiones de Powershell. Estos cmdlets soportan imágenes, archivos de audio, listas de archivos y texto.
  • Clear-RecycleBin se agregó al módulo Microsoft.Powershell.Management, y permite vaciar la papelera de reciclaje (posta? no se me había ocurrido) de cualquier disco, sea interno o externo.
  • New-TemporaryFile, permite crear un archivo temporal (por defecto en %userprofile%\AppData\Local\Temp) perfecto para scripting.
  • La consola de Powershell ahora usa coloreo de sintaxis, como en el ISE (Integrated Scripting Environment)
  • Y, obviamente, el valor de $PSVersionTable.PSVersion se actualizo a 5.0

 

En cuanto salga el instalador oficial prometo hacer un update con el paso a paso (y los datos a tener en cuenta) para poder actualizar y empezar a disfrutar de todas estas funcionalidades nuevas.

Para chequear todas las novedades, podes revisar este link de TechNet

 

Gracias por visitar!

 

Se viene se viene…

Confirmado para finales de febrero: Poweshell 5.0!

En unos dias voy a armar la introduccion completa, con prerequisitos, instrucciones paso a paso para instalar, y las cositas nuevas que trae para hacernos la vida mas facil.
Por ahora eso es todo, nos vemos!

Como actualizar a PowerShell 4.0

Hoy vengo a mostrarles como actualizar a PowerShell 4.0

En esta ocasion voy a usar Windows Server 2008r2 como maquina de prueba.
Voy a verificar la version de PowerShell instalada mostrando la variable $PSVersionTable

$PSVersionTable
$PSVersionTable

Bien, ahora necesito saber si mi sistema operativo es de 32 o 64 bits. Para verificar esto, voy a revisar la variable $env:PROCESSOR_ARCHITECTURE

Continua leyendo “Como actualizar a PowerShell 4.0” »

Buscar pertenencia de grupos en un ciertos usuarios

Entre los miles (?) de pedidos que recibo diariamente, me tocó algo que crei interesante compartir.

Me pidieron un reporte que incluyera los grupos a los que pertenecen una lista de usuarios. OBVIAMENTE no lo iba a hacer a mano, asi que…

Powershell!

Los puntos a tener en cuenta son los siguientes:

  1. c:\datos es la ruta de donde, por defecto, se toma el archivo de usuarios y se guarda el reporte.
  2. lista de usuarios.txt debe contener la lista de usuarios.
  3. En caso de que se quieran seleccionar usuarios con algun filtro, se puede usar get-aduser -filter {enabled -eq $true} (Para usuarios habilitados, por ejemplo)
  4. Devuelve un csv con el nombre “Reporte Usuarios”.
## Agregar el modulo de Active Directory.
import-module activedirectory
$Final=@()
## Apunta a la ruta donde esta el archivo
$ruta="c:\datos"
## Apunta al archivo
$archivo="lista de usuarios.txt"
## Obtiene una lista de todos los usuarios que esten habiliados.
$usuariostotal= get-content $ruta\$archivo
foreach ($usuario in $usuariostotal){
## Guarda el nombre del usuario.
$nombre=$usuario.name
## Guarda el username.
$user=$usuario.samaccountname
$Completo=@()
$Grupos="ERROR DESCONOCIDO"
$primero=$true
$agregar=""
## Busca los grupos a los que pertenece el usuario.
$Completo=get-ADPrincipalGroupMembership $user | select-object name
$cantidad=$Completo.count
## Por cada grupo hace una iteracion.
for($a=0;$a -lt ($cantidad);$a++){
if ($primero){
$primero=$false
## Toma el nombre del grupo y lo pasa a una variable.
$agregar=$Completo[$a].name
## Agrega la variable anterior a $grupos para dejarlo todo en una sola variable.
$Grupos="$agregar"
}
else{
$agregar=$Completo[$a].name
$Grupos+=", $agregar"
}
}
$Final+=$usuario | select-object @{Expression={$nombre};Label="Nombre"},@{Expression={$user};Label="Username"}, @{expression={$Grupos};Label="Grupos"},@{expression={$cantidad};Label="Cantidad"}
}
## Exporta el reporte a un CSV
$Final | export-csv $ruta\"ReporteUsuarios.csv"

Esto es todo por hoy!

Como averiguar los administradores locales de los servidores

En este glorioso día (?) me pidieron de superurgencia un reporte que contuviera todos los administradores locales de los servidores que tenemos en uno de nuestros sitios.
Haciendo cuentas en el aire, me di cuenta de que eran mas de 60!

Y ahora… Quien podrá ayudarme? 🙁

OBVIAMENTE POWERSHELL!

Los puntos a tener en cuenta son los siguientes:

  1. $mascara debe ser cambiado a la subred que se desee (por ej, 172.17.*)
  2. Devuelve un csv con el nombre “Reporte admin” y la mascara de subred que se utilice para buscar.
import-module activedirectory
$ruta=get-location
$prueba=@()
$completo=0
## la subred que se quiere buscar
$mascara="172.16.*"
cd "AD:\"
$equipos= Get-ADComputer -Filter {OperatingSystem -like "*server*"} -Properties ipv4address, CanonicalName, operatingsystem | Where-Object {$_.ipv4address -like $mascara}
$total=$equipos.count
foreach ($compu in $equipos){
$nombre=$compu.name
$laip=$compu.ipv4address
$canonico=$compu.canonicalname
$OS=$compu.operatingsystem
$online=$false
$idioma=" "
$admicompleto=@()
$administradores="ERROR DESCONOCIDO"
$sacoadmin=$false
$adminroto=$false
$primero=$true
$agregar=" "
$online = Test-Connection $nombre -Quiet -count 1
if ($online){
## Esta online
$coso=get-wmiobject -ComputerName $nombre win32_operatingsystem
if(!$?){
$idioma="999999"
}else{
$idioma=$coso.oslanguage
}
Switch ($idioma){
"3082" {
#Español Int
$admicompleto= Invoke-Command -ComputerName $nombre -ScriptBlock {net localgroup administradores}
if($?){
$sacoadmin=$true
}else{
$adminroto=$true
}
break
}
"1033" {
#Ingles US
$admicompleto= Invoke-Command -ComputerName $nombre -ScriptBlock {net localgroup administrators}
if($?){
$sacoadmin=$true
}else{
$adminroto=$true
}
break
}
"1046" {
#Portugues bra
$admicompleto= Invoke-Command -ComputerName $nombre -ScriptBlock {net localgroup administradores}
if($?){
$sacoadmin=$true
}else{
$adminroto=$true
}
break
}
"999999" {
# Si dio error en el get idioma
$administradores="ERROR DE WMI"
$sacoadmin=$false
break
}
Default {
# No se encuentra el codigo de idioma
$administradores="NO SE PUDO RESOLVER EL CODIGO $idioma"
$sacoadmin=$false
break
}
}
if($sacoadmin){
## Ejecuto bien el proceso de admin
for($a=6;$a -lt ($admicompleto.count -2);$a++){
if ($primero){
$primero=$false
$agregar=$admicompleto[$a]
$administradores="$agregar"
}
else{
$agregar=$admicompleto[$a]
$administradores+=", $agregar"
}
}
}
if($adminroto){
##no ejecuto el proceso de admin por un error
$administradores="ERROR DE EJECUCION REMOTA"
}
}else{
## No esta online
$idioma="NO DISPONIBLE"
$administradores="NO DISPONIBLE"
}
$PRUEBA+=$compu | select-object @{Expression={$nombre};Label="Nombre"}, @{expression={$online};label="Online"}, @{expression={$laip};label="IP"}, @{expression={$OS};label="OS"}, @{expression={$canonico};label="OU"}, @{Expression={$idioma};Label="Idioma"},@{expression={$sacoadmin};Label="ProcesoAdmins"} ,@{expression={$administradores};Label="Administradores"}
}
cd $ruta
$archivo="./reporte admin "+$mascara.Replace('*','x')+".csv"
$prueba | export-csv $archivo

El resultado no fue 100% exitoso, pero de 60+ servidores, quedaron unos 5-6 en los que tuve que entrar a revisar manualmente. Nada mal, eh?

Prometo mas actualizaciones en las proximas semanas, tengo un par de scripts armados que no tuve tiempo de compartir.

Eso es todo por hoy!

Como migrar un SMTP Relay en Exchange 2013

Como les habré comentado a algunos, estamos en plena migración de sistema de correos (Exchange 2007 a 2013), y como toda migración siempre hay cosas nuevas que probar y aprender 😀

Hoy me toco migrar un Receive Connector que usamos de SMTP Relay (uno en el ambiente viejo) y configurarlo balanceado entre 4 servidores (todos en el ambiente nuevo) Para esto tenía que copiar a mano unos 130 registros. 130 registros. A 4 servidores. NO.

Primero busque una manera rápida de exportar la lista de ips que estaban habilitadas.

SERVIDORBASE es el nombre del server que tiene el Receive Connector del que vamos a copiar la lista de ips.
RC-A-COPIAR es el nombre del Receive Connector del que vamos a copiar esta lista.

$ips=(Get-ReceiveConnector "SERVIDORBASE\RC-A-COPIAR").remoteipranges

Perfecto! Con eso tenemos una array de ips (y rangos de ips, si es que usamos) completamente importables. (Cabe aclarar que lo probé tanto desde un Receive Connector armado en 2007 como en uno armado en 2013. No sé si habrá algún cambio de estructura en cuanto a tipo de dato, pero exportándolo así quedan igualitos)

El paso siguiente fue un poquito más largo. Tenía que crear los RC, configurarlos para hacer Relay y agregarles las ips que ya había exportado.

SERVIDORTARGET es el nombre del server en donde vamos a configurar el RC nuevo.

New-ReceiveConnector -Server SERVIDORTARGET -name "Relay SERVIDORTARGET" -Usage custom -AuthMechanism externalauthoritative -PermissionGroups ExchangeServers -Bindings 0.0.0.0:25 -TransportRole FrontEndTransport -RemoteIPRanges $ips

Pero momento, justo antes de empezar a crear los RC nuevos, se me ocurrió revisar todos los RC que ya existían… Menos mal, porque de 4 servidores, dos ya tenían creados un RC destinado a Relay.
(Asumo que todos son ordenados y que nombran adecuadamente los RC. Si no es así, ordénenlos, no sean giles)

Get-ReceiveConnector | where {$_.name -like "*relay*"}
Oops
Oops

Bien, vamos por partes entonces. Primero usé el código que puse antes (Crear RC nuevos) y armé los dos que no existen. Listo? Bueno, ahora a modificar los que me faltan.
(En mi caso, quería modificar todos los RC cuyo nombre empezara con Relay. Si tuviera que modificar solo un RC lo especificaría en la primer parte del código que pongo más abajo)

Get-ReceiveConnector | where {$_.name -like "relay*"} | Set-ReceiveConnector -RemoteIPRanges $ips

Listo!

Si necesitan verificar que haya quedado bien se pueden ver los datos de cada RC de manera sencilla, como test rápido vamos a revisar que tengamos la misma cantidad de ips habilitadas en todos los RC cuyo nombre comience con Relay.

Get-ReceiveConnector | where {$_.name -like "relay*"} | select name, @{Expression={$_.remoteipranges.count};Label="cantidad"}
Todos

Con esto termina el post de hoy. Hasta la próxima!

Chequear version de windows

Hoy me toco meterle mano al bisabuelo de Powershell: Batch.

Me pidieron que un script viejo no se ejecute en versiones Server de windows, y como no tengo manera de evitar la ejecución, tuve que volver a hacer magia.

Lo que hace este pequeño pedazo de código es chequear la versión de windows, verificar si es una versión “normal” de windows y si es así, vuelve a la etiqueta SIGUE. Simple y sencillo.

:CHEQUEASERVER
REM Se fija que sea windows XP, Vista, 7 u 8.
REM Si no es, no instala
systeminfo | find "Microsoft Windows" > %TEMP%\osname.txt
FOR /F "usebackq delims=: tokens=2" %%i IN (%TEMP%\osname.txt) DO set vers=%%i
echo %vers% | find "Windows 7" > nul
if %ERRORLEVEL% == 0 goto SIGUE
echo %vers% | find "Windows Vista" > nul
if %ERRORLEVEL% == 0 goto SIGUE
echo %vers% | find "Windows XP" > nul
if %ERRORLEVEL% == 0 goto SIGUE
echo %vers% | find "Windows 8" > nul
if %ERRORLEVEL% == 0 goto SIGUE
REM Si llego hasta aca abajo, no es
REM win xp, vista, 7 ni 8. Por descarte
REM es windows server, y no se instala.
:FIN

Limpiapendrives, o como empeze a scriptear.

Hoy comparto mi primer script, de cuando recién arrancaba.
El 11 de julio del 2011, mi hermana vino a casa con un pendrive infectado con un virus que ocultaba todos los archivos y creaba accesos directos que apuntaban a un .vbs que se copiaba a los demás discos.
Básicamente lo que hace es sacarle a todos los archivos del directorio y subcarpetas donde se corre los atributos Hidden, System y Read-Only.

Me había olvidado de este pequeño paso, pero hoy me lleve una sorpresita, ya que me entere que todo el curso de mi hermana (y varias personas mas) lo usan casi a diario!

Pueden bajar el .bat de aca mismo (o para los mas curiosos, acá abajo les va la transcripción)

@echo off
echo Este ejecutable te devuelve todo lo que tenias en el pendrive.
echo Acordate de borrar todos los accesos directos y los .EXE que estan aca.
attrib /d /s -r -h -s *.*
echo.
echo.
echo Listo!
echo.
echo.
echo.
echo Creado por Lucas Camilo
echo.
echo.
pause
exit

Gracias Clari por la inspiración para un nuevo post! 🙂