En este artículo
Si gestionas dispositivos a través de una solución RMM o MDM, puedes usar el script de PowerShell a continuación para instalar, actualizar o reinstalar automáticamente la última versión del cliente Prey para Windows.
Qué Hace el Script
El script realiza automáticamente las siguientes acciones:
- Elimina las tareas existentes de Prey.
- Desinstala la instalación actual de Prey (si existe).
- Descarga el instalador más reciente para Windows directamente desde Prey.
- Reinstala y reconfigura el dispositivo.
- Verifica que la instalación se haya completado con éxito.
Antes de Comenzar
Encuentra tu Clave de Configuración
- Inicia sesión en tu cuenta de Prey.
- Haz clic en Agregar Dispositivo.
- Desplázate hacia abajo y copia la Clave de Configuración que se muestra allí.
Configurar el Script
Antes de la implementación, edita la siguiente variable cerca del inicio del script:
$FALLBACK_API_KEY = ""
Reemplaza el valor vacío con tu Clave de Configuración:
$FALLBACK_API_KEY = "TU_CLAVE_DE_CONFIGURACIÓN"Recomendaciones:
- Ejecuta el script con privilegios de
AdministradoroSYSTEM. - Configura la variable
$FALLBACK_API_KEYantes de la implementación. - Prueba en un pequeño número de dispositivos antes de desplegar en toda tu flota.
Registros de Instalación
El script genera registros que pueden usarse para solucionar problemas:
-
Registro de Reinstalación:
C:\Windows\Prey\reinstall.log
Te dejamos el script a continuación:
<#
.SYNOPSIS
Reinstalls or updates Prey Anti-Theft software.
.DESCRIPTION
This script handles the reinstallation or update process for Prey Anti-Theft software.
It performs the following operations:
- Removes existing Prey tasks
- Uninstalls the current Prey installation (if exists)
- Downloads the latest Prey version
- Installs the new version with appropriate configuration
- Verifies the installation was successful
The script supports configurable behavior through variables defined at the beginning:
- FALLBACK_API_KEY: API key to use if none is found on the system or if FORCE_API_KEY is true
- FORCE_API_KEY: Forces the use of FALLBACK_API_KEY regardless of existing configuration
- FORCE_REINSTALL: Controls whether to reinstall even if the current version is up to date
.NOTES
This script must be run with administrator privileges.
#>
#-----------------------------------------------------------------------------
# Configuration Variables
#-----------------------------------------------------------------------------
# FALLBACK_API_KEY: API key to use for installation when no existing key is found or when FORCE_API_KEY is true
# Mandatory: This must be set or the script will fail
# Type: String
$FALLBACK_API_KEY = ""
# FORCE_API_KEY: When true, always use the FALLBACK_API_KEY instead of any existing API key
# When false, attempt to retrieve the existing API key from the current installation
# Type: Boolean
$FORCE_API_KEY = $false
# FORCE_REINSTALL: When true, reinstall even if the current version matches the latest version
# When false, only reinstall if a newer version is available
# Type: Boolean
$FORCE_REINSTALL = $false
#-----------------------------------------------------------------------------
# Script Variables
#-----------------------------------------------------------------------------
$logFile = "C:\Windows\Temp\preyscript\reinstall.log"
#-----------------------------------------------------------------------------
# Validation and Initialization
#-----------------------------------------------------------------------------
# Check for administrator privileges
if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Host "This script must be run as Administrator. Exiting." -ForegroundColor Red
exit 1
}
# Validate FALLBACK_API_KEY is set
if ([string]::IsNullOrEmpty($FALLBACK_API_KEY)) {
Write-Host "FALLBACK_API_KEY must be set in the script configuration. Exiting." -ForegroundColor Red
exit 1
}
# Create log directory if it doesn't exist
if (-not (Test-Path "C:\Windows\Temp\preyscript")) {
New-Item -Path "C:\Windows\Temp\preyscript" -ItemType Directory -Force | Out-Null
}
# Initialize log file
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Set-Content -Path $logFile -Value "[$timestamp] Starting Prey reinstallation process"
# Function for consistent logging
function Log-Message {
param([string]$message, [string]$level = "INFO")
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$logEntry = "[$timestamp] [$level] $message"
# Output to console with color based on level
switch ($level) {
"ERROR" { Write-Host $logEntry -ForegroundColor Red }
"WARNING" { Write-Host $logEntry -ForegroundColor Yellow }
default { Write-Host $logEntry }
}
# Append to log file
Add-Content -Path $logFile -Value $logEntry
}
# Log configuration settings
Log-Message "Script Configuration:"
Log-Message " FORCE_API_KEY: $FORCE_API_KEY"
Log-Message " FORCE_REINSTALL: $FORCE_REINSTALL"
#-----------------------------------------------------------------------------
# Remove Fenix Task
#-----------------------------------------------------------------------------
# Remove fenix task if exists
Log-Message "Attempting to remove Prey Fenix scheduled task..."
try {
$taskExists = Get-ScheduledTask -TaskName "Prey Fenix" -ErrorAction Stop
if ($taskExists) {
Unregister-ScheduledTask -TaskName "Prey Fenix" -Confirm:$false
Log-Message "Successfully removed Prey Fenix scheduled task."
} else {
Log-Message "Prey Fenix task not found. Continuing." "WARNING"
}
} catch {
Log-Message "Error removing Prey Fenix task: $($_.Exception.Message). Continuing." "WARNING"
}
#-----------------------------------------------------------------------------
# Retrieve Device Key and API Key
#-----------------------------------------------------------------------------
# Try to get current device key
Log-Message "Retrieving device key from current installation..."
$device_key = $null
$device_key_valid = $null
try {
if (Test-Path "C:\Windows\Prey\current\bin\prey") {
$device_key = cmd /c "C:\Windows\Prey\current\bin\prey config settings read control-panel.device_key" 2>$null
if (-not [string]::IsNullOrEmpty($device_key) -and $device_key -match "^[a-fA-F0-9]{1,6}$") {
$device_key_valid = $true
Log-Message "Device key successfully retrieved. this one: $($device_key)"
Log-Message "Device key is Valid: $($device_key_valid)"
} else {
Log-Message "Device key not found or empty. this one: $($device_key)" "WARNING"
}
} else {
Log-Message "Prey binary not found. No device key to retrieve." "WARNING"
}
} catch {
Log-Message "Error retrieving device key: $($_.Exception.Message)" "WARNING"
}
# Try to get current API key
$current_api_key = $null
try {
if (Test-Path "C:\Windows\Prey\current\bin\prey") {
$current_api_key = cmd /c "C:\Windows\Prey\current\bin\prey config settings read control-panel.api_key" 2>$null
if (-not [string]::IsNullOrEmpty($current_api_key) -and $current_api_key -match "^[a-zA-Z0-9]+$") {
Log-Message "API key successfully retrieved: $($current_api_key)."
} else {
Log-Message "API key not found or empty." "WARNING"
}
} else {
Log-Message "Prey binary not found. No API key to retrieve." "WARNING"
}
} catch {
Log-Message "Error retrieving API key: $($_.Exception.Message)" "WARNING"
}
# Determine which API key to use
$use_device_key = $false
if ($FORCE_API_KEY) {
$api_key_to_use = $FALLBACK_API_KEY
Log-Message "FORCE_API_KEY is enabled. Using FALLBACK_API_KEY."
} else {
if (-not [string]::IsNullOrEmpty($current_api_key) -and $current_api_key -match "^[a-zA-Z0-9]+$") {
$api_key_to_use = $current_api_key
Log-Message "Using API key from current installation."
} else {
$current_api_key = $FALLBACK_API_KEY
$api_key_to_use = $current_api_key
Log-Message "No API key found in current installation. Using FALLBACK_API_KEY."
}
}
# Determine if we should use the device key
if ($device_key_valid) {
if ($FORCE_API_KEY) {
# When FORCE_API_KEY is true, only use device key if API keys match
if (-not [string]::IsNullOrEmpty($current_api_key) -and $current_api_key -match "^[a-zA-Z0-9]+$" -and $current_api_key -eq $FALLBACK_API_KEY) {
$use_device_key = $true
Log-Message "API keys match. Will install with existing device key."
} else {
Log-Message "API keys don't match or couldn't be compared. Will install with API key only." "WARNING"
}
} else {
# When FORCE_API_KEY is false, use device key if it exists
$use_device_key = $true
Log-Message "Will install with existing device key."
}
}
#-----------------------------------------------------------------------------
# Get Latest Version
#-----------------------------------------------------------------------------
Log-Message "Fetching latest version information..."
try {
$latest_version = (Invoke-WebRequest -Uri "https://downloads.preyproject.com/prey-client-releases/node-client/latest.txt" -UseBasicParsing).Content.Trim()
Log-Message "Latest available version: $latest_version"
} catch {
Log-Message "Failed to fetch latest version: $($_.Exception.Message)" "ERROR"
exit 1
}
#-----------------------------------------------------------------------------
# Verify Credentials
#-----------------------------------------------------------------------------
# Verify credentials if not forced
$uri = $null
if ($FORCE_API_KEY -eq $false -and $use_device_key) {
$uri = "https://solid.preyproject.com/api/v2/devices/$($device_key)/verify.json"
} elseif ($FORCE_API_KEY -eq $false -and $use_device_key -eq $false) {
$uri = "https://solid.preyproject.com/api/v2/profile.json?lang=en"
} else {
Log-Message "No valid condition met for setting the URL." "WARNING"
}
if ($uri) {
try {
$headers = @{"User-Agent" = "Prey/$($latest_version) (Node v20.16.0 Windows 10.0.26100)"}
$base64Auth = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$($current_api_key):x"))
$headers["Authorization"] = "Basic $base64Auth"
$response = Invoke-WebRequest -Uri $uri -Headers $headers -Method Get -TimeoutSec 120 -UseBasicParsing
$responseData = $response.Content | ConvertFrom-Json
if ($responseData.result -eq "OK") {
$api_key_to_use = $current_api_key
Log-Message "Succesfuly verified credentials. Using API key: $($api_key_to_use) and Device Key: $($device_key) from current installation."
} elseif ($responseData.key -eq $current_api_key) {
$api_key_to_use = $current_api_key
Log-Message "The API KEY found in current installation is VALID. Using current_api_key: $($current_api_key)."
} else {
$api_key_to_use = $FALLBACK_API_KEY
$use_device_key = $false
Log-Message "The credentials found in current installation are NOT VALID. Using FALLBACK_API_KEY: $($FALLBACK_API_KEY)."
}
} catch {
$api_key_to_use = $FALLBACK_API_KEY
$use_device_key = $false
Log-Message "Error verifying credentials [Api Key: $($api_key_to_use), Device Key: $($device_key)]: $($_.Exception.Message)" "WARNING"
}
} else {
Log-Message "Skipping credential verification due to uri configuration." "WARNING"
}
#-----------------------------------------------------------------------------
# Get Current Version
#-----------------------------------------------------------------------------
$current_version = $null
try {
if (Test-Path "C:\Windows\Prey\current\bin\prey") {
$current_version = cmd /c "C:\Windows\Prey\current\bin\prey --version" 2>$null
$current_version = $current_version.Trim()
Log-Message "Current Prey version: $current_version"
} else {
Log-Message "No current installation found or prey binary missing."
}
} catch {
Log-Message "Error reading current version: $($_.Exception.Message)" "WARNING"
}
# Check if reinstallation is needed based on FORCE_REINSTALL setting
if (-not $FORCE_REINSTALL -and -not [string]::IsNullOrEmpty($current_version)) {
# Compare versions to determine if update is needed
if ($current_version -eq $latest_version) {
Log-Message "Current version ($current_version) is already the latest. FORCE_REINSTALL is disabled, so exiting."
exit 0
} elseif ([Version]$current_version -ge [Version]$latest_version) {
# This handles cases where current version might be newer than what's reported as latest
Log-Message "Current version ($current_version) is newer than or equal to latest version ($latest_version). FORCE_REINSTALL is disabled, so exiting."
exit 0
} else {
Log-Message "Current version ($current_version) is older than latest version ($latest_version). Proceeding with update."
}
}
#-----------------------------------------------------------------------------
# Uninstall Existing Prey Installation
#-----------------------------------------------------------------------------
# Attempt to uninstall Prey Anti-Theft
Log-Message "Attempting to uninstall current Prey installation..."
$uninstalled = $false
try {
Log-Message "Attempting WMI-based uninstallation..."
$preyApp = Get-WmiObject Win32_Product -Filter "Name='Prey Anti-Theft'" -ErrorAction Stop
if ($preyApp) {
$preyApp.Uninstall() | Out-Null
$uninstalled = $true
Log-Message "Uninstallation completed via WMI."
}
} catch {
Log-Message "WMI uninstallation failed: $($_.Exception.Message)" "WARNING"
}
# If all else fails, force kill processes and remove services
if (-not $uninstalled) {
Log-Message "Using fallback uninstallation method." "WARNING"
# Check and stop services
try {
$cronService = Get-Service -Name "CronService" -ErrorAction Stop
if ($cronService) {
try {
Set-Service -Name "CronService" -StartupType Disabled
Stop-Service -Name "CronService" -Force -ErrorAction SilentlyContinue
Log-Message "CronService disabled and stopped."
} catch {
Log-Message "Error stopping CronService: $($_.Exception.Message)" "WARNING"
}
}
} catch {
Log-Message "CronService not found: $($_.Exception.Message)" "WARNING"
}
# Check and kill processes
$processes = @("wpxsvc", "node")
foreach ($process in $processes) {
try {
$runningProcesses = Get-Process -Name $process -ErrorAction Stop
if ($runningProcesses) {
Stop-Process -Name $process -Force
Log-Message "Killed process: $process"
}
} catch {
Log-Message "Error killing process $($process): $($_.Exception.Message)" "WARNING"
}
}
# Try to delete the service
try {
$service = Get-WmiObject -Class Win32_Service -Filter "Name='CronService'" -ErrorAction Stop
if ($service) {
$service.Delete() | Out-Null
Log-Message "CronService deleted."
}
} catch {
Log-Message "Error deleting CronService: $($_.Exception.Message)" "WARNING"
}
}
#-----------------------------------------------------------------------------
# Clean Up Prey Folder
#-----------------------------------------------------------------------------
# Clean up Prey folder
Log-Message "Removing Prey folder..."
$prey_folder = "C:\Windows\Prey"
if (Test-Path $prey_folder) {
try {
# First try to remove contents to handle permissions better
try {
Get-ChildItem -Path $prey_folder -Recurse | Remove-Item -Force -Recurse -ErrorAction Stop
} catch {
Log-Message "Error removing Prey folder contents: $($_.Exception.Message)" "WARNING"
}
try {
Remove-Item -Path $prey_folder -Recurse -Force -ErrorAction Stop
} catch {
Log-Message "Error removing Prey folder: $($_.Exception.Message)" "WARNING"
}
# Verify removal
if (Test-Path $prey_folder) {
Log-Message "Warning: Could not completely remove $prey_folder" "WARNING"
} else {
Log-Message "Successfully removed Prey folder."
}
} catch {
Log-Message "Error removing Prey folder: $($_.Exception.Message)" "WARNING"
}
}
#-----------------------------------------------------------------------------
# Download and Install Latest Version
#-----------------------------------------------------------------------------
# Determine architecture
if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64") {
$arch_version = "x64"
} else {
$arch_version = "x86"
}
# Set download and output paths
$msi_filename = "prey-windows-$latest_version-$arch_version.msi"
$download_url = "https://downloads.preyproject.com/prey-client-releases/node-client/$latest_version/$msi_filename"
$output_filepath = Join-Path "C:\Windows\Temp" $msi_filename
# Download the installer
Log-Message "Downloading Prey $latest_version for $arch_version architecture from $download_url"
try {
Invoke-WebRequest -Uri $download_url -OutFile $output_filepath -UseBasicParsing
# Verify download success
if (-not (Test-Path $output_filepath) -or (Get-Item $output_filepath).Length -eq 0) {
Log-Message "Failed to download Prey installer or file is empty." "ERROR"
exit 1
}
Log-Message "Successfully downloaded installer to $output_filepath"
} catch {
Log-Message "Failed to download Prey installer: $($_.Exception.Message)" "ERROR"
exit 1
}
# Install Prey based on configuration
Log-Message "Installing Prey..."
try {
$installArgs = ""
if ($use_device_key) {
Log-Message "Installing with existing device key and API key: $api_key_to_use"
$installArgs = "/i `"$output_filepath`" /q /lv C:\Windows\Temp\preyscript\installer.log AGREETOLICENSE=yes DEVICE_KEY=`"$device_key`" API_KEY=`"$api_key_to_use`""
} else {
Log-Message "Installing with API key only: $api_key_to_use"
$installArgs = "/i `"$output_filepath`" /q /lv C:\Windows\Temp\preyscript\installer.log AGREETOLICENSE=yes API_KEY=`"$api_key_to_use`""
}
$process = Start-Process msiexec.exe -ArgumentList $installArgs -Wait -PassThru
$exitCode = $process.ExitCode
if ($exitCode -eq 0) {
Log-Message "Installation completed successfully with exit code: $exitCode"
} else {
Log-Message "Installation completed with non-zero exit code: $exitCode" "WARNING"
}
} catch {
Log-Message "Error during installation: $($_.Exception.Message)" "ERROR"
exit 1
}
#-----------------------------------------------------------------------------
# Verify Installation
#-----------------------------------------------------------------------------
# Verify installation
Log-Message "Verifying installation..."
if (Test-Path "C:\Windows\Prey\current\bin\prey") {
Log-Message "Prey binary found. Installation appears successful."
# Try to get installed version for verification
try {
$installed_version = cmd /c "C:\Windows\Prey\current\bin\prey --version" 2>$null
$installed_version = $installed_version.Trim()
Log-Message "Installed Prey version: $installed_version"
if ($installed_version -ne $latest_version) {
Log-Message "Warning: Installed version ($installed_version) does not match expected version ($latest_version)" "WARNING"
}
} catch {
Log-Message "Could not verify installed version: $($_.Exception.Message)" "WARNING"
}
# Check if CronService is running
try {
$cronService = Get-Service -Name "CronService" -ErrorAction Stop
Log-Message "CronService status: $($cronService.Status)"
if ($cronService.Status -ne "Running") {
Log-Message "Warning: CronService is not running" "WARNING"
} else {
Log-Message "CronService is running properly."
}
} catch {
Log-Message "Error checking CronService: $($_.Exception.Message)" "ERROR"
}
# Check if wpxsvc.exe is running
try {
$wpxsvcProcess = Get-Process -Name "wpxsvc" -ErrorAction Stop
Log-Message "wpxsvc.exe is running (PID: $($wpxsvcProcess.Id))"
} catch {
Log-Message "wpxsvc.exe is not running: $($_.Exception.Message)" "WARNING"
}
# Log wpxsvc version
try {
if (Test-Path "C:\Windows\Prey\wpxsvc.exe") {
$wpxsvcVersion = cmd /c "C:\Windows\Prey\wpxsvc.exe -winsvc=version" 2>$null
$wpxsvcVersion = $wpxsvcVersion.Trim()
Log-Message "wpxsvc.exe version: $wpxsvcVersion"
} else {
Log-Message "wpxsvc.exe not found" "WARNING"
}
} catch {
Log-Message "Error getting wpxsvc version: $($_.Exception.Message)" "WARNING"
}
} else {
Log-Message "Prey binary not found. Installation may have failed." "ERROR"
# Check installation log for errors
if (Test-Path "C:\Windows\Temp\preyscript\installer.log") {
$logContent = Get-Content "C:\Windows\Temp\preyscript\installer.log"
$errorLines = $logContent | Select-String -Pattern "Error|failed|failure" -CaseSensitive:$false
if ($errorLines) {
Log-Message "Found potential errors in installation log:" "ERROR"
foreach ($line in $errorLines) {
Log-Message " $line" "ERROR"
}
}
} else {
Log-Message "Installation log not found." "ERROR"
}
exit 1
}
#-----------------------------------------------------------------------------
# Clean Up and Finalize
#-----------------------------------------------------------------------------
# Clean up downloaded installer
try {
if (Test-Path $output_filepath) {
Remove-Item -Path $output_filepath -Force
Log-Message "Cleaned up downloaded installer."
}
} catch {
Log-Message "Error cleaning up installer file: $($_.Exception.Message)" "WARNING"
}
# Move log files to Prey folder
try {
# Create Prey folder if it doesn't exist (should exist after installation)
if (-not (Test-Path "C:\Windows\Prey")) {
New-Item -Path "C:\Windows\Prey" -ItemType Directory -Force | Out-Null
}
# Move and rename installer.log
if (Test-Path "C:\Windows\Temp\preyscript\installer.log") {
Copy-Item -Path "C:\Windows\Temp\preyscript\installer.log" -Destination "C:\Windows\Prey\msi_install.log" -Force
Log-Message "Moved installer.log to C:\Windows\Prey\msi_install.log"
}
# Move reinstall.log
if (Test-Path $logFile) {
Copy-Item -Path $logFile -Destination "C:\Windows\Prey\reinstall.log" -Force
Log-Message "Moved reinstall.log to C:\Windows\Prey\reinstall.log"
}
} catch {
Log-Message "Error moving log files: $($_.Exception.Message)" "WARNING"
}
# Log final versions as a summary
Log-Message "Installation Summary:"
try {
$finalPreyVersion = cmd /c "C:\Windows\Prey\current\bin\prey --version" 2>$null
Log-Message " Prey Agent Version: $($finalPreyVersion.Trim())"
} catch {
Log-Message " Could not determine final Prey Agent version: $($_.Exception.Message)" "WARNING"
}
try {
if (Test-Path "C:\Windows\Prey\wpxsvc.exe") {
$finalWpxsvcVersion = cmd /c "C:\Windows\Prey\wpxsvc.exe -winsvc=version" 2>$null
Log-Message " Windows Service (wpxsvc.exe) Version: $($finalWpxsvcVersion.Trim())"
} else {
Log-Message " Windows Service (wpxsvc.exe) not found" "WARNING"
}
} catch {
Log-Message " Could not determine Windows Service version: $($_.Exception.Message)" "WARNING"
}
Log-Message "Script completed successfully."
exit 0¿Necesitas Ayuda?
Si experimentas algún problema durante la implementación, por favor contacta a nuestro Equipo de Soporte a través del widget de Soporte en tu Panel de Prey.