En este artículo, vamos a ver cómo obtener la última hora del BIOS. En en el cambiante entorno de TI actual, es primordial garantizar que los sistemas funcionen con eficacia. Un aspecto crítico de esta eficiencia es el tiempo de arranque del sistema, a menudo denominado “Última hora del BIOS”.
La supervisión y gestión de este tiempo puede ayudar a los profesionales de TI a optimizar el rendimiento del sistema y solucionar problemas de forma más eficaz. Este post profundiza en un script de PowerShell diseñado para obtener la Última hora del BIOS de la sección de inicio del administrador de tareas, alertando a los usuarios si supera un umbral especificado.
Contexto
La Última hora del BIOS es una métrica disponible en la sección de inicio del Administrador de tareas de Windows que indica el tiempo que tarda el BIOS del sistema en inicializarse durante el proceso de arranque. Un tiempo de BIOS más largo puede significar problemas potenciales como problemas de hardware o configuraciones erróneas. Para los profesionales de TI y los proveedores de servicios gestionados (MSP), hacer un seguimiento de esta métrica puede ser crucial para mantener el buen estado del sistema y garantizar tiempos de arranque rápidos.
El script
#Requires -Version 5.1 <# .SYNOPSIS Gets the Last BIOS time from the startup section of task manager and alerts if it exceeds a threshold you specify. .DESCRIPTION Gets the Last BIOS time from the startup section of task manager and alerts if it exceeds a threshold you specify. Can save the result to a custom field. .EXAMPLE (No Parameters) ## EXAMPLE OUTPUT WITHOUT PARAMS ## Last BIOS Time: 14.6s PARAMETER: -BootCustomField "BootTime" Saves the boot time to this Text Custom Field. .EXAMPLE -BootCustomField "BootTime" ## EXAMPLE OUTPUT WITH BootCustomField ## Last BIOS Time: 14.6s PARAMETER: -Seconds 20 Sets the threshold for when the boot time is greater than this number. In this case the boot time is over the threshold. .EXAMPLE -Seconds 20 ## EXAMPLE OUTPUT WITH Seconds ## Last BIOS Time: 14.6s [Error] Boot time exceeded threshold of 20s by 5.41s. Boot time: 14.6s PARAMETER: -Seconds 10 Sets the threshold for when the boot time is greater than this number. In this case the boot time is under the threshold. .EXAMPLE -Seconds 10 ## EXAMPLE OUTPUT WITH Seconds ## Last BIOS Time: 14.6s [Info] Boot time under threshold of 10s by 4.59s. Boot time: 14.6s .OUTPUTS String .NOTES Minimum OS Architecture Supported: Windows 10, Windows Server 2016 Release Notes: Initial Release By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use. Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA). #> [CmdletBinding()] param ( $Seconds, [String]$BootCustomField ) begin { if ($env:bootCustomField -and $env:bootCustomField -notlike "null") { $BootCustomField = $env:bootCustomField } if ($env:bootTimeThreshold -and $env:bootTimeThreshold -notlike "null") { # Remove any non digits [double]$Seconds = $env:bootTimeThreshold -replace '[^0-9.]+' } function Set-NinjaProperty { [CmdletBinding()] Param( [Parameter(Mandatory = $True)] [String]$Name, [Parameter()] [String]$Type, [Parameter(Mandatory = $True, ValueFromPipeline = $True)] $Value, [Parameter()] [String]$DocumentName ) $Characters = $Value | Measure-Object -Character | Select-Object -ExpandProperty Characters if ($Characters -ge 10000) { throw [System.ArgumentOutOfRangeException]::New("Character limit exceeded, value is greater than 10,000 characters.") } # If we're requested to set the field value for a Ninja document we'll specify it here. $DocumentationParams = @{} if ($DocumentName) { $DocumentationParams["DocumentName"] = $DocumentName } # This is a list of valid fields that can be set. If no type is given, it will be assumed that the input doesn't need to be changed. $ValidFields = "Attachment", "Checkbox", "Date", "Date or Date Time", "Decimal", "Dropdown", "Email", "Integer", "IP Address", "MultiLine", "MultiSelect", "Phone", "Secure", "Text", "Time", "URL", "WYSIWYG" if ($Type -and $ValidFields -notcontains $Type) { Write-Warning "$Type is an invalid type! Please check here for valid types. https://ninjarmm.zendesk.com/hc/en-us/articles/16973443979789-Command-Line-Interface-CLI-Supported-Fields-and-Functionality" } # The field below requires additional information to be set $NeedsOptions = "Dropdown" if ($DocumentName) { if ($NeedsOptions -contains $Type) { # We'll redirect the error output to the success stream to make it easier to error out if nothing was found or something else went wrong. $NinjaPropertyOptions = Ninja-Property-Docs-Options -AttributeName $Name @DocumentationParams 2>&1 } } else { if ($NeedsOptions -contains $Type) { $NinjaPropertyOptions = Ninja-Property-Options -Name $Name 2>&1 } } # If an error is received it will have an exception property, the function will exit with that error information. if ($NinjaPropertyOptions.Exception) { throw $NinjaPropertyOptions } # The below type's require values not typically given in order to be set. The below code will convert whatever we're given into a format ninjarmm-cli supports. switch ($Type) { "Checkbox" { # While it's highly likely we were given a value like "True" or a boolean datatype it's better to be safe than sorry. $NinjaValue = [System.Convert]::ToBoolean($Value) } "Date or Date Time" { # Ninjarmm-cli expects the GUID of the option to be selected. Therefore, the given value will be matched with a GUID. $Date = (Get-Date $Value).ToUniversalTime() $TimeSpan = New-TimeSpan (Get-Date "1970-01-01 00:00:00") $Date $NinjaValue = $TimeSpan.TotalSeconds } "Dropdown" { # Ninjarmm-cli is expecting the guid of the option we're trying to select. So we'll match up the value we were given with a guid. $Options = $NinjaPropertyOptions -replace '=', ',' | ConvertFrom-Csv -Header "GUID", "Name" $Selection = $Options | Where-Object { $_.Name -eq $Value } | Select-Object -ExpandProperty GUID if (-not $Selection) { throw [System.ArgumentOutOfRangeException]::New("Value is not present in dropdown") } $NinjaValue = $Selection } default { # All the other types shouldn't require additional work on the input. $NinjaValue = $Value } } # We'll need to set the field differently depending on if its a field in a Ninja Document or not. if ($DocumentName) { $CustomField = Ninja-Property-Docs-Set -AttributeName $Name -AttributeValue $NinjaValue @DocumentationParams 2>&1 } else { $CustomField = Ninja-Property-Set -Name $Name -Value $NinjaValue 2>&1 } if ($CustomField.Exception) { throw $CustomField } } } process { $Ticks = try { # Get boot time from performance event logs $PerfTicks = Get-WinEvent -FilterHashtable @{LogName = "Microsoft-Windows-Diagnostics-Performance/Operational"; Id = 100 } -MaxEvents 1 -ErrorAction SilentlyContinue | ForEach-Object { # Convert the event to XML and grab the Event node $eventXml = ([xml]$_.ToXml()).Event # Output boot time in ms [int64]($eventXml.EventData.Data | Where-Object { $_.Name -eq 'BootTime' }).InnerXml } # Get the boot POST time from the firmware, when available $FirmwareTicks = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Power" -Name "FwPOSTTime" -ErrorAction SilentlyContinue # Get the boot POST time from Windows, used as fall back $OsTicks = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Power" -Name "POSTTime" -ErrorAction SilentlyContinue # Use most likely to be accurate to least accurate if ($FirmwareTicks -gt 0) { $FirmwareTicks } elseif ($OsTicks -gt 0) { $OsTicks } elseif ($PerfTicks -and $PerfTicks -gt 0) { $PerfTicks } else { # Fall back to reading System event logs $StartOfBoot = Get-WinEvent -FilterHashtable @{LogName = 'System'; Id = 12 } -MaxEvents 1 | Select-Object -ExpandProperty TimeCreated $LastUpTime = Get-WmiObject Win32_OperatingSystem -ErrorAction Stop | Select-Object @{Label = 'LastBootUpTime'; Expression = { $_.ConvertToDateTime($_.LastBootUpTime) } } | Select-Object -ExpandProperty LastBootUpTime New-TimeSpan -Start $LastUpTime -End $StartOfBoot -ErrorAction Stop | Select-Object -ExpandProperty TotalMilliseconds } } catch { Write-Host "[Error] Failed to get Last BIOS Time from registry." exit 2 } $TimeSpan = [TimeSpan]::FromMilliseconds($Ticks) $BootTime = if ($TimeSpan.Days -gt 0) { "$($TimeSpan.Days)d, $($TimeSpan.Hours)h, $($TimeSpan.Minutes)m, $($TimeSpan.Seconds + [Math]::Round($TimeSpan.Milliseconds / 1000, 1))s" } elseif ($TimeSpan.Hours -gt 0) { "$($TimeSpan.Hours)h, $($TimeSpan.Minutes)m, $($TimeSpan.Seconds + [Math]::Round($TimeSpan.Milliseconds / 1000, 1))s" } elseif ($TimeSpan.Minutes -gt 0) { "$($TimeSpan.Minutes)m, $($TimeSpan.Seconds + [Math]::Round($TimeSpan.Milliseconds / 1000, 1))s" } elseif ($TimeSpan.Seconds -gt 0) { "$($TimeSpan.Seconds + [Math]::Round($TimeSpan.Milliseconds / 1000, 1))s" } else { # Fail safe output "$($TimeSpan.Days)d, $($TimeSpan.Hours)h, $($TimeSpan.Minutes)m, $($TimeSpan.Seconds + [Math]::Round($TimeSpan.Milliseconds / 1000, 1))s" } Write-Host "Last BIOS Time: $BootTime" if ($BootCustomField) { Set-NinjaProperty -Name $BootCustomField -Type Text -Value $BootTime } if ($Seconds -gt 0) { if ($TimeSpan.TotalSeconds -gt $Seconds) { Write-Host "[Error] Boot time exceeded threshold of $($Seconds)s by $($TimeSpan.TotalSeconds - $Seconds)s. Boot time: $BootTime" exit 1 } Write-Host "[Info] Boot time under threshold of $($Seconds)s by $($Seconds - $TimeSpan.TotalSeconds)s. Boot time: $BootTime" } exit 0 } end { }
Análisis detallado
El script PowerShell proporcionado está diseñado para obtener la Última hora del BIOS de un sistema Windows y alertar al usuario si supera un umbral especificado. Además, puede guardar el resultado en un campo personalizado con fines de documentación. A continuación se explica paso a paso cómo funciona el script.
Explicación paso a paso
1. Definición de parámetros:
- El script comienza definiendo dos parámetros: $Seconds y $BootCustomField.
- $Seconds especifica el umbral para el tiempo de arranque.
- $BootCustomField es un campo personalizado donde se puede guardar el tiempo de arranque.
2. Comprobación de variables de entorno:
- El script comprueba las variables de entorno bootCustomField y bootTimeThreshold.
- Si se establecen, anulan los parámetros del script.
3. Función Set-NinjaProperty:
- Esta función se utiliza para establecer el valor del tiempo de arranque en un campo personalizado especificado.
- Incluye validación para garantizar que el valor no supera los límites de caracteres y gestiona adecuadamente los distintos tipos de datos.
4. Bloque de proceso:
- El script recupera la Última hora del BIOS usando varios métodos, priorizando la precisión:
- Registros de eventos de rendimiento.
- Valores de registro para el tiempo POST del firmware.
- Registros de eventos del sistema como alternativa.
- La hora obtenida se convierte a un formato legible para el ser humano.
5. Salida y alertas:
- El script muestra la última hora del BIOS.
- Si se especifica un campo personalizado, establece este valor utilizando la función Set-NinjaProperty.
- Si se establece un umbral, compara el tiempo de arranque con este umbral y alerta si se supera.
Posibles casos de uso
Imagina a un profesional de TI llamado Alex, que gestiona una flota de portátiles de la empresa. Un día, Alex se da cuenta de que varios usuarios informan de tiempos de arranque inusualmente largos. Desplegando este script PowerShell a través de la red, Alex puede obtener y monitorizar automáticamente la Última hora del BIOS para cada sistema.
Si algún sistema supera el umbral predefinido, Alex recibe inmediatamente una alerta y puede investigar más a fondo, identificando potencialmente problemas de hardware o configuraciones erróneas que deban solucionarse.
Comparaciones
Otros métodos para lograr resultados similares podrían incluir el uso de herramientas integradas de Windows o software de terceros. Sin embargo, estos enfoques a menudo carecen de las capacidades de personalización y automatización de un script PowerShell. Por ejemplo:
- Herramientas integradas: herramientas como el Administrador de Tareas pueden mostrar la Última Hora del BIOS pero no proporcionan alertas o automatización.
- Software de terceros: aunque pueden ofrecer una supervisión exhaustiva, pueden tener un coste más elevado y requerir una configuración adicional.
FAQ
P: ¿Qué ocurre si el script no consigue recuperar la última hora del BIOS?
R: El script incluye varios métodos alternativos para garantizar que la última hora del BIOS se recupere con precisión. Si todos los métodos fallan, muestra un mensaje de error.
P: ¿Puedo modificar el umbral después de desplegar el script?
R: Sí, puedes establecer el umbral utilizando el parámetro -Seconds o estableciendo la variable de entorno bootTimeThreshold.
P: ¿Cómo puedo guardar la Última hora del BIOS en un campo personalizado?
R: Utiliza el parámetro -BootCustomField para especificar el campo personalizado donde debe guardarse la hora de arranque.
Implicaciones
Supervisar la última hora del BIOS puede tener un impacto significativo en la seguridad y el rendimiento informático. Un tiempo prolongado del BIOS podría indicar problemas subyacentes que podrían afectar a la estabilidad general del sistema y a la productividad del usuario. Al supervisar y abordar estos problemas de forma proactiva, los profesionales de TI pueden mantener un rendimiento óptimo del sistema y reducir el tiempo de inactividad.
Recomendaciones
- Monitoriza regularmente la Última hora del BIOS utilizando este script para detectar posibles problemas a tiempo.
- Estableced umbrales realistas basados en el rendimiento típico de tus sistemas.
- Documenta cualquier anomalía e investígala rápidamente para evitar problemas a largo plazo.
Reflexiones finales
En conclusión, este script PowerShell ofrece una solución robusta para monitorizar la Última hora del BIOS, proporcionando información crítica sobre el rendimiento del sistema. Al integrar este script en tus prácticas de gestión de TI, puedes garantizar que los sistemas funcionen sin problemas y con eficacia. NinjaOne ofrece un conjunto de herramientas que pueden mejorar aún más tus operaciones de TI, proporcionando capacidades completas de supervisión y automatización para mantener tus sistemas en plena forma.