<# Pruebas de las funciones de install.ps1, sin instalar nada. Las funciones se extraen del script por AST y se ejercitan contra una tarea programada simulada. Así se prueba el COMPORTAMIENTO —no solo que el archivo parsee— sin necesitar elevación ni registrar una tarea 'CloudRestoreAS' de verdad en la máquina. Complementa a emular-actualizacion-windows.ps1: ese cubre el flujo completo, este cubre los casos límite de la comparación de rutas, que es donde se esconden los fallos silenciosos. Uso: .\probar-funciones-install.ps1 #> param([string]$Installer = (Join-Path (Split-Path -Parent $PSScriptRoot) 'install.ps1')) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $tokens = $null; $errores = $null $ast = [System.Management.Automation.Language.Parser]::ParseFile( (Resolve-Path $Installer).Path, [ref]$tokens, [ref]$errores) if ($errores -and $errores.Count -gt 0) { Write-Host "install.ps1 no parsea: $($errores.Count) error(es)" -ForegroundColor Red $errores | ForEach-Object { Write-Host (" L" + $_.Extent.StartLineNumber + ": " + $_.Message) } exit 1 } # Variables de ámbito de script que usan las funciones. $Prefix = 'C:\Aduanasoft\CloudRestoreAS-win' $dest = Join-Path $Prefix 'CloudRestoreAS.exe' $TaskName = 'CloudRestoreAS' $ProcName = 'CloudRestoreAS' $queremos = @('Write-Step', 'Write-Ok', 'Write-Warn', 'Get-NormalizedPath', 'Test-SamePath', 'Get-AgentTaskExecute', 'Repair-AgentTaskPath', 'Sync-AgentTaskPath') foreach ($f in $ast.FindAll({ param($n) $n -is [System.Management.Automation.Language.FunctionDefinitionAst] }, $true)) { if ($queremos -contains $f.Name) { . ([scriptblock]::Create($f.Extent.Text)) } } $fallos = 0 function Assert($cond, $msg) { if ($cond) { Write-Host " OK $msg" } else { Write-Host " FALLA $msg" -ForegroundColor Red; $script:fallos++ } } Write-Host '=== Test-SamePath: rutas donde una es prefijo de cadena de la otra ===' # El caso que existe en produccion. Un `-like "$a*"` o un StartsWith aqui daria por iguales dos # instalaciones distintas, no se corregiria la tarea, y la actualizacion no surtiria efecto. $porOmision = 'C:\Aduanasoft\CloudRestoreAS' $personalizada = 'C:\Aduanasoft\CloudRestoreAS-win' Assert (-not (Test-SamePath $porOmision $personalizada)) 'no confunde la ruta por omision con la -win' Assert (-not (Test-SamePath $personalizada $porOmision)) 'ni al reves' Assert (-not (Test-SamePath "$porOmision\CloudRestoreAS.exe" "$personalizada\CloudRestoreAS.exe")) ` 'tampoco con el ejecutable completo' Assert (Test-SamePath $personalizada $personalizada) 'y la personalizada sigue siendo igual a si misma' Write-Host '=== Test-SamePath: normalizacion ===' Assert (Test-SamePath "`"$personalizada`"" $personalizada) 'tolera comillas (la tarea las guarda asi)' Assert (Test-SamePath $personalizada.ToUpper() $personalizada) 'NTFS no distingue mayusculas' Assert (Test-SamePath "$personalizada\" $personalizada) 'ignora la barra final' Assert (Test-SamePath "$Prefix\..\CloudRestoreAS-win\x.exe" "$Prefix\x.exe") 'normaliza .. en la ruta' Assert (-not (Test-SamePath '' $personalizada)) 'una ruta vacia no es igual a nada' Write-Host '=== Get-AgentTaskExecute ===' function Get-AgentTask { [pscustomobject]@{ Actions = @( [pscustomobject]@{ Execute = "`"$porOmision\CloudRestoreAS.exe`""; Arguments = '--start-engine --headless' }) } } Assert ((Get-AgentTaskExecute) -eq "$porOmision\CloudRestoreAS.exe") 'devuelve la ruta sin comillas' # Una accion ComHandler no tiene .Execute: con StrictMode, tocarla a ciegas seria un error. function Get-AgentTask { [pscustomobject]@{ Actions = @( [pscustomobject]@{ ClassId = '{guid}' }, [pscustomobject]@{ Execute = "$porOmision\CloudRestoreAS.exe"; Arguments = '' }) } } Assert ((Get-AgentTaskExecute) -eq "$porOmision\CloudRestoreAS.exe") 'se salta acciones sin Execute' function Get-AgentTask { $null } Assert ((Get-AgentTaskExecute) -eq '') 'sin tarea devuelve cadena vacia' Write-Host '=== Sync-AgentTaskPath: el fallo silencioso ===' $script:reapuntadoA = $null $script:argsPreservados = $null function Set-ScheduledTask { param($TaskName, $Action) $ejec = @($Action | Where-Object { $_.PSObject.Properties['Execute'] -and $_.Execute }) $script:reapuntadoA = $ejec[0].Execute $script:argsPreservados = $ejec[0].Arguments return $true } function New-ScheduledTaskAction { param($Execute, $Argument, $WorkingDirectory) [pscustomobject]@{ Execute = $Execute; Arguments = $Argument } } function Get-AgentTask { [pscustomobject]@{ Actions = @( [pscustomobject]@{ Execute = "$porOmision\CloudRestoreAS.exe"; Arguments = '--start-engine --headless' }) } } Sync-AgentTaskPath Assert ($script:reapuntadoA -eq $dest) "reapunta de la carpeta por omision a $dest" Assert ($script:argsPreservados -eq '--start-engine --headless') 'conserva los argumentos originales' $script:reapuntadoA = $null function Get-AgentTask { [pscustomobject]@{ Actions = @( [pscustomobject]@{ Execute = $dest; Arguments = '--start-engine --headless' }) } } Sync-AgentTaskPath Assert ($null -eq $script:reapuntadoA) 'una tarea ya alineada no se toca' # Si no se puede corregir tiene que FALLAR, no arrancar el binario viejo en silencio. function Set-ScheduledTask { param($TaskName, $Action) throw 'Acceso denegado' } function Get-AgentTask { [pscustomobject]@{ Actions = @( [pscustomobject]@{ Execute = "$porOmision\CloudRestoreAS.exe"; Arguments = '' }) } } $lanzo = $false; $msg = '' try { Sync-AgentTaskPath } catch { $lanzo = $true; $msg = $_.Exception.Message } Assert $lanzo 'sin permiso para corregir -> lanza en vez de seguir' Assert ($lanzo -and $msg -match 'sin efecto') 'el mensaje explica que la actualizacion no surtiria efecto' Write-Host '' if ($fallos -gt 0) { Write-Host "FALLOS: $fallos" -ForegroundColor Red; exit 1 } Write-Host 'TODO OK' -ForegroundColor Green