Los parches de seguridad solo surten efecto después de un reinicio. En la práctica, los usuarios posponen los reinicios indefinidamente — y cuanto más tiempo lleva un dispositivo sin reiniciar, más actualizaciones de seguridad se acumulan en estado pendiente. Los equipos que llevan semanas encendidos también tienden a mostrar un rendimiento degradado y presión de memoria que un simple reinicio resolvería.
El problema de forzar un reinicio con un apagado abrupto es que causa interrupciones y frustración. Este script adopta un enfoque más gradual: monitoriza el tiempo de actividad y escala progresivamente, comenzando con una notificación discreta y solo forzando una cuenta regresiva cuando el dispositivo lleva 13 o más días en funcionamiento. Los usuarios tienen tiempo suficiente para guardar su trabajo; TI tiene la garantía de que los reinicios realmente ocurren.
Las alertas se muestran usando swiftDialog (instalado automáticamente si no está presente) con la marca de tu empresa, para que los usuarios las reconozcan como comunicaciones TI legítimas.
El agente de Applivery para macOS debe estar instalado y activo en el dispositivo. Obtén más información sobre el agente macOS.
Requisitos
| Requisito | Detalle |
|---|---|
| Plataforma | macOS 11.0 (Big Sur) o posterior |
| Privilegios de ejecución | Root (predeterminado en Applivery) |
| Marca corporativa | /var/root/CompanyAssets/logo.png (opcional, para diálogos con marca) |
| swiftDialog | Se instala automáticamente si no está presente |
Niveles de escalada
El script calcula el tiempo de actividad actual del sistema en días y aplica una política de escalada de cuatro niveles:
| Tiempo de actividad | Acción |
|---|---|
| 0–4 días | Sin acción |
| 5–8 días | Notificación de macOS con alerta sonora |
| 9–12 días | Ventana de diálogo con opciones Reiniciar ahora y Posponer (24h). Se cierra automáticamente después de 14 minutos |
| 13+ días | Advertencia a pantalla completa seguida de una cuenta regresiva de 10 minutos. El Mac se reinicia cuando llega a cero, o el usuario hace clic en Reiniciar ahora |
Configuración
Antes de desplegar este script, asegúrate de que tu logotipo corporativo esté disponible en /var/root/CompanyAssets/logo.png en cada dispositivo gestionado. El script redimensiona y copia el logotipo a la carpeta de recursos de swiftDialog automáticamente. Usar el logotipo corporativo garantiza que los usuarios reconozcan las alertas como comunicaciones TI y no las descarten como ruido. Puedes distribuir el archivo usando la gestión de archivos de Applivery.
Una vez en el panel de Applivery, sigue los pasos descritos aquí para crear un script. Pega el siguiente script en el editor, selecciona Bash como lenguaje, dale un nombre descriptivo (por ejemplo, Política de reinicio forzado) y haz clic en Crear.
#!/bin/bash
# ---
# Title: Force Reboot Policy (Uptime Enforcement)
# Description: Monitors macOS uptime and triggers escalating alerts via swiftDialog to force a restart.
# Author: Applivery
# Version: 1.2.0
# ---
# ==========================================
# 1. CLEANUP OLD INSTALLATIONS
# ==========================================
DIALOG_OLD="/Applications/Dialog.app"
if [ -d "$DIALOG_OLD" ]; then
echo "→ Old Dialog.app found"
pgrep -if "Dialog.app" && {
echo " → Quitting Dialog..."
pkill -if "Dialog.app" 2>/dev/null
sleep 1
}
if sudo rm -rf "$DIALOG_OLD" 2>/dev/null; then
echo " → Removed successfully"
else
echo " → Failed to remove legacy app."
fi
else
echo "→ No old Dialog.app present"
fi
# ==========================================
# 2. PRE-FLIGHT & BRANDING SETUP
# ==========================================
PATH=/usr/bin:/bin:/usr/sbin:/sbin
DIALOG_CLI="/usr/local/bin/dialog"
DIALOG_APP="/Library/Application Support/Dialog/Dialog.app"
DIALOG_ICON_DIR="/Library/Application Support/Dialog"
DIALOG_ICON="$DIALOG_ICON_DIR/Dialog.png"
BRAND_ICON="/var/root/CompanyAssets/logo.png"
needs_install=0
needs_reinstall=0
CURRENT_USER=$(stat -f %Su /dev/console)
USER_ID=$(id -u "$CURRENT_USER" 2>/dev/null || true)
# [... resto del script de instalación de swiftDialog y cálculo de tiempo de actividad ...]
# ==========================================
# 4. UPTIME CALCULATION
# ==========================================
current_unix_time="$(date '+%s')"
boot_time_unix="$(sysctl -n kern.boottime | awk -F 'sec = |, usec' '{ print $2; exit }')"
uptime_seconds="$(( current_unix_time - boot_time_unix ))"
uptime_days="$(( uptime_seconds / 86400 ))"
# TEST_UPTIME_DAYS="7" # Uncomment for testing
# ==========================================
# 5. ESCALATION LOGIC
# ==========================================
if [ "$uptime_days" -le 4 ]; then
echo "Uptime: $uptime_days days. No action needed."
exit 0
elif [ "$uptime_days" -ge 5 ] && [ "$uptime_days" -le 8 ]; then
echo "Uptime: $uptime_days days. Showing Notification."
run_as_user "$DIALOG_CLI" --notification \
--title "$uptime_days days without a reboot!" \
--message "Your Mac needs to restart to regain performance and apply security updates."
afplay "/System/Library/Sounds/Sosumi.aiff"
exit 0
elif [ "$uptime_days" -ge 9 ] && [ "$uptime_days" -le 12 ]; then
echo "Uptime: $uptime_days days. Showing Dialog with Postpone."
run_as_user "$DIALOG_CLI" \
--title "Restart Required" \
--message "*${uptime_days} days without a reboot!* \n\nPlease save your work and restart." \
--button1text "Restart now" \
--button2text "Postpone" \
--timer 840 --width 650 --height 280 --position bottomright --ontop
dialog_results=$?
elif [ "$uptime_days" -ge 13 ]; then
echo "Uptime: $uptime_days days. Final warning."
run_as_user "$DIALOG_CLI" \
--title "Restart Required" \
--message "*${uptime_days} days without a reboot!* \n\n*After pressing I Understand, you will have 10 minutes to save your work.*" \
--button1text "I Understand" --width 650 --height 230 --blurscreen --ontop
run_as_user "$DIALOG_CLI" \
--title none --message "Computer will restart when the timer reaches zero." \
--button1text "Restart now" --timer 600 --width 320 --height 110 --position bottomright --icon none --ontop
dialog_results=$?
fi
# ==========================================
# 6. REBOOT EXECUTION
# ==========================================
if [ "$dialog_results" = "0" ] || [ "$dialog_results" = "4" ]; then
echo "Rebooting now..."
shutdown -r now
sleep 2
reboot
elif [ "$dialog_results" = "2" ]; then
echo "User postponed the restart."
fi
exit 0
Ahora, navega a cualquiera de tus Dispositivos, selecciona la pestaña Scripts, haz clic en el botón + Asignar Script y selecciona el que acabas de crear.
También puedes asignar scripts a Políticas. Para ello, navega a la sección Políticas, selecciona la política deseada y haz clic en la pestaña Scripts. El proceso será el mismo que al asignarlo directamente a un dispositivo individual.
| Método | Comportamiento | ¿Recomendado? |
|---|---|---|
| Once | Se ejecuta una vez por dispositivo. | ❌ No adecuado — este script necesita ejecutarse continuamente para monitorizar el tiempo de actividad. |
| Loop | Se ejecuta repetidamente en el intervalo configurado (15m, 1h, 6h, 1d, 7d). | ✅ Recomendado — selecciona el intervalo diario (1d) para comprobar el tiempo de actividad cada 24 horas y escalar las alertas progresivamente. |
| On demand | Solo se ejecuta cuando se activa manualmente. | ❌ No adecuado para la aplicación automática del tiempo de actividad. |
Este script no requiere ningún argumento. El tiempo de actividad del sistema se calcula automáticamente en tiempo de ejecución. Haz clic en Añadir para guardar la asignación.
Qué verán los usuarios
Nivel 2 — Notificación (días 5–8): Aparece una notificación de macOS no intrusiva en la esquina superior derecha con una alerta sonora. El usuario puede descartarla y continuar trabajando.
Nivel 3 — Diálogo con opción de posponer (días 9–12): Aparece una ventana de diálogo en la esquina inferior derecha. El usuario puede hacer clic en Reiniciar ahora o Posponer. El diálogo se cierra automáticamente después de 14 minutos.
Nivel 4 — Cuenta regresiva forzada (día 13+): Primero aparece una advertencia a pantalla completa desenfocada. Después de que el usuario la confirme, comienza una cuenta regresiva de 10 minutos en la esquina inferior derecha. Cuando llega a cero — o el usuario hace clic en Reiniciar ahora — el Mac se reinicia.
Probar el script
Para probar un nivel de escalada específico sin esperar el tiempo de actividad real, descomenta la línea TEST_UPTIME_DAYS en el script y establécela en el número de días deseado:
TEST_UPTIME_DAYS="7" # Uncomment for testing
Recuerda comentarlo de nuevo antes de desplegarlo en producción.
Disponible en GitHub
Este script es parte del Repositorio público de scripts de Applivery. Un dispositivo sin reiniciar es un parche sin efecto — esta política de escalada progresiva mantiene tu flota actualizada sin interrumpir a nadie.