PowerShell Utilities Series: DMCredential o cómo no escribir credenciales en PowerShell
Como administradores de sistemas que somos, si nos encontramos bajo Windows es evidente que PowerShell es una de nuestras más potentes y versátiles herramientas de trabajo. Gracias a sus capacidades de Remoting, con PowerShell podemos conectarnos a otros sistemas para llevar a cabo tareas de mantenimiento y administración en ellos. En mi día a día no es raro tener que entrar varias veces a Office 365, Exchange Online y controladores de dominio desde PowerShell. Sin embargo, esto requiere que nos autentiquemos.
Cualquier administrador de sistemas que use PowerShell estará más que familiarizado con esta línea de comando:
1 |
$cred = Get-Credential |
De forma que tendremos que escribir nuestro nombre de usuario y contraseña que se almacenará en la variable $cred, de tipo System.Management.Automation.PSCredential.
En este otro artículo Antonio ya nos contó que podemos automatizar el proceso de inicio de sesión en otra máquina a través de PowerShell, escritura de credenciales incluidas; ya que podemos almacenarlas cifradas en nuestro script. Si somos capaces de hacer esto en un script que conecta con Exchange, ¿no podríamos hacerlo también de forma más genérica y utilizarlo para conectarnos a cualquier sistema? David Moravec, escritor de la PowerShell Magazine llegó a conclusiones similares allá por 2012.
David creó un sencillo módulo que nos permite almacenar las credenciales que necesitemos en un archivo, estando estas perfectamente cifradas de igual forma que las de Antonio. El código del módulo puede verse á continuación:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# Copyright David Moravec, PowerShell Magazine # http://www.powershellmagazine.com/2012/10/30/pstip-storing-of-credentials/ function New-DMCredential { [CmdletBinding()] param( [Parameter(Mandatory = $true, Position = 0)] [string]$UserName, [Parameter( Mandatory = $true, Position = 1)] [string]$Alias, [Parameter(Mandatory = $false, Position = 2)] [string]$Path ) # Where the credentials will be stored if([string]::isNullorEmpty($Path)) { $Path = $env:userprofile } # get credentials for given username $cred = Get-Credential $UserName # and save encrypted text to a file $cred.Password | ConvertFrom-SecureString | Set-Content -Path ("$path$Alias") } function Get-DMCredential { [CmdletBinding()] param( [Parameter(Mandatory = $true, Position = 0)] [string]$UserName, [Parameter(Mandatory = $true, Position = 1)] [string]$Alias, [Parameter(Mandatory = $false, Position = 2)] [string]$Path ) # where to load credentials from if([string]::isNullorEmpty($Path)) { $Path = $env:userprofile } # receive cred as a PSCredential object $pwd = Get-Content -Path ("$path$Alias") | ConvertTo-SecureString $cred = New-Object System.Management.Automation.PSCredential $UserName, $pwd # assign a cred to a global variable based on input Invoke-Expression "`$Global:$($Alias) = `$cred" Remove-Variable -Name cred Remove-Variable -Name pwd } function Show-DMCredential { param($cred) Write-Host "Password is about to be shown in clear text. Press a key to continue o CTRL+C to cancel..." $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") # Just to see password in clear text [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($cred.Password)) } |
Básicamente se compone de tres cmdlets:
- New-DMCredential. Crea un nuevo archivo cifrado que contiene las credenciales que especifiquemos. Por defecto estas se almacenarán en $env:userprofile.
- Get-DMCrednetial. Lee un archivo que contenga credenciales almacenadas con New-DMCredential y las carga en una variable global. Para que este cmdlet funcione correctamente la máquina sobre la que se ejecuta New-DMCredential y Get-DMCredential debe ser la misma.
- Show-DMCredential. Muestra la contraseña cifrada contenida en un archivo en texto plano. De igual forma que Get-DMCredential, es necesario que las credenciales hayan sido almacenadas en la misma máquinas desde la que son leídas.
De esta forma, crear un nuevo archivo es tan sencillo como:
1 |
New-DMCredential -UserName admin@contoso.onmicrosoft.com -Alias o365cred |
Este cmdlet nos pedirá que introduzcamos unas credenciales y acto seguido generará un nuevo archivo llamado o365cred que las contiene. Dichas credenciales pueden ser recuperadas así:
1 |
Get-DMCredential -UserName admin@contoso.onmicrosoft.com -Alias o365cred |
Esto creará la variable $global:o365cred y almacenará las credenciales en ella. Fijaos que el nombre del archivo y el de la variable coinciden y que el cmdlet en sí no devuelve nada salvo por el parámetro Alias. Como la variable es global, la tenemos disponible para usar en cualquier ventana o runspace del sistema.
Útil y sencillo de usar ¿verdad? Pero aquí no acaba la cosa. Viendo el bien trabajo que Moravec hizo, se me ocurrió darle una vuelta de tuerca más y hacer que esta variable con credenciales se cargase en memoria cada vez que hacía el simple gesto de abrir una consola de PowerShell, al igual que ya hacía con el módulo de ls a color.
Conseguir esto es una cuestión tan sencilla como agregar el contenido adecuado a nuestro archivo de $profile. A mí me bastó con estas líneas:
1 2 3 4 5 6 7 8 9 10 11 |
# BEGIN Autoload Credential Write-Host -NoNewline "Loading administrator credentials module..." . "C:Users$env:usernameDocumentsWindowsPowerShellDMCredential.ps1" if(Test-Path -Path "C:Users$env:usernamepscred") { Get-DMCredential -UserName "soyeladmin@plainconcepts.com" -Alias pscred Write-Host -ForegroundColor Green "[OK]" } else { Write-Host -ForegroundColor Red "[Credentials not found]" } # END Autoload Credential |
De esta forma cuando abra una ventana de PowerShell:
Mis credenciales se encontrarán automáticamente disponibles en la variable $global:pscred y no tendré que escribirlas. Ni que decir tiene que en este caso nuestro equipo debe bloquearse siempre (Windows + L) siempre que lo dejemos desatendido por razones obvias.
¡Happy Powershelling!
Enlace relacionado: #PSTip Storing of credentials
0 thoughts on “PowerShell Utilities Series: DMCredential o cómo no escribir credenciales en PowerShell”