Propósito:
El objetivo de este post es avisar a los usuarios que tienen pendiente un reinicio.
Para mi una de las peores cosas que tiene Microsoft es como alertar o advertir a los usuarios de un evento, sinceramente no me gusta nada los pequeños mensajes que pasan desapercibidos en la parte izquierda de la pantalla.
Otra cosa que no da muchas opciones Microsoft, es forzar un reinicio con un numero importante de alertas a los usuarios. Sin utilizar comandos, solo lo permite el Wsus un reinicio forzoso y sus avisos no son los mejores. Con lo que he tenido que pensar en otra manera de alertar a mis usuarios, de las muchas que hay se me ha ocurrido la siguiente, solo avisando, que he querido compartir aquí.
Aunque lo parezca, es uno de los script que me ha llevado más tiempo crear, he pasado por muchas formas y versiones y con la ayuda de Copilot ha acabado como aquí voy a explicar.
Lo he preparado para que salte en el logon de inicio y en cada bloqueo y desbloqueo de la pantalla. Dejará de aparecer cuando ya no tenga ningún reinicio pendiente.
Pasos
La GPO.
Como veréis es una GPO de usuario, no de máquina, ya que es la mejor manera de que las alertas interactúen con el usuario conectado.
Tenemos que crear en la GPO una tarea programada, esta tarea la inyectaremos en los PCs.
Argumentos: -NoProfile
-ExecutionPolicy Bypass -WindowStyle Hidden -Command "& { $Source='\\Midominio.com\SYSVOL\midominio.com\scripts\WSUS\avisoreiniciopendiente.ps1';
$Target=$env:ProgramData+'\RebootAlert\avisoreiniciopendiente.ps1'; if (-not
(Test-Path (Split-Path $Target))) { New-Item -ItemType Directory -Path
(Split-Path $Target) -Force | Out-Null }; Copy-Item $Source $Target -Force;
Start-Process powershell.exe -ArgumentList
@('-NoProfile','-ExecutionPolicy','Bypass','-File', $Target) -WindowStyle
Hidden }"
Poner el script en un recurso compartido donde puedan leer todos los usuarios.
Código:
# ==================================================
# ALERTA DE REINICIO PENDIENTE - PRODUCCION
# ==================================================
# - Muestra aviso WPF si hay reinicio pendiente
# - Muestra aviso si el equipo lleva 15 dias sin reiniciar
# - Sin control de tiempo (sale siempre que haya reboot)
# - Evita doble ejecucion mediante Mutex
# - Pensado para ejecucion via GPO / Tarea programada
# ==================================================
Add-Type -AssemblyName PresentationFramework
# --------------------------------------------------
# EVITAR DOBLE EJECUCION DEL SCRIPT
# --------------------------------------------------
$mutexName = "Global\RebootPendingAlertMutex"
$createdNew = $false
$mutex = New-Object System.Threading.Mutex($true, $mutexName, [ref]$createdNew)
if (-not $createdNew) {
# Ya hay otra instancia ejecutandose
exit
}
# --------------------------------------------------
# FUNCION: Detectar reinicio pendiente
# --------------------------------------------------
function Test-PendingReboot {
if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired") {
return $true
}
if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending") {
return $true
}
return $false
}
# --------------------------------------------------
# FUNCION: Motivo del reinicio pendiente
# --------------------------------------------------
function Get-PendingRebootReason {
if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired") {
return "actualizaciones de Windows"
}
if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending") {
return "actualizaciones del sistema"
}
return "tareas de mantenimiento del sistema"
}
# --------------------------------------------------
# FUNCION: Detectar equipos con 15 dias sin reiniciar
# --------------------------------------------------
function Test-Uptime15Days {
$LastBoot = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
$DaysUp = ((Get-Date) - $LastBoot).Days
if ($DaysUp -ge 15) {
return $true
}
return $false
}
# --------------------------------------------------
# SI NO HAY REINICIO PENDIENTE NI 15 DIAS SIN REINICIAR
# --------------------------------------------------
if ((-not (Test-PendingReboot)) -and (-not (Test-Uptime15Days))) {
exit
}
# --------------------------------------------------
# OBTENER MOTIVO DEL AVISO
# --------------------------------------------------
if (Test-PendingReboot) {
$rebootReason = Get-PendingRebootReason
}
else {
$rebootReason = "mantenimiento recomendado. El equipo lleva mas de 15 dias sin reiniciarse"
}
# --------------------------------------------------
# VENTANA WPF
# --------------------------------------------------
[xml]$xaml = @"
Title="Mi empresa. Reinicio pendiente"
Height="240"
Width="540"
WindowStartupLocation="CenterScreen"
ResizeMode="NoResize"
Topmost="True">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Background="#B71C1C" Grid.Row="0" Padding="10">
<TextBlock Text="Reinicio pendiente."
Foreground="White"
FontSize="16"
FontWeight="Bold"
HorizontalAlignment="Center"/>
</Border>
<Border Grid.Row="1" Padding="20">
<TextBlock
Text="El equipo necesita reiniciarse para completar $rebootReason.
Por favor, guarda tu trabajo y reinicia cuando te sea posible.
Departamento de IT. "
TextWrapping="Wrap"
TextAlignment="Center"
VerticalAlignment="Center"
FontSize="13"/>
</Border>
<Button Name="AceptarBtn"
Grid.Row="2"
Width="120"
Height="35"
Margin="10"
HorizontalAlignment="Right"
Background="#D32F2F"
Foreground="White"
FontWeight="Bold"
Content="Aceptar"/>
</Grid>
</Window>
"@
$reader = New-Object System.Xml.XmlNodeReader $xaml
$window = [Windows.Markup.XamlReader]::Load($reader)
$button = $window.FindName("AceptarBtn")
$button.Add_Click({ $window.Close() })
$window.ShowDialog() | Out-Null
Se me ocurre muchos puntos de mejora, pero los dejo para más adelante.
Sinceramente, se puede usar para lanzar cualquier tipo de alertas.
by GoN | Published: May 2026 | Last Updated: Jul 26
No hay comentarios:
Publicar un comentario