Ejecutar tareas post instalación en Nano Server

Para cerrar la trilogía de posts sobre Nano server hoy toca escribir acerca de las acciones post instalación una vez ha sido desplegado. Y diréis, ¿no me sirven las tareas que he configurables en el MDT? pues no :/

Así pues, para resolver este “problema” existen algunas posibilidades aplicables a varios sistemas operativos Microsoft:

  • Mediante un fichero unnattend.xml
  • Editando el fichero setupcomplete.cmd

Ante esta encrucijada donde las dos opciones disponibles implican editar archivos de sistema, he decidido decantarme por la edición del fichero setupcomplete.cmd situado en la ruta C:\windows\setup\scripts.

IMPORTANTE: Editar archivos de sistema siempre implica un riesgo, así que si no estáis al 100% seguros de lo que tocáis mejor no hacerlo.

Por defecto este fichero tiene el siguiente contenido:

@ECHO OFF
set SCLOG=%SystemRoot%\setup\scripts\setupcomplete.log
echo "Executing 'netsh advfirewall firewall add rule name='WinRM 5985' protocol=TCP dir=in localport=5985 profile=any action=allow'" >> %SCLOG%
netsh advfirewall firewall add rule name="WinRM 5985" protocol=TCP dir=in localport=5985 profile=any action=allow >> %SCLOG%
echo "Executing 'netsh advfirewall firewall set rule group='@FirewallAPI.dll,-29252' new enable=Yes'" >> %SCLOG%
netsh advfirewall firewall set rule group="@FirewallAPI.dll,-29252" new enable=Yes >> %SCLOG%
echo "Executing 'tzutil.exe /s 'UTC''" >> %SCLOG%</pre><pre>

Para ejecutar tareas post instalación tan solo tenemos que añadir unas lineas en este fichero, por ejemplo:

  • Añadir variable de registro:

    reg.exe ADD “HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment” /v Path /t REG_EXPAND_SZ /d “%Path%C:\opscode\chef\bin;C:\opscode\chef\embedded\bin;” /f

  • Ejecutar script en powershell:

    powershell “C:\temp\Scripts\miscript.ps1” >> %SCLOG%

Una vez editado el fichero debemos situarlo en la misma ruta. (En mi caso he usado el script que os comenté en mi anterior articulo que me permite depositar archivos tanto en la raíz de C: como en la carpeta C:\Windows).

Al iniciar el nano server este proceso tarda de 45 a 60 segundos en empezar a ejecutarse y una vez finalizado podemos consultar el log  en la misma ruta (setupcomplete.log).

"Executing 'netsh advfirewall firewall add rule name='WinRM 5985' protocol=TCP dir=in localport=5985 profile=any action=allow'" 
Ok.
"Executing 'netsh advfirewall firewall set rule group='@FirewallAPI.dll,-29252' new enable=Yes'"
Updated 3 rule(s).
Ok.
"Executing 'tzutil.exe /s 'UTC''" 
"Executing 'netsh advfirewall firewall add rule name='WinRM 5985' protocol=TCP dir=in localport=5985 profile=any action=allow'" 
Ok.
"Executing 'netsh advfirewall firewall set rule group='@FirewallAPI.dll,-29252' new enable=Yes'"
Updated 3 rule(s).
Ok.
"Executing 'tzutil.exe /s 'UTC''"

Desplegando una imagen de Nano Server desde MDT

Recientemente me encontré con el reto de automatizar el despliegue de una solución con Nano Server y después de darle varias vueltas, me decidí por realizar el despliegue usando MDT dado que se trata de una herramienta que no solo me permite distribuir varias imágenes de SO, sino que también puedo realizar muchas tareas pre instalación y post instalación.

Así pues, me puse en marcha y vi que la cosa no seria tan fácil dado que usando las Task Sequences que vienen por defecto, el proceso de despliegue no funcionaba bien. Así pues, después de pelearme con la herramienta durante un rato di con los archivos de customización para MDT que ha realizado Michael Niehaus (Estos los podéis descargar desde el siguiente link )

Dentro de este ZIP encontraremos tres carpetas (Scripts, Templates, Tools) con los siguientes ficheros:

  • Microsoft.BDD.DJoin.exe
  • LTIOfflineJoin.wsf
  • ServerNano.xml
  • ServerNanoVHD.xml
  • Unattend_x64.xml.10.0.ServerDatacenterNano
  • Unattend_x64.xml.10.0.ServerStandardNanoNano

Estos deberán ser depositados en:

  • Tools: en la carpeta Tools del deployment share C:\DeploymentShare\Tools\x64
  • Templates: en la carpeta Templates donde se ha instalado el MDT C:\Program Files\Microsoft Deployment Toolkit\Templates
  • Scripts: en la carpeta Scripts del deployment share C:\DeploymentShare\Scripts

Una vez realizados estos cambios, en el momento que queramos crear una Task Sequence desde el MDT ya podremos seleccionar el template Nano Server Task Sequence.

MDT_Nano1.png

Dado que las Task Sequences con Nano Server son bastante limitadas, las podemos combinar con alguno de los muchos scripts que circulan por Internet tanto para MDT como para SCCM.

En mi caso, por ejemplo, lo he combinado con este de copiar ficheros para, una vez finalizado el despliegue de un Nano Server con roles de virtualización, ejecutar scripts a posteriori que crearán maquinas virtuales sobre el servidor que he desplegado.

Personalizando una imagen de Nano Server con NSIB

Hoy, haré un pequeño break del mundo cloud y escribiré sobre una herramienta que he usado recientemente para personalizar imágenes de Nano Server (Por si alguien ha estado muy out los últimos meses y no sabe que es Nano Server podéis leerlo rápidamente en este link o bien si disponéis de algo mas de tiempo podéis darle un vistazo a este vídeo de Channel 9 donde aparezco hablando junto a @joandelgadoa).

La herramienta en cuestión es Nano Server Image Builder, esta nos permitirá tanto crear una imagen de Nano Server personalizada como crear un USB de arranque para instalar este SO.

Es importante destacar que para el uso de Nano Server Image Builder se debe tener instalado en el equipo el Windows Assessment and Deployment Kit (ADK) con las features Deployment tools y Windows Preinstallation Environment (Windows PE) como mínimo.

nanoserver1

En primer lugar se debe proceder a crear la imagen seleccionando la primera opción: Create a new Nano Server image. Seguidamente montar la imagen de Windows Server 2016 e introducir su ruta en el wizard.

nanoserver2

Se acepta el EULA y se selecciona el tipo de despliegue que queremos realizar. Este puede ser de dos tipos:

  • Maquinas virtuales
  • Servidor físico

En caso de seleccionar Máquinas virtuales, recordad que si esa imagen desea ser subida a Azure deberá ser creada con la extensión .VHD

nanoserver3

En la siguiente pantalla debemos seleccionar todos los roles que queremos que nuestro Nano Server posea y su versión.

nanoserver4

Se procede a asignar un nombre a la máquina, se introduce la contraseña del usuario administrador y se selecciona la zona horaria.

nanoserver5

En caso de querer habilitar el soporte remoto vía WinRM y Powershell para todas las subredes o bien configurar los datos de red (IP, Máscara de red,…) lo deberemos realizar desde aquí.

nanoserver6

En los siguientes pasos podremos introducir los datos correspondientes para añadir la máquina en dominio en el momento de su despliegue y un apartado realmente útil que es el disponer de la posibilidad de añadir scripts, ficheros o binarios que deseemos.

nanoserver7

Una vez finalizada la configuración, validamos que todos los datos introducidos son correctos y pulsamos Create.

En tan solo 2 minutos y medio ya tendremos nuestra imagen de Nano Server personalizada (dependiendo siempre de los roles, ficheros, scripts y binarios que le hayamos añadido).

En el caso que queramos realizar esta tarea de forma repetida o bien automatizarla, el mismo wizard nos muestra el comando a ejecutar desde Powershell (aunque siempre se deberá ejecutar con el módulo de Nano Server cargado en la shell).

New-NanoServerImage -MediaPath 'D:\' -Edition 'Datacenter' -DeploymentType Guest -TargetPath 'C:\Nanoserver\nserver.vhd' -MaxSize 5368709120 -ComputerName 'localadmin' -SetupCompleteCommand ('tzutil.exe /s "Romance Standard Time"') -LogPath 'C:\Users\Jordi\AppData\Local\Temp\NanoServerImageBuilder\Logs\2017-03-14 21-15'

Una vez tenemos el .vhd creado ya se puede proceder a alojarlo sobre un Hyper-V o subirlo a Azure y crear una VM, montarlo en un USB de arranque seleccionando en el menú inicial del wizard la opción  Create Bootable USB Media, o bien como veremos en la entrada siguiente, añadirlo a una Task Sequence de MDT para personalizar todavía más su despliegue desde un entorno de Windows PE.

Añadir usuario de Azure AD como administrador en una VM de Azure

Leyendo el título de esta entrada algunos dirán que porque me complico tanto la vida y no agrego a los usuarios como administradores de las VM mediante GPO si estas van a estar en dominio.

Pues bien, pongámonos en el caso que necesitamos agregar al responsable del despliegue de la VM como administrador (o a cualquier otro usuario) de manera automatizada y esta persona no debe tener permisos como admin local en ninguna otra VM que no sea esta.

La solución con la que di pese a que pueda parecer rebuscada, es la más sencilla de todas. Inyectar una extensión que incluya un custom script.

A continuación os muestro el proceso:

En primer lugar debemos generar y guardar un script que añadirá a un usuario como administrador local y que queremos añadir como extensión, en una Storage Account de Azure (En mi caso he creado un contenedor llamado Scripts dentro de la Storage Account y lo he guardado con el nombre de add_localAdmin.ps1). Si buscamos por Internet encontraremos cientos de ellos, como por ejemplo:

param(
[parameter(Mandatory=$true)]
 [String] $UPN
) 

$User = $UPN.split('@')[0]
$domain = $UPN.split('@')[-1]
$group = [ADSI]"WinNT://$ENV:COMPUTERNAME/Administrators,group"
$group.Add("WinNT://XxxDOMINIOxxX/$User,user") 

En este script se pasa por parámetro el User Principal Name ($UPN) de un usuario y este es añadido al grupo de Administradores locales del equipo (Este parámetro será proporcionado por el runbook que lo añadirá como extensión en la VM).

Seguidamente se debe crear el runbook  siguiente:

param(
 [parameter(Mandatory=$true)]
 [String] $Usermail,
 [parameter(Mandatory=$true)]
 [String] $vmname,
 [parameter(Mandatory=$true)]
 [String] $RGNAME
)
$connectionName = "AzureRunAsConnection"
try
{
 # Get the connection "AzureRunAsConnection "
 $servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
 Add-AzureRmAccount `
 -ServicePrincipal `
 -TenantId $servicePrincipalConnection.TenantId `
 -ApplicationId $servicePrincipalConnection.ApplicationId `
 -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
 if (!$servicePrincipalConnection)
 {
 $ErrorMessage = "Connection $connectionName not found."
 throw $ErrorMessage
 } else{
 Write-Error -Message $_.Exception
 throw $_.Exception
 }
}
$StorageAccountName = "XxxNombreStorageAccountxxX"
$filename = "add_localAdmin.ps1"
$StorageAccountKey = Get-AzureRMStorageaccountKey -StorageAccountName $StorageAccountName -ResourceGroupName "XxxRGDeLaStorageAccountxxX"
Get-AzureRmVM -Name $vmname -ResourceGroupName $RGNAME | Set-AzureRmVMCustomScriptExtension -Name CustomScript -VMName $vmname -ResourceGroupName $RGNAME -StorageAccountName $StorageAccountName -StorageAccountKey $storageAccountKey.Key1 -ContainerName "scripts" -FileName $fileName -Run $fileName -Argument $usermail 

Donde podemos observar que se proporciona por parámetro el nombre de la VM sobre la que queremos añadir el usuario local ($vmname), el Resource group al que pertenece ($RGNAME) y el UPN del usuario en cuestión ($Usermail).

Seguidamente haciendo uso del CMDLET Get-AzureRMVM y combinándolo con  Set-AzureRmVMCustomScriptExtension introducimos como extensión el script que hemos alojado en nuestra Storage Account (add_localAdmin.ps1) y con el parámetro -Argument enviamos el usuario que queremos añadir como administrador.

Una vez ejecutado el runbook, ya tenemos un usuario de nuestro AzureAD agregado como Administrador local de una VM de Azure.

Decir que como mejora a este script le podríamos añadir una validación previa donde se comprueba si el usuario introducido existe o no en el Azure AD, pero esta comprobación debería ser lanzada con un usuario del dominio y no con una RunAsAccount.

$user = get-azurermaduser -Mail $usermail
if ($user -eq $null){
 write-output "-----> El usuario introducido NO existe en el AD"
 exit
} else{
 write-output "-----> El usuario $usermail introducido existe en el AD"
}

 

Programar Azure Runbooks desde Powershell ISE

Seguramente cuando vamos a programar un script en Azure Automation pensais que la interfaz disponible actualmente no es del todo cómoda, dado que en muchos casos programar desde el navegador puede dar algún que otro dolor de cabeza, ya que no es tan completo como el PowerShell Integrated Scripting Environment (ISE para los amigos).

integrationrunbooksise3

Pues bien, la solución es un Addon que ofrece el mismo ISE para poder crear, programar y testear runbooks directamente en nuestra suscripción de Azure. Para añadir esta funcionalidad debemos instalarla desde el mismo terminal con los siguientes comandos:

Install-Module AzureAutomationAuthoringToolkit -Scope CurrentUser
Install-AzureAutomationIseAddOn 

integrationrunbooksise

integrationrunbooksise4

Una vez importado el modulo debemos hacer sign in en nuestra suscripción, seleccionar la Automation Account pertinente y ya tendremos a nuestra disposición los runbooks y los Assets existentes.

En caso de cerrar y abrir de nuevo el ISE debemos importar de nuevo el modulo desde la linia de comando, o bien añadirlo desde la pestaña Addons:

 Import-Module AzureAutomationAuthoringToolkit 

Es importante recordar que cada vez que editemos un runbook o lo testemos debemos subirlo (Upload Draft) y publicarlo (Publish Draft) para que los cambios sean aplicados en la suscripción.

Añadir cmdlets a Azure Automation

Hoy hablaré de Azure Automation, esta herramienta que nos ofrece Azure para ejecutar runbooks desde nuestra propia suscripción.

Como muchos de vosotros sabréis, los cmdlets disponibles que aparecen por defecto en vuestra Automation Account son bastante escasos, ya que por defecto cada cuenta solo tiene agregados 15 módulos al ser creada.

Para añadir nuevas funcionalidades a Azure Automation podemos agregar módulos según nos convenga. Tan solo tenemos que dirigirnos a la sección Assets y seleccionar Modules.

automationmodules

No obstante, es importante tener en cuenta las dependencias entre ellos, dado que si actualizamos uno de los módulos existentes probablemente debamos actualizar algunos más para no perder funcionalidad en esos. O bien, si agregamos uno nuevo, es posible que solo funcione con una versión determinada de otros módulos que actualmente ya poseemos.

Así pues, para agregar un modulo debemos pulsar Browse Gallery y seguidamente seleccionar el que deseamos agregar de todos los módulos disponibles que nos aparecen. Una vez escogido, tan solo debemos pulsar Import y en unos minutos ya tendremos disponible todo el conjunto de cmdlets que aparecen en la sección Content.

automationmodules2.PNG

Como se observa en la imagen, las dependencias entre módulos son importantes, así que previamente a la importación del modulo AzureRM.Keyvault deberíamos actualizar el AzureRM.Profile a una versión igual o superior a la 2.5 o nos encontraremos con el error siguiente:

automationmodules3

Una vez actualizadas las dependencias ya podremos agregar sin problemas el modulo y en unos minutos ya podremos usar los cmdlets importados.

automationmodules4

Como obtener una template de DevTest Lab y customizarla

Debido al post de ayer algunos compañeros me han expresado la dificultad para encontrar una template de un devtest lab o bien, no saben que parámetros pueden ser usados para cumplimentar el JSON. A continuación os mostraré el procedimiento que utilizo para obtener los templates y editarlos a mi gusto.

En primer lugar la base la extraigo de github, donde tenemos unas templates bastante completas (También podríamos obtenerla extrayendo el template de un devtest lab que hayamos creado previamente en nuestra suscripción). En caso de querer añadir algún parámetro más y no encontrar su definición por ningún sitio, como por ejemplo los tamaños de VM disponibles, podemos usar a las Dev Tools (tecla F12) de nuestro navegador mientras estamos en el portal de azure:

devteslab

Como podéis observar en la imagen, al modificar cualquier apartado se genera un Put que manda un JSON. En mi ejemplo, al editar los tamaños que vamos a permitir en nuestro devtest lab y pulsar guardar.

Si analizamos el body de esta petición observamos los posibles valores que pueden ser ser añadidos al JSON. En este caso se deberían añadir en la sección que se muestra a continuación:

 "allowedVmSizes": {
 "type": "string",
 "defaultValue": "\"Standard_DS1_v2\", \"Standard_DS3_v2\", \"Standard_DS11_v2\"",
 "minLength": 3,
 "metadata": {
 "description": "Set 'allowed VM sizes' policy: A comma-separated list of VM sizes that are allowed in the lab."
 }