¡Hola de nuevo!
Llevaba mucho tiempo sin pasar por aquí (3 años desde el último post) entre otras cosas, porque documentar y yo, no somos muy amigos aunque lo intento… esta vez, tras una semana de vuelta a tener infra local en la empresa y, con unas granjas de servidores que administrar, he decidido darle una vuelta de tuerca al script que compartí hace unos años con el cual podíamos obtener varios datos de los ESXi, sobretodo, datos de espacio en disco.
Gracias al script que dejo a continuación, podemos conectarnos a los distintos servidores (o vCenters, como en mi caso) y, en cuestión de segundos, tener un bonito excel con varios datos, con la fecha de ejecución del script.
Las hojas que crearemos en excel, con el script, son las siguientes:
- Hosts – Obtenemos datos de los servidores físicos sobre los que corre vSphere, dando información de los recursos totales y los usados.
- Datastores – Nos muestra información de los distintos VMFS que tiene el sistema (espacio usado, libre, total, tanto en GB como en porcentaje).
- Networking – en esta hoja, veremos características de red (IPs, tarjetas y redes) que tienen todas las VM.
- vmDetail – Gracias a esta parte, sabemos con qué recursos cuenta cada VM.
- VMDKs – nos da la información de los discos virtuales de cada máquina, como los ve VMware.
- vDISK – similar a la anterior, pero mostrándonos los datos de los discos a nivel de sistema operativo invitado (particiones, espacio ocupado, disponible, etc) alertándonos, por correo, de cuántos discos virtuales tienen menos de un 10% de espacio disponible.
Por aquí las imágenes, que suelen valer más que mil palabras 😎
¡Os dejo el script!
<#si tenemos un vSphere 5.5 sin certificado, descomentar la siguiente línea para permitirle a powershell hablar con TLS 1.1#> #[System.Net.ServicePointManager]::SecurityProtocol =[System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12' #Importamos módulos de PowerCli Import-Module VMware.VimAutomation.Core Import-Module VMware.VimAutomation.Vds #Definimos entorno de trabajo y variables comunes a las hojas de excel $fecha = Get-Date -format "dd-MM-yyyy" $hora = Get-Date -UFormat %R $file = "D:\IT\Informes\informe.xlsx" <#realizamos la conexion con el nodo o con VCenter como es mi caso Para evitar introducir contraseñas en scripts de powershell, que no dejan de ser textos planos editables, recomiendo el uso de ficheros xml encriptados Cargamos las contraseñas de los nodos en variables#> $encryptedPassword1 = Import-Clixml -Path 'D:\IT\VCSA.xml' $encryptedPassword2 = Import-Clixml -Path 'D:\IT\VCSA97.xml' #nos conectamos a los nodos con la contraseña que pertoque Connect-VIServer 'tu servidor' -credential $encryptedPassword1 Connect-VIServer 'tu otro servidor' -credential $encryptedPassword2 <#Estado de los nodos Con esta parte, creamos una hoja nueva en el libro de excel, donde obtendremos la información del hardware #> $hosts=@() $ws = "hostsInfo" <# la variable $ws es la que usaremos para decirle al comando Export-Excel el nombre de la hoja que usará para volcar los datos del array "report" #> foreach ($nodo in (Get-VMHost)){ $row = "" | Select Fecha,Hora,Hostname, Conexion, Power, Sockets, CoresxSoc, NumCPUs, UsoCPU, TotalCPUMhz,UsoRAMGB, RamTotalGB, VersionESXi $row.Fecha = $fecha $row.Hora = $hora $row.Hostname = $nodo.name $row.Conexion = $nodo.ConnectionState $row.Power = $nodo.PowerState $row.Sockets = $nodo.ExtensionData.Summary.Hardware.NumCpuPkgs $row.CoresxSoc = ($nodo.ExtensionData.Summary.Hardware.NumCpuCores/$nodo.ExtensionData.Summary.Hardware.NumCpuPkgs) $row.NumCPUs= $nodo.ExtensionData.Summary.Hardware.NumCpuCores $row.UsoCPU = $nodo.CpuUsageMhz $row.TotalCpuMhz = $nodo.CpuTotalMhz $row.UsoRAMGB = [math]::Round($nodo.MemoryUsageGB,2) $row.RamTotalGB = [math]::Round($nodo.MemoryTotalGB,2) $row.VersionESXi = $nodo.Version $hosts +=$row } $hosts | Export-Excel -WorksheetName $ws -Path $file -NoNumberConversion Hostname, VersionESXi -Append #Datastores Info $ws ="Datastores" $datastores=@() foreach ($ds in (Get-Datastore)){ $row = "" | Select Fecha,Hora,host, Datastore, EspacioUsadoGB, EspacioLibreGB, EspacioTotalGB, UsedPerc, FreePerc, NumVMs $row.Fecha = $fecha $row.Hora = $hora $row.Host = ($ds.DatastoreBrowserPath.Split("@")[0].TrimStart("vmstores:\")) $row.Datastore = $ds.Name $row.EspacioUsadoGB = [math]::Round(($ds.capacityGB)-($ds.FreeSpaceGB),2) $row.EspacioLibreGB = [math]::Round($ds.FreeSpaceGB,2) $row.EspacioTotalGB = $ds.CapacityGB $row.UsedPerc = [math]::Round(((($ds.capacityGB)-($ds.FreeSpaceGB))*100)/($ds.capacityGB),2) $row.FreePerc =[math]::Round(100-((($ds.capacityGB)-($ds.FreeSpaceGB))*100)/($ds.capacityGB),2) $row.NumVMs = ($ds | Get-VM ).Count $datastores += $row } $datastores | Export-Excel -WorksheetName $ws -Path $file -NoNumberConversion Host -Append # Networking $ws = "Networking" $Network = @() foreach ($vm in (Get-VM |Where { $_.PowerState -eq "PoweredOn" }| Get-VMGuest)){ $l=0 $m=0 if (($vm.VMName).ToString() -eq "SWMS"){ $m=3} foreach ($IP in $vm.IPAddress){ $IPxNic = $vm.IPAddress.count / $vm.Nics.Count while ($m -lt $vm.nics.count){ $row = "" | Select Fecha,Hora, VM, NumRed, vNICType, vNetwork, IP, VMTools $row.Fecha = $fecha $row.Hora = $hora $row.VM = $vm.VMName $row.NumRed = $vm.Nics[$m].Device.Name.ToString() $row.vNICType = $vm.Nics[$m].Device.Type.ToString() $row.vNetwork = $vm.Nics[$m].Device.NetworkName.ToString() $IPs = $vm.Nics[$m].IPAddress[$l] $row.IP = $IPs $row.VMTools = $vm.ToolsVersion $network +=$row <#como tengo VMs con Kubernetes las cuales venían con más de 1 NIC en el template pero sólo uso una red en producción, le decimos a powershell que, si llega a esa VM, salte en el array de NICs hasta el último. #> if ($vm.VMName.toString() -like "VMx*"){$m=2} switch ($IPxNic) { 1 {$m++} 2 {$l=0 $m++} default {$m++ $l=0}} <#aquí tengo otra VM similar a la de kubernetes, (plantilla de firewall del proveedor, con 17 IPs y 12 tarjetas, de las cuales, 10 son fantasmas... #> if (($m -eq 5) -and ($vm.VMName.toString() -eq 'FWquesea')){$m=12} } } } $network | Export-Excel -WorksheetName $ws -Path $file -NoNumberConversion IP,VMTools -Append # Detalle VMs $ws = "vmDetail" $result = @() foreach ($vm in Get-VM) { $row = " " | Select Fecha, Hora, VMHost, VM, vCPUs, vSockets, PerSocket $row.Fecha = $fecha $row.Hora = $hora $row.VMHost = (Get-View -Id $vm.ExtensionData.Runtime.Host -Property Name).Name $row.VM = $vm.Name $row.vCPUs = $vm.ExtensionData.config.hardware.NumCPU $row.vSockets = ($vm.ExtensionData.config.hardware.NumCPU/$vm.ExtensionData.config.hardware.NumCoresPerSocket) $row.PerSocket = $vm.ExtensionData.config.hardware.NumCoresPerSocket $result += $row } $result | Export-Excel -WorksheetName $ws -Path $file -NoNumberConversion VMHOST -Append ## Report VMDKs $ws = "VMDKs" $j=0 $report=@() ForEach ($vm in (Get-VM)){ $discoVM = @(Get-HardDisk -VM $vm) $k=0 Foreach ($disco in $discoVM) { $row = "" | Select Fecha,Hora,Hostname, VM, Datastore, VMXpath, HardDisk, CapacityGB, ProvisionType $row.Fecha = $Fecha $row.Hora = $Hora $row.Hostname = (Get-View -Id $vm.ExtensionData.Runtime.Host -Property Name).Name $row.VM = $VM.Name $row.Datastore = $discoVM[$k].Filename.Split("]")[0].TrimStart("[") $row.VMXpath = $discoVM[$k].FileName $row.HardDisk = $discoVM[$k].Name $row.CapacityGB = [math]::Round(($Disco.CapacityGB),2) $row.ProvisionType = $discoVM[$k].StorageFormat #Contamos cuántos discos tiene la VM y cambiamos el valor de $k en función if ($discoVM.Count -gt 1) { $k=$k+1} else {$k=0} $report += $row } } $report | Export-Excel -WorksheetName $ws -Path $file -NoNumberConversion Hostname -Append <# Hoja de discos virtuales (como los ve el Sistema operativo)#> $ws = "vDISKs" $j=0 $report=@() #$vms = Get-VM ForEach ($vm in (Get-VM | Where { $_.PowerState -eq "PoweredOn" } )){ #$discoVM = @(Get-HardDisk -VM $vm) $k=1 $data = Get-VM $vm | Get-VMGuest | Select VmName -ExpandProperty Disks | Select VmName, Path, @{N="CapacityGB";E={[math]::Round(($_.CapacityGB),2)}}, @{N="UsedSpaceGB"; E={ [math]::Round(($_.CapacityGB - $_.FreeSpaceGB),2)}}, @{N="FreeSpaceGB";E={[math]::Round(($_.FreeSpaceGB),2)}}, @{ N="PercFree"; E={ [math]::Round( (100 * ( $_.FreeSpace / $_.Capacity ) ),0 ) } } Foreach ($disco in $data) { $row = "" | Select Fecha,Hora, VM, Particion, Unidad, CapacityGB, UsedSpaceGB, DiskFreespace, espaciolibre $row.Fecha = $fecha $row.Hora = $hora $row.VM = $VM.Name $row.Particion = "$k" + " de " + $data.count $row.Unidad = $disco.Path $row.CapacityGB = [math]::Round(($Disco.CapacityGB),2) $row.UsedSpaceGB = $disco.UsedSpaceGB $row.DiskFreespace = [math]::Round(($Disco.FreeSpaceGB),2) $estadodisco = $disco.PercFree <# Hacemos una condicion para que si el espacio libre es menor al 10% nos printe en la casilla del excel un aviso, si no pues unicamente el %; además, añadimos la variable $j para que cuente los discos con Warning, si hay más de 1, enviamos mail #> if ($estadodisco -lt 10) { $row.espaciolibre = "Warning " + $estadodisco + " %" $j = $j + 1 # Indicamos que nos guarde todos los datos del servidor cuya unidad tiene problemas de espacio en una nueva variable $discoswarning += $row } else { $row.espaciolibre = "" + $estadodisco + " %"} if ($data.Count -gt 1) { $k=$k+1} else {$k=1} $report += $row } } $report | Export-Excel -WorksheetName $ws -Path $file -Append #Cerramos conexión con los ESXi Disconnect-VIServer * -confirm:$false <# si el valor de $j (discos con warning) no es 0, nos enviamos el informe por correo indicando, en el cuerpo, cuántos discos tienen menos del 10% del espacio libre #> If ($j -ne '0') { # Parámetros mail $sendEmail = $true $emailHost = "aquí tu SMTP" $emailFrom = "correo de origen" $emailTo = "correo de destino" $attachment = "D:\IT\Informes\informe.xlsx" # Email Subject $emailSubject = "Alerta disco sin espacio" #Preparamos correo $message = new-object System.Net.Mail.MailMessage $message.From = $emailFrom $message.To.Add($emailTo) $message.IsBodyHtml = $True $message.Subject = $emailSubject $body = 'Hay ' + $j +' discos con problema de espacio. Revisar <a href="D:\IT\Informes\informe.xlsx">Informe</a>.' $attach = new-object Net.Mail.Attachment($attachment) $message.Attachments.Add($attach) $message.body = $body $smtp = new-object Net.Mail.SmtpClient($emailHost) $smtp.Send($message) } #cls
Esto sería todo; en cuanto sepa cómo reducir el código y aprovechar más el comando Get-View, el cuál tarda mucho menos en recorrer los servidores, mejoraré el código. Por ahora, este script me está dando muy buenos resultados siendo ejecutado cada día con una tarea programada antes de llegar a la oficina, para ser el primer correo en leer al sentarme.
¡Nos vemos!