# param ( # [string]$username, # [string]$password # ) Set-StrictMode -Version Latest $ErrorActionPreference = "Stop" # .\agentController.ps1 -username "blake" -password "blake" # config $ServiceName = "LSTV3_app" $AppDir= "C:\Users\matthes01\Documents\lst_v3" $KeepLast = 10 # how many builds do we want to keep. $Servers = @( [PSCustomObject]@{ server = "uslim1vms006" token = "uslim1" loc = "D$\LST_V3" }, [PSCustomObject]@{ server = "usmcd1vms036" token = "test1" loc = "E$\LST_V3" }, [PSCustomObject]@{ server = "usiow1vms036" token = "test2" loc = "E$\LST_V3" } #@{ server = "usmcd1vms036"; token = "test1"; loc = "E$\LST\lst_backend"; } #@{ server = "usiow1vms036"; token = "test1"; loc = "E$\LST\lst_backend"; } #@{ server = "usbet1vms006"; token = "usbet1";loc = "C$\Users\adm_matthes01\Desktop\lst_backend"; } #@{ server = "usbow1vms006"; token = "usbow1"; loc = "C$\Users\adm_matthes01\Desktop\lst_backend" ; } #@{ server = "usbow2vms006"; token = "usbow2"; loc = "C$\Users\adm_matthes01\Desktop\lst_backend" ; } #@{ server = "usday1vms006"; token = "usday1"; loc = "E$\LST\lst_backend" ; } #@{ server = "usflo1vms006"; token = "usflo1"; loc = "C$\Users\adm_matthes01\Desktop\lst_backend" ; } #@{ server = "ushou1vms006"; token = "ushou1"; loc = "C$\Users\adm_matthes01\Desktop\lst_backend" ;} #@{ server = "usiow1vms006"; token = "usiow1"; loc = "C$\Users\adm_matthes01\Desktop\lst_backend" ; } #@{ server = "usiow1vms006"; token = "usiow2"; loc = "D$\lst\lst_backend_2" ; } #@{ server = "usjci1vms006"; token = "usjci1"; loc = "D$\LST\lst_backend" ; } #@{ server = "usksc1vms006"; token = "uskc1"; loc = "C$\Users\adm_matthes01\Desktop\lst_backend" ;} #@{ server = "usmcd1vms006"; token = "usmcd1"; loc = "C$\Users\adm_matthes01\Desktop\lst_backend" ; } #@{ server = "usshe1vms006"; token = "usshe1"; loc = "C$\Users\adm_matthes01\Desktop\lst_backend" ;} #@{ server = "usslc1vms006"; token = "usslc1"; loc = "C$\Users\adm_matthes01\Desktop\lst_backend" ;} #@{ server = "usstp1vms006"; token = "usstp1"; loc = "E$\LST\lst_backend" ; } #@{ server = "usweb1vms006"; token = "usweb1"; loc = "C$\Users\adm_matthes01\Desktop\lst_backend" ;} #@{ server = "usmar1vms006"; token = "test1"; loc = "E$\LST\lst_backend"; } ) #-------------------------------------------------- # below this shouldn't really need to be messed with #-------------------------------------------------- # create the username and password to sign into the server and do the udpate stuff $credFile = Join-Path $AppDir ".scriptCreds" $credData = @{} Get-Content $credFile | ForEach-Object { if ($_ -match "=") { $key, $value = $_ -split "=", 2 $credData[$key.Trim()] = $value.Trim() } } $username = $credData["user"] $password = $credData["password"] $securePass = ConvertTo-SecureString $password -AsPlainText -Force $credentials = New-Object System.Management.Automation.PSCredential($username, $securePass) function Show-Menu { Clear-Host Write-Host "===============================" Write-Host " Deployment Menu " Write-Host "===============================" Write-Host "1. Build app" Write-Host "2. Deploy New Release" Write-Host "3. Upgrade Node" Write-Host "4. Update Postgres" Write-Host "5. Exit" Write-Host "" } function Select-Server { param([object[]]$List) for ($i = 0; $i -lt $List.Count; $i++) { Write-Host ("{0}. {1}" -f ($i+1), $List[$i].server) } Write-Host "$($List.Count + 1) All" Write-Host "$($List.Count + 2) exit" $sel = Read-Host "Select server by number" if ($sel -eq $List.Count + 1) { return "all" } if ($sel -eq $List.Count + 2) { return $null } if ($sel -match '^\d+$' -and [int]$sel -ge 1 -and [int]$sel -le $List.Count) { return $List[[int]$sel - 1] } else { Write-Host "Invalid selection" Read-Host -Prompt "Press Enter to continue..." Select-Server -List $Servers return $null } } function Build-App { try { Push-Location $AppDir Write-Host "Running: npm run build in $AppDir" npm run build Start-Sleep -Seconds 3 Write-Host "Build completed successfully." } catch { Write-Host "Build failed: $_" throw } finally { Pop-Location } } function Zip-App { $BuildNumber = "1" $buildFile = Join-Path $AppDir ".buildNumber" # validate we have a build file and create it if not there if (-Not (Test-Path $buildfile)) { Write-Error "File not found: $buildfile, creating it." New-Item -Path $buildfile -ItemType File | Out-Null $BuildNumber = "1" Set-Content -Path $BuildFile -Value $BuildNumber } #bump the build number if (Test-Path $BuildFile) { $content = Get-Content $BuildFile | Select-Object -First 1 $num = $content.Trim() -as [int] # safe cast if ($num) { $BuildNumber = $num + 1 } else { $BuildNumber = 1 } } $BuildNumber = $BuildNumber.ToString() Set-Content -Path $BuildFile -Value $BuildNumber Write-Output "New Build Number: $BuildNumber" # get the include data $Includes = Join-Path $AppDir ".includes" if (-Not (Test-Path $Includes)) { Write-Error "File not found: $Includes, exiting as we dont want to zip up the entire app." exit 1 } $BuildFolder = Join-Path $AppDir "builds" if (-Not (Test-Path $BuildFolder)) { write-host "Build folder missing creating it" New-Item -Path $BuildFolder -ItemType Directory | Out-Null } # do the zip stuff $itemsToZip = @() Get-Content $Includes | ForEach-Object { $relPath = $_.Trim() if ($relPath -ne "") { $fullPath = Join-Path $AppDir $relPath if (Test-Path $fullPath) { $itemsToZip += [PSCustomObject]@{ FullPath = $fullPath RelativePath = $relPath } } else { Write-Warning "Path not found: $fullPath" } } } if (-Not $itemsToZip) { Write-Warning "No valid files or folders to zip." return } $zipFileName = Join-Path $BuildFolder "LSTV3-$BuildNumber.zip" if (Test-Path $zipFileName) { Remove-Item $zipFileName } $tempFolder = Join-Path $AppDir "temp\zip-temp-$BuildNumber" if (Test-Path $tempFolder) { Remove-Item $tempFolder -Recurse -Force } New-Item -Path $tempFolder -ItemType Directory | Out-Null foreach ($item in $itemsToZip) { $dest = Join-Path $tempFolder $item.RelativePath $destDir = Split-Path $dest if (-Not (Test-Path $destDir)) { New-Item -Path $destDir -ItemType Directory | Out-Null } if ((Get-Item $item.FullPath).PSIsContainer) { Copy-Item -Path $item.FullPath -Destination $dest -Recurse } else { Copy-Item -Path $item.FullPath -Destination $dest } } Compress-Archive -Path (Join-Path $tempFolder "*") -DestinationPath $zipFileName # Cleanup temp folder Remove-Item $tempFolder -Recurse -Force Write-Output "Created zip: $zipFileName" #clean up builds to not get overwhelmed if (Test-Path $BuildFolder) { # Get all zip files in build folder matching pattern $zips = @(Get-ChildItem -Path $BuildFolder -Filter "LSTV3-*.zip" | Sort-Object LastWriteTime -Descending) $toRemove = $zips | Select-Object -Skip $KeepLast foreach ($zip in $toRemove) { Remove-Item $zip.FullName -Force Write-Output "Removed old build: $($zip.Name)" } } } function Update-Server { param ( [string]$Destination, [string]$Server, [string]$Token ) $buildFile = Join-Path $AppDir ".buildNumber" $BuildNumber = 1 $BuildFolder = Join-Path $AppDir "builds" if (Test-Path $BuildFile) { $content = Get-Content $BuildFile | Select-Object -First 1 $num = $content.Trim() -as [int] # safe cast if ($num) { $BuildNumber = $num + 1 } else { $BuildNumber = 1 } } # Get The current Build we have zipped up $BuildNumber = ([int]$BuildNumber - 1).ToString() # copy the latest build over Write-Host "Forcing the removal of the mapped drive." Get-PSDrive -Name "z" -ErrorAction SilentlyContinue | Remove-PSDrive -Force try { New-PSDrive -Name "z" -PSProvider FileSystem -Root "\\$Server\$Destination" -Credential $credentials # Create the update folder if it doesn't exist if (-not (Test-Path -Path "\\$Server\$Destination")) { New-Item -ItemType Directory -Path "\\$Server\$Destination" -Force } # Copying files to the server Write-Host "Copying files to $($Server)" $zipFile = Join-Path $BuildFolder "LSTV3-$BuildNumber.zip" Copy-Item -Path $zipFile -Destination "z:\" -Force Write-Host "Files copied to $($Server)" } catch { Write-Host "Error: $_" } finally { # Remove the mapped drive after copying if (Get-PSDrive -Name "z" -ErrorAction SilentlyContinue) { Write-Host "Removing mapped drive..." Remove-PSDrive -Name "z" } } Write-Host "Updating the app to LSTV3-$BuildNumber.zip" # do the stop services, unzip, and restart service and pool $AppUpdate = { param ($Server, $Token, $Destination, $BuildFile) #convert everything to the server fun $LocalPath = $Destination -replace '\$', ':' $BuildFileLoc = "$LocalPath\$BuildFile" Write-Host "Updating the app to $($BuildFile)" Write-Host "Stopping the services to do the updates, pkgs and db changes." $app_name = "LSTV3_app$(if ($Token -eq "usiow2") { "_2" })" # TODO: add in the iis reset later Write-Host "Stopping $($app_name)" Stop-Service -DisplayName $app_name -Force Start-Sleep -Seconds 1 Write-Host "Unzipping the folder..." try { # Expand the archive Expand-Archive -Path $BuildFileLoc -DestinationPath $LocalPath -Force } catch { Write-Host "Error: $_" exit 1 # Exit with a non-zero code if there's an error } # Delete the zip file after extraction Write-Host "Deleting the zip file..." Remove-Item -Path $BuildFileLoc -Force Start-Sleep -Seconds 1 try { # do the install/update Push-Location $LocalPath Write-Host "Running install/update in: $LocalPath" npm install Start-Sleep -Seconds 3 Write-Host "Install/update completed." # do the migrations Push-Location $LocalPath Write-Host "Running migrations" npm run dev:db:migrate Start-Sleep -Seconds 3 Write-Host "Migrations Completed." } catch { Write-Host "Migration: $_" } finally { Pop-Location } Write-Host "Starting $($app_name)" Start-Service -DisplayName $app_name -ErrorAction Stop Start-Sleep -Seconds 1 } Invoke-Command -ComputerName $Server -ScriptBlock $AppUpdate -ArgumentList $Server, $Token, $Destination, "LSTV3-$BuildNumber.zip" -Credential $credentials } do { Show-Menu $choice = Read-Host "Select an option" switch ($choice) { "1" { Build-App Zip-App Read-Host -Prompt "Press Enter to continue..." } "2" { $server = Select-Server -List $Servers if($server -eq "all") { Write-Host "Updating all servers" for ($i = 0; $i -lt $Servers.Count; $i++) { Write-Host "Updating $($Servers[$i].server)" Update-Server -Server $Servers[$i].server -Destination $Servers[$i].loc -Token $Servers[$i].token Start-Sleep -Seconds 1 } Read-Host -Prompt "Press Enter to continue..." } if ($server -ne "all") { Write-Host "You selected $($server.server)" # do the update to the server. # copy to the server Update-Server -Server $server.server -Destination $server.loc -Token $server.token # stop service # extract zip # run update check # run migration # start service backup Read-Host -Prompt "Press Enter to continue..." } } "3" { Write-Host "Choose Server to upgrade node on" $server = Select-Server -List $Servers if($server -eq "all") { Write-Host "Updating all servers" for ($i = 0; $i -lt $Servers.Count; $i++) { Write-Host "Updating $($Servers[$i].server)" # Update-Server -Server $Servers[$i].server -Destination $Servers[$i].loc -Token $Servers[$i].token Start-Sleep -Seconds 1 } Read-Host -Prompt "Press Enter to continue..." } if ($server -ne "all") { Write-Host "You selected $($server.server)" # Update-Server -Server $server.server -Destination $server.loc -Token $server.token # validate we have a node file to install in the folder # stop service # do update script on the server # delete the .exe file Read-Host -Prompt "Press Enter to continue..." } } "4" { Write-Host "Choose Server to upgrade postgres on" $server = Select-Server -List $Servers if($server -eq "all") { Write-Host "Updating all servers" for ($i = 0; $i -lt $Servers.Count; $i++) { Write-Host "Updating $($Servers[$i].server)" # Update-Server -Server $Servers[$i].server -Destination $Servers[$i].loc -Token $Servers[$i].token Start-Sleep -Seconds 1 } Read-Host -Prompt "Press Enter to continue..." } if ($server -ne "all") { Write-Host "You selected $($server.server)" # Update-Server -Server $server.server -Destination $server.loc -Token $server.token # validate we have a postgres file to install in the folder # stop service # do update script on the server # delete the .exe file Read-Host -Prompt "Press Enter to continue..." } } "5" { Write-Host "Exiting..." exit } default { Write-Host "Invalid selection" Start-Sleep -Seconds 2 } } } while ($choice -ne "3")