AcuInstallerHelper_Versions.ps1
# -------- Version Module Methods -------- # Add-AcuVersion # Get-AcuVersions # Get-InstalledAcuVersions # Remove-AcuVersion # ---------------------------------------- function Add-AcuVersion { param ( [Parameter(Mandatory = $true)] [Alias("v")] [string] $version, [Alias("dt")] [switch] $debuggerTools, [Alias("p")] [switch] $preview ) Write-AcuHeader -Title "Acumatica Version Installation" -Subtitle "Version $version" Write-AcuSection -Title "Validating Version" Test-VersionFormat $version Write-AcuSuccess "Version format validated: $version" # Check if already installed if (Test-AcuVersionPath -versionNbr $version) { $existingPath = Get-AcuVersionPath -versionNbr $version Write-AcuWarning "Version $version already installed at $existingPath" Write-AcuSummary -Operation "Version Installation" -Status "Already Installed" -Details @{ "Version" = $version "Path" = $existingPath } return } Write-AcuSection -Title "Locating Installation Package" # Build download URL $downloadUrl = Get-AcumaticaDownloadUrl -version $version -preview $preview if (!$downloadUrl) { Write-AcuError "No build found for version $version" throw "No build found for version $version" } Write-AcuSuccess "Installation package located: $downloadUrl" # Download and install $tempInstaller = Join-Path $env:TEMP "AcumaticaERPInstall_$version.msi" Write-AcuSection -Title "Downloading and Installing" try { Write-AcuStep "Downloading installer package" -Step 1 -Total 2 Start-BitsTransfer $downloadUrl $tempInstaller Write-AcuSuccess "Download completed successfully" Write-AcuStep "Installing Acumatica version" -Step 2 -Total 2 Install-AcumaticaVersion -installerPath $tempInstaller -version $version -debuggerTools $debuggerTools } finally { if (Test-Path $tempInstaller) { Write-AcuDebug "Cleaning up temporary installer file" Remove-Item $tempInstaller -Force } } Write-AcuSummary -Operation "Version Installation" -Status "Completed Successfully" -Details @{ "Version" = $version "Path" = Get-AcuVersionPath -versionNbr $version "Build Type" = $(if ($preview) { "Preview" } else { "Release" }) "Debug Tools" = $(if ($debuggerTools) { "Included" } else { "Not included" }) } } function Get-AcumaticaDownloadUrl { param ( [string] $version, [bool] $preview ) Write-AcuDebug "Building download URL for version: $version" $majorRelease = $version.Substring(0, 4) if ($majorRelease -match "\.0$") { $majorRelease = $majorRelease -replace "\.0$", ".1" } Write-AcuDebug "Major release determined: $majorRelease" # Try preview first if requested if ($preview) { Write-AcuDebug "Preview build requested, checking preview URLs first" $urls = @( "https://acumatica-builds.s3.amazonaws.com/builds/preview/$majorRelease/$version/AcumaticaERP/AcumaticaERPInstall.msi", "https://acumatica-builds.s3.amazonaws.com/builds/$majorRelease/$version/AcumaticaERP/AcumaticaERPInstall.msi" ) } else { Write-AcuDebug "Release build requested, checking release URLs first" $urls = @( "https://acumatica-builds.s3.amazonaws.com/builds/$majorRelease/$version/AcumaticaERP/AcumaticaERPInstall.msi", "https://acumatica-builds.s3.amazonaws.com/builds/preview/$majorRelease/$version/AcumaticaERP/AcumaticaERPInstall.msi" ) } foreach ($url in $urls) { Write-AcuDebug "Testing URL: $url" if (Test-Url -Url $url) { $isPreview = $url -match "/preview/" Write-AcuDebug "URL accessible, build type: $(if ($isPreview) { 'Preview' } else { 'Release' })" $prompt = if ($preview -and !$isPreview) { "No preview build found. Use normal build?" } elseif (!$preview -and $isPreview) { "No normal build found. Use preview build?" } else { $null } if (!$prompt -or (PromptYesNo $prompt)) { Write-AcuDebug "Selected URL: $url" return $url } } } Write-AcuDebug "No accessible URLs found" return $null } function Install-AcumaticaVersion { param ( [string] $installerPath, [string] $version, [bool] $debuggerTools ) Write-AcuDebug "Starting installation process" $targetDir = Get-AcuVersionPath -versionNbr $version $null = [System.IO.Directory]::CreateDirectory($targetDir) Write-AcuInfo "Installing Acumatica ERP to: $targetDir" $features = "" if ($debuggerTools) { Write-AcuInfo "Including Debugger Tools in installation" $features = "ADDLOCAL=DEBUGGERTOOLS" } $argumentList = "/a `"$installerPath`" $features /qn TARGETDIR=`"$targetDir`" /passive /l `"$targetDir\install.log`"" Write-AcuDebug "MSI arguments: $argumentList" Write-AcuStep "Executing MSI installer" $process = Start-Process -FilePath "msiexec.exe" -ArgumentList $argumentList -Wait -PassThru if ($process.ExitCode -ne 0) { Write-AcuError "Installation failed with exit code: $($process.ExitCode)" Write-AcuDebug "Check installation log at: $targetDir\install.log" throw "Installation failed with exit code $($process.ExitCode). Check log at $targetDir\install.log" } Write-AcuSuccess "MSI installation completed successfully" # Handle nested installation directory $nestedDir = Join-Path $targetDir "Acumatica ERP" if (Test-Path $nestedDir) { Write-AcuStep "Reorganizing installation directory structure" Write-AcuDebug "Moving files from nested directory: $nestedDir" robocopy $nestedDir $targetDir /E /MOVE /NFL /NDL /NJH /NJS Remove-Item $nestedDir -Force -ErrorAction SilentlyContinue Write-AcuSuccess "Directory structure reorganized" } Write-AcuSuccess "Installation completed successfully" } function Get-AcuVersions { param ( [string] $majorRelease, [switch] $preview ) Write-AcuHeader -Title "Available Acumatica Versions" -Subtitle $(if ($preview) { "Preview Builds" } else { "Release Builds" }) Write-AcuSection -Title "Retrieving Version Information" $allVersions = @{} $token = $null $pageCount = 0 do { $pageCount++ Write-AcuStep "Fetching page $pageCount of version data" $result = Get-S3Keys -ContinuationToken $token -Preview:$preview foreach ($key in $result.Keys) { if (!$allVersions.ContainsKey($key.MinorVersion)) { $allVersions[$key.MinorVersion] = $key } } $token = $result.NextToken } while ($token) Write-AcuSuccess "Retrieved $($allVersions.Count) versions" Write-AcuSection -Title "Version List" # Sort and display $sortedVersions = $allVersions.Values | Sort-Object Type, @{Expression = { [Version]($_.MajorVersion -replace '\.', '.0.') } }, @{Expression = { [Version]$_.MinorVersion } } $sortedVersions | Format-Table -AutoSize Write-AcuInfo "Total versions found: $($allVersions.Count)" } function Get-S3Keys { param ( [string] $ContinuationToken, [switch] $Preview ) Write-AcuDebug "Querying S3 for version information" $baseUrl = "http://acumatica-builds.s3.amazonaws.com/?list-type=2" if ($ContinuationToken) { $baseUrl += "&continuation-token=$([System.Web.HttpUtility]::UrlEncode($ContinuationToken))" Write-AcuDebug "Using continuation token" } if ($Preview) { $baseUrl += "&prefix=builds/preview/" Write-AcuDebug "Searching preview builds" } else { Write-AcuDebug "Searching release builds" } try { $response = Invoke-WebRequest -Uri $baseUrl [xml]$xml = $response.Content Write-AcuDebug "Successfully retrieved S3 listing" } catch { Write-AcuError "Failed to retrieve version listing from S3" throw "Failed to retrieve version listing: $_" } $pattern = if ($Preview) { 'builds/preview/(?<major>\d{2}\.\d)/(?<minor>\d{2}\.\d{3}\.\d{4})/AcumaticaERP/AcumaticaERPInstall.msi' } else { 'builds/(?<major>\d{2}\.\d)/(?<minor>\d{2}\.\d{3}\.\d{4})/AcumaticaERP/AcumaticaERPInstall.msi' } $keys = $xml.ListBucketResult.Contents.Key | ForEach-Object { if ($_ -match $pattern) { [PSCustomObject]@{ Type = if ($Preview) { 'preview' } else { 'release' } MajorVersion = $matches['major'] MinorVersion = $matches['minor'] } } } Write-AcuDebug "Parsed $($keys.Count) version entries from current page" @{ Keys = $keys NextToken = $xml.ListBucketResult.NextContinuationToken } } function Get-InstalledAcuVersions { Write-AcuHeader -Title "Installed Acumatica Versions" Write-AcuSection -Title "Scanning Installation Directory" $versionDir = Join-Path (Get-AcuDir) (Get-AcuVersionDir) if (!(Test-Path $versionDir)) { Write-AcuWarning "Version directory not found: $versionDir" Write-AcuInfo "No versions are currently installed" return } Write-AcuDebug "Scanning directory: $versionDir" $installedVersions = Get-ChildItem -Directory -Path $versionDir if ($installedVersions.Count -eq 0) { Write-AcuInfo "No versions are currently installed" return } Write-AcuSuccess "Found $($installedVersions.Count) installed versions" Write-AcuSection -Title "Version Details" $versionDetails = $installedVersions | Select-Object @{L = 'Installed Version'; E = { $_.Name } }, @{L = 'Install Date'; E = { $_.CreationTime } }, @{L = 'Size (GB)'; E = { [math]::Round((Get-ChildItem $_.FullName -Recurse | Measure-Object -Property Length -Sum).Sum / 1GB, 2) } } $versionDetails | Format-Table -AutoSize $totalSize = ($versionDetails | Measure-Object -Property "Size (GB)" -Sum).Sum Write-AcuInfo "Total disk space used: $([math]::Round($totalSize, 2)) GB" } function Remove-AcuVersion { param ( [Parameter(Mandatory = $true)] [string] $version ) Write-AcuHeader -Title "Acumatica Version Removal" -Subtitle "Version: $version" Write-AcuSection -Title "Validating Version" Test-VersionFormat -version $version Write-AcuSuccess "Version format validated: $version" $versionPath = Get-AcuVersionPath -versionNbr $version if (!(Test-Path $versionPath)) { Write-AcuError "Version $version not found at: $versionPath" Write-AcuInfo "Use Get-InstalledAcuVersions to see available versions" return } Write-AcuSuccess "Version found at: $versionPath" # Calculate size before removal $sizeGB = [math]::Round((Get-ChildItem $versionPath -Recurse | Measure-Object -Property Length -Sum).Sum / 1GB, 2) Write-AcuTable -Data @{ "Version" = $version "Path" = $versionPath "Size" = "$sizeGB GB" } -Title "Version to Remove" Write-AcuSection -Title "Confirmation" if (PromptYesNo "Are you sure you want to remove version $version?") { Write-AcuStep "Removing version files" try { Remove-Item -Recurse -Force $versionPath Write-AcuSuccess "Version files removed successfully" Write-AcuSummary -Operation "Version Removal" -Status "Completed Successfully" -Details @{ "Version" = $version "Space Freed" = "$sizeGB GB" } } catch { Write-AcuError "Failed to remove version files: $_" throw } } else { Write-AcuInfo "Version removal cancelled by user" } } |