From 5aba16a3cbe653ab1e08734f15ea3f146f47832e Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 23 Jan 2023 16:50:29 +0000 Subject: [PATCH 01/61] 2022.3 updated install path --- powershell/Install-Alteryx.ps1 | 10 +++++----- powershell/Uninstall-Alteryx.ps1 | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/powershell/Install-Alteryx.ps1 b/powershell/Install-Alteryx.ps1 index 3e63892..26a19ca 100644 --- a/powershell/Install-Alteryx.ps1 +++ b/powershell/Install-Alteryx.ps1 @@ -16,7 +16,7 @@ function Install-Alteryx { File name: Install-Alteryx.ps1 Author: Florian Carrier Creation date: 2021-07-05 - Last modified: 2022-04-19 + Last modified: 2023-01-17 .LINK https://www.powershellgallery.com/packages/PSAYX @@ -96,15 +96,15 @@ function Install-Alteryx { if ($Properties.InstallAwareLog -eq $true) { $InstallAwareLog = Join-Path -Path $Properties.LogDirectory -ChildPath "${ISOTimeStamp}_${ServerFileName}.log" if ($null -eq $Properties.LicenseEmail -Or $Properties.LicenseEmail -eq "") { - $ServerInstall = Install-AlteryxServer -Path $ServerPath -InstallDirectory $Properties.InstallationPath -Log $InstallAwareLog -Language $Properties.Language -AllUsers -Unattended:$Unattended + $ServerInstall = Install-AlteryxServer -Path $ServerPath -InstallDirectory $Properties.InstallationPath -Log $InstallAwareLog -Language $Properties.Language -Version $Properties.Version -AllUsers -Unattended:$Unattended } else { - $ServerInstall = Install-AlteryxServer -Path $ServerPath -InstallDirectory $Properties.InstallationPath -Log $InstallAwareLog -Serial $Properties.LicenseEmail -Language $Properties.Language -AllUsers -Unattended:$Unattended + $ServerInstall = Install-AlteryxServer -Path $ServerPath -InstallDirectory $Properties.InstallationPath -Log $InstallAwareLog -Serial $Properties.LicenseEmail -Language $Properties.Language -Version $Properties.Version -AllUsers -Unattended:$Unattended } } else { if ($null -eq $Properties.LicenseEmail -Or $Properties.LicenseEmail -eq "") { - $ServerInstall = Install-AlteryxServer -Path $ServerPath -InstallDirectory $Properties.InstallationPath -Language $Properties.Language -AllUsers -Unattended:$Unattended + $ServerInstall = Install-AlteryxServer -Path $ServerPath -InstallDirectory $Properties.InstallationPath -Language $Properties.Language -Version $Properties.Version -AllUsers -Unattended:$Unattended } else { - $ServerInstall = Install-AlteryxServer -Path $ServerPath -InstallDirectory $Properties.InstallationPath -Serial $Properties.LicenseEmail -Language $Properties.Language -AllUsers -Unattended:$Unattended + $ServerInstall = Install-AlteryxServer -Path $ServerPath -InstallDirectory $Properties.InstallationPath -Serial $Properties.LicenseEmail -Language $Properties.Language -Version $Properties.Version -AllUsers -Unattended:$Unattended } } Write-Log -Type "DEBUG" -Message $ServerInstall diff --git a/powershell/Uninstall-Alteryx.ps1 b/powershell/Uninstall-Alteryx.ps1 index 215cb9f..ad046e0 100644 --- a/powershell/Uninstall-Alteryx.ps1 +++ b/powershell/Uninstall-Alteryx.ps1 @@ -16,7 +16,7 @@ function Uninstall-Alteryx { File name: Uninstall-Alteryx.ps1 Author: Florian Carrier Creation date: 2021-07-08 - Last modified: 2022-04-19 + Last modified: 2023-01-17 .LINK https://www.powershellgallery.com/packages/PSAYX @@ -85,9 +85,9 @@ function Uninstall-Alteryx { if (Test-Path -Path $ServerPath) { if ($Properties.InstallAwareLog -eq $true) { $InstallAwareLog = Join-Path -Path $Properties.LogDirectory -ChildPath "${ISOTimeStamp}_${ServerFileName}.log" - $ServerUninstall = Uninstall-AlteryxServer -Path $ServerPath -Log $InstallAwareLog -Unattended:$Unattended + $ServerUninstall = Uninstall-AlteryxServer -Path $ServerPath -Version $Properties.Version -Log $InstallAwareLog -Unattended:$Unattended } else { - $ServerUninstall = Uninstall-AlteryxServer -Path $ServerPath -Unattended:$Unattended + $ServerUninstall = Uninstall-AlteryxServer -Path $ServerPath -Version $Properties.Version -Unattended:$Unattended } Write-Log -Type "DEBUG" -Message $ServerUninstall if ($ServerUninstall.ExitCode -eq 0) { From 764b671cb9a000fe520f93d08ef1bb48d2d8de1f Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 23 Jan 2023 16:51:45 +0000 Subject: [PATCH 02/61] SSL configuration setup --- conf/default.ini | 10 +++++++--- conf/ssl.ini | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 conf/ssl.ini diff --git a/conf/default.ini b/conf/default.ini index bbd5066..95f2a25 100644 --- a/conf/default.ini +++ b/conf/default.ini @@ -35,9 +35,7 @@ InstallationOptions = install.ini # Installation language Language = English # Version -Version = 2021.4.2.02731 -# SSL/TLS -EnableSSL = false +Version = 2022.1.1.25127 # InstallAware log InstallAwareLog = false # Activate Alteryx during installation @@ -53,6 +51,12 @@ LicenseFile = # License email LicenseEmail = +[SSL] +# SSL/TLS +EnableSSL = true +# Application ID +ApplicationID = {eea9431a-a3d4-4c9b-9f9a-b83916c11c67} + [Ports] HTTPPort = 80 HTTPSPort = 443 diff --git a/conf/ssl.ini b/conf/ssl.ini new file mode 100644 index 0000000..e48846e --- /dev/null +++ b/conf/ssl.ini @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------------------ +# SSL/TLS self-signed certificate attributes +# ------------------------------------------------------------------------------ + +# Organisation (O) +Organisation = +# Organizational Unit (OU) +# Country (C) +Country = +# State (S) +State = +# Locality (L) +Locality = +# Common Name (CN) +CommonName = +# Email address +EmailAddress = +# Certificate friendly name +FriendlyName = Alteryx Server \ No newline at end of file From 3e57f3032942c3f1cfe5b81f6f21dd2ac8623837 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 23 Jan 2023 16:52:04 +0000 Subject: [PATCH 03/61] Additional functions --- powershell/Invoke-PatchAlteryx.ps1 | 104 +++++++++++++++++++++++++++++ powershell/Set-Configuration.ps1 | 42 ++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 powershell/Invoke-PatchAlteryx.ps1 create mode 100644 powershell/Set-Configuration.ps1 diff --git a/powershell/Invoke-PatchAlteryx.ps1 b/powershell/Invoke-PatchAlteryx.ps1 new file mode 100644 index 0000000..c8182f0 --- /dev/null +++ b/powershell/Invoke-PatchAlteryx.ps1 @@ -0,0 +1,104 @@ +function Invoke-PatchAlteryx { + <# + .SYNOPSIS + Install Alteryx patch + + .DESCRIPTION + Perform a patch upgrade to Alteryx + + .NOTES + File name: Invoke-PatchAlteryx.ps1 + Author: Florian Carrier + Creation date: 2022-06-29 + Last modified: 2022-06-29 + #> + [CmdletBinding ( + SupportsShouldProcess = $true + )] + Param ( + [Parameter ( + Position = 1, + Mandatory = $true, + HelpMessage = "Properties" + )] + [ValidateNotNullOrEmpty ()] + [System.Collections.Specialized.OrderedDictionary] + $Properties, + [Parameter ( + HelpMessage = "Non-interactive mode" + )] + [Switch] + $Unattended + ) + Begin { + # Get global preference vrariables + Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState + # Log function call + Write-Log -Type "DEBUG" -Message $MyInvocation.ScriptName + # Variables + $ISOTimeStamp = Get-Date -Format "yyyyMMdd_HHmmss" + $Tags = [Ordered]@{"Version" = $Properties.Version} + # Filenames + if ($InstallationProperties.Product -eq "Designer") { + $PatchInstaller = "AlteryxPatchInstall_.exe" + } else { + $PatchInstaller = "AlteryxServerPatchInstall_.exe" + } + # Unattended execution arguments + if ($Unattended) { + $Arguments = "/s" + } else { + $Arguments = "" + } + } + Process { + Write-Log -Type "INFO" -Message "Installation of Alteryx $($InstallationProperties.Product) patch $($Properties.Version)" + if ($InstallationProperties.Product -eq "Designer" -Or $InstallationProperties.Server -eq $true) { + # Update file version number + $PatchFileName = Set-Tags -String $PatchInstaller -Tags (Resolve-Tags -Tags $Tags -Prefix "<" -Suffix ">") + $PatchPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $PatchFileName + if ($PSCmdlet.ShouldProcess($PatchPath, "Install")) { + if (Test-Path -Path $PatchPath) { + # Stop Alteryx Service + Write-Log -Type "INFO" -Message "Check Alteryx Service status" + if ($PSCmdlet.ShouldProcess("Alteryx Service", "Stop")) { + $Service = "AlteryxService" + if (Test-Service -Name $Service) { + $WindowsService = Get-Service -Name $Service + Write-Log -Type "DEBUG" -Message $Service + $ServiceStatus = $WindowsService.Status + if ($ServiceStatus -eq "Running") { + Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended + } + } else { + Write-Log -Type "ERROR" -Message "Alteryx Service ($Service) could not be found" -ExitCode 1 + } + } + if ($Properties.InstallAwareLog -eq $true) { + $InstallAwareLog = Join-Path -Path $Properties.LogDirectory -ChildPath "${ISOTimeStamp}_${PatchFileName}.log" + $PatchInstall = Install-AlteryxServer -Path $PatchPath -InstallDirectory $Properties.InstallationPath -Log $InstallAwareLog -Language $Properties.Language -AllUsers -Unattended:$Unattended + } else { + $PatchInstall = Install-AlteryxServer -Path $PatchPath -InstallDirectory $Properties.InstallationPath -Language $Properties.Language -AllUsers -Unattended:$Unattended + } + Write-Log -Type "DEBUG" -Message $PatchInstall + if ($PatchInstall.ExitCode -eq 0) { + Write-Log -Type "CHECK" -Message "Alteryx $($InstallationProperties.Product) patched successfully" + } else { + Write-Log -Type "ERROR" -Message "An error occured during the patch installation" -ExitCode $PatchInstall.ExitCode + } + # TODO check registry for version and installinfo configuration file + } else { + Write-Log -Type "ERROR" -Message "Path not found $PatchPath" + Write-Log -Type "ERROR" -Message "Alteryx $($InstallationProperties.Product) patch file could not be located" + Write-Log -Type "WARN" -Message "Alteryx patch installation failed" -ExitCode 1 + } + # Restart service if it was running before + if ($ServiceStatus -eq "Running") { + Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended + } + } + } else { + Write-Log -Type "ERROR" -Message "Designer or Server products must be enabled for a patch upgrade" -ExitCode 0 + } + } +} \ No newline at end of file diff --git a/powershell/Set-Configuration.ps1 b/powershell/Set-Configuration.ps1 new file mode 100644 index 0000000..439fb23 --- /dev/null +++ b/powershell/Set-Configuration.ps1 @@ -0,0 +1,42 @@ +function Set-Configuration { + <# + .SYNOPSIS + Configure Alteryx Server + + .DESCRIPTION + Set Alteryx Server configuration + + .NOTES + File name: Set-Configuration.ps1 + Author: Florian Carrier + Creation date: 2022-05-03 + Last modified: 2022-05-03 + #> + [CmdletBinding ()] + Param ( + [Parameter ( + Position = 1, + Mandatory = $true, + HelpMessage = "Script properties" + )] + [ValidateNotNullOrEmpty ()] + [System.Collections.Specialized.OrderedDictionary] + $Properties, + [Parameter ( + Position = 2, + Mandatory = $true, + HelpMessage = "Installation properties" + )] + [ValidateNotNullOrEmpty ()] + [System.Collections.Specialized.OrderedDictionary] + $InstallationProperties + ) + Begin { + # Get global preference vrariables + Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState + + } + Process { + + } +} \ No newline at end of file From 24df7435608fc86aa12f934d37717d944a38cbc3 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 23 Jan 2023 17:00:35 +0000 Subject: [PATCH 04/61] Update Invoke-PatchAlteryx.ps1 --- powershell/Invoke-PatchAlteryx.ps1 | 97 ++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/powershell/Invoke-PatchAlteryx.ps1 b/powershell/Invoke-PatchAlteryx.ps1 index 28b40bb..cce783d 100644 --- a/powershell/Invoke-PatchAlteryx.ps1 +++ b/powershell/Invoke-PatchAlteryx.ps1 @@ -12,3 +12,100 @@ function Invoke-PatchAlteryx { .DESCRIPTION Perform a patch upgrade to Alteryx + + .NOTES + File name: Invoke-PatchAlteryx.ps1 + Author: Florian Carrier + Creation date: 2022-06-29 + Last modified: 2022-06-29 + #> + [CmdletBinding ( + SupportsShouldProcess = $true + )] + Param ( + [Parameter ( + Position = 1, + Mandatory = $true, + HelpMessage = "Properties" + )] + [ValidateNotNullOrEmpty ()] + [System.Collections.Specialized.OrderedDictionary] + $Properties, + [Parameter ( + HelpMessage = "Non-interactive mode" + )] + [Switch] + $Unattended + ) + Begin { + # Get global preference vrariables + Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState + # Log function call + Write-Log -Type "DEBUG" -Message $MyInvocation.ScriptName + # Variables + $ISOTimeStamp = Get-Date -Format "yyyyMMdd_HHmmss" + $Tags = [Ordered]@{"Version" = $Properties.Version} + # Filenames + if ($InstallationProperties.Product -eq "Designer") { + $PatchInstaller = "AlteryxPatchInstall_.exe" + } else { + $PatchInstaller = "AlteryxServerPatchInstall_.exe" + } + # Unattended execution arguments + if ($Unattended) { + $Arguments = "/s" + } else { + $Arguments = "" + } + } + Process { + Write-Log -Type "INFO" -Message "Installation of Alteryx $($InstallationProperties.Product) patch $($Properties.Version)" + if ($InstallationProperties.Product -eq "Designer" -Or $InstallationProperties.Server -eq $true) { + # Update file version number + $PatchFileName = Set-Tags -String $PatchInstaller -Tags (Resolve-Tags -Tags $Tags -Prefix "<" -Suffix ">") + $PatchPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $PatchFileName + if ($PSCmdlet.ShouldProcess($PatchPath, "Install")) { + if (Test-Path -Path $PatchPath) { + # Stop Alteryx Service + Write-Log -Type "INFO" -Message "Check Alteryx Service status" + if ($PSCmdlet.ShouldProcess("Alteryx Service", "Stop")) { + $Service = "AlteryxService" + if (Test-Service -Name $Service) { + $WindowsService = Get-Service -Name $Service + Write-Log -Type "DEBUG" -Message $Service + $ServiceStatus = $WindowsService.Status + if ($ServiceStatus -eq "Running") { + Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended + } + } else { + Write-Log -Type "ERROR" -Message "Alteryx Service ($Service) could not be found" -ExitCode 1 + } + } + if ($Properties.InstallAwareLog -eq $true) { + $InstallAwareLog = Join-Path -Path $Properties.LogDirectory -ChildPath "${ISOTimeStamp}_${PatchFileName}.log" + $PatchInstall = Install-AlteryxServer -Path $PatchPath -InstallDirectory $Properties.InstallationPath -Log $InstallAwareLog -Language $Properties.Language -AllUsers -Unattended:$Unattended + } else { + $PatchInstall = Install-AlteryxServer -Path $PatchPath -InstallDirectory $Properties.InstallationPath -Language $Properties.Language -AllUsers -Unattended:$Unattended + } + Write-Log -Type "DEBUG" -Message $PatchInstall + if ($PatchInstall.ExitCode -eq 0) { + Write-Log -Type "CHECK" -Message "Alteryx $($InstallationProperties.Product) patched successfully" + } else { + Write-Log -Type "ERROR" -Message "An error occured during the patch installation" -ExitCode $PatchInstall.ExitCode + } + # TODO check registry for version and installinfo configuration file + } else { + Write-Log -Type "ERROR" -Message "Path not found $PatchPath" + Write-Log -Type "ERROR" -Message "Alteryx $($InstallationProperties.Product) patch file could not be located" + Write-Log -Type "WARN" -Message "Alteryx patch installation failed" -ExitCode 1 + } + # Restart service if it was running before + if ($ServiceStatus -eq "Running") { + Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended + } + } + } else { + Write-Log -Type "ERROR" -Message "Designer or Server products must be enabled for a patch upgrade" -ExitCode 0 + } + } +} \ No newline at end of file From ebd52783a7a65a73a629c07e22822b657c07fbc0 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 12 Feb 2024 09:45:54 +0100 Subject: [PATCH 05/61] Update copyright --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index a076baf..e5e82ff 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 Florian CARRIER +Copyright (c) 2021-2024 Florian CARRIER Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 716d6336589267c16b162d8b8d1fccdc942ada13 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 12 Feb 2024 09:47:13 +0100 Subject: [PATCH 06/61] Add exception handling for invalid filenames --- powershell/Install-Alteryx.ps1 | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/powershell/Install-Alteryx.ps1 b/powershell/Install-Alteryx.ps1 index 26a19ca..5080563 100644 --- a/powershell/Install-Alteryx.ps1 +++ b/powershell/Install-Alteryx.ps1 @@ -16,7 +16,7 @@ function Install-Alteryx { File name: Install-Alteryx.ps1 Author: Florian Carrier Creation date: 2021-07-05 - Last modified: 2023-01-17 + Last modified: 2023-05-23 .LINK https://www.powershellgallery.com/packages/PSAYX @@ -85,10 +85,18 @@ function Install-Alteryx { $ServerFileName = Set-Tags -String $ServerInstaller -Tags (Resolve-Tags -Tags $Tags -Prefix "<" -Suffix ">") $ServerPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $ServerFileName if (Test-Object -Path $ServerPath -NotFound) { + $DefaultServerPath = $ServerPath # Workaround for files not following naming convention due to duplicate pipeline runs $Workaround = [Ordered]@{"Version" = [System.String]::Concat($Properties.Version, "_1")} $ServerFileName = Set-Tags -String $ServerInstaller -Tags (Resolve-Tags -Tags $Workaround -Prefix "<" -Suffix ">") $ServerPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $ServerFileName + if (Test-Object -Path $ServerPath -NotFound) { + Write-Log -Type "ERROR" -Message "Path not found $DefaultServerPath" + Write-Log -Type "ERROR" -Message "Alteryx $($InstallationProperties.Product) installation file could not be located" + Write-Log -Type "WARN" -Message "Alteryx installation failed" -ExitCode 1 + } else { + Write-Log -Type "DEBUG" -Message "Path not found $DefaultServerPath" + } } Write-Log -Type "INFO" -Message "Installing Alteryx $($InstallationProperties.Product)" if ($PSCmdlet.ShouldProcess($ServerPath, "Install")) { From e235c815cda1c8caac6cadc86939cfc7daf2cdf2 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Thu, 22 Aug 2024 18:04:25 +0200 Subject: [PATCH 07/61] Add repair function Add repair function and improve backup & restore --- Deploy-Alteryx.ps1 | 28 +++++++++++++++++++++++++--- powershell/Invoke-BackupAlteryx.ps1 | 7 ++++--- powershell/Invoke-RestoreAlteryx.ps1 | 11 ++++++++--- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/Deploy-Alteryx.ps1 b/Deploy-Alteryx.ps1 index 92fab22..fc0ee65 100644 --- a/Deploy-Alteryx.ps1 +++ b/Deploy-Alteryx.ps1 @@ -6,12 +6,12 @@ Deploy Alteryx .DESCRIPTION - Deploy and configure Alteryx + Deploy and configure Alteryx on the current machine .PARAMETER Action The action parameter corresponds to the operation to perform. - Eleven options are available: + Fourteen options are available: - activate: activate the Alteryx application license - backup: backup the Alteryx application database @@ -20,6 +20,7 @@ - install: install the Alteryx application - repair: repair the Alteryx application database - patch: patch upgrade the Alteryx application + - repair: repair the Alteryx application database - restart: restart the Alteryx application - restore: restore a backup of the Alteryx application database - show: display the script configuration @@ -35,7 +36,7 @@ File name: Deploy-Alteryx.ps1 Author: Florian Carrier Creation date: 2021-06-13 - Last modified: 2022-11-25 + Last modified: 2024-02-12 Dependencies: - PowerShell Tool Kit (PSTK) - Alteryx PowerShell Module (PSAYX) @@ -70,6 +71,7 @@ Param ( "deactivate", "install", "patch", + "repair", "restart", "restore", "show", @@ -219,6 +221,25 @@ Begin { Sync-EnvironmentVariable -Name $EnvironmentVariable -Scope $Properties.EnvironmentVariableScope | Out-Null } + # Check installation path + if ($Properties.InstallationPath -eq "") { + if ($Unattended -eq $false) { + do { + Write-Log -Type "WARN" -Message "Path not found $($Properties.InstallationPath)" + $Properties.InstallationPath = Read-Host -Prompt "Please enter the Alteryx installation path" + } until (Test-Object -Path $Properties.InstallationPath) + } else { + if ($Action -ne "install") { + # Retrieve path from registry + $Properties.InstallationPath = Get-AlteryxInstallDirectory + } else { + Write-Log -Type "ERROR" -Message "No Alteryx installation path has been provided" -ExitCode 1 + } + } + } elseif (Test-Object -Path $Properties.InstallationPath -NotFound) { + New-Item -Path $Properties.InstallationPath -ItemType "Directory" -Force | Out-Null + } + # ---------------------------------------------------------------------------- # * Options # ---------------------------------------------------------------------------- @@ -256,6 +277,7 @@ Process { "install" { Install-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } "repair" { Repair-Alteryx -Properties $Properties -Unattended:$Unattended } "patch" { Invoke-PatchAlteryx -Properties $Properties -Unattended:$Unattended } + "repair" { Repair-Alteryx -Properties $Properties -Unattended:$Unattended } "restart" { Invoke-RestartAlteryx -Properties $Properties -Unattended:$Unattended } "restore" { Invoke-RestoreAlteryx -Properties $Properties -Unattended:$Unattended } "show" { Show-Configuration -Properties $Properties -InstallationProperties $InstallationProperties } diff --git a/powershell/Invoke-BackupAlteryx.ps1 b/powershell/Invoke-BackupAlteryx.ps1 index 6b72518..88e9a8c 100644 --- a/powershell/Invoke-BackupAlteryx.ps1 +++ b/powershell/Invoke-BackupAlteryx.ps1 @@ -10,7 +10,7 @@ function Invoke-BackupAlteryx { File name: Invoke-BackupAlteryx.ps1 Author: Florian Carrier Creation date: 2021-08-26 - Last modified: 2022-04-19 + Last modified: 2024-03-26 #> [CmdletBinding ( SupportsShouldProcess = $true @@ -36,9 +36,10 @@ function Invoke-BackupAlteryx { # Log function call Write-Log -Type "DEBUG" -Message $MyInvocation.ScriptName # Variables + $Version = Get-AlteryxRegistryVersion $ISOTimeStamp = Get-Date -Format "yyyyMMdd_HHmmss" - $BackupPath = Join-Path -Path $Properties.BackupDirectory -ChildPath "${ISOTimeStamp}_Alteryx_Server_$($Properties.Version).zip" - $TempBackupPath = Join-Path -Path $Properties.TempDirectory -ChildPath "${ISOTimeStamp}_Alteryx_Server_$($Properties.Version)" + $BackupPath = Join-Path -Path $Properties.BackupDirectory -ChildPath "${ISOTimeStamp}_Alteryx_Server_$($Version).zip" + $TempBackupPath = Join-Path -Path $Properties.TempDirectory -ChildPath "${ISOTimeStamp}_Alteryx_Server_$($Version)" $MongoDBPath = Join-Path -Path $TempBackupPath -ChildPath "MongoDB" $ServicePath = Join-Path -Path $Properties.InstallationPath -ChildPath "bin\AlteryxService.exe" # Backup options diff --git a/powershell/Invoke-RestoreAlteryx.ps1 b/powershell/Invoke-RestoreAlteryx.ps1 index af91c12..dfbe657 100644 --- a/powershell/Invoke-RestoreAlteryx.ps1 +++ b/powershell/Invoke-RestoreAlteryx.ps1 @@ -88,11 +88,10 @@ function Invoke-RestoreAlteryx { # Check source backup path if ($PSCmdlet.ShouldProcess("Backup files", "Retrieve")) { if ($null -eq (Get-KeyValue -Hashtable $Properties -Key "BackupPath" -Silent)) { - $SourcePath = $Properties.BackupDirectory - } else { + # If no path is specified revert to backup repository $SourcePath = $Properties.BackupPath } - if (Test-Object -Path $SourcePath) { + elseif (Test-Object -Path $SourcePath) { if ($SourcePath -is [System.IO.FileInfo]) { if ([System.IO.Path]::GetExtension($SourcePath) -eq ".zip") { # Extract archive file @@ -106,6 +105,12 @@ function Invoke-RestoreAlteryx { } else { # Select most recent backup in the directory Write-Log -Type "WARN" -Message "No backup file was specified" + if ($Unattended -eq $false) { + $Confirmation = Confirm-Prompt -Prompt "Do you want to fetch the latest backup file?" + if ($Confirmation -eq $false) { + Write-Log -Type "WARN" -Message "Restore operation cancelled by user" -ExitCode 0 + } + } Write-Log -Type "DEBUG" -Message $SourcePath Write-Log -Type "INFO" -Message "Retrieving most recent backup" $BackupFile = (Get-Object -Path $SourcePath -ChildItem -Type "File" -Filter "*.zip" | Sort-Object -Descending -Property "LastWriteTime" | Select-Object -First 1).FullName From c16917bfa10cb719934c7e594c812b3e649e140a Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Wed, 11 Sep 2024 15:12:50 +0200 Subject: [PATCH 08/61] Add download function Add new function to download release from Alteryx license portal --- Deploy-Alteryx.ps1 | 71 ++++++++++----- conf/default.ini | 8 +- powershell/Invoke-DownloadAlteryx.ps1 | 119 ++++++++++++++++++++++++++ 3 files changed, 174 insertions(+), 24 deletions(-) create mode 100644 powershell/Invoke-DownloadAlteryx.ps1 diff --git a/Deploy-Alteryx.ps1 b/Deploy-Alteryx.ps1 index fc0ee65..09ca7b5 100644 --- a/Deploy-Alteryx.ps1 +++ b/Deploy-Alteryx.ps1 @@ -11,12 +11,13 @@ .PARAMETER Action The action parameter corresponds to the operation to perform. - Fourteen options are available: + Fifteen options are available: - activate: activate the Alteryx application license - backup: backup the Alteryx application database - configure: configure the Alteryx application - deactivate: deactivate the Alteryx application license + - download: download latest Alteryx application release - install: install the Alteryx application - repair: repair the Alteryx application database - patch: patch upgrade the Alteryx application @@ -36,7 +37,7 @@ File name: Deploy-Alteryx.ps1 Author: Florian Carrier Creation date: 2021-06-13 - Last modified: 2024-02-12 + Last modified: 2024-09-11 Dependencies: - PowerShell Tool Kit (PSTK) - Alteryx PowerShell Module (PSAYX) @@ -65,6 +66,7 @@ Param ( "activate", "backup", "deactivate", + "download", "install", "repair", "configure", @@ -153,8 +155,8 @@ Begin { # ---------------------------------------------------------------------------- # Dependencies $Modules = [Ordered]@{ - "PSTK" = "1.2.4" - "PSAYX" = "1.0.1" + "PSTK" = "1.2.6" + "PSAYX" = "1.0.4" } # Load modules foreach ($Module in $Modules.GetEnumerator()) { @@ -197,7 +199,8 @@ Begin { # ------------------------------------------------------------------------------ # Ensure shell is running as 64 bit process if ([Environment]::Is64BitProcess -eq $false) { - Write-Log -Type "ERROR" -Message "PowerShell is running as a 32-bit process" -ExitCode 1 + Write-Log -Type "ERROR" -Message "PowerShell is running as a 32-bit process" + Write-Log -Type "INFO" -Message "Please run PowerShell as a 64-bit process" -ExitCode 1 } # ---------------------------------------------------------------------------- @@ -270,26 +273,48 @@ Begin { Process { # Check operation to perform switch ($Action) { - "activate" { Invoke-ActivateAlteryx -Properties $Properties -Unattended:$Unattended } - "backup" { Invoke-BackupAlteryx -Properties $Properties -Unattended:$Unattended } - "configure" { Set-Configuration -Properties $Properties -Unattended:$Unattended } - "deactivate" { Invoke-DeactivateAlteryx -Properties $Properties -Unattended:$Unattended } - "install" { Install-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } - "repair" { Repair-Alteryx -Properties $Properties -Unattended:$Unattended } - "patch" { Invoke-PatchAlteryx -Properties $Properties -Unattended:$Unattended } - "repair" { Repair-Alteryx -Properties $Properties -Unattended:$Unattended } - "restart" { Invoke-RestartAlteryx -Properties $Properties -Unattended:$Unattended } - "restore" { Invoke-RestoreAlteryx -Properties $Properties -Unattended:$Unattended } - "show" { Show-Configuration -Properties $Properties -InstallationProperties $InstallationProperties } - "start" { Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended } - "stop" { Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended } - "uninstall" { Uninstall-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } - "upgrade" { Update-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } - default { Write-Log -Type "ERROR" -Message """$Action"" operation is not supported" -ExitCode 1 } + "activate" { $Process = Invoke-ActivateAlteryx -Properties $Properties -Unattended:$Unattended } + "backup" { $Process = Invoke-BackupAlteryx -Properties $Properties -Unattended:$Unattended } + "configure" { $Process = Set-Configuration -Properties $Properties -Unattended:$Unattended } + "deactivate" { $Process = Invoke-DeactivateAlteryx -Properties $Properties -Unattended:$Unattended } + "download" { $Process = Invoke-DownloadAlteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } + "install" { $Process = Install-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } + "repair" { $Process = Repair-Alteryx -Properties $Properties -Unattended:$Unattended } + "patch" { $Process = Invoke-PatchAlteryx -Properties $Properties -Unattended:$Unattended } + "repair" { $Process = Repair-Alteryx -Properties $Properties -Unattended:$Unattended } + "restart" { $Process = Invoke-RestartAlteryx -Properties $Properties -Unattended:$Unattended } + "restore" { $Process = Invoke-RestoreAlteryx -Properties $Properties -Unattended:$Unattended } + "show" { $Process = Show-Configuration -Properties $Properties -InstallationProperties $InstallationProperties } + "start" { $Process = Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended } + "stop" { $Process = Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended } + "uninstall" { $Process = Uninstall-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } + "upgrade" { $Process = Update-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } + default { Write-Log -Type "ERROR" -Message """$Action"" operation is not supported" -ExitCode 1 } } } End { - # Stop script and transcript - Stop-Script -ExitCode 0 + # Check outcome and gracefully end script + Write-Log -Type "DEBUG" -Message ($Process | Format-Table) + if ($Process.Success -And ($Process.Status -eq "Completed")) { + Write-Log -Type "CHECK" -Message "Alteryx $Action process completed successfully" -ExitCode $Process.ExitCode + } else { + if ($Process.ErrorCount -gt 0) { + if ($Process.ErrorCount -gt 1) { + $Errors = "with $($Process.ErrorCount) errors" + } else { + $Errors = "with $($Process.ErrorCount) error" + } + } else { + $Errors = "" + } + switch ($Process.Status) { + "Cancelled" { $Outcome = "was cancelled" } + "Completed" { $Outcome = "completed" } + "Failed" { $Outcome = "failed" } + "Stopped" { $Outcome = "was stopped" } + default { $Outcome = "failed" } + } + Write-Log -Type "ERROR" -Message "Alteryx $Action process $Outcome $Errors" -ExitCode $Process.ExitCode + } } \ No newline at end of file diff --git a/conf/default.ini b/conf/default.ini index 860a998..3369862 100644 --- a/conf/default.ini +++ b/conf/default.ini @@ -35,7 +35,9 @@ InstallationOptions = install.ini # Installation language Language = English # Version -Version = 2022.1.1.25127 +Version = 2024.1.1.136 +# Service name +ServiceName = AlteryxService # InstallAware log InstallAwareLog = false # Activate Alteryx during installation @@ -50,6 +52,10 @@ LicensingURL = whitelist.alteryx.com LicenseFile = # License email LicenseEmail = +# License Account ID +LicenseAccountID = +# License API refresh token file +LicenseAPIFile = [SSL] # SSL/TLS diff --git a/powershell/Invoke-DownloadAlteryx.ps1 b/powershell/Invoke-DownloadAlteryx.ps1 new file mode 100644 index 0000000..6c6c6c0 --- /dev/null +++ b/powershell/Invoke-DownloadAlteryx.ps1 @@ -0,0 +1,119 @@ +function Invoke-DownloadAlteryx { + <# + .SYNOPSIS + Download Alteryx release + + .DESCRIPTION + Download the latest Alteryx release for a specified product + + .NOTES + File name: Invoke-DownloadAlteryx.ps1 + Author: Florian Carrier + Creation date: 2024-09-04 + Last modified: 2024-09-06 + #> + [CmdletBinding ()] + Param ( + [Parameter ( + Position = 1, + Mandatory = $true, + HelpMessage = "Script properties" + )] + [ValidateNotNullOrEmpty ()] + [System.Collections.Specialized.OrderedDictionary] + $Properties, + [Parameter ( + Position = 2, + Mandatory = $true, + HelpMessage = "Installation properties" + )] + [ValidateNotNullOrEmpty ()] + [System.Collections.Specialized.OrderedDictionary] + $InstallationProperties, + [Parameter ( + HelpMessage = "Non-interactive mode" + )] + [Switch] + $Unattended + ) + Begin { + # Get global preference vrariables + Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState + # Log function call + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $Process = New-ProcessObject -Name $MyInvocation.MyCommand.Name + # Product IDs + $Products = [Ordered]@{ + "Designer" = "Alteryx Designer" + "Server" = "Alteryx Server" + } + $ProductID = $Products.$($InstallationProperties.Product) + # License API refresh token + $RefreshToken = Get-Content -Path $Properties.LicenseAPIFile -Raw + # Placeholder + $Skip = $false + } + Process { + $Process = Update-ProcessObject -ProcessObject $Process -Status "Running" + # Get license API access token + $AccessToken = Update-AlteryxLicenseToken -Token $RefreshToken -Type "Access" + Write-Log -Type "DEBUG" -Message $AccessToken + # Check current and target versions + $CurrentVersion = Get-AlteryxVersion + $MajorVersion = [System.String]::Concat([System.Version]::Parse($CurrentVersion).Major , ".", [System.Version]::Parse($CurrentVersion).Minor) + $TargetVersion = [System.String]::Concat([System.Version]::Parse($Properties.Version).Major, ".", [System.Version]::Parse($Properties.Version).Minor) + # Check latest version + Write-Log -Type "INFO" -Message "Retrieve latest release for $ProductID version $TargetVersion" + $Release = Get-AlteryxLatestRelease -AccountID $Properties.LicenseAccountID -Token $AccessToken -ProductID $ProductID -Version $TargetVersion + # Compare versions + if (Compare-Version -Version $Release.Version -Operator "lt" -Reference $CurrentVersion) { + Write-Log -Type "WARN" -Message "The specified version ($($Release.Version)) is lower than the current one ($CurrentVersion)" + if (($Unattended -eq $false) -And (-Not (Confirm-Prompt -Prompt "Do you still want to download $ProductID version $($Release.Version)?"))) { + $Skip = $true + } + } elseif (Compare-Version -Version $Release.Version -Operator "eq" -Reference $CurrentVersion) { + Write-Log -Type "WARN" -Message "The version installed ($CurrentVersion) is the latest version available for $ProductID" + if (($Unattended -eq $false) -And (-Not (Confirm-Prompt -Prompt "Do you still want to download $ProductID version $($Release.Version)?"))) { + $Skip = $true + } + } else { + Write-Log -Type "INFO" -Message "$ProductID version $($Release.Version) is available" + if (-Not $Unattended) { + $Continue = Confirm-Prompt -Prompt "Do you want to download it?" + if (-Not $Continue) { + $Skip = $true + } + } + } + # Check if download should proceed + if ($Skip -eq $false) { + # Check if + if (Compare-Version -Version $TargetVersion -Operator "ne" -Reference $MajorVersion) { + # If major upgrade, download installer + Write-Log -Type "INFO" -Message "Downloading $($Release.Product) version $($Release.Version)" + } else { + # If minor or patch upgrade, download patch + Write-Log -Type "INFO" -Message "Downloading $($Release.Product) patch version $($Release.Version)" + $Release = Get-AlteryxLatestRelease -AccountID $Properties.LicenseAccountID -Token $AccessToken -ProductID $ProductID -Version $TargetVersion -Patch + } + $DownloadPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $Release.FileName + Invoke-WebRequest -Uri $Release.URL -OutFile $DownloadPath + # Check downloaded file + Write-Log -Type "DEBUG" -Message $DownloadPath + if (Test-Path -Path $DownloadPath) { + Write-Log -Type "CHECK" -Message "Download completed successfully" + $Process = Update-ProcessObject -ProcessObject $Process -Status "Completed" -Success $true -ExitCode 0 -ErrorCount 0 + } else { + Write-Log -Type "ERROR" -Message "Download failed" + $Process = Update-ProcessObject -ProcessObject $Process -Status "Failed" -Success $false -ExitCode 1 -ErrorCount 1 + } + } else { + Write-Log -Type "WARN" -Message "Skipping download process" + $Process = Update-ProcessObject -ProcessObject $Process -Status "Cancelled" -Success $true -ExitCode 0 -ErrorCount 0 + } + } + End { + return $Process + } +} \ No newline at end of file From 08fd523c85cb22bd46ab202735394698fa56128f Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Wed, 11 Sep 2024 16:39:49 +0200 Subject: [PATCH 09/61] Update service functions Update start, stop, and restart functions to report status properly --- powershell/Invoke-RestartAlteryx.ps1 | 27 +++++++++--- powershell/Invoke-StartAlteryx.ps1 | 65 ++++++++++++++++++---------- powershell/Invoke-StopAlteryx.ps1 | 41 +++++++++++------- 3 files changed, 89 insertions(+), 44 deletions(-) diff --git a/powershell/Invoke-RestartAlteryx.ps1 b/powershell/Invoke-RestartAlteryx.ps1 index e3a8d3d..1549a84 100644 --- a/powershell/Invoke-RestartAlteryx.ps1 +++ b/powershell/Invoke-RestartAlteryx.ps1 @@ -10,7 +10,7 @@ function Invoke-RestartAlteryx { File name: Invoke-RestartAlteryx.ps1 Author: Florian Carrier Creation date: 2021-08-27 - Last modified: 2022-04-19 + Last modified: 2024-09-11 #> [CmdletBinding ()] Param ( @@ -32,12 +32,27 @@ function Invoke-RestartAlteryx { # Get global preference vrariables Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState # Log function call - Write-Log -Type "DEBUG" -Message $MyInvocation.ScriptName + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $RestartProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name } Process { - Write-Log -Type "CHECK" -Message "Restarting Alteryx Service" - Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended - Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended - Write-Log -Type "CHECK" -Message "Alteryx Service restart complete" + $RestartProcess = Update-ProcessObject -ProcessObject $RestartProcess -Status "Running" + Write-Log -Type "NOTICE" -Message "Restarting Alteryx Service" + $StartProcess = Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended + if ($StartProcess.Success) { + $StopProcess = Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended + if ($StopProcess.Success) { + Write-Log -Type "CHECK" -Message "Alteryx Service restart process complete" + $RestartProcess = Update-ProcessObject -ProcessObject $RestartProcess -Status "Completed" -Success $true + } else { + $RestartProcess = Update-ProcessObject -ProcessObject $RestartProcess -Status $StopProcess.Status -ErrorCount $StopProcess.ErrorCount -ExitCode $StopProcess.ExitCode + } + } else { + $RestartProcess = Update-ProcessObject -ProcessObject $RestartProcess -Status $StartProcess.Status -ErrorCount $StartProcess.ErrorCount -ExitCode $StartProcess.ExitCode + } + } + End { + return $RestartProcess } } \ No newline at end of file diff --git a/powershell/Invoke-StartAlteryx.ps1 b/powershell/Invoke-StartAlteryx.ps1 index 01717c1..dfe58f0 100644 --- a/powershell/Invoke-StartAlteryx.ps1 +++ b/powershell/Invoke-StartAlteryx.ps1 @@ -10,16 +10,16 @@ function Invoke-StartAlteryx { File name: Invoke-StartAlteryx.ps1 Author: Florian Carrier Creation date: 2021-07-08 - Last modified: 2022-04-19 + Last modified: 2024-09-11 #> [CmdletBinding ( SupportsShouldProcess = $true )] Param ( [Parameter ( - Position = 1, - Mandatory = $true, - HelpMessage = "Script properties" + Position = 1, + Mandatory = $true, + HelpMessage = "Script properties" )] [ValidateNotNullOrEmpty ()] [System.Collections.Specialized.OrderedDictionary] @@ -34,28 +34,36 @@ function Invoke-StartAlteryx { # Get global preference vrariables Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState # Log function call - Write-Log -Type "DEBUG" -Message $MyInvocation.ScriptName - # Variables - $ServiceName = "AlteryxService" + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $StartProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # Retrieve Alteryx Service utility path $AlteryxService = Get-AlteryxUtility -Utility "Service" -Path $Properties.InstallationPath + # Check installed version + $InstalledVersion = Get-AlteryxVersion + if (Compare-Version -Version $InstalledVersion -Operator "ne" -Reference $Properties.Version) { + Write-Log -Type "WARN" -Message "The configured version ($($Properties.Version)) does not match the version currently installed ($InstalledVersion)" + $Properties.Version = $InstalledVersion + } } Process { + $StartProcess = Update-ProcessObject -ProcessObject $StartProcess -Status "Running" Write-Log -Type "INFO" -Message "Starting Alteryx Service" - if ($PSCmdlet.ShouldProcess("Alteryx Service", "Start")) { - # Check service status - $WindowsService = Get-Service -Name $ServiceName - Write-Log -Type "DEBUG" -Message $WindowsService - if ($WindowsService.Status -eq "Running") { - Write-Log -Type "WARN" -Message "Alteryx Service ($ServiceName) is already running" - } else { + # Check service status + $WindowsService = Get-Service -Name $Properties.ServiceName + Write-Log -Type "DEBUG" -Message $WindowsService + if ($WindowsService.Status -eq "Running") { + Write-Log -Type "WARN" -Message "Alteryx Service ($($Properties.ServiceName)) is already running" + $StartProcess = Update-ProcessObject -ProcessObject $StartProcess -Status "Completed" -Success $true + } else { + if ($PSCmdlet.ShouldProcess("Alteryx Service", "Start")) { if ($Unattended -eq $false) { $Confirm = Confirm-Prompt -Prompt "Do you want to start the Alteryx Service?" } if ($Unattended -Or ($Confirm -eq $true)) { # Start service - $Process = Start-Process -FilePath $AlteryxService -ArgumentList "start" -Verb "RunAs" -PassThru -Wait - Write-Log -Type "DEBUG" -Message $Process + $ServiceProcess = Start-Process -FilePath $AlteryxService -ArgumentList "start" -Verb "RunAs" -PassThru -Wait + Write-Log -Type "DEBUG" -Message $ServiceProcess # Check process outcome if (Compare-Version -Version $Properties.Version -Operator "ge" -Reference "2021.4.1") { $ExpectedExitCode = 0 @@ -63,26 +71,37 @@ function Invoke-StartAlteryx { # Do not ask $ExpectedExitCode = 2 } - if ($Process.ExitCode -eq $ExpectedExitCode) { + if ($ServiceProcess.ExitCode -eq $ExpectedExitCode) { # Wait for service to start - while ((Get-Service -Name $ServiceName).Status -eq "StartPending") { + while ((Get-Service -Name $Properties.ServiceName).Status -eq "StartPending") { Write-Log -Type "INFO" -Message "Alteryx Service is starting..." Start-Sleep -Seconds 1 } # Check status - if ((Get-Service -Name $ServiceName).Status -eq "Running") { - Write-Log -Type "DEBUG" -Message (Get-Service -Name $ServiceName) + if ((Get-Service -Name $Properties.ServiceName).Status -eq "Running") { + Write-Log -Type "DEBUG" -Message (Get-Service -Name $Properties.ServiceName) Write-Log -Type "CHECK" -Message "Alteryx Service successfully started" + $StartProcess = Update-ProcessObject -ProcessObject $StartProcess -Status "Completed" -Success $true } else { - Write-Log -Type "ERROR" -Message "Attempt to start the Alteryx Service ($ServiceName) failed" -ExitCode 1 + Write-Log -Type "ERROR" -Message "Attempt to start the Alteryx Service ($($Properties.ServiceName)) failed" + $StartProcess = Update-ProcessObject -ProcessObject $StartProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 } } else { - Write-Log -Type "ERROR" -Message "Alteryx Service could not be started" -ExitCode $Process.ExitCode + Write-Log -Type "DEBUG" -Message $ServiceProcess.ExitCode + Write-Log -Type "ERROR" -Message "Alteryx Service could not be started" + $StartProcess = Update-ProcessObject -ProcessObject $StartProcess -Status "Failed" -ErrorCount 1 -ExitCode $ServiceProcess.ExitCode } } else { - Write-Log -Type "WARN" -Message "Action was cancelled by the user" -ExitCode 0 + Write-Log -Type "WARN" -Message "Action was cancelled by the user" + $StartProcess = Update-ProcessObject -ProcessObject $StartProcess -Status "Cancelled" } + } else { + # Dummy success return for test run + $StartProcess = Update-ProcessObject -ProcessObject $StartProcess -Status "Completed" -Success $true } } } + End { + return $StartProcess + } } \ No newline at end of file diff --git a/powershell/Invoke-StopAlteryx.ps1 b/powershell/Invoke-StopAlteryx.ps1 index 6a34dcc..afed155 100644 --- a/powershell/Invoke-StopAlteryx.ps1 +++ b/powershell/Invoke-StopAlteryx.ps1 @@ -10,7 +10,7 @@ function Invoke-StopAlteryx { File name: Invoke-StopAlteryx.ps1 Author: Florian Carrier Creation date: 2021-07-08 - Last modified: 2022-04-19 + Last modified: 2024-09-11 #> [CmdletBinding ( SupportsShouldProcess = $true @@ -34,19 +34,21 @@ function Invoke-StopAlteryx { # Get global preference vrariables Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState # Log function call - Write-Log -Type "DEBUG" -Message $MyInvocation.ScriptName - # Variables - $ServiceName = "AlteryxService" + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $StopProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # Retrieve Alteryx Service utility path $AlteryxService = Get-AlteryxUtility -Utility "Service" -Path $Properties.InstallationPath } Process { + $StopProcess = Update-ProcessObject -ProcessObject $StopProcess -Status "Running" Write-Log -Type "INFO" -Message "Stopping Alteryx Service" # Check service status - $WindowsService = Get-Service -Name $ServiceName + $WindowsService = Get-Service -Name $Properties.ServiceName Write-Log -Type "DEBUG" -Message $WindowsService if ($WindowsService.Status -eq "Stopped") { - Write-Log -Type "WARN" -Message "Alteryx Service ($ServiceName) is already stopped" + Write-Log -Type "WARN" -Message "Alteryx Service ($($Properties.ServiceName)) is already stopped" + $StopProcess = Update-ProcessObject -ProcessObject $StopProcess -Status "Completed" -Success $true } else { if ($PSCmdlet.ShouldProcess("Alteryx Service", "Stop")) { if ($Unattended -eq $false) { @@ -54,29 +56,38 @@ function Invoke-StopAlteryx { } if ($Unattended -Or ($Confirm -eq $true)) { # Stop service - $Process = Start-Process -FilePath $AlteryxService -ArgumentList "stop" -Verb "RunAs" -PassThru -Wait - Write-Log -Type "DEBUG" -Message $Process + $ServiceProcess = Start-Process -FilePath $AlteryxService -ArgumentList "stop" -Verb "RunAs" -PassThru -Wait + Write-Log -Type "DEBUG" -Message $ServiceProcess # Check process outcome - if ($Process.ExitCode -eq 0) { + if ($ServiceProcess.ExitCode -eq 0) { # Wait for service to stop - while ((Get-Service -Name $ServiceName).Status -eq "StopPending") { + while ((Get-Service -Name $Properties.ServiceName).Status -eq "StopPending") { Write-Log -Type "INFO" -Message "Alteryx Service is stopping..." Start-Sleep -Seconds 1 } # Check status - if ((Get-Service -Name $ServiceName).Status -eq "Stopped") { - Write-Log -Type "DEBUG" -Message (Get-Service -Name $ServiceName) + if ((Get-Service -Name $Properties.ServiceName).Status -eq "Stopped") { + Write-Log -Type "DEBUG" -Message (Get-Service -Name $Properties.ServiceName) Write-Log -Type "CHECK" -Message "Alteryx Service successfully stopped" + $StopProcess = Update-ProcessObject -ProcessObject $StopProcess -Status "Completed" -Success $true } else { - Write-Log -Type "ERROR" -Message "Attempt to stop the Alteryx Service ($ServiceName) failed" -ExitCode 1 + Write-Log -Type "DEBUG" -Message $ServiceProcess + Write-Log -Type "ERROR" -Message "Attempt to stop the Alteryx Service ($Properties.ServiceName) failed" + $StopProcess = Update-ProcessObject -ProcessObject $StopProcess -Status "Failed" -ExitCode 1 } } else { - Write-Log -Type "ERROR" -Message "Alteryx Service could not be stopped" -ExitCode $Process.ExitCode + Write-Log -Type "DEBUG" -Message $ServiceProcess + Write-Log -Type "ERROR" -Message "Alteryx Service could not be stopped" + $StopProcess = Update-ProcessObject -ProcessObject $StopProcess -Status "Failed" -ExitCode $ServiceProcess.ExitCode } } else { - Write-Log -Type "WARN" -Message "Action was cancelled by the user" -ExitCode 0 + Write-Log -Type "WARN" -Message "Action was cancelled by the user" + $StopProcess = Update-ProcessObject -ProcessObject $StopProcess -Status "Cancelled" } } } } + End { + return $StopProcess + } } \ No newline at end of file From 55e5239855453d4c72aa7a4f73e88144adacdc5c Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Wed, 11 Sep 2024 16:39:55 +0200 Subject: [PATCH 10/61] Update Show-Configuration.ps1 --- powershell/Show-Configuration.ps1 | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/powershell/Show-Configuration.ps1 b/powershell/Show-Configuration.ps1 index ae48151..708a5e0 100644 --- a/powershell/Show-Configuration.ps1 +++ b/powershell/Show-Configuration.ps1 @@ -16,7 +16,7 @@ function Show-Configuration { File name: Show-Configuration.ps1 Author: Florian Carrier Creation date: 2021-07-08 - Last modified: 2022-04-19 + Last modified: 2024-09-11 #> [CmdletBinding ()] Param ( @@ -41,16 +41,24 @@ function Show-Configuration { # Get global preference variables Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState # Log function call - Write-Log -Type "DEBUG" -Message $MyInvocation.ScriptName + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $ShowProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # Display colour $Colour = "Cyan" } Process { - # Display default x custom script configuration - Write-Log -Type "INFO" -Object "Script configuration" + $ShowProcess = Update-ProcessObject -ProcessObject $ShowProcess -Status "Running" + Write-Log -Type "NOTICE" -Message "Displaying script configuration" + # Display default x custom script parameters + Write-Log -Type "INFO" -Object "Script parameters" Write-Host -Object ($Properties | Out-String).Trim() -ForegroundColor $Colour - # Display installation configuration - Write-Log -Type "INFO" -Object "Installation configuration" + # Display installation parameters + Write-Log -Type "INFO" -Object "Installation parameters" Write-Host -Object ($InstallationProperties | Out-String).Trim() -ForegroundColor $Colour + $ShowProcess = Update-ProcessObject -ProcessObject $ShowProcess -Status "Completed" -Success $true + } + End { + return $ShowProcess } } \ No newline at end of file From 3c1ff5d24dd7346a4de6174ec6dd8da2cb7e66aa Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Wed, 11 Sep 2024 16:40:19 +0200 Subject: [PATCH 11/61] Update Invoke-PatchAlteryx.ps1 --- powershell/Invoke-PatchAlteryx.ps1 | 46 ++++++++++++++---------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/powershell/Invoke-PatchAlteryx.ps1 b/powershell/Invoke-PatchAlteryx.ps1 index cce783d..68fb5fc 100644 --- a/powershell/Invoke-PatchAlteryx.ps1 +++ b/powershell/Invoke-PatchAlteryx.ps1 @@ -5,19 +5,12 @@ function Invoke-PatchAlteryx { .DESCRIPTION Perform a patch upgrade to Alteryx -function Invoke-PatchAlteryx { - <# - .SYNOPSIS - Install Alteryx patch - - .DESCRIPTION - Perform a patch upgrade to Alteryx .NOTES File name: Invoke-PatchAlteryx.ps1 Author: Florian Carrier Creation date: 2022-06-29 - Last modified: 2022-06-29 + Last modified: 2024-09-10 #> [CmdletBinding ( SupportsShouldProcess = $true @@ -41,31 +34,31 @@ function Invoke-PatchAlteryx { # Get global preference vrariables Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState # Log function call - Write-Log -Type "DEBUG" -Message $MyInvocation.ScriptName + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $PatchProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # Variables $ISOTimeStamp = Get-Date -Format "yyyyMMdd_HHmmss" - $Tags = [Ordered]@{"Version" = $Properties.Version} # Filenames if ($InstallationProperties.Product -eq "Designer") { - $PatchInstaller = "AlteryxPatchInstall_.exe" + $PatchPrefix = "AlteryxPatchInstall" } else { - $PatchInstaller = "AlteryxServerPatchInstall_.exe" - } - # Unattended execution arguments - if ($Unattended) { - $Arguments = "/s" - } else { - $Arguments = "" + $PatchPrefix = "AlteryxServerPatchInstall" } } Process { + $PatchProcess = Update-ProcessObject -ProcessObject $PatchProcess -Status "Running" Write-Log -Type "INFO" -Message "Installation of Alteryx $($InstallationProperties.Product) patch $($Properties.Version)" + # Check products to install if ($InstallationProperties.Product -eq "Designer" -Or $InstallationProperties.Server -eq $true) { - # Update file version number - $PatchFileName = Set-Tags -String $PatchInstaller -Tags (Resolve-Tags -Tags $Tags -Prefix "<" -Suffix ">") - $PatchPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $PatchFileName + # Generate patch file version number + $PatchVersion = [System.Version]::Parse($Properties.Version).Major.ToString() + "." + [System.Version]::Parse($Properties.Version).Minor.ToString() + "." + [System.Version]::Parse($Properties.Version).Build.ToString() + ".?." + [System.Version]::Parse($Properties.Version).Revision.ToString() + $PatchInstaller = "$($PatchPrefix)_$($PatchVersion).exe" + $PatchPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $PatchInstaller if ($PSCmdlet.ShouldProcess($PatchPath, "Install")) { if (Test-Path -Path $PatchPath) { + # Get actual filepath + $PatchPath = (Resolve-Path -Path $PatchPath).Path # Stop Alteryx Service Write-Log -Type "INFO" -Message "Check Alteryx Service status" if ($PSCmdlet.ShouldProcess("Alteryx Service", "Stop")) { @@ -78,14 +71,16 @@ function Invoke-PatchAlteryx { Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended } } else { - Write-Log -Type "ERROR" -Message "Alteryx Service ($Service) could not be found" -ExitCode 1 + Write-Log -Type "ERROR" -Message "Alteryx Service ($Service) could not be found" + $PatchProcess = Update-ProcessObject -ProcessObject $PatchProcess -Status "Failed" -Success $false -ExitCode 1 -ErrorCount 1 + return $PatchProcess } } if ($Properties.InstallAwareLog -eq $true) { $InstallAwareLog = Join-Path -Path $Properties.LogDirectory -ChildPath "${ISOTimeStamp}_${PatchFileName}.log" - $PatchInstall = Install-AlteryxServer -Path $PatchPath -InstallDirectory $Properties.InstallationPath -Log $InstallAwareLog -Language $Properties.Language -AllUsers -Unattended:$Unattended + $PatchInstall = Install-AlteryxServer -Path $PatchPath -InstallDirectory $Properties.InstallationPath -Log $InstallAwareLog -Language $Properties.Language -Version $Properties.Version -AllUsers -Unattended:$Unattended } else { - $PatchInstall = Install-AlteryxServer -Path $PatchPath -InstallDirectory $Properties.InstallationPath -Language $Properties.Language -AllUsers -Unattended:$Unattended + $PatchInstall = Install-AlteryxServer -Path $PatchPath -InstallDirectory $Properties.InstallationPath -Language $Properties.Language -Version $Properties.Version -AllUsers -Unattended:$Unattended } Write-Log -Type "DEBUG" -Message $PatchInstall if ($PatchInstall.ExitCode -eq 0) { @@ -108,4 +103,7 @@ function Invoke-PatchAlteryx { Write-Log -Type "ERROR" -Message "Designer or Server products must be enabled for a patch upgrade" -ExitCode 0 } } + End { + return $PatchProcess + } } \ No newline at end of file From c5eaa54048aaa943f7f3da20204de6fe290fc555 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Wed, 11 Sep 2024 18:06:19 +0200 Subject: [PATCH 12/61] Update Invoke-BackupAlteryx.ps1 --- powershell/Invoke-BackupAlteryx.ps1 | 36 +++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/powershell/Invoke-BackupAlteryx.ps1 b/powershell/Invoke-BackupAlteryx.ps1 index 88e9a8c..381a106 100644 --- a/powershell/Invoke-BackupAlteryx.ps1 +++ b/powershell/Invoke-BackupAlteryx.ps1 @@ -10,7 +10,7 @@ function Invoke-BackupAlteryx { File name: Invoke-BackupAlteryx.ps1 Author: Florian Carrier Creation date: 2021-08-26 - Last modified: 2024-03-26 + Last modified: 2024-09-11 #> [CmdletBinding ( SupportsShouldProcess = $true @@ -34,7 +34,9 @@ function Invoke-BackupAlteryx { # Get global preference vrariables Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState # Log function call - Write-Log -Type "DEBUG" -Message $MyInvocation.ScriptName + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $BackupProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # Variables $Version = Get-AlteryxRegistryVersion $ISOTimeStamp = Get-Date -Format "yyyyMMdd_HHmmss" @@ -63,7 +65,8 @@ function Invoke-BackupAlteryx { } } Process { - Write-Log -Type "CHECK" -Message "Start $BackupType backup of Alteryx Server" + $BackupProcess = Update-ProcessObject -ProcessObject $BackupProcess -Status "Running" + Write-Log -Type "NOTICE" -Message "Start $BackupType backup of Alteryx Server" # ---------------------------------------------------------------------------- # Check Alteryx service status Write-Log -Type "INFO" -Message "Check Alteryx Service status" @@ -74,10 +77,16 @@ function Invoke-BackupAlteryx { Write-Log -Type "DEBUG" -Message $Service $ServiceStatus = $WindowsService.Status if ($ServiceStatus -eq "Running") { - Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended + $StopProcess = Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended + if ($StopProcess.Success -eq $false) { + $BackupProcess = Update-ProcessObject -ProcessObject $BackupProcess -Status $StopProcess.Status -ErrorCount $StopProcess.ErrorCount -ExitCode $StopProcess.ExitCode + return $BackupProcess + } } } else { - Write-Log -Type "ERROR" -Message "Alteryx Service ($Service) could not be found" -ExitCode 1 + Write-Log -Type "ERROR" -Message "Alteryx Service ($Service) could not be found" + $BackupProcess = Update-ProcessObject -ProcessObject $BackupProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $BackupProcess } } # ---------------------------------------------------------------------------- @@ -92,7 +101,9 @@ function Invoke-BackupAlteryx { $DatabaseBackup = Backup-AlteryxDatabase -Path $MongoDBPath -ServicePath $ServicePath if ($DatabaseBackup -match "EMongoDump failed") { Write-Log -Type "ERROR" -Message "$DatabaseBackup" - Write-Log -Type "ERROR" -Message "Database backup failed" -ExitCode 1 + Write-Log -Type "ERROR" -Message "Database backup failed" + $BackupProcess = Update-ProcessObject -ProcessObject $BackupProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $BackupProcess } else { Write-Log -Type "DEBUG" -Message "$DatabaseBackup" } @@ -151,7 +162,8 @@ function Invoke-BackupAlteryx { Compress-Archive -Path "$TempBackupPath\*" -DestinationPath $BackupPath -CompressionLevel "Optimal" -WhatIf:$WhatIfPreference Write-Log -Type "DEBUG" -Message $BackupPath if (Test-Object -Path $BackupPath -NotFound) { - Write-Log -Type "ERROR" -Message "Backup files compression failed" -ErrorCode 1 + Write-Log -Type "ERROR" -Message "Backup files compression failed" + $BackupProcess = Update-ProcessObject -ProcessObject $BackupProcess -ErrorCount 1 } else { # Remove staging folder Write-Log -Type "INFO" -Message "Remove staging backup folder" @@ -163,11 +175,15 @@ function Invoke-BackupAlteryx { # ---------------------------------------------------------------------------- # Restart service if it was running before if ($ServiceStatus -eq "Running") { - Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended + $StartProcess = Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended + if ($StartProcess.Success -eq $false) { + $BackupProcess = Update-ProcessObject -ProcessObject $BackupProcess -ErrorCount 1 + } } + Write-Log -Type "CHECK" -Message "Alteryx Server $BackupType backup complete" + $BackupProcess = Update-ProcessObject -ProcessObject $BackupProcess -Status "Completed" -Success $true } End { - # If no error occured - Write-Log -Type "CHECK" -Message "Alteryx Server $BackupType backup complete" + return $BackupProcess } } \ No newline at end of file From b9a653f4b18136494f2fea918f9542b167104f1b Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Wed, 11 Sep 2024 18:55:35 +0200 Subject: [PATCH 13/61] Update Invoke-RestoreAlteryx.ps1 --- powershell/Invoke-RestoreAlteryx.ps1 | 65 ++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/powershell/Invoke-RestoreAlteryx.ps1 b/powershell/Invoke-RestoreAlteryx.ps1 index dfbe657..8cc8122 100644 --- a/powershell/Invoke-RestoreAlteryx.ps1 +++ b/powershell/Invoke-RestoreAlteryx.ps1 @@ -10,13 +10,13 @@ function Invoke-RestoreAlteryx { File name: Invoke-RestoreAlteryx.ps1 Author: Florian Carrier Creation date: 2021-08-26 - Last modified: 2022-04-19 + Last modified: 2024-09-11 Comment: User configuration files are out of scope of this procedure: - %APPDATA%\Alteryx\Engine\UserConnections.xml - %APPDATA%\Alteryx\Engine\UserAlias.xml .LINK - https://help.alteryx.com/20213/server/server-host-recovery-guide + https://help.alteryx.com/current/en/server/install/server-host-recovery-guide.html #> [CmdletBinding ( SupportsShouldProcess = $true @@ -40,7 +40,9 @@ function Invoke-RestoreAlteryx { # Get global preference vrariables Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState # Log function call - Write-Log -Type "DEBUG" -Message $MyInvocation.ScriptName + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $RestoreProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # Variables $ServicePath = Join-Path -Path $Properties.InstallationPath -ChildPath "bin\AlteryxService.exe" $Staging = $false @@ -67,7 +69,8 @@ function Invoke-RestoreAlteryx { } } Process { - Write-Log -Type "CHECK" -Message "Start $RestoreType restore of Alteryx Server" + $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -Status "Running" + Write-Log -Type "NOTICE" -Message "Start $RestoreType restore of Alteryx Server" if ($PSCmdlet.ShouldProcess("Alteryx Service", "Stop")) { # ---------------------------------------------------------------------------- # Check Alteryx service status @@ -81,17 +84,22 @@ function Invoke-RestoreAlteryx { Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended } } else { - Write-Log -Type "ERROR" -Message "Alteryx Service ($Service) could not be found" -ExitCode 1 + Write-Log -Type "ERROR" -Message "Alteryx Service ($Service) could not be found" + $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -Status "Failed" -ErrorCode 1 -ExitCode 1 + return $RestoreProcess } } # ---------------------------------------------------------------------------- # Check source backup path if ($PSCmdlet.ShouldProcess("Backup files", "Retrieve")) { + # Check if custom backup path is specified if ($null -eq (Get-KeyValue -Hashtable $Properties -Key "BackupPath" -Silent)) { - # If no path is specified revert to backup repository + $SourcePath = $Properties.BackupDirectory + } else { $SourcePath = $Properties.BackupPath } - elseif (Test-Object -Path $SourcePath) { + # Look for backup file + if (Test-Object -Path $SourcePath) { if ($SourcePath -is [System.IO.FileInfo]) { if ([System.IO.Path]::GetExtension($SourcePath) -eq ".zip") { # Extract archive file @@ -100,21 +108,35 @@ function Invoke-RestoreAlteryx { Expand-Archive -Path $SourcePath -DestinationPath $BackupPath -Force -WhatIf:$WhatIfPreference $Staging = $true } else { - Write-Log -Type "ERROR" -Message "Only ZIP or uncompressed files are supported" -ExitCode 1 + Write-Log -Type "ERROR" -Message "Only ZIP or uncompressed files are supported" + $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -Status "Failed" -ErrorCode 1 -ExitCode 1 + return $RestoreProcess } } else { # Select most recent backup in the directory Write-Log -Type "WARN" -Message "No backup file was specified" + # Ask user confirmation on most recent file if ($Unattended -eq $false) { $Confirmation = Confirm-Prompt -Prompt "Do you want to fetch the latest backup file?" if ($Confirmation -eq $false) { - Write-Log -Type "WARN" -Message "Restore operation cancelled by user" -ExitCode 0 + Write-Log -Type "WARN" -Message "Restore operation cancelled by user" + $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -Status "Cancelled" + return $RestoreProcess } } Write-Log -Type "DEBUG" -Message $SourcePath Write-Log -Type "INFO" -Message "Retrieving most recent backup" $BackupFile = (Get-Object -Path $SourcePath -ChildItem -Type "File" -Filter "*.zip" | Sort-Object -Descending -Property "LastWriteTime" | Select-Object -First 1).FullName Write-Log -Type "DEBUG" -Message $BackupFile + # Ask user confirmation on backup file + if ($Unattended -eq $false) { + $Confirmation = Confirm-Prompt -Prompt "Do you want to restore backup from $BackupFile?" + if ($Confirmation -eq $false) { + Write-Log -Type "WARN" -Message "Restore operation cancelled by user" + $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -Status "Cancelled" + return $RestoreProcess + } + } # Extract archive file Write-Log -Type "INFO" -Message "Extract backup file contents" $BackupPath = Join-Path -Path $Properties.TempDirectory -ChildPath ([System.IO.Path]::GetFileNameWithoutExtension($BackupFile)) @@ -122,7 +144,9 @@ function Invoke-RestoreAlteryx { $Staging = $true } } else { - Write-Log -Type "ERROR" -Message "No database backup could be found" -ExitCode 1 + Write-Log -Type "ERROR" -Message "No database backup could be found" + $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $RestoreProcess } } # ---------------------------------------------------------------------------- @@ -233,6 +257,7 @@ function Invoke-RestoreAlteryx { $ControllerSettingsXML.Save($ConfigurationFiles.RunTimeSettings) } else { Write-Log -Type "WARN" -Message "Encrypted controller token could not be found" + $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -ErrorCount 1 } } Write-Log -Type "INFO" -Message "Restore controller token" @@ -244,12 +269,18 @@ function Invoke-RestoreAlteryx { if ($SetToken -match "failed") { Write-Log -Type "ERROR" -Message $SetToken Write-Log -Type "ERROR" -Message "Controller token update failed" + $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -ErrorCount 1 } else { # Ignore successfull empty output if ($SetToken -ne "") { Write-Log -Type "DEBUG" -Message $SetToken } } + } else { + Write-Log -Type "DEBUG" -Message $TokenFile + Write-Log -Type "ERROR" -Message "No controller token backup file could not be found" + $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -ErrorCount 1 + Write-Log -Type "WARN" -Message "Skipping controller token restore" } } } @@ -290,6 +321,7 @@ function Invoke-RestoreAlteryx { $StorageSettingsXML.Save($ConfigurationFiles.RunTimeSettings) } else { Write-Log -Type "WARN" -Message "RunTimeSettings.xml backup configuration file could not be located" + $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -ErrorCount 1 } } } @@ -311,13 +343,15 @@ function Invoke-RestoreAlteryx { $DatabaseRestore = Restore-AlteryxDatabase -SourcePath $MongoDBPath -TargetPath $TargetPath -ServicePath $ServicePath if ($DatabaseRestore -match "failed") { Write-Log -Type "ERROR" -Message $DatabaseRestore - Write-Log -Type "ERROR" -Message "Database restore failed" -ExitCode 1 + Write-Log -Type "ERROR" -Message "Database restore failed" + $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 } else { Write-Log -Type "DEBUG" -Message $DatabaseRestore } } else { Write-Log -Type "ERROR" -Message "User-managed MongoDB is not supported" Write-Log -Type "WARN" -Message "Skipping database restore" + $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 } } } @@ -333,9 +367,14 @@ function Invoke-RestoreAlteryx { Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended } } + if (($RestoreProcess.ErrorCount -eq 0) -And ($RestoreProcess.ExitCode -eq 0)) { + Write-Log -Type "CHECK" -Message "Alteryx Server $RestoreType restore complete" + $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -Status "Completed" -Success $true + } else { + Write-Log -Type "ERROR" -Message "Alteryx Server $RestoreType restore could not be completed" + } } End { - # If no error occured - Write-Log -Type "CHECK" -Message "Alteryx Server $RestoreType restore complete" + return $RestoreProcess } } \ No newline at end of file From ae9c19fb797961b620dedf4bdfbac44f3ba7a1b3 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Thu, 12 Sep 2024 17:17:28 +0200 Subject: [PATCH 14/61] Update licensing functions --- powershell/Invoke-ActivateAlteryx.ps1 | 141 +++++++++++++++----- powershell/Invoke-DeactivateAlteryx.ps1 | 163 +++++++++++++++--------- 2 files changed, 209 insertions(+), 95 deletions(-) diff --git a/powershell/Invoke-ActivateAlteryx.ps1 b/powershell/Invoke-ActivateAlteryx.ps1 index aca5aea..11c9be3 100644 --- a/powershell/Invoke-ActivateAlteryx.ps1 +++ b/powershell/Invoke-ActivateAlteryx.ps1 @@ -16,13 +16,13 @@ function Invoke-ActivateAlteryx { File name: Invoke-ActivateAlteryx.ps1 Author: Florian Carrier Creation date: 2021-07-05 - Last modified: 2022-04-19 + Last modified: 2024-09-12 .LINK https://www.powershellgallery.com/packages/PSAYX .LINK - https://help.alteryx.com/current/product-activation-and-licensing/use-command-line-options + https://help.alteryx.com/current/en/license-and-activate/administer/use-command-line-options.html #> [CmdletBinding ( SupportsShouldProcess = $true @@ -46,54 +46,95 @@ function Invoke-ActivateAlteryx { # Get global preference variables Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState # Log function call - Write-Log -Type "DEBUG" -Message $MyInvocation.ScriptName + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $ActivateProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # License utility $LicenseUtility = Get-AlteryxUtility -Utility "License" -Path $Properties.InstallationPath + # Expected license format + $LicensePattern = "\w{4}-\w{4}-\w{4}-\w{4}-\w{4}-\w{4}-\w{4}-\w{4}" } Process { - Write-Log -Type "INFO" -Message "Activating Alteryx" + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -Status "Running" + Write-Log -Type "NOTICE" -Message "Activating Alteryx" if ($PSCmdlet.ShouldProcess("Alteryx", "Activate")) { # Check licensing system connectivity Write-Log -Type "INFO" -Message "Checking licensing system connectivity" if ((Test-HTTPStatus -URI $Properties.LicensingURL) -eq $true) { - # Check license key(s) + # Check license keys + Write-Log -Type "INFO" -Message "Checking license keys" if (-Not (Find-Key -Hashtable $Properties -Key "LicenseKey")) { # Check license file if ($null -eq $Properties.LicenseFile -Or $Properties.LicenseFile -eq "") { Write-Log -Type "ERROR" -Message "No license key or file have been specified" - Write-Log -Type "WARN" -Message "Alteryx product activation failed" -ExitCode 1 + Write-Log -Type "WARN" -Message "Alteryx product activation failed" + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -Status "Failed" -ErrorCode 1 -ExitCode 1 + return $ActivateProcess } # Read keys from license file if (Test-Object -Path $Properties.LicenseFile -NotFound) { Write-Log -Type "ERROR" -Message "License file path not found $($Properties.LicenseFile)" - Write-Log -Type "WARN" -Message "Alteryx product activation failed" -ExitCode 1 + Write-Log -Type "WARN" -Message "Alteryx product activation failed" + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -Status "Failed" -ErrorCode 1 -ExitCode 1 + return $ActivateProcess } $Properties.LicenseKey = @(Get-Content -Path $Properties.LicenseFile) } + Write-Log -Type "DEBUG" -Message $Properties.LicenseKey # Count keys - if ($Properties.LicenseKey.Count -gt 1) { - $Success = "$($Properties.LicenseKey.Count) licenses were successfully activated" - $Failure = "Licenses could not be activated" - $Grammar = "licenses" - $Properties.LicenseKey = $Properties.LicenseKey -join " " - } elseif ($Properties.LicenseKey.Count -eq 1) { - $Success = "$($Properties.LicenseKey.Count) license was successfully activated" - $Failure = "License could not be activated" - $Grammar = "license" - } else { + if ($Properties.LicenseKey.Count -eq 0) { Write-Log -Type "ERROR" -Message "No license key was provided" - Write-Log -Type "WARN" -Message "Alteryx product activation failed" -ExitCode 1 + Write-Log -Type "WARN" -Message "Alteryx product activation failed" + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $ActivateProcess + } else { + # Check existing licenses keys + $CurrentLicenses = Get-AlteryxLicense -Path $LicenseUtility + $NewLicenses = New-Object -TypeName "System.Collections.ArrayList" + if ($CurrentLicenses | Select-String -Pattern "\b$LicensePattern\b" -Quiet) { + $CurrentKeys = ($CurrentLicenses | Select-String -Pattern "\b$LicensePattern\b" -AllMatches).Matches.Value + foreach ($Key in $Properties.LicenseKey) { + if ($CurrentKeys.Contains($Key)) { + Write-Log -Type "WARN" -Message "$Key is already activated" + } elseif ($Key -notmatch "^$LicensePattern$") { + Write-Log -Type "ERROR" -Message "$Key key does not match the expected format" + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -ErrorCount 1 + Write-Log -Type "WARN" -Message "Skipping license $Key" + } else { + $NewLicenses.Add($Key) + } + } + } else { + $NewLicenses.AddRange($Properties.LicenseKey) + } + } + # Check remaining list of keys + if ($NewLicenses.Count -eq 0) { + if ($ActivateProcess.ErrorCount -ge 1) { + Write-Log -Type "ERROR" -Message "No valid license key was provided" + Write-Log -Type "WARN" -Message "Alteryx product activation failed" + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -Status "Failed" -ExitCode 1 + } else { + Write-Log -Type "WARN" -Message "No new license key was provided" + Write-Log -Type "WARN" -Message "Skipping license activation process" + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -Status "Completed" -Success 1 + } + return $ActivateProcess } # Check email address - if ($null -eq $Properties.LicenseEmail -Or $Properties.LicenseEmail -eq "") { + $Email = $Properties.LicenseEmail + if ($null -eq $Email -Or $Email -eq "") { if ($Unattended) { Write-Log -Type "ERROR" -Message "No email address provided for license activation" + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -ErrorCount 1 Write-Log -Type "WARN" -Message "Retrieving email address associated with current session through Windows Active Directory" try { $Email = Get-ADUser -Identity $env:UserName -Properties "mail" | Select-Object -ExpandProperty "mail" Write-Log -Type "DEBUG" -Message $Email } catch { Write-Log -Type "ERROR" -Message $Error[0].Exception + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -ErrorCount 1 + Write-Log -Type "INFO" -Message "Failed to retrieve email from active session" $Email = $null } } else { @@ -103,29 +144,63 @@ function Invoke-ActivateAlteryx { } until ($Email -as [System.Net.Mail.MailAddress]) } } else { - $Email = $Properties.LicenseEmail + if ($Email -as [System.Net.Mail.MailAddress]) { + $Email = $Properties.LicenseEmail + } else { + if ($null -eq $Email) { + Write-Log -Type "ERROR" -Message "Email address is missing" + } else { + Write-Log -Type "ERROR" -Message "Email address is invalid" + } + Write-Log -Type "WARN" -Message "Skipping product activation" + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $ActivateProcess + } + } + # Call license utility + $Count = 0 + foreach ($Key in $NewLicenses) { + Write-Log -Type "INFO" -Message "Activating license $Key" + if ($Key -match "^$LicensePattern$") { + $Activation = Add-AlteryxLicense -Path $LicenseUtility -Key $Key -Email $Email + # Check activation status + if (Select-String -InputObject $Activation -Pattern "License(s) successfully activated." -SimpleMatch -Quiet) { + Write-Log -Type "CHECK" -Message "License key $Key successfully activated" + $Count += 1 + } else { + Write-Log -Type "ERROR" -Message $Activation + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -ErrorCount 1 + } + } else { + Write-Log -Type "ERROR" -Message "$Key does not match the expected Alteryx license key format" + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -ErrorCount 1 + } + } - # TODO check email format - if ($Email -as [System.Net.Mail.MailAddress]) { - # Call license utility - Write-Log -Type "INFO" -Message "Activating $Grammar" - $Activation = Add-AlteryxLicense -Path $LicenseUtility -Key $Properties.LicenseKey -Email $Email - # Check activation status - if (Select-String -InputObject $Activation -Pattern "License(s) successfully activated." -SimpleMatch -Quiet) { - Write-Log -Type "CHECK" -Message $Success + # Check activation results + if ($Count -eq $NewLicenses.Count) { + if ($NewLicenses.Count -eq 1) { + $Success = "$($NewLicenses.Count) license was successfully activated" } else { - # Output error and stop script - Write-Log -Type "ERROR" -Message $Activation - Write-Log -Type "ERROR" -Message $Failure -ExitCode 1 + $Success = "$($NewLicenses.Count) licenses were successfully activated" } + Write-Log -Type "CHECK" -Message $Success + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -Status "Completed" -Success $true + } elseif ($Count -gt 0) { + Write-Log -Type "WARN" -Message "$Count out of $($NewLicenses.Count) could not be activated" + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -Status "Completed" } else { - Write-Log -Type "ERROR" -Message "Email address is missing or invalid" - Write-Log -Type "WARN" -Message "Skipping product activation" + Write-Log -Type "WARN" -Message "No license could not be activated" + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -Status "Failed" -ExitCode 1 } } else { Write-Log -Type "ERROR" -Message "Unable to reach licensing system" Write-Log -Type "WARN" -Message "Skipping product activation" + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 } } } + End { + return $ActivateProcess + } } \ No newline at end of file diff --git a/powershell/Invoke-DeactivateAlteryx.ps1 b/powershell/Invoke-DeactivateAlteryx.ps1 index 3216c89..b3b56cf 100644 --- a/powershell/Invoke-DeactivateAlteryx.ps1 +++ b/powershell/Invoke-DeactivateAlteryx.ps1 @@ -16,13 +16,13 @@ function Invoke-DeactivateAlteryx { File name: Invoke-DeactivateAlteryx.ps1 Author: Florian Carrier Creation date: 2021-11-20 - Last modified: 2023-01-17 + Last modified: 2024-09-12 .LINK https://www.powershellgallery.com/packages/PSAYX .LINK - https://help.alteryx.com/current/product-activation-and-licensing/use-command-line-options + https://help.alteryx.com/current/en/license-and-activate/administer/use-command-line-options.html #> [CmdletBinding ( SupportsShouldProcess = $true @@ -51,84 +51,123 @@ function Invoke-DeactivateAlteryx { # Get global preference variables Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState # Log function call - Write-Log -Type "DEBUG" -Message $MyInvocation.ScriptName + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $DeactivateProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # License utility $LicenseUtility = Get-AlteryxUtility -Utility "License" -Path $Properties.InstallationPath + # Expected license format + $LicensePattern = "\w{4}-\w{4}-\w{4}-\w{4}-\w{4}-\w{4}-\w{4}-\w{4}" } Process { - Write-Log -Type "INFO" -Message "Deactivating Alteryx" + $DeactivateProcess = Update-ProcessObject -ProcessObject $DeactivateProcess -Status "Running" + Write-Log -Type "NOTICE" -Message "Deactivating Alteryx" if ($PSCmdlet.ShouldProcess("Alteryx", "Deactivate")) { - # Check licensing system connectivity - Write-Log -Type "INFO" -Message "Checking licensing system connectivity" - if ((Test-HTTPStatus -URI $Properties.LicensingURL) -eq $true) { - # Deactivate license - if ($All) { - # Remove all license keys - $Deactivation = Remove-AlteryxLicense -Path $LicenseUtility - # Check deactivation status - if (Select-String -InputObject $Deactivation -Pattern "License(s) successfully removed." -SimpleMatch -Quiet) { - Write-Log -Type "CHECK" -Message "All licenses were successfully deactivated" - } else { - # Output error - Write-Log -Type "DEBUG" -Message $Deactivation - } + # Check licensing system connectivity + Write-Log -Type "INFO" -Message "Checking licensing system connectivity" + if ((Test-HTTPStatus -URI $Properties.LicensingURL) -eq $true) { + # Check existing license keys + $CurrentLicenses = Get-AlteryxLicense -Path $LicenseUtility + if ($CurrentLicenses -match "No license keys found.") { + Write-Log -Type "WARN" -Message "No license key is currently activated" + Write-Log -Type "WARN" -Message "Skipping Alteryx product deactivation" + $DeactivateProcess = Update-ProcessObject -ProcessObject $DeactivateProcess -Status "Completed" -Success $true } else { - # Check license key(s) - if (-Not (Find-Key -Hashtable $Properties -Key "LicenseKey")) { - # Check license file - if ($null -eq $Properties.LicenseFile -Or $Properties.LicenseFile -eq "") { - Write-Log -Type "ERROR" -Message "No license key or file have been specified" - Write-Log -Type "WARN" -Message "Alteryx product deactivation failed" -ExitCode 1 - } - # Read keys from license file - if (Test-Object -Path $Properties.LicenseFile -NotFound) { - Write-Log -Type "ERROR" -Message "License file path not found $($Properties.LicenseFile)" - Write-Log -Type "WARN" -Message "Alteryx product deactivation failed" -ExitCode 1 - } - $Properties.LicenseKey = @(Get-Content -Path $Properties.LicenseFile) - } - if ($Properties.LicenseKey.Count -eq 0) { - Write-Log -Type "ERROR" -Message "No license key was provided" - Write-Log -Type "WARN" -Message "Alteryx product deactivation failed" -ExitCode 1 - } - # Deactivate each key - $Count = 0 - foreach ($Key in $Properties.LicenseKey) { - Write-Log -Type "INFO" -Message "Deactivating license key $Key" - $Dectivation = Remove-AlteryxLicense -Path $LicenseUtility -Key $Key + # Deactivate licenses + if ($All) { + # Remove all license keys + $Deactivation = Remove-AlteryxLicense -Path $LicenseUtility # Check deactivation status - if (Select-String -InputObject $Dectivation -Pattern "License(s) successfully removed." -SimpleMatch -Quiet) { - $Count += 1 + if (Select-String -InputObject $Deactivation -Pattern "License(s) successfully removed." -SimpleMatch -Quiet) { + Write-Log -Type "CHECK" -Message "All licenses were successfully deactivated" + $DeactivateProcess = Update-ProcessObject -ProcessObject $DeactivateProcess -Status "Completed" -Success $true } else { # Output error - Write-Log -Type "DEBUG" -Message $Deactivation + Write-Log -Type "ERROR" -Message $Deactivation + $DeactivateProcess = Update-ProcessObject -ProcessObject $DeactivateProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $DeactivateProcess } - } - # Check outcome - if ($Properties.LicenseKey.Count -gt 1) { - $Success = "$($Properties.LicenseKey.Count) licenses were successfully deactivated" - $ErrorCount = $Properties.LicenseKey.Count - $Count - if ($ErrorCount -eq $Properties.LicenseKey.Count) { - $Failure = "None of the licenses could not be deactivated" + } else { + # Check license keys + Write-Log -Type "INFO" -Message "Checking license keys" + if (-Not (Find-Key -Hashtable $Properties -Key "LicenseKey")) { + # Check license file + if ($null -eq $Properties.LicenseFile -Or $Properties.LicenseFile -eq "") { + Write-Log -Type "ERROR" -Message "No license key or file have been specified" + Write-Log -Type "WARN" -Message "Alteryx product deactivation failed" + $DeactivateProcess = Update-ProcessObject -ProcessObject $DeactivateProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $DeactivateProcess + } + # Read keys from license file + if (Test-Object -Path $Properties.LicenseFile -NotFound) { + Write-Log -Type "ERROR" -Message "License file path not found $($Properties.LicenseFile)" + Write-Log -Type "WARN" -Message "Alteryx product deactivation failed" + $DeactivateProcess = Update-ProcessObject -ProcessObject $DeactivateProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $DeactivateProcess + } else { + $Properties.LicenseKey = @(Get-Content -Path $Properties.LicenseFile) + } + } + Write-Log -Type "DEBUG" -Message $Properties.LicenseKey + if ($Properties.LicenseKey.Count -eq 0) { + Write-Log -Type "ERROR" -Message "No license key was provided" + Write-Log -Type "WARN" -Message "Alteryx product deactivation failed" + $DeactivateProcess = Update-ProcessObject -ProcessObject $DeactivateProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $DeactivateProcess + } + # Deactivate each key + $CurrentKeys = ($CurrentLicenses | Select-String -Pattern "\b$LicensePattern\b" -AllMatches).Matches.Value + $Count = 0 + foreach ($Key in $Properties.LicenseKey) { + if ($CurrentKeys.Contains($Key)) { + Write-Log -Type "INFO" -Message "Deactivating license key $Key" + $Dectivation = Remove-AlteryxLicense -Path $LicenseUtility -Key $Key + # Check deactivation status + if (Select-String -InputObject $Dectivation -Pattern "License(s) successfully removed." -SimpleMatch -Quiet) { + Write-Log -Type "CHECK" -Message "License key $Key successfully deactivated" + $Count += 1 + } else { + Write-Log -Type "ERROR" -Message $Deactivation + $DeactivateProcess = Update-ProcessObject -ProcessObject $DeactivateProcess -ErrorCount 1 + } + } else { + Write-Log -Type "ERROR" -Message "$Key is not currently activated" + $DeactivateProcess = Update-ProcessObject -ProcessObject $DeactivateProcess -ErrorCount 1 + } + } + # Check outcome + if ($Properties.LicenseKey.Count -gt 1) { + $Success = "$($Properties.LicenseKey.Count) licenses were successfully deactivated" + $ErrorCount = $Properties.LicenseKey.Count - $Count + if ($ErrorCount -eq $Properties.LicenseKey.Count) { + $Failure = "None of the licenses could not be deactivated" + } else { + $Failure = "$ErrorCount out of $($Properties.LicenseKey.Count) licenses could not be deactivated" + } + } elseif ($Properties.LicenseKey.Count -eq 1) { + $Success = "$($Properties.LicenseKey.Count) license was successfully deactivated" + $Failure = "License could not be deactivated" + } + if ($Count -eq $Properties.LicenseKey.Count) { + Write-Log -Type "CHECK" -Message $Success + $DeactivateProcess = Update-ProcessObject -ProcessObject $DeactivateProcess -Status "Completed" -Success $true + } elseif ($ErrorCount -eq $Properties.LicenseKey.Count) { + Write-Log -Type "ERROR" -Message $Failure + $DeactivateProcess = Update-ProcessObject -ProcessObject $DeactivateProcess -Status "Failed" -ExitCode 1 } else { - $Failure = "$ErrorCount out of $($Properties.LicenseKey.Count) licenses could not be deactivated" + Write-Log -Type "WARN" -Message $Failure + $DeactivateProcess = Update-ProcessObject -ProcessObject $DeactivateProcess -Status "Completed" } - } elseif ($Properties.LicenseKey.Count -eq 1) { - $Success = "$($Properties.LicenseKey.Count) license was successfully deactivated" - $Failure = "License could not be deactivated" - } - if ($Count -eq $Properties.LicenseKey.Count) { - Write-Log -Type "CHECK" -Message $Success - } elseif ($ErrorCount -eq $Properties.LicenseKey.Count) { - Write-Log -Type "ERROR" -Message $Failure - } else { - Write-Log -Type "WARN" -Message $Failure } } } else { Write-Log -Type "ERROR" -Message "Unable to reach licensing system" Write-Log -Type "WARN" -Message "Skipping license deactivation" + $DeactivateProcess = Update-ProcessObject -ProcessObject $DeactivateProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 } } } + End { + return $DeactivateProcess + } } \ No newline at end of file From 1e92383f87dc6e608458b8e432a35e32a8618040 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Thu, 12 Sep 2024 17:18:03 +0200 Subject: [PATCH 15/61] Error handling Fix issue with multiple return statements and better reporting for completion with errors --- Deploy-Alteryx.ps1 | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Deploy-Alteryx.ps1 b/Deploy-Alteryx.ps1 index 09ca7b5..288242e 100644 --- a/Deploy-Alteryx.ps1 +++ b/Deploy-Alteryx.ps1 @@ -295,22 +295,25 @@ Process { End { # Check outcome and gracefully end script - Write-Log -Type "DEBUG" -Message ($Process | Format-Table) - if ($Process.Success -And ($Process.Status -eq "Completed")) { - Write-Log -Type "CHECK" -Message "Alteryx $Action process completed successfully" -ExitCode $Process.ExitCode + $Process = $Process[0] + if ($Process.ErrorCount -gt 0) { + if ($Process.ErrorCount -gt 1) { + $Errors = "with $($Process.ErrorCount) errors" + } else { + $Errors = "with $($Process.ErrorCount) error" + } } else { - if ($Process.ErrorCount -gt 0) { - if ($Process.ErrorCount -gt 1) { - $Errors = "with $($Process.ErrorCount) errors" - } else { - $Errors = "with $($Process.ErrorCount) error" - } + $Errors = "" + } + if ($Process.Status -eq "Completed") { + if ($Process.Success) { + Write-Log -Type "CHECK" -Message "Alteryx $Action process completed successfully" -ExitCode $Process.ExitCode } else { - $Errors = "" + Write-Log -Type "WARN" -Message "Alteryx $Action process completed $Errors" -ExitCode $Process.ExitCode } + } else { switch ($Process.Status) { "Cancelled" { $Outcome = "was cancelled" } - "Completed" { $Outcome = "completed" } "Failed" { $Outcome = "failed" } "Stopped" { $Outcome = "was stopped" } default { $Outcome = "failed" } From f4d884cb75a242ffaaf85cff2134b49ea70387e2 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 16 Sep 2024 12:07:13 +0200 Subject: [PATCH 16/61] Add ping operation Add new ping option to check the status of Alteryx Server --- Deploy-Alteryx.ps1 | 27 +++++---- powershell/Invoke-PingAlteryx.ps1 | 98 +++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 11 deletions(-) create mode 100644 powershell/Invoke-PingAlteryx.ps1 diff --git a/Deploy-Alteryx.ps1 b/Deploy-Alteryx.ps1 index 288242e..17ad532 100644 --- a/Deploy-Alteryx.ps1 +++ b/Deploy-Alteryx.ps1 @@ -11,7 +11,7 @@ .PARAMETER Action The action parameter corresponds to the operation to perform. - Fifteen options are available: + Sixteen options are available: - activate: activate the Alteryx application license - backup: backup the Alteryx application database @@ -21,6 +21,7 @@ - install: install the Alteryx application - repair: repair the Alteryx application database - patch: patch upgrade the Alteryx application + - ping: check the status of the Alteryx application - repair: repair the Alteryx application database - restart: restart the Alteryx application - restore: restore a backup of the Alteryx application database @@ -37,7 +38,7 @@ File name: Deploy-Alteryx.ps1 Author: Florian Carrier Creation date: 2021-06-13 - Last modified: 2024-09-11 + Last modified: 2024-09-12 Dependencies: - PowerShell Tool Kit (PSTK) - Alteryx PowerShell Module (PSAYX) @@ -73,6 +74,7 @@ Param ( "deactivate", "install", "patch", + "ping", "repair", "restart", "restore", @@ -144,11 +146,13 @@ Begin { # General $ISOTimeStamp = Get-Date -Format "yyyyMMdd_HHmmss" - # Configuration - $LibDirectory = Join-Path -Path $PSScriptRoot -ChildPath "lib" - $ConfDirectory = Join-Path -Path $PSScriptRoot -ChildPath "conf" - $DefaultProperties = "default.ini" - $CustomProperties = "custom.ini" + # Script configuration + $ScriptProperties = [Ordered]@{ + LibDirectory = (Join-Path -Path $PSScriptRoot -ChildPath "lib") + ConfDirectory = (Join-Path -Path $PSScriptRoot -ChildPath "conf") + DefaultProperties = "default.ini" + CustomProperties = "custom.ini" + } # ---------------------------------------------------------------------------- # * Modules @@ -162,7 +166,7 @@ Begin { foreach ($Module in $Modules.GetEnumerator()) { try { # Check if package is available locally - Import-Module -Name (Join-Path -Path $LibDirectory -ChildPath $Module.Name) -MinimumVersion $Module.Value -ErrorAction "Stop" -Force + Import-Module -Name (Join-Path -Path $ScriptProperties.LibDirectory -ChildPath $Module.Name) -MinimumVersion $Module.Value -ErrorAction "Stop" -Force $ModuleVersion = (Get-Module -Name $Module.Name).Version Write-Log -Type "CHECK" -Object "The $($Module.Name) module (v$ModuleVersion) was successfully loaded from the library directory." } catch { @@ -172,7 +176,7 @@ Begin { $ModuleVersion = (Get-Module -Name $Module.Name).Version Write-Log -Type "CHECK" -Object "The $($Module.Name) module (v$ModuleVersion) was successfully loaded." } catch { - Throw "The $($Module.Name) module (v$($Module.Value)) could not be loaded. Make sure it has been installed on the machine or packaged in the ""$LibDirectory"" directory" + Throw "The $($Module.Name) module (v$($Module.Value)) could not be loaded. Make sure it has been installed on the machine or packaged in the ""$($ScriptProperties.LibDirectory)"" directory" } } } @@ -181,7 +185,7 @@ Begin { # * Script configuration # ---------------------------------------------------------------------------- # General settings - $Properties = Get-Properties -File $DefaultProperties -Directory $ConfDirectory -Custom $CustomProperties + $Properties = Get-Properties -File $ScriptProperties.DefaultProperties -Directory $ScriptProperties.ConfDirectory -Custom $ScriptProperties.CustomProperties # Resolve relative paths Write-Log -Type "DEBUG" -Message "Script structure check" $Properties = Get-Path -PathToResolve $Properties.RelativePaths -Hashtable $Properties -Root $PSScriptRoot @@ -275,12 +279,13 @@ Process { switch ($Action) { "activate" { $Process = Invoke-ActivateAlteryx -Properties $Properties -Unattended:$Unattended } "backup" { $Process = Invoke-BackupAlteryx -Properties $Properties -Unattended:$Unattended } - "configure" { $Process = Set-Configuration -Properties $Properties -Unattended:$Unattended } + "configure" { $Process = Set-Configuration -Properties $Properties -ScriptProperties $ScriptProperties } "deactivate" { $Process = Invoke-DeactivateAlteryx -Properties $Properties -Unattended:$Unattended } "download" { $Process = Invoke-DownloadAlteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } "install" { $Process = Install-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } "repair" { $Process = Repair-Alteryx -Properties $Properties -Unattended:$Unattended } "patch" { $Process = Invoke-PatchAlteryx -Properties $Properties -Unattended:$Unattended } + "ping" { $Process = Invoke-PingAlteryx -Properties $Properties -Unattended:$Unattended } "repair" { $Process = Repair-Alteryx -Properties $Properties -Unattended:$Unattended } "restart" { $Process = Invoke-RestartAlteryx -Properties $Properties -Unattended:$Unattended } "restore" { $Process = Invoke-RestoreAlteryx -Properties $Properties -Unattended:$Unattended } diff --git a/powershell/Invoke-PingAlteryx.ps1 b/powershell/Invoke-PingAlteryx.ps1 new file mode 100644 index 0000000..b211600 --- /dev/null +++ b/powershell/Invoke-PingAlteryx.ps1 @@ -0,0 +1,98 @@ +function Invoke-PingAlteryx { + <# + .SYNOPSIS + Ping Alteryx Server + + .DESCRIPTION + Ping Alteryx Server to check if it alive + + .NOTES + File name: Invoke-PingAlteryx.ps1 + Author: Florian Carrier + Creation date: 2024-09-16 + Last modified: 2024-09-16 + #> + [CmdletBinding ( + SupportsShouldProcess = $true + )] + Param ( + [Parameter ( + Position = 1, + Mandatory = $true, + HelpMessage = "Script properties" + )] + [ValidateNotNullOrEmpty ()] + [System.Collections.Specialized.OrderedDictionary] + $Properties, + [Parameter ( + HelpMessage = "Non-interactive mode" + )] + [Switch] + $Unattended + ) + Begin { + # Get global preference vrariables + Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState + # Log function call + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $PingProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name + # Parameters + $HostName = [System.Net.Dns]::GetHostName() + $ServiceName = "AlteryxService" + } + Process { + $PingProcess = Update-ProcessObject -ProcessObject $PingProcess -Status "Running" + Write-Log -Type "NOTICE" -Message "Pinging Alteryx Server" + # ---------------------------------------------------------------------------- + # Check Alteryx service status + Write-Log -Type "INFO" -Message "Check Alteryx Service status" + if ($PSCmdlet.ShouldProcess("Alteryx Service", "Check")) { + $AlteryxService = Get-Service -Name $ServiceName + Write-Log -Type "DEBUG" -Message $AlteryxService + $ServiceStatus = Format-String -String $AlteryxService.Status -Format "LowerCase" + if ($AlteryxService.Status -eq "Running") { + Write-Log -Type "CHECK" -Message "$ServiceName is $ServiceStatus" + } else { + Write-Log -Type "ERROR" -Message "$ServiceName is $ServiceStatus" + $PingProcess = Update-ProcessObject -ProcessObject $PingProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + if ($Unattended -eq $false) { + $Continue = Confirm-Prompt -Prompt "Alteryx Service does not appear to be running, do you still want to try to ping the Gallery?" + if ($Continue -eq $false) { + return $PingProcess + } + } else { + return $PingProcess + } + } + } else { + # WhatIf + Write-Log -Type "CHECK" -Message "$ServiceName is running" + } + # ---------------------------------------------------------------------------- + # Check Gallery + Write-Log -Type "INFO" -Message "Check Alteryx Gallery status" + if ($PSCmdlet.ShouldProcess("Alteryx Gallery", "Ping")) { + if ($Properties.EnableSSL -eq $true) { + $Protocol = "https" + } else { + $Protocol = "http" + } + $GalleryURL = "$($Protocol)://$($HostName)/gallery" + if (Test-HTTPStatus -URI $GalleryURL) { + Write-Log -Type "CHECK" -Message "Alteryx Gallery is accessible" + $PingProcess = Update-ProcessObject -ProcessObject $PingProcess -Status "Completed" -Success $true + } else { + Write-Log -Type "ERROR" -Message "Alteryx Gallery is not accessible" + $PingProcess = Update-ProcessObject -ProcessObject $PingProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + } + } else { + # WhatIf + Write-Log -Type "CHECK" -Message "Alteryx Gallery is accessible" + $PingProcess = Update-ProcessObject -ProcessObject $PingProcess -Status "Completed" -Success $true + } + } + End { + return $PingProcess + } +} \ No newline at end of file From bf2e52f99edafd6d1cfe80c286b0617daa100b53 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 16 Sep 2024 12:25:25 +0200 Subject: [PATCH 17/61] Use service version Revert to calling service utility to retrieve full version number --- powershell/Invoke-BackupAlteryx.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powershell/Invoke-BackupAlteryx.ps1 b/powershell/Invoke-BackupAlteryx.ps1 index 381a106..beca617 100644 --- a/powershell/Invoke-BackupAlteryx.ps1 +++ b/powershell/Invoke-BackupAlteryx.ps1 @@ -10,7 +10,7 @@ function Invoke-BackupAlteryx { File name: Invoke-BackupAlteryx.ps1 Author: Florian Carrier Creation date: 2021-08-26 - Last modified: 2024-09-11 + Last modified: 2024-09-16 #> [CmdletBinding ( SupportsShouldProcess = $true @@ -38,7 +38,7 @@ function Invoke-BackupAlteryx { # Process status $BackupProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # Variables - $Version = Get-AlteryxRegistryVersion + $Version = Get-AlteryxVersion $ISOTimeStamp = Get-Date -Format "yyyyMMdd_HHmmss" $BackupPath = Join-Path -Path $Properties.BackupDirectory -ChildPath "${ISOTimeStamp}_Alteryx_Server_$($Version).zip" $TempBackupPath = Join-Path -Path $Properties.TempDirectory -ChildPath "${ISOTimeStamp}_Alteryx_Server_$($Version)" From 08a1080e088c6f371d5bb8860ce2955750054631 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 16 Sep 2024 14:06:52 +0200 Subject: [PATCH 18/61] Fix file check Fix check for backup path and amend error message --- powershell/Invoke-RestoreAlteryx.ps1 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/powershell/Invoke-RestoreAlteryx.ps1 b/powershell/Invoke-RestoreAlteryx.ps1 index 8cc8122..cb7e67b 100644 --- a/powershell/Invoke-RestoreAlteryx.ps1 +++ b/powershell/Invoke-RestoreAlteryx.ps1 @@ -100,15 +100,17 @@ function Invoke-RestoreAlteryx { } # Look for backup file if (Test-Object -Path $SourcePath) { - if ($SourcePath -is [System.IO.FileInfo]) { - if ([System.IO.Path]::GetExtension($SourcePath) -eq ".zip") { + $Source = Get-Item -Path $SourcePath + # Check if source is a file + if ($Source.PSIsContainer -eq $false) { + if ((Format-String -String $Source.Extension -Format "LowerCase") -eq ".zip") { # Extract archive file Write-Log -Type "INFO" -Message "Extract backup file contents" $BackupPath = Join-Path -Path $Properties.TempDirectory -ChildPath ([System.IO.Path]::GetFileNameWithoutExtension($SourcePath)) Expand-Archive -Path $SourcePath -DestinationPath $BackupPath -Force -WhatIf:$WhatIfPreference $Staging = $true } else { - Write-Log -Type "ERROR" -Message "Only ZIP or uncompressed files are supported" + Write-Log -Type "ERROR" -Message "Only ZIP files are supported" $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -Status "Failed" -ErrorCode 1 -ExitCode 1 return $RestoreProcess } From 2004aaff8853d91d2bc2323ecbb4ec11b491afac Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 16 Sep 2024 14:19:53 +0200 Subject: [PATCH 19/61] Add open operation Add option to open the Alteryx application --- Deploy-Alteryx.ps1 | 40 ++++++++++-------- powershell/Open-Alteryx.ps1 | 84 +++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 18 deletions(-) create mode 100644 powershell/Open-Alteryx.ps1 diff --git a/Deploy-Alteryx.ps1 b/Deploy-Alteryx.ps1 index 17ad532..1ce0825 100644 --- a/Deploy-Alteryx.ps1 +++ b/Deploy-Alteryx.ps1 @@ -20,6 +20,7 @@ - download: download latest Alteryx application release - install: install the Alteryx application - repair: repair the Alteryx application database + - open: open the Alteryx application - patch: patch upgrade the Alteryx application - ping: check the status of the Alteryx application - repair: repair the Alteryx application database @@ -38,7 +39,7 @@ File name: Deploy-Alteryx.ps1 Author: Florian Carrier Creation date: 2021-06-13 - Last modified: 2024-09-12 + Last modified: 2024-09-16 Dependencies: - PowerShell Tool Kit (PSTK) - Alteryx PowerShell Module (PSAYX) @@ -73,6 +74,7 @@ Param ( "configure", "deactivate", "install", + "open", "patch", "ping", "repair", @@ -259,6 +261,7 @@ Begin { ) $InstallationProperties = Get-Properties -File $Properties.InstallationOptions -Directory $Properties.ConfDirectory -ValidateSet $ValidateSet $InstallationProperties.Add("Product", $Product) + $Properties.Add("Product", $Product) # Optional parameters if ($PSBoundParameters.ContainsKey("Version")) { $Properties.Version = $Version @@ -277,23 +280,24 @@ Begin { Process { # Check operation to perform switch ($Action) { - "activate" { $Process = Invoke-ActivateAlteryx -Properties $Properties -Unattended:$Unattended } - "backup" { $Process = Invoke-BackupAlteryx -Properties $Properties -Unattended:$Unattended } - "configure" { $Process = Set-Configuration -Properties $Properties -ScriptProperties $ScriptProperties } - "deactivate" { $Process = Invoke-DeactivateAlteryx -Properties $Properties -Unattended:$Unattended } - "download" { $Process = Invoke-DownloadAlteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } - "install" { $Process = Install-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } - "repair" { $Process = Repair-Alteryx -Properties $Properties -Unattended:$Unattended } - "patch" { $Process = Invoke-PatchAlteryx -Properties $Properties -Unattended:$Unattended } - "ping" { $Process = Invoke-PingAlteryx -Properties $Properties -Unattended:$Unattended } - "repair" { $Process = Repair-Alteryx -Properties $Properties -Unattended:$Unattended } - "restart" { $Process = Invoke-RestartAlteryx -Properties $Properties -Unattended:$Unattended } - "restore" { $Process = Invoke-RestoreAlteryx -Properties $Properties -Unattended:$Unattended } - "show" { $Process = Show-Configuration -Properties $Properties -InstallationProperties $InstallationProperties } - "start" { $Process = Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended } - "stop" { $Process = Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended } - "uninstall" { $Process = Uninstall-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } - "upgrade" { $Process = Update-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } + "activate" { $Process = Invoke-ActivateAlteryx -Properties $Properties -Unattended:$Unattended } + "backup" { $Process = Invoke-BackupAlteryx -Properties $Properties -Unattended:$Unattended } + "configure" { $Process = Set-Configuration -Properties $Properties -ScriptProperties $ScriptProperties } + "deactivate" { $Process = Invoke-DeactivateAlteryx -Properties $Properties -Unattended:$Unattended } + "download" { $Process = Invoke-DownloadAlteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } + "install" { $Process = Install-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } + "repair" { $Process = Repair-Alteryx -Properties $Properties -Unattended:$Unattended } + "open" { $Process = Open-Alteryx -Properties $Properties -Unattended:$Unattended } + "patch" { $Process = Invoke-PatchAlteryx -Properties $Properties -Unattended:$Unattended } + "ping" { $Process = Invoke-PingAlteryx -Properties $Properties -Unattended:$Unattended } + "repair" { $Process = Repair-Alteryx -Properties $Properties -Unattended:$Unattended } + "restart" { $Process = Invoke-RestartAlteryx -Properties $Properties -Unattended:$Unattended } + "restore" { $Process = Invoke-RestoreAlteryx -Properties $Properties -Unattended:$Unattended } + "show" { $Process = Show-Configuration -Properties $Properties -InstallationProperties $InstallationProperties } + "start" { $Process = Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended } + "stop" { $Process = Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended } + "uninstall" { $Process = Uninstall-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } + "upgrade" { $Process = Update-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } default { Write-Log -Type "ERROR" -Message """$Action"" operation is not supported" -ExitCode 1 } } } diff --git a/powershell/Open-Alteryx.ps1 b/powershell/Open-Alteryx.ps1 new file mode 100644 index 0000000..62c5f28 --- /dev/null +++ b/powershell/Open-Alteryx.ps1 @@ -0,0 +1,84 @@ +function Open-Alteryx { + <# + .SYNOPSIS + Open Alteryx Server + + .DESCRIPTION + Open the default web-browser and navigate to Alteryx Gallery + + .NOTES + File name: Open-Alteryx.ps1 + Author: Florian Carrier + Creation date: 2024-09-16 + Last modified: 2024-09-16 + #> + [CmdletBinding ( + SupportsShouldProcess = $true + )] + Param ( + [Parameter ( + Position = 1, + Mandatory = $true, + HelpMessage = "Script properties" + )] + [ValidateNotNullOrEmpty ()] + [System.Collections.Specialized.OrderedDictionary] + $Properties, + [Parameter ( + HelpMessage = "Non-interactive mode" + )] + [Switch] + $Unattended + ) + Begin { + # Get global preference vrariables + Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState + # Log function call + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $OpenProcess= New-ProcessObject -Name $MyInvocation.MyCommand.Name + # Parameters + $HostName = [System.Net.Dns]::GetHostName() + } + Process { + $OpenProcess = Update-ProcessObject -ProcessObject $OpenProcess -Status "Running" + Write-Log -Type "NOTICE" -Message "Opening Alteryx $($Properties.Product)" + if ($Properties.Product -eq "Server") { + Write-Log -Type "INFO" -Message "Opening Alteryx Gallery" + if ($PSCmdlet.ShouldProcess("Alteryx Gallery", "Open")) { + if ($Properties.EnableSSL -eq $true) { + $Protocol = "https" + } else { + $Protocol = "http" + } + $GalleryURL = "$($Protocol)://$($HostName)/gallery" + Start-Process -FilePath $GalleryURL + Write-Log -Type "CHECK" -Message "Alteryx Gallery opened successfully" + $OpenProcess = Update-ProcessObject -ProcessObject $OpenProcess -Status "Completed" -Success $true + } else { + # WhatIf + $OpenProcess = Update-ProcessObject -ProcessObject $OpenProcess -Status "Completed" -Success $true + } + } else { + if ($PSCmdlet.ShouldProcess("Alteryx $($Properties.Product)", "Open")) { + $DesignerPath = Get-AlteryxUtility -Utility $Properties.Product + $DesignerProcess = Start-Process -FilePath $DesignerPath -PassThru + $DesignerProcess.Refresh() + Write-Log -Type "DEBUG" -Message $DesignerProcess + if ($DesignerProcess.Responding -eq $true) { + Write-Log -Type "CHECK" -Message "Alteryx $($Properties.Product) opened successfully" + $OpenProcess = Update-ProcessObject -ProcessObject $OpenProcess -Status "Completed" -Success $true + } else { + Write-Log -Type "ERROR" -Message "Alteryx $($Properties.Product) could not be started" + $OpenProcess = Update-ProcessObject -ProcessObject $OpenProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + } + } else { + Write-Log -Type "CHECK" -Message "Alteryx $($Properties.Product) opened successfully" + $OpenProcess = Update-ProcessObject -ProcessObject $OpenProcess -Status "Completed" -Success $true + } + } + } + End { + return $OpenProcess + } +} \ No newline at end of file From c8b320afdd14bd7169b22d4a5d0d737f59de7b9f Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 16 Sep 2024 14:20:46 +0200 Subject: [PATCH 20/61] Use default property object Update product reference to global properties --- powershell/Invoke-DownloadAlteryx.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/powershell/Invoke-DownloadAlteryx.ps1 b/powershell/Invoke-DownloadAlteryx.ps1 index 6c6c6c0..979e4c1 100644 --- a/powershell/Invoke-DownloadAlteryx.ps1 +++ b/powershell/Invoke-DownloadAlteryx.ps1 @@ -10,7 +10,7 @@ function Invoke-DownloadAlteryx { File name: Invoke-DownloadAlteryx.ps1 Author: Florian Carrier Creation date: 2024-09-04 - Last modified: 2024-09-06 + Last modified: 2024-09-16 #> [CmdletBinding ()] Param ( @@ -48,7 +48,7 @@ function Invoke-DownloadAlteryx { "Designer" = "Alteryx Designer" "Server" = "Alteryx Server" } - $ProductID = $Products.$($InstallationProperties.Product) + $ProductID = $Products.$($Properties.Product) # License API refresh token $RefreshToken = Get-Content -Path $Properties.LicenseAPIFile -Raw # Placeholder @@ -112,6 +112,7 @@ function Invoke-DownloadAlteryx { Write-Log -Type "WARN" -Message "Skipping download process" $Process = Update-ProcessObject -ProcessObject $Process -Status "Cancelled" -Success $true -ExitCode 0 -ErrorCount 0 } + # TODO download add-ons } End { return $Process From 7ab93364de8078d903a408b5ac580b350dcaf14b Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Tue, 17 Sep 2024 15:43:02 +0200 Subject: [PATCH 21/61] Update .gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 235636f..7b15558 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # Ignore log files +log *.log # Ignore temporary directory @@ -6,4 +7,5 @@ tmp # Ignore custom configuration files custom.ini -registry.info \ No newline at end of file +registry.info +*.token \ No newline at end of file From 4ca04702fbe1a3193ed5c573b10a4dafdde2da1c Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Tue, 17 Sep 2024 15:43:50 +0200 Subject: [PATCH 22/61] Add configuration wizard Add option to customise script configuration interactively --- Deploy-Alteryx.ps1 | 2 +- conf/default.ini | 22 ++-- powershell/Set-Configuration.ps1 | 192 +++++++++++++++++++++++++++++-- 3 files changed, 199 insertions(+), 17 deletions(-) diff --git a/Deploy-Alteryx.ps1 b/Deploy-Alteryx.ps1 index 1ce0825..d222860 100644 --- a/Deploy-Alteryx.ps1 +++ b/Deploy-Alteryx.ps1 @@ -258,7 +258,7 @@ Begin { "PredictiveTools" "IntelligenceSuite" "DataPackages" - ) + ) $InstallationProperties = Get-Properties -File $Properties.InstallationOptions -Directory $Properties.ConfDirectory -ValidateSet $ValidateSet $InstallationProperties.Add("Product", $Product) $Properties.Add("Product", $Product) diff --git a/conf/default.ini b/conf/default.ini index 3369862..829454b 100644 --- a/conf/default.ini +++ b/conf/default.ini @@ -20,16 +20,22 @@ SrcDirectory = C:\Sources InstallationPath = C:\Program Files\Alteryx # Backup directory BackupDirectory = C:\ProgramData\Alteryx\Backup -# Predictive Tools directory -RDirectory = RInstaller # Data packages installation directory DataPackagesPath = C:\Program Files\Alteryx\Data +# Predictive Tools directory +RDirectory = RInstaller # 7zip application path (required for data packages) 7zipPath = C:\Program Files\7-Zip\7z.exe [Filenames] # Installation properties InstallationOptions = install.ini +# License file +LicenseFile = license.key +# License API refresh token file +LicenseAPIFile = license.token +# Server admin API key & secret +ServerAdminAPI = server.token [Misc.] # Installation language @@ -48,25 +54,25 @@ ActivateOnUpgrade = true [License] # Licensing system URL LicensingURL = whitelist.alteryx.com -# License file -LicenseFile = # License email LicenseEmail = # License Account ID LicenseAccountID = -# License API refresh token file -LicenseAPIFile = [SSL] # SSL/TLS -EnableSSL = true +EnableSSL = false # Application ID ApplicationID = {eea9431a-a3d4-4c9b-9f9a-b83916c11c67} [Ports] +# Gallery HTTP communication port HTTPPort = 80 +# Gallery HTTPS communication port HTTPSPort = 443 +# Embedded MongoDB database communication port MongoDBPort = 27018 [Checks] -RelativePaths = ConfDirectory, PSDirectory, TempDirectory, LogDirectory, ResDirectory +# Script internal structure +RelativePaths = ConfDirectory, PSDirectory, TempDirectory, LogDirectory, ResDirectory \ No newline at end of file diff --git a/powershell/Set-Configuration.ps1 b/powershell/Set-Configuration.ps1 index 439fb23..0b14f33 100644 --- a/powershell/Set-Configuration.ps1 +++ b/powershell/Set-Configuration.ps1 @@ -1,18 +1,20 @@ function Set-Configuration { <# .SYNOPSIS - Configure Alteryx Server + Configure Alteryx deploy utility .DESCRIPTION - Set Alteryx Server configuration + Configuration wizard for the required parameters of the alteryx-deploy utility .NOTES File name: Set-Configuration.ps1 Author: Florian Carrier Creation date: 2022-05-03 - Last modified: 2022-05-03 + Last modified: 2024-09-17 #> - [CmdletBinding ()] + [CmdletBinding ( + SupportsShouldProcess = $true + )] Param ( [Parameter ( Position = 1, @@ -25,18 +27,192 @@ function Set-Configuration { [Parameter ( Position = 2, Mandatory = $true, - HelpMessage = "Installation properties" + HelpMessage = "Default script properties" )] [ValidateNotNullOrEmpty ()] [System.Collections.Specialized.OrderedDictionary] - $InstallationProperties + $ScriptProperties ) Begin { # Get global preference vrariables Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState - + # Log function call + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $ConfigureProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name + # Parameters + $ConfDirectory = $ScriptProperties.ConfDirectory + $DefaultPath = Join-Path -Path $ConfDirectory -ChildPath $ScriptProperties.DefaultProperties + $CustomPath = Join-Path -Path $ConfDirectory -ChildPath $ScriptProperties.CustomProperties + $CustomHeader = +"# ------------------------------------------------------------------------------ +# Add your custom configuration here +# e.g. TempDirectory = D:\Temp +# ------------------------------------------------------------------------------" } Process { - + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Running" + Write-Log -Type "NOTICE" -Message "Configuring script" + # ------------------------------------------------------------------------------ + # * Configure script parameters + Write-Log -Type "INFO" -Message "Configuring script parameters" + if ($PSCmdlet.ShouldProcess("Script parameters", "Configure")) { + Write-Log -Type "INFO" -Message "Leave blank to keep default value" + # Fetch default configuration + $DefaultConfiguration = Get-Properties -Path $DefaultPath -Metadata + $CustomConfiguration = New-Object -TypeName "System.Collections.Specialized.OrderedDictionary" + # Define parameters to exclude + $ExclusionList = ($($DefaultConfiguration.GetEnumerator()).Value | Where-Object { $PSItem.Section -eq "Checks" }).Value + # Loop through parameters + foreach ($Property in $DefaultConfiguration.GetEnumerator()) { + # Exclude reserved parameters + if ($($Property.Value).Section -notin ("SSL", "Checks") -And (-Not $ExclusionList.Contains($Property.Name))) { + $ValuePrompt = [System.String]::Concat($($Property.Value).Description, " (", $Property.Name, ")") + $DefaultValue = $($Property.Value).Value + # Check if a default value exists to display back to user + if ($DefaultValue.Trim() -notin @($null, "")) { + $ValuePrompt = "$ValuePrompt [default value: $DefaultValue]" + } + # Prompt user for input + $NewValue = (Read-Host -Prompt $ValuePrompt).Trim() + if ($NewValue -notin @($null, "")) { + $NewProperty = [Ordered]@{ + "Value" = $NewValue + "Description" = $($Property.Value).Description + "Section" = $($Property.Value).Section + } + $CustomConfiguration.Add($Property.Name, $NewProperty) + Write-Log -Type "DEBUG" -Message $CustomConfiguration[$Property.Name] + } + } + } + # Generate custom configuration file + Write-Log -Type "DEBUG" -Message $CustomConfiguration + $CustomProperties = $CustomHeader + if ($CustomConfiguration.Count -ge 1) { + foreach ($CustomProperty in $CustomConfiguration.GetEnumerator()) { + $Name = $CustomProperty.Name + $Value = $($CustomProperty.Value).Value + $Description = $($CustomProperty.Value).Description + $CustomProperties += [System.String]::Concat("`n", "# $Description", "`n", $Name, " = ", "$Value") + } + } + # Save back to file + try { + Write-Log -Type "DEBUG" -Message $CustomPath + Set-Content -Path $CustomPath -Value $CustomProperties.Trim() -Force + } catch { + Write-Log -Type "ERROR" -Message (Get-Error) + Write-Log -Type "ERROR" -Message "Custom configuration could not be saved" + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -ErrorCount 1 + } + # Reload properties + $Properties = Get-Properties -Path $DefaultPath -CustomPath $CustomPath + } + # ------------------------------------------------------------------------------ + # # * Configure license API token + Write-Log -Type "INFO" -Message "Configuring License Portal API refresh token" + if ($PSCmdlet.ShouldProcess("License Portal API refresh token", "Configure")) { + $LicenseAPIPath = Join-Path -Path "$PSScriptRoot/.." -ChildPath "$($Properties.ResDirectory)/$($Properties.LicenseAPIFile)" + $LicenseAPIPrompt = "License Portal API refresh token" + $ConfigureLicenseAPI = $true + if (Test-Path -Path $LicenseAPIPath) { + $RefreshAPIToken = Get-Content -Path $LicenseAPIPath + if ($RefreshAPIToken -notin ($null, "")) { + Write-Log -Type "WARN" -Message "License Portal API refresh token has already been configured" + Write-Log -Type "DEBUG" -Message $RefreshAPIToken + $ConfigureLicenseAPI = Confirm-Prompt -Prompt "Do you want to reconfigure the License Portal API refresh token?" + } + } + if ($ConfigureLicenseAPI) { + $LicenseAPIToken = Read-Host -Prompt $LicenseAPIPrompt + Write-Log -Type "DEBUG" -Message $LicenseAPIToken + Write-Log -Type "DEBUG" -Message $LicenseAPIPath + Out-File -FilePath $LicenseAPIPath -InputObject $LicenseAPIToken -Force + if (Test-Path -Path $LicenseAPIPath) { + Write-Log -Type "CHECK" -Message "License Portal API refresh token saved successfully" + } else { + Write-Log -Type "ERROR" -Message (Get-Error) + Write-Log -Type "ERROR" -Message "License Portal API refresh token could not be saved" + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -ErrorCount 1 + } + } else { + Write-Log -Type "WARN" -Message "Skipping License Portal API refresh token configuration" + } + } + # # ------------------------------------------------------------------------------ + # # * Configure Server API keys + Write-Log -Type "INFO" -Message "Configuring Server API keys" + if ($PSCmdlet.ShouldProcess("Server API keys", "Configure")) { + $ServerAPIPath = Join-Path -Path "$PSScriptRoot/.." -ChildPath "$($Properties.ResDirectory)/$($Properties.ServerAdminAPI)" + $APIKeyPrompt = "Admin Server API key" + $APISecretPrompt = "Admin Server API secret" + $ConfigureServerAPI = $true + # Check if API keys have already been saved + if (Test-Path -Path $ServerAPIPath) { + $APIKeys = Get-Content -Path $ServerAPIPath | ConvertFrom-JSON + if ($APIKeys -notin ($null, "")) { + Write-Log -Type "WARN" -Message "Server API keys have already been configured" + Write-Log -Type "DEBUG" -Message $APIKeys + $ConfigureServerAPI = Confirm-Prompt -Prompt "Do you want to reconfigure Server API keys?" + if ($ConfigureServerAPI) { + $APIKeyPrompt = "$APIKeyPrompt (current $($APIKeys.Key))" + $APISecretPrompt = "$APISecretPrompt (current $($APIKeys.Secret))" + } + } + } + if ($ConfigureServerAPI) { + $ServerAPIKey = Read-Host -Prompt $APIKeyPrompt + $ServerAPISecret = Read-Host -Prompt $APISecretPrompt + $ServerAPIToken = [Ordered]@{ + "key" = $ServerAPIKey + "secret" = $ServerAPISecret + } | ConvertTo-JSON + Write-Log -Type "DEBUG" -Message $ServerAPIToken + Write-Log -Type "DEBUG" -Message $ServerAPIPath + Out-File -FilePath $ServerAPIPath -InputObject $ServerAPIToken -Force + if (Test-Path -Path $ServerAPIPath) { + Write-Log -Type "CHECK" -Message "Server API keys saved successfully" + } else { + Write-Log -Type "ERROR" -Message (Get-Error) + Write-Log -Type "ERROR" -Message "Server API keys could not be saved" + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -ErrorCount 1 + } + } else { + Write-Log -Type "WARN" -Message "Skipping Server API keys configuration" + } + } + # ------------------------------------------------------------------------------ + # * Configure installation properties + Write-Log -Type "INFO" -Message "Configuring installation properties" + $InstallationPropertiesPath = Join-Path -Path $ConfDirectory -ChildPath $Properties.InstallationOptions + $InstallationProperties = Get-Properties -Path $InstallationPropertiesPath + $NewInstallationProperties = "[Installation]" + foreach ($InstallationProperty in $InstallationProperties.GetEnumerator()) { + $Product = [regex]::Replace($InstallationProperty.Name, '([a-z])([A-Z])', '$1 $2') + if (Confirm-Prompt -Prompt "Install $($Product)?") { + $Newvalue = "true" + } else { + $NewValue = "false" + } + $NewInstallationProperties += [System.String]::Concat("`n", $InstallationProperty.Name, " = ", $NewValue) + } + try { + Write-Log -Type "DEBUG" -Message $NewInstallationProperties + Set-Content -Path $InstallationPropertiesPath -Value $NewInstallationProperties + } catch { + Write-Log -Type "ERROR" -Message (Get-Error) + Write-Log -Type "ERROR" -Message "Installation properties could not be saved" + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -ErrorCount 1 + } + # ------------------------------------------------------------------------------ + # TODO Configure SSL certificate + # Write-Log -Type "INFO" -Message "Configuring SSL/TLS" + # ------------------------------------------------------------------------------ + Write-Log -Type "CHECK" -Message "Configuration wizard complete" + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Completed" -Success $true + } + End { + return $ConfigureProcess } } \ No newline at end of file From fcbfe7fe6c18770ee19bd495e9f3940ac87062c5 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Tue, 17 Sep 2024 15:44:15 +0200 Subject: [PATCH 23/61] Update debug log --- powershell/Install-Alteryx.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powershell/Install-Alteryx.ps1 b/powershell/Install-Alteryx.ps1 index 5080563..7234b69 100644 --- a/powershell/Install-Alteryx.ps1 +++ b/powershell/Install-Alteryx.ps1 @@ -55,7 +55,7 @@ function Install-Alteryx { # Get global preference variables Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState # Log function call - Write-Log -Type "DEBUG" -Message $MyInvocation.ScriptName + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name # Variables $ISOTimeStamp = Get-Date -Format "yyyyMMdd_HHmmss" $Tags = [Ordered]@{"Version" = $Properties.Version} From f17c0bc2407125035b7d9f21b27352414485172a Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Tue, 17 Sep 2024 18:04:22 +0200 Subject: [PATCH 24/61] Add license key configuration --- .gitignore | 3 +- powershell/Set-Configuration.ps1 | 215 ++++++++++++++++++++++++++++++- 2 files changed, 216 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 235636f..9cdc3bc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ tmp # Ignore custom configuration files custom.ini -registry.info \ No newline at end of file +*.token +*.key diff --git a/powershell/Set-Configuration.ps1 b/powershell/Set-Configuration.ps1 index 439fb23..c42233c 100644 --- a/powershell/Set-Configuration.ps1 +++ b/powershell/Set-Configuration.ps1 @@ -37,6 +37,219 @@ function Set-Configuration { } Process { - + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Running" + Write-Log -Type "NOTICE" -Message "Configuring script" + # ------------------------------------------------------------------------------ + # * Configure script parameters + Write-Log -Type "INFO" -Message "Configuring script parameters" + if ($PSCmdlet.ShouldProcess("Script parameters", "Configure")) { + $ConfigureParameters = $true + # Check if custom configuration ahs already been set + if (Test-Path -Path $CustomPath) { + $CustomConfig = (Get-Content -Path $CustomPath).Trim() + if ($CustomConfig -ne $CustomHeader) { + $ConfigureParameters = Confirm-Prompt -Prompt "Do you want to overwrite the existing configuration?" + } + } + if ($ConfigureParameters -eq $true) { + Write-Log -Type "INFO" -Message "Leave blank to keep default value" + # Fetch default configuration + $DefaultConfiguration = Get-Properties -Path $DefaultPath -Metadata + $CustomConfiguration = New-Object -TypeName "System.Collections.Specialized.OrderedDictionary" + # Define parameters to exclude + $ExclusionList = ($($DefaultConfiguration.GetEnumerator()).Value | Where-Object { $PSItem.Section -eq "Checks" }).Value + # Loop through parameters + foreach ($Property in $DefaultConfiguration.GetEnumerator()) { + # Exclude reserved parameters + if ($($Property.Value).Section -notin ("SSL", "Checks") -And (-Not $ExclusionList.Contains($Property.Name))) { + $ValuePrompt = [System.String]::Concat($($Property.Value).Description, " (", $Property.Name, ")") + $DefaultValue = $($Property.Value).Value + # Check if a default value exists to display back to user + if ($DefaultValue.Trim() -notin @($null, "")) { + $ValuePrompt = "$ValuePrompt [default value: $DefaultValue]" + } + # Prompt user for input + $NewValue = (Read-Host -Prompt $ValuePrompt).Trim() + if ($NewValue -notin @($null, "")) { + $NewProperty = [Ordered]@{ + "Value" = $NewValue + "Description" = $($Property.Value).Description + "Section" = $($Property.Value).Section + } + $CustomConfiguration.Add($Property.Name, $NewProperty) + Write-Log -Type "DEBUG" -Message $CustomConfiguration[$Property.Name] + } + } + } + # Generate custom configuration file + Write-Log -Type "DEBUG" -Message $CustomConfiguration + $CustomProperties = $CustomHeader + if ($CustomConfiguration.Count -ge 1) { + foreach ($CustomProperty in $CustomConfiguration.GetEnumerator()) { + $Name = $CustomProperty.Name + $Value = $($CustomProperty.Value).Value + $Description = $($CustomProperty.Value).Description + $CustomProperties += [System.String]::Concat("`n", "# $Description", "`n", $Name, " = ", "$Value") + } + } + # Save back to file + try { + Write-Log -Type "DEBUG" -Message $CustomPath + Set-Content -Path $CustomPath -Value $CustomProperties.Trim() -Force + } catch { + Write-Log -Type "ERROR" -Message (Get-Error) + Write-Log -Type "ERROR" -Message "Custom configuration could not be saved" + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -ErrorCount 1 + } + } + # Reload properties + $Properties = Get-Properties -Path $DefaultPath -CustomPath $CustomPath + } + # ------------------------------------------------------------------------------ + # # * Configure license API token + Write-Log -Type "INFO" -Message "Configuring License Portal API refresh token" + if ($PSCmdlet.ShouldProcess("License Portal API refresh token", "Configure")) { + $LicenseAPIPath = Join-Path -Path "$PSScriptRoot/.." -ChildPath "$($Properties.ResDirectory)/$($Properties.LicenseAPIFile)" + $LicenseAPIPrompt = "License Portal API refresh token" + $ConfigureLicenseAPI = $true + if (Test-Path -Path $LicenseAPIPath) { + $RefreshAPIToken = Get-Content -Path $LicenseAPIPath + if ($RefreshAPIToken -notin ($null, "")) { + Write-Log -Type "WARN" -Message "License Portal API refresh token has already been configured" + Write-Log -Type "DEBUG" -Message $RefreshAPIToken + $ConfigureLicenseAPI = Confirm-Prompt -Prompt "Do you want to reconfigure the License Portal API refresh token?" + } + } + if ($ConfigureLicenseAPI) { + $LicenseAPIToken = Read-Host -Prompt $LicenseAPIPrompt + Write-Log -Type "DEBUG" -Message $LicenseAPIToken + Write-Log -Type "DEBUG" -Message $LicenseAPIPath + Out-File -FilePath $LicenseAPIPath -InputObject $LicenseAPIToken -Force + if (Test-Path -Path $LicenseAPIPath) { + Write-Log -Type "CHECK" -Message "License Portal API refresh token saved successfully" + } else { + Write-Log -Type "ERROR" -Message (Get-Error) + Write-Log -Type "ERROR" -Message "License Portal API refresh token could not be saved" + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -ErrorCount 1 + } + } else { + Write-Log -Type "WARN" -Message "Skipping License Portal API refresh token configuration" + } + } + # # ------------------------------------------------------------------------------ + # # * Configure Server API keys + Write-Log -Type "INFO" -Message "Configuring Server API keys" + if ($PSCmdlet.ShouldProcess("Server API keys", "Configure")) { + $ServerAPIPath = Join-Path -Path "$PSScriptRoot/.." -ChildPath "$($Properties.ResDirectory)/$($Properties.ServerAdminAPI)" + $APIKeyPrompt = "Admin Server API key" + $APISecretPrompt = "Admin Server API secret" + $ConfigureServerAPI = $true + # Check if API keys have already been saved + if (Test-Path -Path $ServerAPIPath) { + $APIKeys = Get-Content -Path $ServerAPIPath | ConvertFrom-JSON + if ($APIKeys -notin ($null, "")) { + Write-Log -Type "WARN" -Message "Server API keys have already been configured" + Write-Log -Type "DEBUG" -Message $APIKeys + $ConfigureServerAPI = Confirm-Prompt -Prompt "Do you want to reconfigure Server API keys?" + if ($ConfigureServerAPI) { + $APIKeyPrompt = "$APIKeyPrompt (current $($APIKeys.Key))" + $APISecretPrompt = "$APISecretPrompt (current $($APIKeys.Secret))" + } + } + } + if ($ConfigureServerAPI) { + $ServerAPIKey = Read-Host -Prompt $APIKeyPrompt + $ServerAPISecret = Read-Host -Prompt $APISecretPrompt + $ServerAPIToken = [Ordered]@{ + "key" = $ServerAPIKey + "secret" = $ServerAPISecret + } | ConvertTo-JSON + Write-Log -Type "DEBUG" -Message $ServerAPIToken + Write-Log -Type "DEBUG" -Message $ServerAPIPath + Out-File -FilePath $ServerAPIPath -InputObject $ServerAPIToken -Force + if (Test-Path -Path $ServerAPIPath) { + Write-Log -Type "CHECK" -Message "Server API keys saved successfully" + } else { + Write-Log -Type "ERROR" -Message (Get-Error) + Write-Log -Type "ERROR" -Message "Server API keys could not be saved" + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -ErrorCount 1 + } + } else { + Write-Log -Type "WARN" -Message "Skipping Server API keys configuration" + } + } + # ------------------------------------------------------------------------------ + # * Configure installation properties + Write-Log -Type "INFO" -Message "Configuring installation properties" + if ($PSCmdlet.ShouldProcess("Installation properties", "Configure")) { + $InstallationPropertiesPath = Join-Path -Path $ConfDirectory -ChildPath $Properties.InstallationOptions + $InstallationProperties = Get-Properties -Path $InstallationPropertiesPath + $NewInstallationProperties = "[Installation]" + foreach ($InstallationProperty in $InstallationProperties.GetEnumerator()) { + $Product = [regex]::Replace($InstallationProperty.Name, '([a-z])([A-Z])', '$1 $2') + if (Confirm-Prompt -Prompt "Install $($Product)?") { + $Newvalue = "true" + } else { + $NewValue = "false" + } + $NewInstallationProperties += [System.String]::Concat("`n", $InstallationProperty.Name, " = ", $NewValue) + } + try { + Write-Log -Type "DEBUG" -Message $NewInstallationProperties + Set-Content -Path $InstallationPropertiesPath -Value $NewInstallationProperties + } catch { + Write-Log -Type "ERROR" -Message (Get-Error) + Write-Log -Type "ERROR" -Message "Installation properties could not be saved" + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -ErrorCount 1 + } + } + # ------------------------------------------------------------------------------ + # * Configure license file + Write-Log -Type "INFO" -Message "Configuring license file" + if ($PSCmdlet.ShouldProcess("License file", "Configure")) { + Write-Log -Type "NOTICE" -Message $Properties + $LicenseFilePath = Join-Path -Path "$PSScriptRoot/.." -ChildPath "$($Properties.ResDirectory)/$($Properties.LicenseFile)" + $ConfigureLicenseFile = $true + if (Test-Path -Path $LicenseFilePath) { + $LicenseKeys = Get-Content -Path $LicenseFilePath + if ($LicenseKeys -notin ($null, "")) { + Write-Log -Type "WARN" -Message "License keys have already been configured" + Write-Log -Type "DEBUG" -Message $LicenseKeys + $ConfigureLicenseFile = Confirm-Prompt -Prompt "Do you want to overwrite the existing license keys?" + } + } + if ($ConfigureLicenseFile) { + $LicenseKeys = (Read-Host -Prompt "Enter Alteryx license key(s)") -split '[ ,]+' + Write-Log -Type "DEBUG" -Message $LicenseKeys + try { + Write-Log -Type "DEBUG" $LicenseFilePath + Set-Content -Path $LicenseFilePath -Value $LicenseKeys + } catch { + Write-Log -Type "ERROR" -Message (Get-Error) + Write-Log -Type "ERROR" -Message "License file could not be saved" + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -ErrorCount 1 + } + } + } + # ------------------------------------------------------------------------------ + # TODO Configure SSL certificate + # Write-Log -Type "INFO" -Message "Configuring SSL/TLS" + # ------------------------------------------------------------------------------ + if ($ConfigureProcess.ErrorCount -eq 5) { + # If all configuration failed + Write-Log -Type "ERROR" -Message "Configuration wizard failed" + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Failed" -ExitCode 1 + } elseif ($ConfigureProcess.ErrorCount -gt 0) { + # If only partial failure + Write-Log -Type "WARN" -Message "Configuration wizard completed with errors" + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Completed" + } else { + # Otherwise success + Write-Log -Type "CHECK" -Message "Configuration wizard complete" + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Completed" -Success $true + } + } + End { + return $ConfigureProcess } } \ No newline at end of file From ea0db3e71deed6cf938ea6f32f7434e1e288c7ae Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Tue, 17 Sep 2024 19:13:41 +0200 Subject: [PATCH 25/61] Remove debug message --- powershell/Set-Configuration.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/powershell/Set-Configuration.ps1 b/powershell/Set-Configuration.ps1 index 2952b02..98b1e14 100644 --- a/powershell/Set-Configuration.ps1 +++ b/powershell/Set-Configuration.ps1 @@ -221,7 +221,6 @@ function Set-Configuration { # * Configure license file Write-Log -Type "INFO" -Message "Configuring license file" if ($PSCmdlet.ShouldProcess("License file", "Configure")) { - Write-Log -Type "NOTICE" -Message $Properties $LicenseFilePath = Join-Path -Path "$PSScriptRoot/.." -ChildPath "$($Properties.ResDirectory)/$($Properties.LicenseFile)" $ConfigureLicenseFile = $true if (Test-Path -Path $LicenseFilePath) { From a6a4172d472c5628c9c2bf12cc74b032a558cf9d Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Tue, 17 Sep 2024 19:14:48 +0200 Subject: [PATCH 26/61] Fix issue when Alteryx is not (yet) installed --- powershell/Invoke-DownloadAlteryx.ps1 | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/powershell/Invoke-DownloadAlteryx.ps1 b/powershell/Invoke-DownloadAlteryx.ps1 index 979e4c1..bed4523 100644 --- a/powershell/Invoke-DownloadAlteryx.ps1 +++ b/powershell/Invoke-DownloadAlteryx.ps1 @@ -10,7 +10,7 @@ function Invoke-DownloadAlteryx { File name: Invoke-DownloadAlteryx.ps1 Author: Florian Carrier Creation date: 2024-09-04 - Last modified: 2024-09-16 + Last modified: 2024-09-17 #> [CmdletBinding ()] Param ( @@ -49,8 +49,11 @@ function Invoke-DownloadAlteryx { "Server" = "Alteryx Server" } $ProductID = $Products.$($Properties.Product) + # Alteryx installation registry key + $RegistryKey = "HKLM:HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\SRC\Alteryx" # License API refresh token - $RefreshToken = Get-Content -Path $Properties.LicenseAPIFile -Raw + $LicenseAPIPath = Join-Path -Path $Properties.ResDirectory -ChildPath $Properties.LicenseAPIFile + $RefreshToken = Get-Content -Path $LicenseAPIPath -Raw # Placeholder $Skip = $false } @@ -60,7 +63,11 @@ function Invoke-DownloadAlteryx { $AccessToken = Update-AlteryxLicenseToken -Token $RefreshToken -Type "Access" Write-Log -Type "DEBUG" -Message $AccessToken # Check current and target versions - $CurrentVersion = Get-AlteryxVersion + if (Test-Path -Path $RegistryKey) { + $CurrentVersion = Get-AlteryxVersion + } else { + $CurrentVersion = "0.0" + } $MajorVersion = [System.String]::Concat([System.Version]::Parse($CurrentVersion).Major , ".", [System.Version]::Parse($CurrentVersion).Minor) $TargetVersion = [System.String]::Concat([System.Version]::Parse($Properties.Version).Major, ".", [System.Version]::Parse($Properties.Version).Minor) # Check latest version From 71b52df2b96a98ca65053da47e4f33ec04d91670 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Wed, 18 Sep 2024 13:52:59 +0200 Subject: [PATCH 27/61] Remove unused parameter --- conf/default.ini | 2 -- 1 file changed, 2 deletions(-) diff --git a/conf/default.ini b/conf/default.ini index 829454b..ae93573 100644 --- a/conf/default.ini +++ b/conf/default.ini @@ -22,8 +22,6 @@ InstallationPath = C:\Program Files\Alteryx BackupDirectory = C:\ProgramData\Alteryx\Backup # Data packages installation directory DataPackagesPath = C:\Program Files\Alteryx\Data -# Predictive Tools directory -RDirectory = RInstaller # 7zip application path (required for data packages) 7zipPath = C:\Program Files\7-Zip\7z.exe From 18d1677307df8fe2e3e5a7152101950bea0409d6 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Wed, 18 Sep 2024 13:53:21 +0200 Subject: [PATCH 28/61] Update comment format --- powershell/Invoke-BackupAlteryx.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/powershell/Invoke-BackupAlteryx.ps1 b/powershell/Invoke-BackupAlteryx.ps1 index beca617..8adc0c5 100644 --- a/powershell/Invoke-BackupAlteryx.ps1 +++ b/powershell/Invoke-BackupAlteryx.ps1 @@ -68,7 +68,7 @@ function Invoke-BackupAlteryx { $BackupProcess = Update-ProcessObject -ProcessObject $BackupProcess -Status "Running" Write-Log -Type "NOTICE" -Message "Start $BackupType backup of Alteryx Server" # ---------------------------------------------------------------------------- - # Check Alteryx service status + # * Check Alteryx service status Write-Log -Type "INFO" -Message "Check Alteryx Service status" if ($PSCmdlet.ShouldProcess("Alteryx Service", "Stop")) { $Service = "AlteryxService" @@ -90,7 +90,7 @@ function Invoke-BackupAlteryx { } } # ---------------------------------------------------------------------------- - # Create database dump + # * Create database dump if ($Backup.Database -eq $true) { Write-Log -Type "INFO" -Message "Create MongoDB database backup" if ($PSCmdlet.ShouldProcess("MongoDB", "Back-up")) { @@ -113,7 +113,7 @@ function Invoke-BackupAlteryx { } } # ---------------------------------------------------------------------------- - # Backup configuration files + # * Backup configuration files if ($Backup.Configuration -eq $true) { Write-Log -Type "INFO" -Message "Backup configuration files" if ($PSCmdlet.ShouldProcess("Configuration files", "Back-up")) { @@ -141,7 +141,7 @@ function Invoke-BackupAlteryx { } } # ---------------------------------------------------------------------------- - # Backup tokens + # * Backup tokens if ($Backup.Token -eq $true) { Write-Log -Type "INFO" -Message "Backup controller token" if ($PSCmdlet.ShouldProcess("Controller token", "Back-up")) { @@ -153,7 +153,7 @@ function Invoke-BackupAlteryx { } } # ---------------------------------------------------------------------------- - # Compress backup + # * Compress backup Write-Log -Type "INFO" -Message "Compress backup files" if ($PSCmdlet.ShouldProcess("Compress", "Back-up")) { if (Test-Object -Path $Properties.BackupDirectory -NotFound) { @@ -173,7 +173,7 @@ function Invoke-BackupAlteryx { } } # ---------------------------------------------------------------------------- - # Restart service if it was running before + # * Restart service if it was running before if ($ServiceStatus -eq "Running") { $StartProcess = Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended if ($StartProcess.Success -eq $false) { From 2aac8766c69f468ea80946673f2aa2e9cbafa276 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Wed, 18 Sep 2024 13:53:40 +0200 Subject: [PATCH 29/61] Fix license file path --- powershell/Invoke-ActivateAlteryx.ps1 | 13 +++++++------ powershell/Invoke-DeactivateAlteryx.ps1 | 7 ++++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/powershell/Invoke-ActivateAlteryx.ps1 b/powershell/Invoke-ActivateAlteryx.ps1 index 11c9be3..70d42c3 100644 --- a/powershell/Invoke-ActivateAlteryx.ps1 +++ b/powershell/Invoke-ActivateAlteryx.ps1 @@ -16,7 +16,7 @@ function Invoke-ActivateAlteryx { File name: Invoke-ActivateAlteryx.ps1 Author: Florian Carrier Creation date: 2021-07-05 - Last modified: 2024-09-12 + Last modified: 2024-09-18 .LINK https://www.powershellgallery.com/packages/PSAYX @@ -68,17 +68,18 @@ function Invoke-ActivateAlteryx { if ($null -eq $Properties.LicenseFile -Or $Properties.LicenseFile -eq "") { Write-Log -Type "ERROR" -Message "No license key or file have been specified" Write-Log -Type "WARN" -Message "Alteryx product activation failed" - $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -Status "Failed" -ErrorCode 1 -ExitCode 1 + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 return $ActivateProcess } # Read keys from license file - if (Test-Object -Path $Properties.LicenseFile -NotFound) { - Write-Log -Type "ERROR" -Message "License file path not found $($Properties.LicenseFile)" + $LicenseFilePath = Join-Path -Path $Properties.ResDirectory -ChildPath $Properties.LicenseFile + if (Test-Object -Path $LicenseFilePath -NotFound) { + Write-Log -Type "ERROR" -Message "License file does not exist $($Properties.LicenseFile)" Write-Log -Type "WARN" -Message "Alteryx product activation failed" - $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -Status "Failed" -ErrorCode 1 -ExitCode 1 + $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 return $ActivateProcess } - $Properties.LicenseKey = @(Get-Content -Path $Properties.LicenseFile) + $Properties.LicenseKey = @(Get-Content -Path $LicenseFilePath) } Write-Log -Type "DEBUG" -Message $Properties.LicenseKey # Count keys diff --git a/powershell/Invoke-DeactivateAlteryx.ps1 b/powershell/Invoke-DeactivateAlteryx.ps1 index b3b56cf..44231ae 100644 --- a/powershell/Invoke-DeactivateAlteryx.ps1 +++ b/powershell/Invoke-DeactivateAlteryx.ps1 @@ -16,7 +16,7 @@ function Invoke-DeactivateAlteryx { File name: Invoke-DeactivateAlteryx.ps1 Author: Florian Carrier Creation date: 2021-11-20 - Last modified: 2024-09-12 + Last modified: 2024-09-18 .LINK https://www.powershellgallery.com/packages/PSAYX @@ -99,13 +99,14 @@ function Invoke-DeactivateAlteryx { return $DeactivateProcess } # Read keys from license file - if (Test-Object -Path $Properties.LicenseFile -NotFound) { + $LicenseFilePath = Join-Path -Path $Properties.ResDirectory -ChildPath $Properties.LicenseFile + if (Test-Object -Path $LicenseFilePath -NotFound) { Write-Log -Type "ERROR" -Message "License file path not found $($Properties.LicenseFile)" Write-Log -Type "WARN" -Message "Alteryx product deactivation failed" $DeactivateProcess = Update-ProcessObject -ProcessObject $DeactivateProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 return $DeactivateProcess } else { - $Properties.LicenseKey = @(Get-Content -Path $Properties.LicenseFile) + $Properties.LicenseKey = @(Get-Content -Path $LicenseFilePath) } } Write-Log -Type "DEBUG" -Message $Properties.LicenseKey From f6317e36b5a59622dcae8d3f3d0a11d8e2bdcbf1 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Wed, 18 Sep 2024 13:54:54 +0200 Subject: [PATCH 30/61] Improve error handling --- powershell/Install-Alteryx.ps1 | 183 ++++++++++++++++++++----------- powershell/Uninstall-Alteryx.ps1 | 49 +++++++-- 2 files changed, 162 insertions(+), 70 deletions(-) diff --git a/powershell/Install-Alteryx.ps1 b/powershell/Install-Alteryx.ps1 index 7234b69..bec2d07 100644 --- a/powershell/Install-Alteryx.ps1 +++ b/powershell/Install-Alteryx.ps1 @@ -16,13 +16,13 @@ function Install-Alteryx { File name: Install-Alteryx.ps1 Author: Florian Carrier Creation date: 2021-07-05 - Last modified: 2023-05-23 + Last modified: 2024-09-18 .LINK https://www.powershellgallery.com/packages/PSAYX .LINK - https://help.alteryx.com/current/product-activation-and-licensing/use-command-line-options + https://help.alteryx.com/current/en/license-and-activate/administer/use-command-line-options.html #> [CmdletBinding ( @@ -56,6 +56,8 @@ function Install-Alteryx { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState # Log function call Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $Installprocess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # Variables $ISOTimeStamp = Get-Date -Format "yyyyMMdd_HHmmss" $Tags = [Ordered]@{"Version" = $Properties.Version} @@ -65,7 +67,8 @@ function Install-Alteryx { } else { $ServerInstaller = "AlteryxServerInstallx64_.exe" } - # $RFileName AISFileName + # Add-ons paths + $RDirectory = Join-Path -Path $Properties.InstallationPath -ChildPath "RInstaller" $RInstaller = "RInstaller_.exe" $AISInstaller = "AlteryxAISInstall_.exe" # Unattended execution arguments @@ -76,9 +79,10 @@ function Install-Alteryx { } } Process { + $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -Status "Running" Write-Log -Type "INFO" -Message "Installation of Alteryx $($InstallationProperties.Product) $($Properties.Version)" # ------------------------------------------------------------------------------ - # Alteryx Server + # * Alteryx Server # ------------------------------------------------------------------------------ if ($InstallationProperties.Product -eq "Designer" -Or $InstallationProperties.Server -eq $true) { # Update file version number @@ -93,7 +97,9 @@ function Install-Alteryx { if (Test-Object -Path $ServerPath -NotFound) { Write-Log -Type "ERROR" -Message "Path not found $DefaultServerPath" Write-Log -Type "ERROR" -Message "Alteryx $($InstallationProperties.Product) installation file could not be located" - Write-Log -Type "WARN" -Message "Alteryx installation failed" -ExitCode 1 + Write-Log -Type "WARN" -Message "Alteryx installation failed" + $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $Installprocess } else { Write-Log -Type "DEBUG" -Message "Path not found $DefaultServerPath" } @@ -124,7 +130,9 @@ function Install-Alteryx { } else { Write-Log -Type "ERROR" -Message "Path not found $ServerPath" Write-Log -Type "ERROR" -Message "Alteryx $($InstallationProperties.Product) installation file could not be located" - Write-Log -Type "WARN" -Message "Alteryx installation failed" -ExitCode 1 + Write-Log -Type "WARN" -Message "Alteryx installation failed" + $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $Installprocess } } # Configuration @@ -138,39 +146,54 @@ function Install-Alteryx { } } # ------------------------------------------------------------------------------ - # Predictive Tools + # * Predictive Tools # ------------------------------------------------------------------------------ if ($InstallationProperties.PredictiveTools -eq $true) { + $RInstall = $true # Update file version number $RFileName = Set-Tags -String $RInstaller -Tags (Resolve-Tags -Tags $Tags -Prefix "<" -Suffix ">") if ($InstallationProperties.Product -eq "Server") { # Use embedded R installer - $RPath = Join-Path -Path $Properties.InstallationPath -ChildPath "RInstaller\$RFileName" + $RPath = Join-Path -Path $RDirectory -ChildPath $RFileName } elseif ($InstallationProperties.Product -eq "Designer") { $RPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $RFileName } # Check source file Write-Log -Type "INFO" -Message "Installing Predictive Tools" if ($PSCmdlet.ShouldProcess($RPath, "Install")) { - if (Test-Path -Path $RPath) { + if (Test-Object -Path $RPath -NotFound) { + # Look for a file which may not match the patch versioning + $RFile = Get-ChildItem -Path $RDirectory -Filter "RInstaller_*.exe" + if (($InstallationProperties.Product -eq "Server") -Or (($RFile | Measure-Object).Count) -eq 1) { + $RPath = $RFile.FullName + } else { + Write-Log -Type "ERROR" -Message "Path not found $RPath" + Write-Log -Type "ERROR" -Message "Predictive Tools installation file could not be located" + Write-Log -Type "WARN" -Message "Predictive Tools installation failed" + $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -ErrorCount 1 + $RInstall = $false + } + } + if (($RInstall = $true) -And (Test-Object -Path $RPath)) { $RCommand = (@("&", $RPath, $Arguments) -join " ").Trim() Write-Log -Type "DEBUG" -Message $RCommand - $RInstall = Start-Process -FilePath $RPath -ArgumentList $Arguments -Verb "RunAs" -PassThru -Wait + if ($Unattended) { + $RInstall = Start-Process -FilePath $RPath -ArgumentList $Arguments -Verb "RunAs" -PassThru -Wait + } else { + $RInstall = Start-Process -FilePath $RPath -Verb "RunAs" -PassThru -Wait + } Write-Log -Type "DEBUG" -Message $RInstall if ($RInstall.ExitCode -eq 0) { Write-Log -Type "CHECK" -Message "Predictive Tools installed successfully" } else { - Write-Log -Type "ERROR" -Message "An error occured during the installation" -ExitCode $RInstall.ExitCode + Write-Log -Type "ERROR" -Message "An error occured during the installation" + $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -ErrorCount 1 } - } else { - Write-Log -Type "ERROR" -Message "Path not found $RPath" - Write-Log -Type "ERROR" -Message "Predictive Tools installation file could not be located" - Write-Log -Type "WARN" -Message "Predictive Tools installation failed" -ExitCode 1 } } } # ------------------------------------------------------------------------------ - # Intelligence Suite + # * Intelligence Suite # ------------------------------------------------------------------------------ if ($InstallationProperties.IntelligenceSuite -eq $true) { # Update file version number @@ -187,7 +210,11 @@ function Install-Alteryx { if (Test-Path -Path $AISPath) { $AISCommand = (@("&", $AISPath, $Arguments) -join " ").Trim() Write-Log -Type "DEBUG" -Message $AISCommand - $AISInstall = Start-Process -FilePath $AISPath -ArgumentList $Arguments -Verb "RunAs" -PassThru -Wait + if ($Unattended) { + $AISInstall = Start-Process -FilePath $AISPath -ArgumentList $Arguments -Verb "RunAs" -PassThru -Wait + } else { + $AISInstall = Start-Process -FilePath $AISPath -Verb "RunAs" -PassThru -Wait + } Write-Log -Type "DEBUG" -Message $AISInstall if ($AISInstall.ExitCode -eq 0) { Write-Log -Type "CHECK" -Message "Intelligence Suite installed successfully" @@ -197,70 +224,102 @@ function Install-Alteryx { } else { Write-Log -Type "ERROR" -Message "Path not found $AISPath" Write-Log -Type "ERROR" -Message "Intelligence Suite installation file could not be located" - Write-Log -Type "WARN" -Message "Intelligence Suite installation failed" -ExitCode 1 + Write-Log -Type "WARN" -Message "Intelligence Suite installation failed" + $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -ErrorCount 1 } } } # ------------------------------------------------------------------------------ - # Data packages + # * Data packages # ------------------------------------------------------------------------------ + # TODO if ($InstallationProperties.DataPackages -eq $true) { - # TODO - $DataPackage = $null - if ($null -ne $DataPackage) { - $DataPackagePath = Join-Path -Path $Properties.SrcDirectory -ChildPath "$DataPackage.7z" - $DataPackageLog = Join-Path -Path $Properties.LogDirectory -ChildPath "${ISOTimeStamp}_${DataPackage}.log" - if (-Not (Test-Path -Path $DataPackagePath)) { - Write-Log -Type "ERROR" -Message "Path not found $DataPackagePath" - Write-Log -Type "ERROR" -Message "Data package could not be located" - Write-Log -Type "WARN" -Message "Data package installation failed" -ExitCode 1 - } - # Unzip data package - $Destination = $DataPackagePath.Replace('.7z', '') - if (Test-Path -Path $Destination) { - Write-Log -Type "WARN" -Message "Path already exists $Destination" - Write-Log -Type "INFO" -Message "Skipping data package unzip" - } else { - $7zip = "& ""$($Properties.'7zipPath')"" x ""$DataPackagePath"" -o$Destination -y" - Write-Log -Type "DEBUG" -Message $7zip - if (Test-Path -Path $Properties.'7zipPath') { - if ($PSCmdlet.ShouldProcess($DataPackagePath, "Unzip")) { - $Unzip = Invoke-Expression -Command $7zip | Out-String - } - } else { - Write-Log -Type "ERROR" -Message "Path not found $($Properties.'7zipPath')" - Write-Log -Type "ERROR" -Message "7zip could not be located" - Write-Log -Type "WARN" -Message "Data package installation failed" -ExitCode 1 + if ($PSCmdlet.ShouldProcess("Alteryx Data Packages", "Install")) { + $InstallDataPackage = $true + $DataPackage = $null + if ($null -ne $DataPackage) { + $DataPackagePath = Join-Path -Path $Properties.SrcDirectory -ChildPath "$DataPackage.7z" + $DataPackageLog = Join-Path -Path $Properties.LogDirectory -ChildPath "${ISOTimeStamp}_${DataPackage}.log" + if (-Not (Test-Path -Path $DataPackagePath)) { + Write-Log -Type "ERROR" -Message "Path not found $DataPackagePath" + Write-Log -Type "ERROR" -Message "Data package could not be located" + Write-Log -Type "WARN" -Message "Data package installation failed" + $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -ErrorCount 1 + $InstallDataPackage = false } - # ! TODO check unzip - Write-Log -Type "DEBUG" -Message $Unzip - } - # Check unzip outcome - if (Test-Path -Path $Destination) { - # Run installer - $DataPackageInstaller = Join-Path -Path $Destination -ChildPath "DataInstallCmd.exe" - if (Test-Path -Path $DataPackageInstaller) { - Install-AlteryxDataPackage -Path $DataPackageInstaller -InstallDirectory $Properties.DataPackagesPath -Log $DataPackageLog -Action "Install" -Unattended:$Unattended + if ($InstallDataPackage -eq $true) { + # Unzip data package + $Destination = $DataPackagePath.Replace('.7z', '') + if (Test-Path -Path $Destination) { + Write-Log -Type "WARN" -Message "Path already exists $Destination" + Write-Log -Type "INFO" -Message "Skipping data package unzip" + } else { + $7zip = "& ""$($Properties.'7zipPath')"" x ""$DataPackagePath"" -o$Destination -y" + Write-Log -Type "DEBUG" -Message $7zip + if (Test-Path -Path $Properties.'7zipPath') { + if ($PSCmdlet.ShouldProcess($DataPackagePath, "Unzip")) { + $Unzip = Invoke-Expression -Command $7zip | Out-String + } + } else { + Write-Log -Type "ERROR" -Message "Path not found $($Properties.'7zipPath')" + Write-Log -Type "ERROR" -Message "7zip could not be located" + Write-Log -Type "WARN" -Message "Data package installation failed" + $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -ErrorCount 1 + $InstallDataPackage = false + } + # ! TODO check unzip + Write-Log -Type "DEBUG" -Message $Unzip + } + # Check unzip outcome + if (Test-Path -Path $Destination) { + # Run installer + $DataPackageInstaller = Join-Path -Path $Destination -ChildPath "DataInstallCmd.exe" + if (Test-Path -Path $DataPackageInstaller) { + Install-AlteryxDataPackage -Path $DataPackageInstaller -InstallDirectory $Properties.DataPackagesPath -Log $DataPackageLog -Action "Install" -Unattended:$Unattended + } + } else { + Write-Log -Type "ERROR" -Message "Path not found $Destination" + Write-Log -Type "ERROR" -Message "Data package unzipping failed" + Write-Log -Type "WARN" -Message "Data package installation failed" + $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -ErrorCount 1 + } } } else { - Write-Log -Type "ERROR" -Message "Path not found $Destination" - Write-Log -Type "ERROR" -Message "Data package unzipping failed" - Write-Log -Type "WARN" -Message "Data package installation failed" -ExitCode 1 + Write-Log -Type "DEBUG" -Message "No data package specified" + Write-Log -Type "WARN" -Message "Skipping data package installation" } - } else { - Write-Log -Type "DEBUG" -Message "No data package specified" } } # ------------------------------------------------------------------------------ - # Licensing + # * Licensing # ------------------------------------------------------------------------------ if ($Properties.ActivateOnInstall -eq $true) { - Invoke-ActivateAlteryx -Properties $Properties -Unattended:$Unattended + if ($PSCmdlet.ShouldProcess("Alteryx license", "Activate")) { + $ActivateProcess = Invoke-ActivateAlteryx -Properties $Properties -Unattended:$Unattended + if ($ActivateProcess.Success -eq $false) { + $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -ErrorCount 1 + } + } } else { Write-Log -Type "WARN" -Message "Skipping license activation" } + # ------------------------------------------------------------------------------ + # * Check + # ------------------------------------------------------------------------------ + if ($Installprocess.ErrorCount -eq 0) { + Write-Log -Type "CHECK" -Message "Alteryx $($InstallationProperties.Product) $($Properties.Version) installed successfully" + $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -Status "Completed" -Success $true + } else { + if ($Installprocess.ErrorCount -eq 1) { + $ErrorCount = "one error" + } else { + $ErrorCount = "$($Installprocess.ErrorCount) errors" + } + Write-Log -Type "WARN" -Message "Alteryx $($InstallationProperties.Product) $($Properties.Version) was installed with $ErrorCount" + $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -Status "Completed" + } } End { - Write-Log -Type "CHECK" -Message "Alteryx $($InstallationProperties.Product) $($Properties.Version) installed successfully" + return $Installprocess } } \ No newline at end of file diff --git a/powershell/Uninstall-Alteryx.ps1 b/powershell/Uninstall-Alteryx.ps1 index ad046e0..1cd2eb1 100644 --- a/powershell/Uninstall-Alteryx.ps1 +++ b/powershell/Uninstall-Alteryx.ps1 @@ -16,13 +16,13 @@ function Uninstall-Alteryx { File name: Uninstall-Alteryx.ps1 Author: Florian Carrier Creation date: 2021-07-08 - Last modified: 2023-01-17 + Last modified: 2024-09-18 .LINK https://www.powershellgallery.com/packages/PSAYX .LINK - https://help.alteryx.com/current/product-activation-and-licensing/use-command-line-options + https://help.alteryx.com/current/en/license-and-activate/administer/use-command-line-options.html .LINK https://community.alteryx.com/t5/Alteryx-Designer-Knowledge-Base/Complete-Uninstall-of-Alteryx-Designer/ta-p/402897 @@ -58,7 +58,9 @@ function Uninstall-Alteryx { # Get global preference variables Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState # Log function call - Write-Log -Type "DEBUG" -Message $MyInvocation.ScriptName + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $Uninstallprocess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # Variables $ISOTimeStamp = Get-Date -Format "yyyyMMdd_HHmmss" $Tags = [Ordered]@{"Version" = $Properties.Version} @@ -70,13 +72,19 @@ function Uninstall-Alteryx { } } Process { + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Running" Write-Log -Type "INFO" -Message "Uninstallation of Alteryx Server $($Properties.Version)" # ------------------------------------------------------------------------------ - # Alteryx Server + # * Deactivate license keys + # ------------------------------------------------------------------------------ + $DeactivateProcess = Invoke-DeactivateAlteryx -Properties $Properties -All -Unattended:$Unattended + if ($DeactivateProcess.Success -eq $false) { + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -ErrorCount 1 + } + # ------------------------------------------------------------------------------ + # * Uninstall Alteryx Server # ------------------------------------------------------------------------------ # TODO check if Alteryx is installed - # Deactivate license keys - Invoke-DeactivateAlteryx -Properties $Properties -All -Unattended:$Unattended # Update file version number $ServerFileName = Set-Tags -String $ServerInstaller -Tags (Resolve-Tags -Tags $Tags -Prefix "<" -Suffix ">") $ServerPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $ServerFileName @@ -94,15 +102,40 @@ function Uninstall-Alteryx { Write-Log -Type "CHECK" -Message "Alteryx Server uninstalled successfully" } else { Write-Log -Type "ERROR" -Message "An error occured during the uninstallation" -ExitCode $ServerUninstall.ExitCode + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $Uninstallprocess + } } else { Write-Log -Type "ERROR" -Message "Path not found $ServerPath" - Write-Log -Type "ERROR" -Message "Alteryx $($InstallationProperties.Product) executable file could not be located" -ExitCode 1 + Write-Log -Type "ERROR" -Message "Alteryx $($InstallationProperties.Product) executable file could not be located" + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $Uninstallprocess } } # TODO remove leftover files # TODO remove registry keys + # ------------------------------------------------------------------------------ + # * Uninstall add-ons + # ------------------------------------------------------------------------------ # TODO enable uninstall of standalone components - Write-Log -Type "CHECK" -Message "Uninstallation of Alteryx $($InstallationProperties.Product) $Version successfull" + # ------------------------------------------------------------------------------ + # * Check + # ------------------------------------------------------------------------------ + if ($Uninstallprocess.ErrorCount -eq 0) { + Write-Log -Type "CHECK" -Message "Uninstallation of Alteryx $($InstallationProperties.Product) $Version successfull" + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Completed" -Success $true + } else { + if ($Uninstallprocess.ErrorCount -eq 1) { + $ErrorCount = "one error" + } else { + $ErrorCount = "$($Uninstallprocess.ErrorCount) errors" + } + Write-Log -Type "WARN" -Message "Alteryx $($InstallationProperties.Product) $($Properties.Version) was uninstalled with $ErrorCount" + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Completed" + } + } + End { + return $Uninstallprocess } } \ No newline at end of file From 2c6fa36a5533608212fbdb72a93d736deebb5d9f Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Wed, 18 Sep 2024 18:24:02 +0200 Subject: [PATCH 31/61] Add exception Prevent displaying the workaround in case file does not exist --- powershell/Install-Alteryx.ps1 | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/powershell/Install-Alteryx.ps1 b/powershell/Install-Alteryx.ps1 index bec2d07..c1f236e 100644 --- a/powershell/Install-Alteryx.ps1 +++ b/powershell/Install-Alteryx.ps1 @@ -201,9 +201,14 @@ function Install-Alteryx { $AISPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $AISFileName if (Test-Object -Path $AISPath -NotFound) { # Workaround for files not following naming convention due to duplicate pipeline runs - $Workaround = [Ordered]@{"Version" = [System.String]::Concat($Properties.Version, "_1")} - $AISFileName = Set-Tags -String $AISInstaller -Tags (Resolve-Tags -Tags $Workaround -Prefix "<" -Suffix ">") - $AISPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $AISFileName + $Workaround = [Ordered]@{"Version" = [System.String]::Concat($Properties.Version, "_1")} + $WorkaroundPath = Set-Tags -String $AISInstaller -Tags (Resolve-Tags -Tags $Workaround -Prefix "<" -Suffix ">") + if (Test-Path -Path $WorkaroundPath) { + $AISFileName = Set-Tags -String $AISInstaller -Tags (Resolve-Tags -Tags $Workaround -Prefix "<" -Suffix ">") + $AISPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $AISFileName + } else { + # TODO Check latest file that matches the major version + } } Write-Log -Type "INFO" -Message "Installing Intelligence Suite" if ($PSCmdlet.ShouldProcess($AISPath, "Install")) { From 3cc9120cb1efd217ad4728d9687bcb8c6bf2e1d0 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Wed, 18 Sep 2024 18:24:25 +0200 Subject: [PATCH 32/61] Add user confirmation --- powershell/Uninstall-Alteryx.ps1 | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/powershell/Uninstall-Alteryx.ps1 b/powershell/Uninstall-Alteryx.ps1 index 1cd2eb1..9d671b4 100644 --- a/powershell/Uninstall-Alteryx.ps1 +++ b/powershell/Uninstall-Alteryx.ps1 @@ -65,7 +65,7 @@ function Uninstall-Alteryx { $ISOTimeStamp = Get-Date -Format "yyyyMMdd_HHmmss" $Tags = [Ordered]@{"Version" = $Properties.Version} # Filenames - if ($InstallationProperties.Product -eq "Designer") { + if ($Properties.Product -eq "Designer") { $ServerInstaller = "AlteryxInstallx64_.exe" } else { $ServerInstaller = "AlteryxServerInstallx64_.exe" @@ -74,6 +74,31 @@ function Uninstall-Alteryx { Process { $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Running" Write-Log -Type "INFO" -Message "Uninstallation of Alteryx Server $($Properties.Version)" + if ($Unattended -eq $false) { + # Ask for confirmation to uninstall + $ConfirmUninstall = Confirm-Prompt -Prompt "Are you sure that you want to uninstall $($Properties.Product)?" + if ($ConfirmUninstall -eq $false) { + Write-Log -Type "WARN" -Message "Cancelling uninstallation" + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Cancelled" + return $Uninstallprocess + } else { + # Suggest backup + $Backup = Confirm-Prompt -Prompt "Do you want to take a back-up of the database?" + if ($Backup) { + $BackupProcess = Invoke-BackupAlteryx -Properties $BackUpProperties -Unattended:$Unattended + if ($BackupProcess.Success -eq $false) { + if (Confirm-Prompt -Prompt "Do you still want to proceed with the uninstallation?") { + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -ErrorCount 1 + } else { + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Cancelled" -ErrorCount 1 + return $Uninstallprocess + } + } + } else { + Write-Log -Type "WARN" -Message "Skipping database back-up" + } + } + } # ------------------------------------------------------------------------------ # * Deactivate license keys # ------------------------------------------------------------------------------ From c20159ae5db8510c90924f9969ea2d06e32ab408 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Wed, 18 Sep 2024 18:24:43 +0200 Subject: [PATCH 33/61] Add localhost fall-back --- powershell/Invoke-PingAlteryx.ps1 | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/powershell/Invoke-PingAlteryx.ps1 b/powershell/Invoke-PingAlteryx.ps1 index b211600..f11050a 100644 --- a/powershell/Invoke-PingAlteryx.ps1 +++ b/powershell/Invoke-PingAlteryx.ps1 @@ -10,7 +10,7 @@ function Invoke-PingAlteryx { File name: Invoke-PingAlteryx.ps1 Author: Florian Carrier Creation date: 2024-09-16 - Last modified: 2024-09-16 + Last modified: 2024-09-18 #> [CmdletBinding ( SupportsShouldProcess = $true @@ -45,7 +45,8 @@ function Invoke-PingAlteryx { $PingProcess = Update-ProcessObject -ProcessObject $PingProcess -Status "Running" Write-Log -Type "NOTICE" -Message "Pinging Alteryx Server" # ---------------------------------------------------------------------------- - # Check Alteryx service status + # * Alteryx service + # ---------------------------------------------------------------------------- Write-Log -Type "INFO" -Message "Check Alteryx Service status" if ($PSCmdlet.ShouldProcess("Alteryx Service", "Check")) { $AlteryxService = Get-Service -Name $ServiceName @@ -65,12 +66,10 @@ function Invoke-PingAlteryx { return $PingProcess } } - } else { - # WhatIf - Write-Log -Type "CHECK" -Message "$ServiceName is running" } # ---------------------------------------------------------------------------- - # Check Gallery + # * Gallery + # ---------------------------------------------------------------------------- Write-Log -Type "INFO" -Message "Check Alteryx Gallery status" if ($PSCmdlet.ShouldProcess("Alteryx Gallery", "Ping")) { if ($Properties.EnableSSL -eq $true) { @@ -83,12 +82,18 @@ function Invoke-PingAlteryx { Write-Log -Type "CHECK" -Message "Alteryx Gallery is accessible" $PingProcess = Update-ProcessObject -ProcessObject $PingProcess -Status "Completed" -Success $true } else { - Write-Log -Type "ERROR" -Message "Alteryx Gallery is not accessible" - $PingProcess = Update-ProcessObject -ProcessObject $PingProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + # Try localhost + if (Test-HTTPStatus -URI "$($Protocol)://localhost/gallery") { + Write-Log -Type "CHECK" -Message "Alteryx Gallery is accessible" + Write-Log -Type "WARN" -Message "Consider changing the base address not to use localhost" + $PingProcess = Update-ProcessObject -ProcessObject $PingProcess -Status "Completed" -Success $true + } else { + Write-Log -Type "ERROR" -Message "Alteryx Gallery is not accessible" + $PingProcess = Update-ProcessObject -ProcessObject $PingProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + } } } else { # WhatIf - Write-Log -Type "CHECK" -Message "Alteryx Gallery is accessible" $PingProcess = Update-ProcessObject -ProcessObject $PingProcess -Status "Completed" -Success $true } } From 17b4fb093195ea56819fd8305e9046482484026a Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Wed, 18 Sep 2024 18:25:15 +0200 Subject: [PATCH 34/61] Add SupportsShouldProcess --- powershell/Invoke-DownloadAlteryx.ps1 | 195 +++++++++++++++++++------- 1 file changed, 144 insertions(+), 51 deletions(-) diff --git a/powershell/Invoke-DownloadAlteryx.ps1 b/powershell/Invoke-DownloadAlteryx.ps1 index bed4523..8eca56c 100644 --- a/powershell/Invoke-DownloadAlteryx.ps1 +++ b/powershell/Invoke-DownloadAlteryx.ps1 @@ -10,9 +10,11 @@ function Invoke-DownloadAlteryx { File name: Invoke-DownloadAlteryx.ps1 Author: Florian Carrier Creation date: 2024-09-04 - Last modified: 2024-09-17 + Last modified: 2024-09-18 #> - [CmdletBinding ()] + [CmdletBinding ( + SupportsShouldProcess = $true + )] Param ( [Parameter ( Position = 1, @@ -42,7 +44,7 @@ function Invoke-DownloadAlteryx { # Log function call Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name # Process status - $Process = New-ProcessObject -Name $MyInvocation.MyCommand.Name + $DownloadProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # Product IDs $Products = [Ordered]@{ "Designer" = "Alteryx Designer" @@ -58,70 +60,161 @@ function Invoke-DownloadAlteryx { $Skip = $false } Process { - $Process = Update-ProcessObject -ProcessObject $Process -Status "Running" + $DownloadProcess = Update-ProcessObject -ProcessObject $DownloadProcess -Status "Running" + # ------------------------------------------------------------------------------ + # * Fetch latest version + # ------------------------------------------------------------------------------ # Get license API access token + if ($PSCmdlet.ShouldProcess("License Portal access token", "Refresh")) { $AccessToken = Update-AlteryxLicenseToken -Token $RefreshToken -Type "Access" - Write-Log -Type "DEBUG" -Message $AccessToken - # Check current and target versions - if (Test-Path -Path $RegistryKey) { - $CurrentVersion = Get-AlteryxVersion - } else { - $CurrentVersion = "0.0" + Write-Log -Type "DEBUG" -Message $AccessToken } - $MajorVersion = [System.String]::Concat([System.Version]::Parse($CurrentVersion).Major , ".", [System.Version]::Parse($CurrentVersion).Minor) - $TargetVersion = [System.String]::Concat([System.Version]::Parse($Properties.Version).Major, ".", [System.Version]::Parse($Properties.Version).Minor) - # Check latest version - Write-Log -Type "INFO" -Message "Retrieve latest release for $ProductID version $TargetVersion" - $Release = Get-AlteryxLatestRelease -AccountID $Properties.LicenseAccountID -Token $AccessToken -ProductID $ProductID -Version $TargetVersion - # Compare versions - if (Compare-Version -Version $Release.Version -Operator "lt" -Reference $CurrentVersion) { - Write-Log -Type "WARN" -Message "The specified version ($($Release.Version)) is lower than the current one ($CurrentVersion)" - if (($Unattended -eq $false) -And (-Not (Confirm-Prompt -Prompt "Do you still want to download $ProductID version $($Release.Version)?"))) { - $Skip = $true - } - } elseif (Compare-Version -Version $Release.Version -Operator "eq" -Reference $CurrentVersion) { - Write-Log -Type "WARN" -Message "The version installed ($CurrentVersion) is the latest version available for $ProductID" - if (($Unattended -eq $false) -And (-Not (Confirm-Prompt -Prompt "Do you still want to download $ProductID version $($Release.Version)?"))) { - $Skip = $true + # Check current and target versions + if ($PSCmdlet.ShouldProcess("Latest release version", "Fetch")) { + if (Test-Path -Path $RegistryKey) { + $CurrentVersion = Get-AlteryxVersion + } else { + $CurrentVersion = "0.0" } - } else { - Write-Log -Type "INFO" -Message "$ProductID version $($Release.Version) is available" - if (-Not $Unattended) { - $Continue = Confirm-Prompt -Prompt "Do you want to download it?" - if (-Not $Continue) { + $MajorVersion = [System.String]::Concat([System.Version]::Parse($CurrentVersion).Major , ".", [System.Version]::Parse($CurrentVersion).Minor) + $TargetVersion = [System.String]::Concat([System.Version]::Parse($Properties.Version).Major, ".", [System.Version]::Parse($Properties.Version).Minor) + # Check latest version + Write-Log -Type "INFO" -Message "Retrieve latest release for $ProductID version $TargetVersion" + $Release = Get-AlteryxLatestRelease -AccountID $Properties.LicenseAccountID -Token $AccessToken -ProductID $ProductID -Version $TargetVersion + # Compare versions + if (Compare-Version -Version $Release.Version -Operator "lt" -Reference $CurrentVersion) { + Write-Log -Type "WARN" -Message "The specified version ($($Release.Version)) is lower than the current one ($CurrentVersion)" + if (($Unattended -eq $false) -And (-Not (Confirm-Prompt -Prompt "Do you still want to download $ProductID version $($Release.Version)?"))) { + $Skip = $true + } + } elseif (Compare-Version -Version $Release.Version -Operator "eq" -Reference $CurrentVersion) { + Write-Log -Type "WARN" -Message "The version installed ($CurrentVersion) is the latest version available for $ProductID" + if (($Unattended -eq $false) -And (-Not (Confirm-Prompt -Prompt "Do you still want to download $ProductID version $($Release.Version)?"))) { $Skip = $true } + } else { + Write-Log -Type "INFO" -Message "$ProductID version $($Release.Version) is available" + if (-Not $Unattended) { + $Continue = Confirm-Prompt -Prompt "Do you want to download it?" + if (-Not $Continue) { + $Skip = $true + } + } } } + # ------------------------------------------------------------------------------ + # * Download + # ------------------------------------------------------------------------------ # Check if download should proceed if ($Skip -eq $false) { - # Check if - if (Compare-Version -Version $TargetVersion -Operator "ne" -Reference $MajorVersion) { - # If major upgrade, download installer - Write-Log -Type "INFO" -Message "Downloading $($Release.Product) version $($Release.Version)" - } else { - # If minor or patch upgrade, download patch - Write-Log -Type "INFO" -Message "Downloading $($Release.Product) patch version $($Release.Version)" - $Release = Get-AlteryxLatestRelease -AccountID $Properties.LicenseAccountID -Token $AccessToken -ProductID $ProductID -Version $TargetVersion -Patch + # TODO improve and loop through installation properties + if ($PSCmdlet.ShouldProcess("Patch installer", "Check")) { + # Check upgrade step + if (Compare-Version -Version $TargetVersion -Operator "ne" -Reference $MajorVersion) { + # If major upgrade, download installer + Write-Log -Type "INFO" -Message "Downloading $($Release.Product) version $($Release.Version)" + } else { + # If minor or patch upgrade, download patch + Write-Log -Type "INFO" -Message "Downloading $($Release.Product) patch version $($Release.Version)" + $Release = Get-AlteryxLatestRelease -AccountID $Properties.LicenseAccountID -Token $AccessToken -ProductID $ProductID -Version $TargetVersion -Patch + } } - $DownloadPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $Release.FileName - Invoke-WebRequest -Uri $Release.URL -OutFile $DownloadPath - # Check downloaded file - Write-Log -Type "DEBUG" -Message $DownloadPath - if (Test-Path -Path $DownloadPath) { - Write-Log -Type "CHECK" -Message "Download completed successfully" - $Process = Update-ProcessObject -ProcessObject $Process -Status "Completed" -Success $true -ExitCode 0 -ErrorCount 0 - } else { - Write-Log -Type "ERROR" -Message "Download failed" - $Process = Update-ProcessObject -ProcessObject $Process -Status "Failed" -Success $false -ExitCode 1 -ErrorCount 1 + # ------------------------------------------------------------------------------ + # * Server/Designer + # ------------------------------------------------------------------------------ + if ($PSCmdlet.ShouldProcess($ProductID, "Download")) { + $DownloadEXE = $true + $DownloadPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $Release.FileName + # Check if file already exists + if (Test-Path -Path $DownloadPath) { + Write-Log -Type "WARN" -Message "$ProductID installation file already exist in source directory" + Write-Log -Type "DEBUG" -Message $DownloadPath + if ($Unattended -eq $false) { + $DownloadEXE = Confirm-Prompt "Do you want to redownload and overwrite the existing file?" + } else { + $DownloadEXE = $false + } + } + if ($DownloadEXE -eq $true) { + Invoke-WebRequest -Uri $Release.URL -OutFile $DownloadPath + # Check downloaded file + Write-Log -Type "DEBUG" -Message $DownloadPath + if (Test-Path -Path $DownloadPath) { + Write-Log -Type "CHECK" -Message "$ProductID download completed successfully" + } else { + Write-Log -Type "ERROR" -Message "Download failed" + $DownloadProcess = Update-ProcessObject -ProcessObject $DownloadProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + } + } else { + Write-Log -Type "WARN" -Message "Skipping download of $ProductID version $($Release.Version)" + } + } + # ------------------------------------------------------------------------------ + # * Predictive Tools + # ------------------------------------------------------------------------------ + # Check if download should proceed + if ($InstallationProperties.PredictiveTools -eq $true) { + if ($PSCmdlet.ShouldProcess("Predictive Tools", "Download")) { + $DownloadR = $true + if ($Properties.Product -eq "Server") { + Write-Log -Type "INFO" -Message "Predictive Tools installer is packaged within the main installation file" + if ($Unattended -eq $false) { + $DownloadR = Confirm-Prompt -Prompt "Do you still want to download Predictive Tools separately?" + } else { + $DownloadR = $false + } + } + if ($DownloadR = $true) { + # TODO download RInstaller + } + } + } + # ------------------------------------------------------------------------------ + # * Intelligence Suite + # ------------------------------------------------------------------------------ + if ($InstallationProperties.IntelligenceSuite -eq $true) { + if ($PSCmdlet.ShouldProcess("Intelligence Suite", "Download")) { + $DownloadIS = $true + if ($Unattended -eq $false) { + $DownloadIS = Confirm-Prompt -Prompt "Do you want to download Intelligence Suite?" + } + if ($DownloadIS -eq $true) { + # TODO download IS + } + } + } + # ------------------------------------------------------------------------------ + # * Data packages + # ------------------------------------------------------------------------------ + if ($InstallationProperties.DataPackages -eq $true) { + if ($PSCmdlet.ShouldProcess("Data Packages", "Download")) { + # TODO download data packages + } } } else { Write-Log -Type "WARN" -Message "Skipping download process" - $Process = Update-ProcessObject -ProcessObject $Process -Status "Cancelled" -Success $true -ExitCode 0 -ErrorCount 0 + $DownloadProcess = Update-ProcessObject -ProcessObject $DownloadProcess -Status "Cancelled" -Success $true -ExitCode 0 -ErrorCount 0 + } + # ------------------------------------------------------------------------------ + # * Check + # ------------------------------------------------------------------------------ + if ($DownloadProcess.ErrorCount -eq 0) { + Write-Log -Type "CHECK" -Message "Download of Alteryx $($InstallationProperties.Product) $Version successfull" + $DownloadProcess = Update-ProcessObject -ProcessObject $DownloadProcess -Status "Completed" -Success $true + } elseif ($DownloadProcess.ErrorCount -eq 4) { + Write-Log -Type "ERROR" -Message "Download failed" + $DownloadProcess = Update-ProcessObject -ProcessObject $DownloadProcess -Status "Failed" -ExitCode 1 + } else { + if ($DownloadProcess.ErrorCount -eq 1) { + $ErrorCount = "one error" + } else { + $ErrorCount = "$($DownloadProcess.ErrorCount) errors" + } + Write-Log -Type "WARN" -Message "Download completed with $ErrorCount" + $DownloadProcess = Update-ProcessObject -ProcessObject $DownloadProcess -Status "Completed" } - # TODO download add-ons } End { - return $Process + return $DownloadProcess } } \ No newline at end of file From 721f6034027f0664511eb49f55890d93018836d7 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Wed, 18 Sep 2024 18:25:37 +0200 Subject: [PATCH 35/61] Error handling and reporting --- powershell/Update-Alteryx.ps1 | 70 ++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/powershell/Update-Alteryx.ps1 b/powershell/Update-Alteryx.ps1 index 6b6f618..454bec1 100644 --- a/powershell/Update-Alteryx.ps1 +++ b/powershell/Update-Alteryx.ps1 @@ -4,13 +4,13 @@ function Update-Alteryx { Update Alteryx .DESCRIPTION - Upgrade Alteryx Server + Upgrade Alteryx Server and rollback if process fails .NOTES File name: Update-Alteryx.ps1 Author: Florian Carrier Creation date: 2021-09-02 - Last modified: 2022-04-19 + Last modified: 2024-09-18 #> [CmdletBinding ( SupportsShouldProcess = $true @@ -42,7 +42,9 @@ function Update-Alteryx { # Get global preference vrariables Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState # Log function call - Write-Log -Type "DEBUG" -Message $MyInvocation.ScriptName + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $Uninstallprocess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # Clear error pipeline $Error.Clear() # Retrieve current version @@ -57,9 +59,11 @@ function Update-Alteryx { $Properties.ActivateOnInstall = $Properties.ActivateOnUpgrade } Process { + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Running" Write-Log -Type "CHECK" -Object "Starting Alteryx Server upgrade from $BackupVersion to $($Properties.Version)" # Check installation path - $InstallationPath = Get-AlteryxInstallDirectory + $InstallDirectory = Get-AlteryxInstallDirectory + $InstallationPath = Resolve-Path -Path "$InstallDirectory\.." if ($Properties.InstallationPath -ne $InstallationPath) { # If new installation directory is specified Write-Log -Type "WARN" -Message "New installation directory specified" @@ -71,30 +75,68 @@ function Update-Alteryx { if ($Confirm -Or $Unattended) { $AlteryxService = Get-AlteryxUtility -Utility "Service" -Path $InstallationPath } else { - Write-Log -Type "WARN" -Message "Upgrade cancelled by user" -ExitCode 0 + Write-Log -Type "WARN" -Message "Upgrade cancelled by user" + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Cancelled" + return $Uninstallprocess } } else { # Retrieve Alteryx Service utility path $AlteryxService = Get-AlteryxUtility -Utility "Service" -Path $Properties.InstallationPath } + # ------------------------------------------------------------------------------ + # * Back-up + # ------------------------------------------------------------------------------ # Create back-up $BackUpProperties = Copy-OrderedHashtable -Hashtable $Properties $BackUpProperties.Version = $BackupVersion $BackupProperties.InstallationPath = $InstallationPath - Invoke-BackupAlteryx -Properties $BackUpProperties -Unattended:$Unattended - # Upgrade - Install-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended - # Check for errors + $BackupProcess = Invoke-BackupAlteryx -Properties $BackUpProperties -Unattended:$Unattended + if ($BackupProcess.Success -eq $false) { + if (Confirm-Prompt -Prompt "Do you still want to proceed with the upgrade?") { + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -ErrorCount 1 + } else { + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Cancelled" -ErrorCount 1 + return $Uninstallprocess + } + } + # ------------------------------------------------------------------------------ + # * Upgrade + # ------------------------------------------------------------------------------ + $InstallProcess = Install-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended + if ($InstallProcess.Success -eq $false) { + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Failed" -ErrorCount $InstallProcess.ErrorCount -ExitCode 1 + return $Uninstallprocess + } + # ------------------------------------------------------------------------------ + # * Rollback + # ------------------------------------------------------------------------------ if ($Error.Count -gt 0) { - # Rollback Write-Log -Type "ERROR" -Object "Upgrade process failed with $($Error.Count) errors" Write-Log -Type "WARN" -Object "Restoring previous version ($BackupVersion)" - # Reinstall Alteryx - Install-Alteryx -Properties $BackUpProperties -Unattended:$Unattended - # Restore backup - Invoke-RestoreAlteryx -Properties $BackUpProperties -Unattended:$Unattended + # Reinstall previous Alteryx version + $InstallProcess = Install-Alteryx -Properties $Properties -InstallationProperties $BackUpProperties -Unattended:$Unattended + if ($InstallProcess.Success -eq $false) { + Write-Log -Type "ERROR" -Message "Rollback process failed" + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Failed" -ErrorCount $InstallProcess.ErrorCount -ExitCode 1 + return $Uninstallprocess + } else { + # Restore backup + $RestoreProcess = Invoke-RestoreAlteryx -Properties $BackUpProperties -Unattended:$Unattended + if ($RestoreProcess.Success -eq $false) { + Write-Log -Type "ERROR" -Message "Rollback process failed" + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Failed" -ErrorCount $RestoreProcess.ErrorCount -ExitCode 1 + return $Uninstallprocess + } else { + Write-Log -Type "CHECK" -Object "Alteryx Server rollback completed successfully" + Write-Log -Type "WARN" -Message "Check the logs to troubleshoot issue with upgrade" + Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Failed" -ExitCode 1 + } + } } else { Write-Log -Type "CHECK" -Object "Alteryx Server upgrade completed successfully" } } + End { + return $Uninstallprocess + } } \ No newline at end of file From 14037860ac70857e150106f740a8d2589bc6f895 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Fri, 20 Sep 2024 13:26:55 +0200 Subject: [PATCH 36/61] Rename setup action --- Deploy-Alteryx.ps1 | 16 ++--- ...nfiguration.ps1 => Invoke-SetupScript.ps1} | 58 +++++++++---------- powershell/Set-AlteryxConfiguration.ps1 | 54 +++++++++++++++++ 3 files changed, 91 insertions(+), 37 deletions(-) rename powershell/{Set-Configuration.ps1 => Invoke-SetupScript.ps1} (85%) create mode 100644 powershell/Set-AlteryxConfiguration.ps1 diff --git a/Deploy-Alteryx.ps1 b/Deploy-Alteryx.ps1 index d222860..f2fed0a 100644 --- a/Deploy-Alteryx.ps1 +++ b/Deploy-Alteryx.ps1 @@ -11,7 +11,7 @@ .PARAMETER Action The action parameter corresponds to the operation to perform. - Sixteen options are available: + Nineteen options are available: - activate: activate the Alteryx application license - backup: backup the Alteryx application database @@ -26,6 +26,7 @@ - repair: repair the Alteryx application database - restart: restart the Alteryx application - restore: restore a backup of the Alteryx application database + - setup: set-up the script configuration - show: display the script configuration - start: start the Alteryx application - stop: stop the Alteryx application @@ -39,7 +40,7 @@ File name: Deploy-Alteryx.ps1 Author: Florian Carrier Creation date: 2021-06-13 - Last modified: 2024-09-16 + Last modified: 2024-09-20 Dependencies: - PowerShell Tool Kit (PSTK) - Alteryx PowerShell Module (PSAYX) @@ -67,19 +68,18 @@ Param ( [ValidateSet ( "activate", "backup", - "deactivate", - "download", - "install", - "repair", "configure", "deactivate", + "download", "install", "open", "patch", "ping", "repair", + "repair", "restart", "restore", + "setup", "show", "start", "stop", @@ -260,7 +260,6 @@ Begin { "DataPackages" ) $InstallationProperties = Get-Properties -File $Properties.InstallationOptions -Directory $Properties.ConfDirectory -ValidateSet $ValidateSet - $InstallationProperties.Add("Product", $Product) $Properties.Add("Product", $Product) # Optional parameters if ($PSBoundParameters.ContainsKey("Version")) { @@ -282,7 +281,7 @@ Process { switch ($Action) { "activate" { $Process = Invoke-ActivateAlteryx -Properties $Properties -Unattended:$Unattended } "backup" { $Process = Invoke-BackupAlteryx -Properties $Properties -Unattended:$Unattended } - "configure" { $Process = Set-Configuration -Properties $Properties -ScriptProperties $ScriptProperties } + "configure" { $Process = Set-AlteryxConfiguration -Properties $Properties -ScriptProperties $ScriptProperties } "deactivate" { $Process = Invoke-DeactivateAlteryx -Properties $Properties -Unattended:$Unattended } "download" { $Process = Invoke-DownloadAlteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } "install" { $Process = Install-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } @@ -293,6 +292,7 @@ Process { "repair" { $Process = Repair-Alteryx -Properties $Properties -Unattended:$Unattended } "restart" { $Process = Invoke-RestartAlteryx -Properties $Properties -Unattended:$Unattended } "restore" { $Process = Invoke-RestoreAlteryx -Properties $Properties -Unattended:$Unattended } + "setup" { $Process = Invoke-SetupScript -Properties $Properties -ScriptProperties $ScriptProperties } "show" { $Process = Show-Configuration -Properties $Properties -InstallationProperties $InstallationProperties } "start" { $Process = Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended } "stop" { $Process = Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended } diff --git a/powershell/Set-Configuration.ps1 b/powershell/Invoke-SetupScript.ps1 similarity index 85% rename from powershell/Set-Configuration.ps1 rename to powershell/Invoke-SetupScript.ps1 index 98b1e14..864e630 100644 --- a/powershell/Set-Configuration.ps1 +++ b/powershell/Invoke-SetupScript.ps1 @@ -1,16 +1,16 @@ -function Set-Configuration { +function Invoke-SetupScript { <# .SYNOPSIS - Configure Alteryx deploy utility + Set-up Alteryx deploy utility .DESCRIPTION - Configuration wizard for the required parameters of the alteryx-deploy utility + Set-up wizard to configure the required parameters of the alteryx-deploy utility .NOTES - File name: Set-Configuration.ps1 + File name: Invoke-SetupScript.ps1 Author: Florian Carrier Creation date: 2022-05-03 - Last modified: 2024-09-17 + Last modified: 2024-09-20 #> [CmdletBinding ( SupportsShouldProcess = $true @@ -39,20 +39,20 @@ function Set-Configuration { # Log function call Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name # Process status - $ConfigureProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name + $SetupProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # Parameters $ConfDirectory = $ScriptProperties.ConfDirectory $DefaultPath = Join-Path -Path $ConfDirectory -ChildPath $ScriptProperties.DefaultProperties $CustomPath = Join-Path -Path $ConfDirectory -ChildPath $ScriptProperties.CustomProperties - $CustomHeader = -"# ------------------------------------------------------------------------------ + $CustomHeader = "# ------------------------------------------------------------------------------ # Add your custom configuration here # e.g. TempDirectory = D:\Temp -# ------------------------------------------------------------------------------" +# ------------------------------------------------------------------------------ +" } Process { - $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Running" - Write-Log -Type "NOTICE" -Message "Configuring script" + $SetupProcess = Update-ProcessObject -ProcessObject $SetupProcess -Status "Running" + Write-Log -Type "NOTICE" -Message "Setting up script" # ------------------------------------------------------------------------------ # * Configure script parameters Write-Log -Type "INFO" -Message "Configuring script parameters" @@ -113,7 +113,7 @@ function Set-Configuration { } catch { Write-Log -Type "ERROR" -Message (Get-Error) Write-Log -Type "ERROR" -Message "Custom configuration could not be saved" - $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -ErrorCount 1 + $SetupProcess = Update-ProcessObject -ProcessObject $SetupProcess -ErrorCount 1 } } # Reload properties @@ -135,7 +135,7 @@ function Set-Configuration { } } if ($ConfigureLicenseAPI) { - $LicenseAPIToken = Read-Host -Prompt $LicenseAPIPrompt + $LicenseAPIToken = (Read-Host -Prompt $LicenseAPIPrompt).Trim() Write-Log -Type "DEBUG" -Message $LicenseAPIToken Write-Log -Type "DEBUG" -Message $LicenseAPIPath Out-File -FilePath $LicenseAPIPath -InputObject $LicenseAPIToken -Force @@ -144,7 +144,7 @@ function Set-Configuration { } else { Write-Log -Type "ERROR" -Message (Get-Error) Write-Log -Type "ERROR" -Message "License Portal API refresh token could not be saved" - $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -ErrorCount 1 + $SetupProcess = Update-ProcessObject -ProcessObject $SetupProcess -ErrorCount 1 } } else { Write-Log -Type "WARN" -Message "Skipping License Portal API refresh token configuration" @@ -172,8 +172,8 @@ function Set-Configuration { } } if ($ConfigureServerAPI) { - $ServerAPIKey = Read-Host -Prompt $APIKeyPrompt - $ServerAPISecret = Read-Host -Prompt $APISecretPrompt + $ServerAPIKey = (Read-Host -Prompt $APIKeyPrompt).Trim() + $ServerAPISecret = (Read-Host -Prompt $APISecretPrompt).Trim() $ServerAPIToken = [Ordered]@{ "key" = $ServerAPIKey "secret" = $ServerAPISecret @@ -186,7 +186,7 @@ function Set-Configuration { } else { Write-Log -Type "ERROR" -Message (Get-Error) Write-Log -Type "ERROR" -Message "Server API keys could not be saved" - $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -ErrorCount 1 + $SetupProcess = Update-ProcessObject -ProcessObject $SetupProcess -ErrorCount 1 } } else { Write-Log -Type "WARN" -Message "Skipping Server API keys configuration" @@ -214,7 +214,7 @@ function Set-Configuration { } catch { Write-Log -Type "ERROR" -Message (Get-Error) Write-Log -Type "ERROR" -Message "Installation properties could not be saved" - $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -ErrorCount 1 + $SetupProcess = Update-ProcessObject -ProcessObject $SetupProcess -ErrorCount 1 } } # ------------------------------------------------------------------------------ @@ -232,7 +232,7 @@ function Set-Configuration { } } if ($ConfigureLicenseFile) { - $LicenseKeys = (Read-Host -Prompt "Enter Alteryx license key(s)") -split '[ ,]+' + $LicenseKeys = ((Read-Host -Prompt "Enter Alteryx license key(s)").Trim()) -split '[ ,]+' Write-Log -Type "DEBUG" -Message $LicenseKeys try { Write-Log -Type "DEBUG" $LicenseFilePath @@ -240,7 +240,7 @@ function Set-Configuration { } catch { Write-Log -Type "ERROR" -Message (Get-Error) Write-Log -Type "ERROR" -Message "License file could not be saved" - $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -ErrorCount 1 + $SetupProcess = Update-ProcessObject -ProcessObject $SetupProcess -ErrorCount 1 } } } @@ -248,21 +248,21 @@ function Set-Configuration { # TODO Configure SSL certificate # Write-Log -Type "INFO" -Message "Configuring SSL/TLS" # ------------------------------------------------------------------------------ - if ($ConfigureProcess.ErrorCount -eq 5) { + if ($SetupProcess.ErrorCount -eq 5) { # If all configuration failed - Write-Log -Type "ERROR" -Message "Configuration wizard failed" - $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Failed" -ExitCode 1 - } elseif ($ConfigureProcess.ErrorCount -gt 0) { + Write-Log -Type "ERROR" -Message "Set-up wizard failed" + $SetupProcess = Update-ProcessObject -ProcessObject $SetupProcess -Status "Failed" -ExitCode 1 + } elseif ($SetupProcess.ErrorCount -gt 0) { # If only partial failure - Write-Log -Type "WARN" -Message "Configuration wizard completed with errors" - $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Completed" + Write-Log -Type "WARN" -Message "Set-up wizard completed with errors" + $SetupProcess = Update-ProcessObject -ProcessObject $SetupProcess -Status "Completed" } else { # Otherwise success - Write-Log -Type "CHECK" -Message "Configuration wizard complete" - $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Completed" -Success $true + Write-Log -Type "CHECK" -Message "Set-up wizard complete" + $SetupProcess = Update-ProcessObject -ProcessObject $SetupProcess -Status "Completed" -Success $true } } End { - return $ConfigureProcess + return $SetupProcess } } \ No newline at end of file diff --git a/powershell/Set-AlteryxConfiguration.ps1 b/powershell/Set-AlteryxConfiguration.ps1 new file mode 100644 index 0000000..1181de3 --- /dev/null +++ b/powershell/Set-AlteryxConfiguration.ps1 @@ -0,0 +1,54 @@ +function Set-AlteryxConfiguration { + <# + .SYNOPSIS + Configure Alteryx + + .DESCRIPTION + Automatically configure Alteryx System Settings + + .NOTES + File name: Set-Configuration.ps1 + Author: Florian Carrier + Creation date: 2022-05-03 + Last modified: 2024-09-20 + #> + [CmdletBinding ( + SupportsShouldProcess = $true + )] + Param ( + [Parameter ( + Position = 1, + Mandatory = $true, + HelpMessage = "Script properties" + )] + [ValidateNotNullOrEmpty ()] + [System.Collections.Specialized.OrderedDictionary] + $Properties, + [Parameter ( + Position = 2, + Mandatory = $true, + HelpMessage = "Default script properties" + )] + [ValidateNotNullOrEmpty ()] + [System.Collections.Specialized.OrderedDictionary] + $ScriptProperties + ) + Begin { + # Get global preference vrariables + Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState + # Log function call + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $ConfigureProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name + } + Process { + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Running" + # TODO + Write-Log -Type "ERROR" -Message "Automated configuration of Alteryx is not yet support" + Write-Log -Type "WARN" -Message "Please configure the application through Alteryx System Settings" + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Cancelled" + } + End { + return $ConfigureProcess + } +} \ No newline at end of file From 89f14413e6024967e7276dc3b6c134154dcef965 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Fri, 20 Sep 2024 13:27:22 +0200 Subject: [PATCH 37/61] Add directory check Add check to create target directory if it does not exist --- powershell/Invoke-DownloadAlteryx.ps1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/powershell/Invoke-DownloadAlteryx.ps1 b/powershell/Invoke-DownloadAlteryx.ps1 index 8eca56c..a2925f9 100644 --- a/powershell/Invoke-DownloadAlteryx.ps1 +++ b/powershell/Invoke-DownloadAlteryx.ps1 @@ -10,7 +10,7 @@ function Invoke-DownloadAlteryx { File name: Invoke-DownloadAlteryx.ps1 Author: Florian Carrier Creation date: 2024-09-04 - Last modified: 2024-09-18 + Last modified: 2024-09-20 #> [CmdletBinding ( SupportsShouldProcess = $true @@ -136,6 +136,11 @@ function Invoke-DownloadAlteryx { } } if ($DownloadEXE -eq $true) { + if (Test-Object -Path $DownloadPath -NotFound) { + Write-Log -Type "INFO" -Message "Creating source directory $DownloadPath" + New-Item -Path $DownloadPath -ItemType "Directory" | Out-Null + } + # Download file Invoke-WebRequest -Uri $Release.URL -OutFile $DownloadPath # Check downloaded file Write-Log -Type "DEBUG" -Message $DownloadPath From 1a17d5a0069ed41a58ac4d315a7ba02e08f049cd Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Fri, 20 Sep 2024 13:27:39 +0200 Subject: [PATCH 38/61] Error reporting --- powershell/Invoke-PatchAlteryx.ps1 | 36 +++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/powershell/Invoke-PatchAlteryx.ps1 b/powershell/Invoke-PatchAlteryx.ps1 index 68fb5fc..9e3d71d 100644 --- a/powershell/Invoke-PatchAlteryx.ps1 +++ b/powershell/Invoke-PatchAlteryx.ps1 @@ -68,11 +68,14 @@ function Invoke-PatchAlteryx { Write-Log -Type "DEBUG" -Message $Service $ServiceStatus = $WindowsService.Status if ($ServiceStatus -eq "Running") { - Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended + $StopProcess = Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended + if ($StopProcess.Success -eq $false) { + $PatchProcess = Update-ProcessObject -ProcessObject $PatchProcess -ErrorCount $StopProcess.ErrorCount + } } } else { Write-Log -Type "ERROR" -Message "Alteryx Service ($Service) could not be found" - $PatchProcess = Update-ProcessObject -ProcessObject $PatchProcess -Status "Failed" -Success $false -ExitCode 1 -ErrorCount 1 + $PatchProcess = Update-ProcessObject -ProcessObject $PatchProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 return $PatchProcess } } @@ -87,20 +90,43 @@ function Invoke-PatchAlteryx { Write-Log -Type "CHECK" -Message "Alteryx $($InstallationProperties.Product) patched successfully" } else { Write-Log -Type "ERROR" -Message "An error occured during the patch installation" -ExitCode $PatchInstall.ExitCode + $PatchProcess = Update-ProcessObject -ProcessObject $PatchProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $PatchProcess } # TODO check registry for version and installinfo configuration file } else { Write-Log -Type "ERROR" -Message "Path not found $PatchPath" Write-Log -Type "ERROR" -Message "Alteryx $($InstallationProperties.Product) patch file could not be located" - Write-Log -Type "WARN" -Message "Alteryx patch installation failed" -ExitCode 1 + Write-Log -Type "WARN" -Message "Alteryx patch installation failed" + $PatchProcess = Update-ProcessObject -ProcessObject $PatchProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $PatchProcess } # Restart service if it was running before if ($ServiceStatus -eq "Running") { - Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended + $StartProcess = Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended + if ($StartProcess.Success -eq $false) { + $PatchProcess = Update-ProcessObject -ProcessObject $PatchProcess -ErrorCount $StartProcess.ErrorCount + } } } } else { - Write-Log -Type "ERROR" -Message "Designer or Server products must be enabled for a patch upgrade" -ExitCode 0 + Write-Log -Type "ERROR" -Message "Designer or Server products must be enabled for a patch upgrade" + $PatchProcess = Update-ProcessObject -ProcessObject $PatchProcess -Status "Completed" + } + # ------------------------------------------------------------------------------ + # * Check + # ------------------------------------------------------------------------------ + if ($PatchProcess.ErrorCount -eq 0) { + Write-Log -Type "CHECK" -Message "Alteryx $($InstallationProperties.Product) $($Properties.Version) patched successfully" + $PatchProcess = Update-ProcessObject -ProcessObject $PatchProcess -Status "Completed" -Success $true + } else { + if ($PatchProcess.ErrorCount -eq 1) { + $ErrorCount = "one error" + } else { + $ErrorCount = "$($PatchProcess.ErrorCount) errors" + } + Write-Log -Type "WARN" -Message "Alteryx $($InstallationProperties.Product) $($Properties.Version) was patched with $ErrorCount" + $PatchProcess = Update-ProcessObject -ProcessObject $PatchProcess -Status "Completed" } } End { From 6054944d828f874f83cdb40c433bc32c0bc7f5c4 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Fri, 20 Sep 2024 13:53:14 +0200 Subject: [PATCH 39/61] Prevent AIS version mismatch --- Deploy-Alteryx.ps1 | 2 +- powershell/Install-Alteryx.ps1 | 32 +++++++++++++++---------- powershell/Set-AlteryxConfiguration.ps1 | 21 ++++++++-------- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/Deploy-Alteryx.ps1 b/Deploy-Alteryx.ps1 index f2fed0a..8166226 100644 --- a/Deploy-Alteryx.ps1 +++ b/Deploy-Alteryx.ps1 @@ -281,7 +281,7 @@ Process { switch ($Action) { "activate" { $Process = Invoke-ActivateAlteryx -Properties $Properties -Unattended:$Unattended } "backup" { $Process = Invoke-BackupAlteryx -Properties $Properties -Unattended:$Unattended } - "configure" { $Process = Set-AlteryxConfiguration -Properties $Properties -ScriptProperties $ScriptProperties } + "configure" { $Process = Set-AlteryxConfiguration -Properties $Properties -Unattended:$Unattended } "deactivate" { $Process = Invoke-DeactivateAlteryx -Properties $Properties -Unattended:$Unattended } "download" { $Process = Invoke-DownloadAlteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } "install" { $Process = Install-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } diff --git a/powershell/Install-Alteryx.ps1 b/powershell/Install-Alteryx.ps1 index c1f236e..98266e7 100644 --- a/powershell/Install-Alteryx.ps1 +++ b/powershell/Install-Alteryx.ps1 @@ -16,7 +16,7 @@ function Install-Alteryx { File name: Install-Alteryx.ps1 Author: Florian Carrier Creation date: 2021-07-05 - Last modified: 2024-09-18 + Last modified: 2024-09-20 .LINK https://www.powershellgallery.com/packages/PSAYX @@ -60,6 +60,7 @@ function Install-Alteryx { $Installprocess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # Variables $ISOTimeStamp = Get-Date -Format "yyyyMMdd_HHmmss" + $MajorVersion = [System.String]::Concat([System.Version]::Parse($Properties.Version).Major, ".", [System.Version]::Parse($Properties.Version).Minor) $Tags = [Ordered]@{"Version" = $Properties.Version} # Filenames if ($InstallationProperties.Product -eq "Designer") { @@ -135,15 +136,6 @@ function Install-Alteryx { return $Installprocess } } - # Configuration - if ($InstallationProperties.Product -eq "Server") { - if ($Unattended) { - Write-Log -Type "WARN" -Message "Do not forget to configure system settings" - } else { - # TODO start system settings - Write-Log -Type "WARN" -Message "Do not forget to configure system settings" - } - } } # ------------------------------------------------------------------------------ # * Predictive Tools @@ -204,10 +196,17 @@ function Install-Alteryx { $Workaround = [Ordered]@{"Version" = [System.String]::Concat($Properties.Version, "_1")} $WorkaroundPath = Set-Tags -String $AISInstaller -Tags (Resolve-Tags -Tags $Workaround -Prefix "<" -Suffix ">") if (Test-Path -Path $WorkaroundPath) { - $AISFileName = Set-Tags -String $AISInstaller -Tags (Resolve-Tags -Tags $Workaround -Prefix "<" -Suffix ">") + $AISFileName = $WorkaroundPath $AISPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $AISFileName } else { # TODO Check latest file that matches the major version + $Check = [Ordered]@{"Version" = "$MajorVersion.*"} + $CheckPattern = Set-Tags -String $AISInstaller -Tags (Resolve-Tags -Tags $Check -Prefix "<" -Suffix ">") + $CheckFile = Get-ChildItem -Path $CheckPattern | Sort-Object -Property "LastWriteTime" -Descending -Top 1 + if ($null -ne $CheckFile) { + $AISFileName = $CheckFile.Name + $AISPath = $CheckFile.FullName + } } } Write-Log -Type "INFO" -Message "Installing Intelligence Suite" @@ -302,13 +301,22 @@ function Install-Alteryx { if ($PSCmdlet.ShouldProcess("Alteryx license", "Activate")) { $ActivateProcess = Invoke-ActivateAlteryx -Properties $Properties -Unattended:$Unattended if ($ActivateProcess.Success -eq $false) { - $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -ErrorCount 1 + $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -ErrorCount $ActivateProcess.ErrorCount } } } else { Write-Log -Type "WARN" -Message "Skipping license activation" } # ------------------------------------------------------------------------------ + # * Configuration + # ------------------------------------------------------------------------------ + if ($InstallationProperties.Product -eq "Server") { + $ConfigureProcess = Set-AlteryxConfiguration -Properties $Properties + if ($ConfigureProcess.Success -eq $false) { + $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -ErrorCount $ConfigureProcess.ErrorCount + } + } + # ------------------------------------------------------------------------------ # * Check # ------------------------------------------------------------------------------ if ($Installprocess.ErrorCount -eq 0) { diff --git a/powershell/Set-AlteryxConfiguration.ps1 b/powershell/Set-AlteryxConfiguration.ps1 index 1181de3..f778267 100644 --- a/powershell/Set-AlteryxConfiguration.ps1 +++ b/powershell/Set-AlteryxConfiguration.ps1 @@ -25,13 +25,10 @@ function Set-AlteryxConfiguration { [System.Collections.Specialized.OrderedDictionary] $Properties, [Parameter ( - Position = 2, - Mandatory = $true, - HelpMessage = "Default script properties" + HelpMessage = "Non-interactive mode" )] - [ValidateNotNullOrEmpty ()] - [System.Collections.Specialized.OrderedDictionary] - $ScriptProperties + [Switch] + $Unattended ) Begin { # Get global preference vrariables @@ -43,10 +40,14 @@ function Set-AlteryxConfiguration { } Process { $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Running" - # TODO - Write-Log -Type "ERROR" -Message "Automated configuration of Alteryx is not yet support" - Write-Log -Type "WARN" -Message "Please configure the application through Alteryx System Settings" - $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Cancelled" + if ($PSCmdlet.ShouldProcess("Alteryx System Settings", "Configure")) { + # TODO + Write-Log -Type "ERROR" -Message "Automated configuration of Alteryx is not yet support" + Write-Log -Type "WARN" -Message "Please configure the application through Alteryx System Settings" + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Cancelled" + } else { + $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Completed" -Success $true + } } End { return $ConfigureProcess From 94cfadf5ee958e4e620fdd693659e7f5a6a53744 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Fri, 20 Sep 2024 14:00:46 +0200 Subject: [PATCH 40/61] Fix check error --- powershell/Install-Alteryx.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powershell/Install-Alteryx.ps1 b/powershell/Install-Alteryx.ps1 index 98266e7..1f8be91 100644 --- a/powershell/Install-Alteryx.ps1 +++ b/powershell/Install-Alteryx.ps1 @@ -199,10 +199,10 @@ function Install-Alteryx { $AISFileName = $WorkaroundPath $AISPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $AISFileName } else { - # TODO Check latest file that matches the major version + # Check latest file that matches the major version $Check = [Ordered]@{"Version" = "$MajorVersion.*"} $CheckPattern = Set-Tags -String $AISInstaller -Tags (Resolve-Tags -Tags $Check -Prefix "<" -Suffix ">") - $CheckFile = Get-ChildItem -Path $CheckPattern | Sort-Object -Property "LastWriteTime" -Descending -Top 1 + $CheckFile = Get-ChildItem -Path $CheckPattern | Sort-Object -Property "LastWriteTime" -Descending | Select-Object -First 1 if ($null -ne $CheckFile) { $AISFileName = $CheckFile.Name $AISPath = $CheckFile.FullName From 48298d200f310cdb2b8ca636c0ab2337b649f7be Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Fri, 20 Sep 2024 15:00:23 +0200 Subject: [PATCH 41/61] Refactor product reference --- powershell/Install-Alteryx.ps1 | 26 +++++++++++++------------- powershell/Invoke-DownloadAlteryx.ps1 | 2 +- powershell/Invoke-PatchAlteryx.ps1 | 14 +++++++------- powershell/Repair-Alteryx.ps1 | 2 +- powershell/Uninstall-Alteryx.ps1 | 8 ++++---- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/powershell/Install-Alteryx.ps1 b/powershell/Install-Alteryx.ps1 index 1f8be91..bb15785 100644 --- a/powershell/Install-Alteryx.ps1 +++ b/powershell/Install-Alteryx.ps1 @@ -63,7 +63,7 @@ function Install-Alteryx { $MajorVersion = [System.String]::Concat([System.Version]::Parse($Properties.Version).Major, ".", [System.Version]::Parse($Properties.Version).Minor) $Tags = [Ordered]@{"Version" = $Properties.Version} # Filenames - if ($InstallationProperties.Product -eq "Designer") { + if ($Properties.Product -eq "Designer") { $ServerInstaller = "AlteryxInstallx64_.exe" } else { $ServerInstaller = "AlteryxServerInstallx64_.exe" @@ -81,11 +81,11 @@ function Install-Alteryx { } Process { $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -Status "Running" - Write-Log -Type "INFO" -Message "Installation of Alteryx $($InstallationProperties.Product) $($Properties.Version)" + Write-Log -Type "INFO" -Message "Installation of Alteryx $($Properties.Product) $($Properties.Version)" # ------------------------------------------------------------------------------ # * Alteryx Server # ------------------------------------------------------------------------------ - if ($InstallationProperties.Product -eq "Designer" -Or $InstallationProperties.Server -eq $true) { + if ($Properties.Product -eq "Designer" -Or $InstallationProperties.Server -eq $true) { # Update file version number $ServerFileName = Set-Tags -String $ServerInstaller -Tags (Resolve-Tags -Tags $Tags -Prefix "<" -Suffix ">") $ServerPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $ServerFileName @@ -97,7 +97,7 @@ function Install-Alteryx { $ServerPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $ServerFileName if (Test-Object -Path $ServerPath -NotFound) { Write-Log -Type "ERROR" -Message "Path not found $DefaultServerPath" - Write-Log -Type "ERROR" -Message "Alteryx $($InstallationProperties.Product) installation file could not be located" + Write-Log -Type "ERROR" -Message "Alteryx $($Properties.Product) installation file could not be located" Write-Log -Type "WARN" -Message "Alteryx installation failed" $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -Status "Failed" -ErrorCount 1 -ExitCode 1 return $Installprocess @@ -105,7 +105,7 @@ function Install-Alteryx { Write-Log -Type "DEBUG" -Message "Path not found $DefaultServerPath" } } - Write-Log -Type "INFO" -Message "Installing Alteryx $($InstallationProperties.Product)" + Write-Log -Type "INFO" -Message "Installing Alteryx $($Properties.Product)" if ($PSCmdlet.ShouldProcess($ServerPath, "Install")) { if (Test-Path -Path $ServerPath) { if ($Properties.InstallAwareLog -eq $true) { @@ -124,13 +124,13 @@ function Install-Alteryx { } Write-Log -Type "DEBUG" -Message $ServerInstall if ($ServerInstall.ExitCode -eq 0) { - Write-Log -Type "CHECK" -Message "Alteryx $($InstallationProperties.Product) installed successfully" + Write-Log -Type "CHECK" -Message "Alteryx $($Properties.Product) installed successfully" } else { Write-Log -Type "ERROR" -Message "An error occured during the installation" -ExitCode $ServerInstall.ExitCode } } else { Write-Log -Type "ERROR" -Message "Path not found $ServerPath" - Write-Log -Type "ERROR" -Message "Alteryx $($InstallationProperties.Product) installation file could not be located" + Write-Log -Type "ERROR" -Message "Alteryx $($Properties.Product) installation file could not be located" Write-Log -Type "WARN" -Message "Alteryx installation failed" $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -Status "Failed" -ErrorCount 1 -ExitCode 1 return $Installprocess @@ -144,10 +144,10 @@ function Install-Alteryx { $RInstall = $true # Update file version number $RFileName = Set-Tags -String $RInstaller -Tags (Resolve-Tags -Tags $Tags -Prefix "<" -Suffix ">") - if ($InstallationProperties.Product -eq "Server") { + if ($Properties.Product -eq "Server") { # Use embedded R installer $RPath = Join-Path -Path $RDirectory -ChildPath $RFileName - } elseif ($InstallationProperties.Product -eq "Designer") { + } elseif ($Properties.Product -eq "Designer") { $RPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $RFileName } # Check source file @@ -156,7 +156,7 @@ function Install-Alteryx { if (Test-Object -Path $RPath -NotFound) { # Look for a file which may not match the patch versioning $RFile = Get-ChildItem -Path $RDirectory -Filter "RInstaller_*.exe" - if (($InstallationProperties.Product -eq "Server") -Or (($RFile | Measure-Object).Count) -eq 1) { + if (($Properties.Product -eq "Server") -Or (($RFile | Measure-Object).Count) -eq 1) { $RPath = $RFile.FullName } else { Write-Log -Type "ERROR" -Message "Path not found $RPath" @@ -310,7 +310,7 @@ function Install-Alteryx { # ------------------------------------------------------------------------------ # * Configuration # ------------------------------------------------------------------------------ - if ($InstallationProperties.Product -eq "Server") { + if ($Properties.Product -eq "Server") { $ConfigureProcess = Set-AlteryxConfiguration -Properties $Properties if ($ConfigureProcess.Success -eq $false) { $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -ErrorCount $ConfigureProcess.ErrorCount @@ -320,7 +320,7 @@ function Install-Alteryx { # * Check # ------------------------------------------------------------------------------ if ($Installprocess.ErrorCount -eq 0) { - Write-Log -Type "CHECK" -Message "Alteryx $($InstallationProperties.Product) $($Properties.Version) installed successfully" + Write-Log -Type "CHECK" -Message "Alteryx $($Properties.Product) $($Properties.Version) installed successfully" $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -Status "Completed" -Success $true } else { if ($Installprocess.ErrorCount -eq 1) { @@ -328,7 +328,7 @@ function Install-Alteryx { } else { $ErrorCount = "$($Installprocess.ErrorCount) errors" } - Write-Log -Type "WARN" -Message "Alteryx $($InstallationProperties.Product) $($Properties.Version) was installed with $ErrorCount" + Write-Log -Type "WARN" -Message "Alteryx $($Properties.Product) $($Properties.Version) was installed with $ErrorCount" $Installprocess = Update-ProcessObject -ProcessObject $Installprocess -Status "Completed" } } diff --git a/powershell/Invoke-DownloadAlteryx.ps1 b/powershell/Invoke-DownloadAlteryx.ps1 index a2925f9..7a92513 100644 --- a/powershell/Invoke-DownloadAlteryx.ps1 +++ b/powershell/Invoke-DownloadAlteryx.ps1 @@ -204,7 +204,7 @@ function Invoke-DownloadAlteryx { # * Check # ------------------------------------------------------------------------------ if ($DownloadProcess.ErrorCount -eq 0) { - Write-Log -Type "CHECK" -Message "Download of Alteryx $($InstallationProperties.Product) $Version successfull" + Write-Log -Type "CHECK" -Message "Download of Alteryx $($Properties.Product) $Version successfull" $DownloadProcess = Update-ProcessObject -ProcessObject $DownloadProcess -Status "Completed" -Success $true } elseif ($DownloadProcess.ErrorCount -eq 4) { Write-Log -Type "ERROR" -Message "Download failed" diff --git a/powershell/Invoke-PatchAlteryx.ps1 b/powershell/Invoke-PatchAlteryx.ps1 index 9e3d71d..558815f 100644 --- a/powershell/Invoke-PatchAlteryx.ps1 +++ b/powershell/Invoke-PatchAlteryx.ps1 @@ -40,7 +40,7 @@ function Invoke-PatchAlteryx { # Variables $ISOTimeStamp = Get-Date -Format "yyyyMMdd_HHmmss" # Filenames - if ($InstallationProperties.Product -eq "Designer") { + if ($Properties.Product -eq "Designer") { $PatchPrefix = "AlteryxPatchInstall" } else { $PatchPrefix = "AlteryxServerPatchInstall" @@ -48,9 +48,9 @@ function Invoke-PatchAlteryx { } Process { $PatchProcess = Update-ProcessObject -ProcessObject $PatchProcess -Status "Running" - Write-Log -Type "INFO" -Message "Installation of Alteryx $($InstallationProperties.Product) patch $($Properties.Version)" + Write-Log -Type "INFO" -Message "Installation of Alteryx $($Properties.Product) patch $($Properties.Version)" # Check products to install - if ($InstallationProperties.Product -eq "Designer" -Or $InstallationProperties.Server -eq $true) { + if ($Properties.Product -eq "Designer" -Or $InstallationProperties.Server -eq $true) { # Generate patch file version number $PatchVersion = [System.Version]::Parse($Properties.Version).Major.ToString() + "." + [System.Version]::Parse($Properties.Version).Minor.ToString() + "." + [System.Version]::Parse($Properties.Version).Build.ToString() + ".?." + [System.Version]::Parse($Properties.Version).Revision.ToString() $PatchInstaller = "$($PatchPrefix)_$($PatchVersion).exe" @@ -87,7 +87,7 @@ function Invoke-PatchAlteryx { } Write-Log -Type "DEBUG" -Message $PatchInstall if ($PatchInstall.ExitCode -eq 0) { - Write-Log -Type "CHECK" -Message "Alteryx $($InstallationProperties.Product) patched successfully" + Write-Log -Type "CHECK" -Message "Alteryx $($Properties.Product) patched successfully" } else { Write-Log -Type "ERROR" -Message "An error occured during the patch installation" -ExitCode $PatchInstall.ExitCode $PatchProcess = Update-ProcessObject -ProcessObject $PatchProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 @@ -96,7 +96,7 @@ function Invoke-PatchAlteryx { # TODO check registry for version and installinfo configuration file } else { Write-Log -Type "ERROR" -Message "Path not found $PatchPath" - Write-Log -Type "ERROR" -Message "Alteryx $($InstallationProperties.Product) patch file could not be located" + Write-Log -Type "ERROR" -Message "Alteryx $($Properties.Product) patch file could not be located" Write-Log -Type "WARN" -Message "Alteryx patch installation failed" $PatchProcess = Update-ProcessObject -ProcessObject $PatchProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 return $PatchProcess @@ -117,7 +117,7 @@ function Invoke-PatchAlteryx { # * Check # ------------------------------------------------------------------------------ if ($PatchProcess.ErrorCount -eq 0) { - Write-Log -Type "CHECK" -Message "Alteryx $($InstallationProperties.Product) $($Properties.Version) patched successfully" + Write-Log -Type "CHECK" -Message "Alteryx $($Properties.Product) $($Properties.Version) patched successfully" $PatchProcess = Update-ProcessObject -ProcessObject $PatchProcess -Status "Completed" -Success $true } else { if ($PatchProcess.ErrorCount -eq 1) { @@ -125,7 +125,7 @@ function Invoke-PatchAlteryx { } else { $ErrorCount = "$($PatchProcess.ErrorCount) errors" } - Write-Log -Type "WARN" -Message "Alteryx $($InstallationProperties.Product) $($Properties.Version) was patched with $ErrorCount" + Write-Log -Type "WARN" -Message "Alteryx $($Properties.Product) $($Properties.Version) was patched with $ErrorCount" $PatchProcess = Update-ProcessObject -ProcessObject $PatchProcess -Status "Completed" } } diff --git a/powershell/Repair-Alteryx.ps1 b/powershell/Repair-Alteryx.ps1 index bd75f20..643f338 100644 --- a/powershell/Repair-Alteryx.ps1 +++ b/powershell/Repair-Alteryx.ps1 @@ -47,7 +47,7 @@ function Repair-Alteryx { $Command = "--rebuild -mongoconnection:mongodb://user:@:/AlteryxGallery?connectTimeoutMS=25000 -luceneconnection:mongodb://user:@:/AlteryxGallery_Lucene?connectTimeoutMS=25000 -searchProvider:Lucene" } Process { - Write-Log -Type "INFO" -Message "Starting repair of Alteryx $($InstallationProperties.Product) $($Properties.Version)" + Write-Log -Type "INFO" -Message "Starting repair of Alteryx $($Properties.Product) $($Properties.Version)" $Path = Get-AlteryxUtility -Utility $Utility # Retrieve database password $Passwords = Get-AlteryxEMongoPassword diff --git a/powershell/Uninstall-Alteryx.ps1 b/powershell/Uninstall-Alteryx.ps1 index 9d671b4..dd5b530 100644 --- a/powershell/Uninstall-Alteryx.ps1 +++ b/powershell/Uninstall-Alteryx.ps1 @@ -113,7 +113,7 @@ function Uninstall-Alteryx { # Update file version number $ServerFileName = Set-Tags -String $ServerInstaller -Tags (Resolve-Tags -Tags $Tags -Prefix "<" -Suffix ">") $ServerPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $ServerFileName - Write-Log -Type "INFO" -Message "Uninstalling Alteryx $($InstallationProperties.Product)" + Write-Log -Type "INFO" -Message "Uninstalling Alteryx $($Properties.Product)" if ($PSCmdlet.ShouldProcess($ServerPath, "Uninstall")) { if (Test-Path -Path $ServerPath) { if ($Properties.InstallAwareLog -eq $true) { @@ -133,7 +133,7 @@ function Uninstall-Alteryx { } } else { Write-Log -Type "ERROR" -Message "Path not found $ServerPath" - Write-Log -Type "ERROR" -Message "Alteryx $($InstallationProperties.Product) executable file could not be located" + Write-Log -Type "ERROR" -Message "Alteryx $($Properties.Product) executable file could not be located" $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Failed" -ErrorCount 1 -ExitCode 1 return $Uninstallprocess } @@ -148,7 +148,7 @@ function Uninstall-Alteryx { # * Check # ------------------------------------------------------------------------------ if ($Uninstallprocess.ErrorCount -eq 0) { - Write-Log -Type "CHECK" -Message "Uninstallation of Alteryx $($InstallationProperties.Product) $Version successfull" + Write-Log -Type "CHECK" -Message "Uninstallation of Alteryx $($Properties.Product) $Version successfull" $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Completed" -Success $true } else { if ($Uninstallprocess.ErrorCount -eq 1) { @@ -156,7 +156,7 @@ function Uninstall-Alteryx { } else { $ErrorCount = "$($Uninstallprocess.ErrorCount) errors" } - Write-Log -Type "WARN" -Message "Alteryx $($InstallationProperties.Product) $($Properties.Version) was uninstalled with $ErrorCount" + Write-Log -Type "WARN" -Message "Alteryx $($Properties.Product) $($Properties.Version) was uninstalled with $ErrorCount" $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Completed" } } From 4ee9943d9e5b6847f544007cc1936744d64d8291 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Fri, 20 Sep 2024 15:21:38 +0200 Subject: [PATCH 42/61] Remove error message --- powershell/Set-AlteryxConfiguration.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powershell/Set-AlteryxConfiguration.ps1 b/powershell/Set-AlteryxConfiguration.ps1 index f778267..d9f4397 100644 --- a/powershell/Set-AlteryxConfiguration.ps1 +++ b/powershell/Set-AlteryxConfiguration.ps1 @@ -42,8 +42,8 @@ function Set-AlteryxConfiguration { $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Running" if ($PSCmdlet.ShouldProcess("Alteryx System Settings", "Configure")) { # TODO - Write-Log -Type "ERROR" -Message "Automated configuration of Alteryx is not yet support" - Write-Log -Type "WARN" -Message "Please configure the application through Alteryx System Settings" + Write-Log -Type "WARN" -Message "Automated configuration of Alteryx is not yet supported" + Write-Log -Type "WARN" -Message "Please configure the application through Alteryx System Settings" $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Cancelled" } else { $ConfigureProcess = Update-ProcessObject -ProcessObject $ConfigureProcess -Status "Completed" -Success $true From fa21490139264b4fe77fe783342b81d1041c5318 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Fri, 20 Sep 2024 15:23:46 +0200 Subject: [PATCH 43/61] Fix overwrite check --- powershell/Invoke-SetupScript.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powershell/Invoke-SetupScript.ps1 b/powershell/Invoke-SetupScript.ps1 index 864e630..6ab9ccd 100644 --- a/powershell/Invoke-SetupScript.ps1 +++ b/powershell/Invoke-SetupScript.ps1 @@ -60,7 +60,7 @@ function Invoke-SetupScript { $ConfigureParameters = $true # Check if custom configuration ahs already been set if (Test-Path -Path $CustomPath) { - $CustomConfig = (Get-Content -Path $CustomPath).Trim() + $CustomConfig = Get-Content -Path $CustomPath -Raw if ($CustomConfig -ne $CustomHeader) { $ConfigureParameters = Confirm-Prompt -Prompt "Do you want to overwrite the existing configuration?" } From a3958663372969c32c573cff9a1ad0580f807b3a Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Fri, 20 Sep 2024 16:03:56 +0200 Subject: [PATCH 44/61] Reformat comment structure --- powershell/Invoke-SetupScript.ps1 | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/powershell/Invoke-SetupScript.ps1 b/powershell/Invoke-SetupScript.ps1 index 6ab9ccd..a164467 100644 --- a/powershell/Invoke-SetupScript.ps1 +++ b/powershell/Invoke-SetupScript.ps1 @@ -55,6 +55,7 @@ function Invoke-SetupScript { Write-Log -Type "NOTICE" -Message "Setting up script" # ------------------------------------------------------------------------------ # * Configure script parameters + # ------------------------------------------------------------------------------ Write-Log -Type "INFO" -Message "Configuring script parameters" if ($PSCmdlet.ShouldProcess("Script parameters", "Configure")) { $ConfigureParameters = $true @@ -120,7 +121,8 @@ function Invoke-SetupScript { $Properties = Get-Properties -Path $DefaultPath -CustomPath $CustomPath } # ------------------------------------------------------------------------------ - # # * Configure license API token + # * Configure license API token + # ------------------------------------------------------------------------------ Write-Log -Type "INFO" -Message "Configuring License Portal API refresh token" if ($PSCmdlet.ShouldProcess("License Portal API refresh token", "Configure")) { $LicenseAPIPath = Join-Path -Path "$PSScriptRoot/.." -ChildPath "$($Properties.ResDirectory)/$($Properties.LicenseAPIFile)" @@ -151,7 +153,8 @@ function Invoke-SetupScript { } } # # ------------------------------------------------------------------------------ - # # * Configure Server API keys + # * Configure Server API keys + # ------------------------------------------------------------------------------ Write-Log -Type "INFO" -Message "Configuring Server API keys" if ($PSCmdlet.ShouldProcess("Server API keys", "Configure")) { $ServerAPIPath = Join-Path -Path "$PSScriptRoot/.." -ChildPath "$($Properties.ResDirectory)/$($Properties.ServerAdminAPI)" @@ -194,6 +197,7 @@ function Invoke-SetupScript { } # ------------------------------------------------------------------------------ # * Configure installation properties + # ------------------------------------------------------------------------------ Write-Log -Type "INFO" -Message "Configuring installation properties" if ($PSCmdlet.ShouldProcess("Installation properties", "Configure")) { $InstallationPropertiesPath = Join-Path -Path $ConfDirectory -ChildPath $Properties.InstallationOptions @@ -219,6 +223,7 @@ function Invoke-SetupScript { } # ------------------------------------------------------------------------------ # * Configure license file + # ------------------------------------------------------------------------------ Write-Log -Type "INFO" -Message "Configuring license file" if ($PSCmdlet.ShouldProcess("License file", "Configure")) { $LicenseFilePath = Join-Path -Path "$PSScriptRoot/.." -ChildPath "$($Properties.ResDirectory)/$($Properties.LicenseFile)" @@ -245,8 +250,16 @@ function Invoke-SetupScript { } } # ------------------------------------------------------------------------------ - # TODO Configure SSL certificate + # * Configure SSL/TLS + # ------------------------------------------------------------------------------ # Write-Log -Type "INFO" -Message "Configuring SSL/TLS" + # TODO Check if certificate if provided + # TODO Generate self-signed cetrificate + # TODO Enable SSL configuration + # ------------------------------------------------------------------------------ + # * Configure SMTP + # ------------------------------------------------------------------------------ + # TODO Configure SMTP settings # ------------------------------------------------------------------------------ if ($SetupProcess.ErrorCount -eq 5) { # If all configuration failed From 89a70c8776717220f6477c638ac82c88940fddfb Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Fri, 20 Sep 2024 17:29:18 +0200 Subject: [PATCH 45/61] Update README.md --- README.md | 269 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 193 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index d3f3a52..67d4db9 100644 --- a/README.md +++ b/README.md @@ -4,18 +4,18 @@ `alteryx-deploy` is a small PowerShell utility for the automation of the deployment and maintenance of Alteryx. -## Table of contents +## Table of Contents 1. [Usage](#usage) + 1. [Installation](#installation) + 2. [Configuration](#configuration) + 3. [Execution](#execution) 2. [Pre-requisites](#pre-requisites) 1. [Permissions](#permissions) 2. [PowerShell version](#powershell-version) 3. [PowerShell Modules](#powershell-modules) 4. [Alteryx](#alteryx) -3. [Configuration](#configuration) - 1. [Script configuration](#script-configuration) - 2. [Installation configuration](#installation-configuration) -4. [Parameters](#parameters) +3. [Parameters](#parameters) 1. [Mandatory](#mandatory) 1. [Action](#action) 2. [Optional](#optional) @@ -26,41 +26,84 @@ 5. [Unattended](#unattended) 6. [WhatIf](#whatif) 7. [Debug](#debug) -5. [Process](#process) - 1. [Installation](#installation) - 2. [Upgrade](#upgrade) - 3. [Uninstallation](#uninstallation) - 4. [Activation](#activation) - 5. [Deactivation](#deactivation) - 6. [Backup](#backup) - 7. [Restore](#restore) - 8. [Start](#start) - 9. [Stop](#stop) - 10. [Restart](#restart) -6. [Logs](#logs) -7. [Dependencies](#dependencies) -8. [Compatibility](#compatibility) -9. [Known issues](#known-issues) +4. [Process](#process) + 1. [Set-up](#set-up) + 2. [Show](#show) + 3. [Download](#download) + 4. [Installation](#installation-1) + 5. [Upgrade](#upgrade) + 6. [Patch](#patch) + 7. [Uninstallation](#uninstallation) + 8. [Activation](#activation) + 9. [Deactivation](#deactivation) + 10. [Backup](#backup) + 11. [Restore](#restore) + 12. [Repair](#repair) + 13. [Start](#start) + 14. [Stop](#stop) + 15. [Restart](#restart) + 16. [Ping](#ping) + 17. [Open](#open) +5. [Logs](#logs) +6. [Dependencies](#dependencies) +7. [Compatibility](#compatibility) +8. [Known issues](#known-issues) 1. [Access to the cloud file is denied](#access-to-the-cloud-file-is-denied) ## Usage -1. Check the `default.ini` configuration file located under the `conf` folder; -2. If needed, add custom configuration to the `custom.ini` configuration file in the same configuration folder; -3. Update the installation configuration in the file `install.ini`; -4. Run the `Deploy-Alteryx.ps1` script with the corresponding action parameter; - - activate: activate the Alteryx application license - - backup: backup the Alteryx application database - - deactivate: deactivate the Alteryx application license - - install: install the Alteryx application - - restart: restart the Alteryx application - - restore: restore a backup of the Alteryx application database - - show: display the script configuration - - start: start the Alteryx application - - stop: stop the Alteryx application - - uninstall: uninstall the Alteryx application - - upgrade: upgrade the Alteryx application -5. Check the logs. +### Installation + +Download the latest stable version from the [`alteryx-deploy`](https://github.com/Akaizoku/alteryx-deploy) GitHub repository. + +```powershell +curl --remote-name --remote-header-name "https://github.com/Akaizoku/alteryx-deploy/releases/download/1.1.2/alteryx-deploy.1.1.2.zip" +``` + +Alternatively, if you do not wish to install the PowerShell modules required as dependencies, you can download the portable version. + +```powershell +curl --remote-name --remote-header-name "https://github.com/Akaizoku/alteryx-deploy/releases/download/1.1.2/alteryx-deploy.1.1.2.portable.zip" +``` + +### Configuration + +A set-up wizard is available to interactively configure the script from the command prompt. + +```powershell +.\Deploy-Alteryx.ps1 -Action "setup" +``` + +### Execution + +1. Run the [`Deploy-Alteryx.ps1`](./Deploy-Alteryx.ps1) script with the corresponding action parameter; + - [activate](#activation): activate the Alteryx application license + - [backup](#backup): backup the Alteryx application database + - [configure](#configure): configure the Alteryx application + - [deactivate](#deactivation): deactivate the Alteryx application license + - [download](#download): download latest Alteryx application release + - [install](#installation): install the Alteryx application + - [open](#open): open the Alteryx application + - [patch](#patch): patch upgrade the Alteryx application + - [ping](#ping): check the status of the Alteryx application + - [repair](#repair): repair the Alteryx application database + - [restart](#restart): restart the Alteryx application + - [restore](#restore): restore a backup of the Alteryx application database + - [setup](#set-up): set-up the script configuration + - [show](#show): display the script configuration + - [start](#start): start the Alteryx application + - [stop](#stop): stop the Alteryx application + - [uninstall](#uninstallation): uninstall the Alteryx application + - [upgrade](#upgrade): upgrade the Alteryx application +2. Check the logs. + +Example to display the current script configuration: + +```powershell +.\Deploy-Alteryx.ps1 -Action "show" +``` + +**Remark** It is strongly recommended to perform a test run using the [`-WhatIf`](#whatif) parameter if you are running the script or operation for the first time. ## Pre-requisites @@ -78,9 +121,16 @@ This script makes use of functions from the PowerShell Tool Kit ([PSTK]) module The modules must be [installed](https://docs.microsoft.com/en-us/powershell/module/powershellget/install-module) on the local machine, or placed in the `lib` folder at the root of the script directory. +```PowerShell +Install-Module -Name "PSTK" +Install-Module -Name "PSAYX" +``` + +Alternatively, do install the portable version of the script made available in the [`alteryx-deploy`](https://github.com/Akaizoku/alteryx-deploy) GitHub repository. + Example script structure with embedded dependencies: -```cmd +```bash .alteryx-deploy +---conf +---lib @@ -94,44 +144,10 @@ Example script structure with embedded dependencies: Alteryx installation files must be made available in the source directory (default `C:\Sources`). See the [compatibility section](#compatibility) for more information about the supported versions. -You can download them from . +You can download them from or download via the `download` action. Please refer to [Alteryx system requirements](https://help.alteryx.com/current/server/system-requirements) for minimum machine requirements. -## Configuration - -### Script configuration - -The default configuration of the utility is stored into `default.ini`. This file should not be amended. All custom configuration must be made in the `custom.ini` file. Any customisation done in that file will override the default values. - -Below is an example of custom configuration file: - -```ini -[Paths] -# Sources directory -SrcDirectory = D:\Alteryx\Sources -# Alteryx installation directory -InstallationPath = D:\Alteryx\Server -# Backup directory -BackupDirectory = D:\Alteryx\Server\backup -# Data packages installation directory -DataPackagesPath = D:\Alteryx\Data -``` - -### Installation configuration - -To configure which products should be installed, edit the `install.ini` configuration file located in the `conf` directory. - -Below is an example of installation configuration file: - -```ini -[Installation] -Server = true -PredictiveTools = true -IntelligenceSuite = true -DataPackages = false -``` - ## Parameters In addition to the configuration files presented above, parameters will define the operation performed during the execution. @@ -144,14 +160,22 @@ This section lists the mandatory parameters that must be specified to run the sc The `Action` parameter corresponds to the operation to perform. -Eleven options are available: +Nineteen options are available: - activate: activate the Alteryx application license - backup: backup the Alteryx application database +- configure: configure the Alteryx application - deactivate: deactivate the Alteryx application license +- download: download latest Alteryx application release - install: install the Alteryx application +- repair: repair the Alteryx application database +- open: open the Alteryx application +- patch: patch upgrade the Alteryx application +- ping: check the status of the Alteryx application +- repair: repair the Alteryx application database - restart: restart the Alteryx application - restore: restore a backup of the Alteryx application database +- setup: set-up the script configuration - show: display the script configuration - start: start the Alteryx application - stop: stop the Alteryx application @@ -207,6 +231,47 @@ Below are the execution steps of the `.\Deploy-Alteryx.ps1` script. 1. The execution steps will vary depending on the configuration of the scripts. 2. The steps described below correspond to a complete and successfull execution of the script. +### Set-up + +The set-up wizard will walk you through the required configuration for the script to run. + +Below are the steps to set-up the `alteryx-deploy` script configuration. + +```powershell +.\Deploy-Alteryx.ps1 -Action "setup" +``` + +1. Configure script parameters; +2. Configure license API token; +3. Configure Server API admin keys; +4. Configure installation properties; +5. Configure license key file + + +### Show + +Below are the steps to display the `alteryx-deploy` script configuration. + +```powershell +.\Deploy-Alteryx.ps1 -Action "show" +``` + +### Download + +Below are the steps to download the Alteryx application. + +```powershell +.\Deploy-Alteryx.ps1 -Action "download" +``` + +1. Refresh license API portal access token; +2. Fetch information on latest release; +3. Download latest version of Alteryx Server (or Designer if specified with the `-Product` parameter); +4. Download Predictive Tools (if enabled); +5. Download Intelligence Suite (if enabled). + + ### Installation Below are the steps to install the Alteryx application. @@ -218,7 +283,10 @@ Below are the steps to install the Alteryx application. 1. Install Alteryx Server (or Designer if specified with the `-Product` parameter); 2. Install Predictive Tools (if enabled); 3. Install Intelligence Suite (if enabled); -4. Install Data packages (if enabled). +4. Install Data packages (if enabled); +5. Activate licenses (if enabled). + ### Upgrade @@ -235,6 +303,18 @@ Below are the steps to upgrade the Alteryx application. 5. Install Data packages (if enabled); 6. Check installation status and rollback if errors occurred. +### Patch + +Below are the steps to patch the Alteryx application. + +```powershell +.\Deploy-Alteryx.ps1 -Action "patch" +``` + +1. Backup Alteryx database and configuration files; +2. Patch Alteryx Server (or Designer if specified with the `-Product` parameter); +3. Check installation status. + ### Uninstallation Below are the steps to uninstall the Alteryx application. @@ -308,6 +388,19 @@ Below are the steps to restore the Alteryx application database. 7. Restore MongoDB database; 8. Restart Alteryx Service (if it was running previously). +### Repair + +Below are the steps to repair the Alteryx application database. + +```powershell +.\Deploy-Alteryx.ps1 -Action "repair" +``` + +1. Rebuild MongoDB indexes. + + +**Remark**: No repair steps are available for version 2022.1 and above. + ### Start Below are the steps to start the Alteryx application. @@ -343,6 +436,28 @@ Below are the steps to restart the Alteryx application. 1. Stop Alteryx Service; 2. Start Alteryx Service. +### Ping + +Below are the steps to ping the Alteryx application. + +```powershell +.\Deploy-Alteryx.ps1 -Action "ping" +``` + +1. Check that the Alteryx Service is running; +2. Check the HTTP status of the Gallery. + +### Open + +Below are the steps to open the Alteryx application. + +```powershell +.\Deploy-Alteryx.ps1 -Action "open" +``` + +- Server: open the Gallery using the default web-browser; +- Designer: open the GUI. + ## Logs Transcript log files are generated in the log directory of the script. @@ -375,8 +490,8 @@ Below is an example of a successful installation log: This module depends on the usage of functions provided by two PowerShell modules: -1. PowerShell Tool Kit ([PSTK]) module (version 1.2.5) -2. Alteryx PowerShell ([PSAYX]) module (version 1.0.1) +1. PowerShell Tool Kit ([PSTK]) module (version 1.2.6); +2. Alteryx PowerShell ([PSAYX]) module (version 1.1.0). ## Compatibility @@ -390,6 +505,7 @@ Only the first version supported is listed. Later releases should also be compat | [1.1.0] | [2021.3] | 5.0 | 1.2.5 | 1.0.1 | | [1.1.1] | [2021.3] | 5.0 | 1.2.5 | 1.0.1 | | [1.1.2] | [2021.3] | 5.0 | 1.2.5 | 1.0.1 | +| [2.0.0] | [2024.1] | 5.0 | 1.2.6 | 1.1.0 | ## Known issues @@ -417,4 +533,5 @@ It can be prevented by configuring a temporary directory (`TempDirectory`) that [1.1.1]:https://github.com/Akaizoku/alteryx-deploy/releases/1.1.1 [1.1.2]:https://github.com/Akaizoku/alteryx-deploy/releases/1.1.2 [2021.3]:https://help.alteryx.com/release-notes/server/server-20213-release-notes +[2024.1]:https://help.alteryx.com/release-notes/en/release-notes/server-release-notes/server-2024-1-release-notes.html [whitelist.alteryx.com]:(whitelist.alteryx.com) From dc45665fadbbaa1e1628e540869b4161e748e401 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 23 Sep 2024 16:34:50 +0200 Subject: [PATCH 46/61] Update README.md --- README.md | 123 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 100 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 67d4db9..74a516e 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,15 @@ [![PSScriptAnalyzer](https://github.com/Akaizoku/alteryx-deploy/actions/workflows/scan.yml/badge.svg?branch=main)](https://github.com/Akaizoku/alteryx-deploy/actions/workflows/scan.yml) +```asci + _ _ _ _ + __ _| | |_ ___ _ __ _ ___ __ __| | ___ _ __ | | ___ _ _ + / _` | | __/ _ \ '__| | | \ \/ /____ / _` |/ _ \ '_ \| |/ _ \| | | | +| (_| | | || __/ | | |_| |> <|____| (_| | __/ |_) | | (_) | |_| | + \__,_|_|\__\___|_| \__, /_/\_\ \__,_|\___| .__/|_|\___/ \__, | + |___/ |_| |___/ +``` + `alteryx-deploy` is a small PowerShell utility for the automation of the deployment and maintenance of Alteryx. ## Table of Contents @@ -27,28 +36,31 @@ 6. [WhatIf](#whatif) 7. [Debug](#debug) 4. [Process](#process) - 1. [Set-up](#set-up) - 2. [Show](#show) - 3. [Download](#download) - 4. [Installation](#installation-1) - 5. [Upgrade](#upgrade) - 6. [Patch](#patch) - 7. [Uninstallation](#uninstallation) - 8. [Activation](#activation) - 9. [Deactivation](#deactivation) - 10. [Backup](#backup) - 11. [Restore](#restore) - 12. [Repair](#repair) - 13. [Start](#start) - 14. [Stop](#stop) - 15. [Restart](#restart) - 16. [Ping](#ping) - 17. [Open](#open) + 1. [Help](#help) + 2. [Set-up](#set-up) + 3. [Show](#show) + 4. [Download](#download) + 5. [Installation](#installation-1) + 6. [Upgrade](#upgrade) + 7. [Patch](#patch) + 8. [Uninstallation](#uninstallation) + 9. [Activation](#activation) + 10. [Deactivation](#deactivation) + 11. [Backup](#backup) + 12. [Restore](#restore) + 13. [Repair](#repair) + 14. [Rollback](#rollback) + 15. [Start](#start) + 16. [Stop](#stop) + 17. [Restart](#restart) + 18. [Ping](#ping) + 19. [Open](#open) 5. [Logs](#logs) 6. [Dependencies](#dependencies) 7. [Compatibility](#compatibility) 8. [Known issues](#known-issues) 1. [Access to the cloud file is denied](#access-to-the-cloud-file-is-denied) + 2. [Transcript is not stopped](#transcript-is-not-stopped) ## Usage @@ -79,9 +91,10 @@ A set-up wizard is available to interactively configure the script from the comm 1. Run the [`Deploy-Alteryx.ps1`](./Deploy-Alteryx.ps1) script with the corresponding action parameter; - [activate](#activation): activate the Alteryx application license - [backup](#backup): backup the Alteryx application database - - [configure](#configure): configure the Alteryx application + - [configure](#configuration): configure the Alteryx application - [deactivate](#deactivation): deactivate the Alteryx application license - [download](#download): download latest Alteryx application release + - [help](#help) display the help documentation of the script - [install](#installation): install the Alteryx application - [open](#open): open the Alteryx application - [patch](#patch): patch upgrade the Alteryx application @@ -89,6 +102,7 @@ A set-up wizard is available to interactively configure the script from the comm - [repair](#repair): repair the Alteryx application database - [restart](#restart): restart the Alteryx application - [restore](#restore): restore a backup of the Alteryx application database + - [rollback](#rollback) restore a previous known state of the Alteryx application - [setup](#set-up): set-up the script configuration - [show](#show): display the script configuration - [start](#start): start the Alteryx application @@ -167,6 +181,7 @@ Nineteen options are available: - configure: configure the Alteryx application - deactivate: deactivate the Alteryx application license - download: download latest Alteryx application release +- help: display the help documentation - install: install the Alteryx application - repair: repair the Alteryx application database - open: open the Alteryx application @@ -175,6 +190,7 @@ Nineteen options are available: - repair: repair the Alteryx application database - restart: restart the Alteryx application - restore: restore a backup of the Alteryx application database +- rollback: restore a previous known state of the Alteryx application - setup: set-up the script configuration - show: display the script configuration - start: start the Alteryx application @@ -231,9 +247,17 @@ Below are the execution steps of the `.\Deploy-Alteryx.ps1` script. 1. The execution steps will vary depending on the configuration of the scripts. 2. The steps described below correspond to a complete and successfull execution of the script. +### Help + +Display the help documentation of the script. + +```powershell +Get-Help -Name "Deploy-Alteryx.ps1" -Full +``` + ### Set-up -The set-up wizard will walk you through the required configuration for the script to run. +Start the configuration wizard to guide the user through the set-up of the alteryx-deploy script. Below are the steps to set-up the `alteryx-deploy` script configuration. @@ -251,6 +275,8 @@ Below are the steps to set-up the `alteryx-deploy` script configuration. ### Show +Display the current script configuration back to the user. + Below are the steps to display the `alteryx-deploy` script configuration. ```powershell @@ -259,6 +285,8 @@ Below are the steps to display the `alteryx-deploy` script configuration. ### Download +Download the latest version of the licensed Alteryx application from the Alteryx license portal. + Below are the steps to download the Alteryx application. ```powershell @@ -274,6 +302,8 @@ Below are the steps to download the Alteryx application. ### Installation +Start the installation process of the Alteryx application and its add-ons if configured. + Below are the steps to install the Alteryx application. ```powershell @@ -290,6 +320,8 @@ Below are the steps to install the Alteryx application. ### Upgrade +Start the (major) upgrade process of the Alteryx application and its add-ons if configured. + Below are the steps to upgrade the Alteryx application. ```powershell @@ -305,6 +337,8 @@ Below are the steps to upgrade the Alteryx application. ### Patch +Start the patch process of the Alteryx application. + Below are the steps to patch the Alteryx application. ```powershell @@ -317,6 +351,8 @@ Below are the steps to patch the Alteryx application. ### Uninstallation +Start the uninstallation process of the Alteryx application and all of its add-ons. + Below are the steps to uninstall the Alteryx application. ```powershell @@ -332,6 +368,8 @@ Below are the steps to uninstall the Alteryx application. ### Activation +License the Alteryx application by registering the specified license keys through the Alteryx licensing system. + Below are the steps to activate (license) the Alteryx application. ```powershell @@ -344,6 +382,8 @@ Below are the steps to activate (license) the Alteryx application. ### Deactivation +Deregister the specified license keys through the Alteryx licensing system. + Below are the steps to deactivate (license) the Alteryx application. ```powershell @@ -356,7 +396,9 @@ Below are the steps to deactivate (license) the Alteryx application. ### Backup -Below are the steps to backup the Alteryx application database. +Start the back-up process of the Alteryx database and all of the configuration files of the application. + +Below are the steps to back-up the Alteryx application database. ```powershell .\Deploy-Alteryx.ps1 -Action "backup" @@ -366,11 +408,13 @@ Below are the steps to backup the Alteryx application database. 2. Create database dump; 3. Create copy of application configuration files; 4. Backup controller token; -5. Compress all backup files; +5. Compress all back-up files; 6. Restart Alteryx Service (if it was running previously). ### Restore +Start the restoration process of the Alteryx database and all of the configuration files of the application from a back-up file. + Below are the steps to restore the Alteryx application database. ```powershell @@ -390,6 +434,8 @@ Below are the steps to restore the Alteryx application database. ### Repair +Start the repair process of the Alteryx database. + Below are the steps to repair the Alteryx application database. ```powershell @@ -401,8 +447,25 @@ Below are the steps to repair the Alteryx application database. **Remark**: No repair steps are available for version 2022.1 and above. +### Rollback + +Start the rollback process of the Alteryx application back to a previous known state from a back-up file. + +Below are the steps to roll-back the Alteryx application. + +```powershell +.\Deploy-Alteryx.ps1 -Action "rollback" +``` + +1. Uninstall the current version; +2. Install previous version; +3. Restore database; +4. Restart service. + ### Start +Start the Alteryx service. + Below are the steps to start the Alteryx application. ```powershell @@ -415,6 +478,8 @@ Below are the steps to start the Alteryx application. ### Stop +Stop the service powering the Alteryx application. + Below are the steps to stop the Alteryx application. ```powershell @@ -427,6 +492,8 @@ Below are the steps to stop the Alteryx application. ### Restart +Restart the service powering the Alteryx application. + Below are the steps to restart the Alteryx application. ```powershell @@ -438,6 +505,8 @@ Below are the steps to restart the Alteryx application. ### Ping +Check the status of the service powering the Alteryx application and the connectivity to the Gallery. + Below are the steps to ping the Alteryx application. ```powershell @@ -449,6 +518,8 @@ Below are the steps to ping the Alteryx application. ### Open +Open the user interface of the Alteryx applciation. + Below are the steps to open the Alteryx application. ```powershell @@ -520,18 +591,24 @@ This error can occur during the backup of the application when [OneDrive](https: This has no impact on the backup process and only affects temporary files used to generate the backup archive. > 2021-11-21 02:12:55 INFO Remove staging backup folder -> > 2021-11-21 02:12:55 ERROR Access to the cloud file is denied It can be prevented by configuring a temporary directory (`TempDirectory`) that is not synchronised by OneDrive. Temporary files can also be removed manually. +### Transcript is not stopped + +It appears that in some environments, the transcript it not stopped as expected when exiting the script. + +If this occurs, simply run the command [`Stop-Transcript`](https://learn.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Host/Stop-Transcript) or [`Stop-AllTranscripts`](https://github.com/Akaizoku/PSTK/blob/main/Public/Stop-AllTranscripts.ps1). + [PSTK]: https://www.powershellgallery.com/packages/PSTK -[PSAYX]: https://www.powershellgallery.com/packages/PSAYX +[PSAYX]:https://www.powershellgallery.com/packages/PSAYX [1.0.0]:https://github.com/Akaizoku/alteryx-deploy/releases/1.0.0 [1.1.0]:https://github.com/Akaizoku/alteryx-deploy/releases/1.1.0 [1.1.1]:https://github.com/Akaizoku/alteryx-deploy/releases/1.1.1 [1.1.2]:https://github.com/Akaizoku/alteryx-deploy/releases/1.1.2 +[2.0.0]:https://github.com/Akaizoku/alteryx-deploy/releases/2.0.0 [2021.3]:https://help.alteryx.com/release-notes/server/server-20213-release-notes [2024.1]:https://help.alteryx.com/release-notes/en/release-notes/server-release-notes/server-2024-1-release-notes.html [whitelist.alteryx.com]:(whitelist.alteryx.com) From 14fcea5d535db255c5bfe8f4a71104b9e0b5dcf7 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 23 Sep 2024 16:35:32 +0200 Subject: [PATCH 47/61] Add help option --- powershell/Show-Help.ps1 | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 powershell/Show-Help.ps1 diff --git a/powershell/Show-Help.ps1 b/powershell/Show-Help.ps1 new file mode 100644 index 0000000..9b5f14b --- /dev/null +++ b/powershell/Show-Help.ps1 @@ -0,0 +1,46 @@ +function Show-Help { + <# + .SYNOPSIS + Show help documentation + + .DESCRIPTION + Displays the help documentation and provide usefull links + + .NOTES + File name: Show-Help.ps1 + Author: Florian Carrier + Creation date: 2024-09-23 + Last modified: 2024-09-23 + #> + Begin { + # Get global preference vrariables + Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState + # Log function call + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $HelpProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name + # Variables + $Path = Resolve-Path -Path "$PSScriptRoot\..\" + $Script = "Deploy-Alteryx.ps1" + $ReadMe = "README.md" + } + Process { + $HelpProcess = Update-ProcessObject -ProcessObject $HelpProcess -Status "Running" + Write-Log -Type "NOTICE" -Message @" +Help documentation + _ _ _ _ + __ _| | |_ ___ _ __ _ ___ __ __| | ___ _ __ | | ___ _ _ + / _`` | | __/ _ \ '__| | | \ \/ /____ / _`` |/ _ \ '_ \| |/ _ \| | | | +| (_| | | || __/ | | |_| |> <|____| (_| | __/ |_) | | (_) | |_| | + \__,_|_|\__\___|_| \__, /_/\_\ \__,_|\___| .__/|_|\___/ \__, | + |___/ |_| |___/ +"@ + $Documentation = Get-Help -Name "$Path\$Script" -Full + Write-Log -Type "INFO" -Message $Documentation + Write-Log -Type "INFO" -Message "Additional information is available in the README file ($PSScriptRoot\$ReadMe)" + $HelpProcess = Update-ProcessObject -ProcessObject $HelpProcess -Status "Completed" -Success $true + } + End { + return $HelpProcess + } +} \ No newline at end of file From c78b8926f053592f556a6a57461db28bc88e6f9f Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 23 Sep 2024 16:36:38 +0200 Subject: [PATCH 48/61] Remove newlines Fix issue where the license token would be incorrectly parsed due to a carriage return --- powershell/Invoke-SetupScript.ps1 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/powershell/Invoke-SetupScript.ps1 b/powershell/Invoke-SetupScript.ps1 index a164467..cf157ca 100644 --- a/powershell/Invoke-SetupScript.ps1 +++ b/powershell/Invoke-SetupScript.ps1 @@ -10,7 +10,7 @@ function Invoke-SetupScript { File name: Invoke-SetupScript.ps1 Author: Florian Carrier Creation date: 2022-05-03 - Last modified: 2024-09-20 + Last modified: 2024-09-23 #> [CmdletBinding ( SupportsShouldProcess = $true @@ -112,7 +112,7 @@ function Invoke-SetupScript { Write-Log -Type "DEBUG" -Message $CustomPath Set-Content -Path $CustomPath -Value $CustomProperties.Trim() -Force } catch { - Write-Log -Type "ERROR" -Message (Get-Error) + Write-Log -Type "ERROR" -Message (Get-PowerShellError) Write-Log -Type "ERROR" -Message "Custom configuration could not be saved" $SetupProcess = Update-ProcessObject -ProcessObject $SetupProcess -ErrorCount 1 } @@ -140,11 +140,11 @@ function Invoke-SetupScript { $LicenseAPIToken = (Read-Host -Prompt $LicenseAPIPrompt).Trim() Write-Log -Type "DEBUG" -Message $LicenseAPIToken Write-Log -Type "DEBUG" -Message $LicenseAPIPath - Out-File -FilePath $LicenseAPIPath -InputObject $LicenseAPIToken -Force + Set-Content -Path $LicenseAPIPath -Value $LicenseAPIToken -NoNewline -Force if (Test-Path -Path $LicenseAPIPath) { Write-Log -Type "CHECK" -Message "License Portal API refresh token saved successfully" } else { - Write-Log -Type "ERROR" -Message (Get-Error) + Write-Log -Type "ERROR" -Message (Get-PowerShellError) Write-Log -Type "ERROR" -Message "License Portal API refresh token could not be saved" $SetupProcess = Update-ProcessObject -ProcessObject $SetupProcess -ErrorCount 1 } @@ -183,11 +183,11 @@ function Invoke-SetupScript { } | ConvertTo-JSON Write-Log -Type "DEBUG" -Message $ServerAPIToken Write-Log -Type "DEBUG" -Message $ServerAPIPath - Out-File -FilePath $ServerAPIPath -InputObject $ServerAPIToken -Force + Set-Content -Path $ServerAPIPath -Value $ServerAPIToken -Force if (Test-Path -Path $ServerAPIPath) { Write-Log -Type "CHECK" -Message "Server API keys saved successfully" } else { - Write-Log -Type "ERROR" -Message (Get-Error) + Write-Log -Type "ERROR" -Message (Get-PowerShellError) Write-Log -Type "ERROR" -Message "Server API keys could not be saved" $SetupProcess = Update-ProcessObject -ProcessObject $SetupProcess -ErrorCount 1 } @@ -214,9 +214,9 @@ function Invoke-SetupScript { } try { Write-Log -Type "DEBUG" -Message $NewInstallationProperties - Set-Content -Path $InstallationPropertiesPath -Value $NewInstallationProperties + Set-Content -Path $InstallationPropertiesPath -Value $NewInstallationProperties -Force } catch { - Write-Log -Type "ERROR" -Message (Get-Error) + Write-Log -Type "ERROR" -Message (Get-PowerShellError) Write-Log -Type "ERROR" -Message "Installation properties could not be saved" $SetupProcess = Update-ProcessObject -ProcessObject $SetupProcess -ErrorCount 1 } @@ -241,9 +241,9 @@ function Invoke-SetupScript { Write-Log -Type "DEBUG" -Message $LicenseKeys try { Write-Log -Type "DEBUG" $LicenseFilePath - Set-Content -Path $LicenseFilePath -Value $LicenseKeys + Set-Content -Path $LicenseFilePath -Value $LicenseKeys -Force } catch { - Write-Log -Type "ERROR" -Message (Get-Error) + Write-Log -Type "ERROR" -Message (Get-PowerShellError) Write-Log -Type "ERROR" -Message "License file could not be saved" $SetupProcess = Update-ProcessObject -ProcessObject $SetupProcess -ErrorCount 1 } From 9d2ba6b31d51819a75e66ee9ebfa119c1773d058 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 23 Sep 2024 16:38:52 +0200 Subject: [PATCH 49/61] Add error handling --- powershell/Invoke-DownloadAlteryx.ps1 | 49 ++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/powershell/Invoke-DownloadAlteryx.ps1 b/powershell/Invoke-DownloadAlteryx.ps1 index 7a92513..96afa3d 100644 --- a/powershell/Invoke-DownloadAlteryx.ps1 +++ b/powershell/Invoke-DownloadAlteryx.ps1 @@ -10,7 +10,7 @@ function Invoke-DownloadAlteryx { File name: Invoke-DownloadAlteryx.ps1 Author: Florian Carrier Creation date: 2024-09-04 - Last modified: 2024-09-20 + Last modified: 2024-09-23 #> [CmdletBinding ( SupportsShouldProcess = $true @@ -55,19 +55,52 @@ function Invoke-DownloadAlteryx { $RegistryKey = "HKLM:HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\SRC\Alteryx" # License API refresh token $LicenseAPIPath = Join-Path -Path $Properties.ResDirectory -ChildPath $Properties.LicenseAPIFile - $RefreshToken = Get-Content -Path $LicenseAPIPath -Raw + $RefreshToken = (Get-Content -Path $LicenseAPIPath -Raw) -replace "`r|`n", "" # Placeholder $Skip = $false } Process { $DownloadProcess = Update-ProcessObject -ProcessObject $DownloadProcess -Status "Running" + Write-Log -Type "NOTICE" -Message "Starting download process" + # ------------------------------------------------------------------------------ + # * Checks + # ------------------------------------------------------------------------------ + if ($null -eq $RefreshToken) { + Write-Log -Type "ERROR" -Message "The Alteryx license portal API refresh token has not been configured" + if (-Not $Unattended) { + $RefreshToken = Read-Host -Prompt "Enter your Alteryx license portal API refresh token" + } else { + Write-Log -Type "ERROR" -Message "Download process cannot proceed" + $DownloadProcess = Update-ProcessObject -ProcessObject $DownloadProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $DownloadProcess + } + } + if ($null -eq $Properties.AccountID) { + Write-Log -Type "ERROR" -Message "The AccountID parameter has not been configured" + if (-Not $Unattended) { + $Properties.AccountID = Read-Host -Prompt "What is the ID of your account in the Alteryx license portal?" + } else { + Write-Log -Type "ERROR" -Message "Download process cannot proceed" + $DownloadProcess = Update-ProcessObject -ProcessObject $DownloadProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $DownloadProcess + } + } # ------------------------------------------------------------------------------ # * Fetch latest version # ------------------------------------------------------------------------------ # Get license API access token if ($PSCmdlet.ShouldProcess("License Portal access token", "Refresh")) { - $AccessToken = Update-AlteryxLicenseToken -Token $RefreshToken -Type "Access" - Write-Log -Type "DEBUG" -Message $AccessToken + try { + # Catch issues calling the API + $AccessToken = Update-AlteryxLicenseToken -Token $RefreshToken -Type "Access" + Write-Log -Type "DEBUG" -Message $AccessToken + } catch { + Write-Log -Type "ERROR" -Message (Get-PowerShellError) + Write-Log -Type "ERROR" -Message "Cannot connect to License portal API" + $DownloadProcess = Update-ProcessObject -ProcessObject $DownloadProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $DownloadProcess + } + } # Check current and target versions if ($PSCmdlet.ShouldProcess("Latest release version", "Fetch")) { @@ -141,7 +174,13 @@ function Invoke-DownloadAlteryx { New-Item -Path $DownloadPath -ItemType "Directory" | Out-Null } # Download file - Invoke-WebRequest -Uri $Release.URL -OutFile $DownloadPath + try { + Invoke-WebRequest -Uri $Release.URL -OutFile $DownloadPath -UseBasicParsing + } catch { + Write-Log -Type "ERROR" -Message (Get-PowerShellError) + # Remove failed download file + Remove-Item -Path $DownloadPath -Force + } # Check downloaded file Write-Log -Type "DEBUG" -Message $DownloadPath if (Test-Path -Path $DownloadPath) { From bba19a82e6c0bbe2fd3938cc7122ae02bbf5a175 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 23 Sep 2024 16:39:12 +0200 Subject: [PATCH 50/61] Fix variable names --- powershell/Invoke-RestartAlteryx.ps1 | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/powershell/Invoke-RestartAlteryx.ps1 b/powershell/Invoke-RestartAlteryx.ps1 index 1549a84..ce94a9d 100644 --- a/powershell/Invoke-RestartAlteryx.ps1 +++ b/powershell/Invoke-RestartAlteryx.ps1 @@ -10,7 +10,7 @@ function Invoke-RestartAlteryx { File name: Invoke-RestartAlteryx.ps1 Author: Florian Carrier Creation date: 2021-08-27 - Last modified: 2024-09-11 + Last modified: 2024-09-23 #> [CmdletBinding ()] Param ( @@ -39,17 +39,17 @@ function Invoke-RestartAlteryx { Process { $RestartProcess = Update-ProcessObject -ProcessObject $RestartProcess -Status "Running" Write-Log -Type "NOTICE" -Message "Restarting Alteryx Service" - $StartProcess = Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended - if ($StartProcess.Success) { - $StopProcess = Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended - if ($StopProcess.Success) { + $StopProcess = Invoke-StopAlteryx -Properties $Properties -Unattended:$Unattended + if ($StopProcess.Success) { + $StartProcess = Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended + if ($StartProcess.Success) { Write-Log -Type "CHECK" -Message "Alteryx Service restart process complete" $RestartProcess = Update-ProcessObject -ProcessObject $RestartProcess -Status "Completed" -Success $true } else { - $RestartProcess = Update-ProcessObject -ProcessObject $RestartProcess -Status $StopProcess.Status -ErrorCount $StopProcess.ErrorCount -ExitCode $StopProcess.ExitCode + $RestartProcess = Update-ProcessObject -ProcessObject $RestartProcess -Status $StopProcess.Status -ErrorCount $StartProcess.ErrorCount -ExitCode $StartProcess.ExitCode } } else { - $RestartProcess = Update-ProcessObject -ProcessObject $RestartProcess -Status $StartProcess.Status -ErrorCount $StartProcess.ErrorCount -ExitCode $StartProcess.ExitCode + $RestartProcess = Update-ProcessObject -ProcessObject $RestartProcess -Status $StartProcess.Status -ErrorCount $StopProcess.ErrorCount -ExitCode $StopProcess.ExitCode } } End { From 5cff4ab4b5ae6c14a16dd818333fee4a5a6692f6 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 23 Sep 2024 17:13:27 +0200 Subject: [PATCH 51/61] Fix directory check --- powershell/Invoke-DownloadAlteryx.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powershell/Invoke-DownloadAlteryx.ps1 b/powershell/Invoke-DownloadAlteryx.ps1 index 96afa3d..2a4b34a 100644 --- a/powershell/Invoke-DownloadAlteryx.ps1 +++ b/powershell/Invoke-DownloadAlteryx.ps1 @@ -169,8 +169,8 @@ function Invoke-DownloadAlteryx { } } if ($DownloadEXE -eq $true) { - if (Test-Object -Path $DownloadPath -NotFound) { - Write-Log -Type "INFO" -Message "Creating source directory $DownloadPath" + if (Test-Object -Path $Properties.SrcDirectory -NotFound) { + Write-Log -Type "INFO" -Message "Creating source directory $($Properties.SrcDirectory)" New-Item -Path $DownloadPath -ItemType "Directory" | Out-Null } # Download file From 363e2468d372490c53e240beea6e3d177b547521 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 23 Sep 2024 18:14:13 +0200 Subject: [PATCH 52/61] Fix file search --- powershell/Install-Alteryx.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/powershell/Install-Alteryx.ps1 b/powershell/Install-Alteryx.ps1 index bb15785..39aea77 100644 --- a/powershell/Install-Alteryx.ps1 +++ b/powershell/Install-Alteryx.ps1 @@ -202,7 +202,8 @@ function Install-Alteryx { # Check latest file that matches the major version $Check = [Ordered]@{"Version" = "$MajorVersion.*"} $CheckPattern = Set-Tags -String $AISInstaller -Tags (Resolve-Tags -Tags $Check -Prefix "<" -Suffix ">") - $CheckFile = Get-ChildItem -Path $CheckPattern | Sort-Object -Property "LastWriteTime" -Descending | Select-Object -First 1 + $CheckPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $CheckPattern + $CheckFile = Get-ChildItem -Path $CheckPath | Sort-Object -Property "LastWriteTime" -Descending | Select-Object -First 1 if ($null -ne $CheckFile) { $AISFileName = $CheckFile.Name $AISPath = $CheckFile.FullName From c7088222f9f75e6f116441f97405b16390c32b4d Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 23 Sep 2024 18:17:09 +0200 Subject: [PATCH 53/61] Fetch latest suitable file --- powershell/Invoke-RestoreAlteryx.ps1 | 52 ++++++++++++++++++---------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/powershell/Invoke-RestoreAlteryx.ps1 b/powershell/Invoke-RestoreAlteryx.ps1 index cb7e67b..c023098 100644 --- a/powershell/Invoke-RestoreAlteryx.ps1 +++ b/powershell/Invoke-RestoreAlteryx.ps1 @@ -46,6 +46,7 @@ function Invoke-RestoreAlteryx { # Variables $ServicePath = Join-Path -Path $Properties.InstallationPath -ChildPath "bin\AlteryxService.exe" $Staging = $false + $MajorVersion = [System.String]::Concat([System.Version]::Parse($Properties.Version).Major, ".", [System.Version]::Parse($Properties.Version).Minor) # Restore options $Restore = [Ordered]@{ "Database" = $true @@ -71,8 +72,10 @@ function Invoke-RestoreAlteryx { Process { $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -Status "Running" Write-Log -Type "NOTICE" -Message "Start $RestoreType restore of Alteryx Server" + # ---------------------------------------------------------------------------- + # * Checks + # ---------------------------------------------------------------------------- if ($PSCmdlet.ShouldProcess("Alteryx Service", "Stop")) { - # ---------------------------------------------------------------------------- # Check Alteryx service status Write-Log -Type "INFO" -Message "Check Alteryx Service status" $Service = "AlteryxService" @@ -89,7 +92,6 @@ function Invoke-RestoreAlteryx { return $RestoreProcess } } - # ---------------------------------------------------------------------------- # Check source backup path if ($PSCmdlet.ShouldProcess("Backup files", "Retrieve")) { # Check if custom backup path is specified @@ -127,17 +129,24 @@ function Invoke-RestoreAlteryx { } } Write-Log -Type "DEBUG" -Message $SourcePath - Write-Log -Type "INFO" -Message "Retrieving most recent backup" - $BackupFile = (Get-Object -Path $SourcePath -ChildItem -Type "File" -Filter "*.zip" | Sort-Object -Descending -Property "LastWriteTime" | Select-Object -First 1).FullName + Write-Log -Type "INFO" -Message "Retrieving most recent backup matching major version $MajorVersion" + $Pattern = ".+Alteryx_$($Properties.Product)_$($MajorVersion).+" + $BackupFile = (Get-Object -Path $SourcePath -ChildItem -Type "File" -Filter "*.zip" | Where-Object -Property "Name" -Match $Pattern | Sort-Object -Descending -Property "LastWriteTime" | Select-Object -First 1).FullName Write-Log -Type "DEBUG" -Message $BackupFile + if ($null -ne $BackupFile) { # Ask user confirmation on backup file - if ($Unattended -eq $false) { - $Confirmation = Confirm-Prompt -Prompt "Do you want to restore backup from $BackupFile?" - if ($Confirmation -eq $false) { - Write-Log -Type "WARN" -Message "Restore operation cancelled by user" - $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -Status "Cancelled" - return $RestoreProcess + if ($Unattended -eq $false) { + $Confirmation = Confirm-Prompt -Prompt "Do you want to restore backup from $BackupFile?" + if ($Confirmation -eq $false) { + Write-Log -Type "WARN" -Message "Restore operation cancelled by user" + $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -Status "Cancelled" + return $RestoreProcess + } } + } else { + Write-Log -Type "ERROR" -Message "No suitable database back-up file could be found" + $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + return $RestoreProcess } # Extract archive file Write-Log -Type "INFO" -Message "Extract backup file contents" @@ -146,13 +155,14 @@ function Invoke-RestoreAlteryx { $Staging = $true } } else { - Write-Log -Type "ERROR" -Message "No database backup could be found" + Write-Log -Type "ERROR" -Message "No database back-up file could be found" $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 return $RestoreProcess } } # ---------------------------------------------------------------------------- - # Restore configuration files + # * Restore configuration files + # ---------------------------------------------------------------------------- if ($Restore.Configuration -eq $true) { Write-Log -Type "INFO" -Message "Restore configuration files" # TODO restore extra configuration files @@ -170,7 +180,8 @@ function Invoke-RestoreAlteryx { } } # ---------------------------------------------------------------------------- - # Update configuration + # * Update configuration + # ---------------------------------------------------------------------------- Write-Log -Type "INFO" -Message "Updating configuration" if ($PSCmdlet.ShouldProcess("RunTimeSetting.xml", "Update")) { $RunTimeSettingsXML = New-Object -TypeName "System.XML.XMLDocument" @@ -246,7 +257,8 @@ function Invoke-RestoreAlteryx { } } # ---------------------------------------------------------------------------- - # (Re)Set controller token + # * (Re)Set controller token + # ---------------------------------------------------------------------------- if ($Restore.Token -eq $true) { Write-Log -Type "INFO" -Message "Remove encrypted controller token" if ($PSCmdlet.ShouldProcess("Encrypted controller token", "Remove")) { @@ -287,7 +299,8 @@ function Invoke-RestoreAlteryx { } } # ---------------------------------------------------------------------------- - # Set Run-as user + # * Set Run-as user + # ---------------------------------------------------------------------------- if ($Restore.RunAsUser -eq $true) { if ($PSCmdlet.ShouldProcess("Run-as user credentials", "Restore")) { # TODO @@ -295,7 +308,8 @@ function Invoke-RestoreAlteryx { } } # ---------------------------------------------------------------------------- - # Set SMTP password + # * Set SMTP password + # ---------------------------------------------------------------------------- if ($Restore.SMTPPassword -eq $true) { if ($PSCmdlet.ShouldProcess("SMTP password", "Restore")) { # TODO @@ -303,7 +317,8 @@ function Invoke-RestoreAlteryx { } } # ---------------------------------------------------------------------------- - # Reset storage key + # * Reset storage key + # ---------------------------------------------------------------------------- if ($Restore.Configuration -eq $true) { Write-Log -Type "INFO" -Message "Restore storage key" if ($PSCmdlet.ShouldProcess("Storage Key", "Restore")) { @@ -328,7 +343,8 @@ function Invoke-RestoreAlteryx { } } # ---------------------------------------------------------------------------- - # Restore database + # * Restore database + # ---------------------------------------------------------------------------- if ($Restore.Database -eq $true) { Write-Log -Type "INFO" -Message "Restore MongoDB database from backup" if ($PSCmdlet.ShouldProcess("MongoDB", "Restore")) { From e98b124b714758a12ecd3ea71caf0a2f8b82b06f Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 23 Sep 2024 18:17:34 +0200 Subject: [PATCH 54/61] Formatting --- powershell/Update-Alteryx.ps1 | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/powershell/Update-Alteryx.ps1 b/powershell/Update-Alteryx.ps1 index 454bec1..e0fe3cb 100644 --- a/powershell/Update-Alteryx.ps1 +++ b/powershell/Update-Alteryx.ps1 @@ -10,7 +10,7 @@ function Update-Alteryx { File name: Update-Alteryx.ps1 Author: Florian Carrier Creation date: 2021-09-02 - Last modified: 2024-09-18 + Last modified: 2024-09-23 #> [CmdletBinding ( SupportsShouldProcess = $true @@ -44,7 +44,7 @@ function Update-Alteryx { # Log function call Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name # Process status - $Uninstallprocess = New-ProcessObject -Name $MyInvocation.MyCommand.Name + $UninstallProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # Clear error pipeline $Error.Clear() # Retrieve current version @@ -59,7 +59,7 @@ function Update-Alteryx { $Properties.ActivateOnInstall = $Properties.ActivateOnUpgrade } Process { - $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Running" + $UninstallProcess = Update-ProcessObject -ProcessObject $UninstallProcess -Status "Running" Write-Log -Type "CHECK" -Object "Starting Alteryx Server upgrade from $BackupVersion to $($Properties.Version)" # Check installation path $InstallDirectory = Get-AlteryxInstallDirectory @@ -76,8 +76,8 @@ function Update-Alteryx { $AlteryxService = Get-AlteryxUtility -Utility "Service" -Path $InstallationPath } else { Write-Log -Type "WARN" -Message "Upgrade cancelled by user" - $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Cancelled" - return $Uninstallprocess + $UninstallProcess = Update-ProcessObject -ProcessObject $UninstallProcess -Status "Cancelled" + return $UninstallProcess } } else { # Retrieve Alteryx Service utility path @@ -93,10 +93,10 @@ function Update-Alteryx { $BackupProcess = Invoke-BackupAlteryx -Properties $BackUpProperties -Unattended:$Unattended if ($BackupProcess.Success -eq $false) { if (Confirm-Prompt -Prompt "Do you still want to proceed with the upgrade?") { - $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -ErrorCount 1 + $UninstallProcess = Update-ProcessObject -ProcessObject $UninstallProcess -ErrorCount 1 } else { - $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Cancelled" -ErrorCount 1 - return $Uninstallprocess + $UninstallProcess = Update-ProcessObject -ProcessObject $UninstallProcess -Status "Cancelled" -ErrorCount 1 + return $UninstallProcess } } # ------------------------------------------------------------------------------ @@ -104,8 +104,8 @@ function Update-Alteryx { # ------------------------------------------------------------------------------ $InstallProcess = Install-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended if ($InstallProcess.Success -eq $false) { - $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Failed" -ErrorCount $InstallProcess.ErrorCount -ExitCode 1 - return $Uninstallprocess + $UninstallProcess = Update-ProcessObject -ProcessObject $UninstallProcess -Status "Failed" -ErrorCount $InstallProcess.ErrorCount -ExitCode 1 + return $UninstallProcess } # ------------------------------------------------------------------------------ # * Rollback @@ -117,19 +117,19 @@ function Update-Alteryx { $InstallProcess = Install-Alteryx -Properties $Properties -InstallationProperties $BackUpProperties -Unattended:$Unattended if ($InstallProcess.Success -eq $false) { Write-Log -Type "ERROR" -Message "Rollback process failed" - $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Failed" -ErrorCount $InstallProcess.ErrorCount -ExitCode 1 - return $Uninstallprocess + $UninstallProcess = Update-ProcessObject -ProcessObject $UninstallProcess -Status "Failed" -ErrorCount $InstallProcess.ErrorCount -ExitCode 1 + return $UninstallProcess } else { # Restore backup $RestoreProcess = Invoke-RestoreAlteryx -Properties $BackUpProperties -Unattended:$Unattended if ($RestoreProcess.Success -eq $false) { Write-Log -Type "ERROR" -Message "Rollback process failed" - $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Failed" -ErrorCount $RestoreProcess.ErrorCount -ExitCode 1 - return $Uninstallprocess + $UninstallProcess = Update-ProcessObject -ProcessObject $UninstallProcess -Status "Failed" -ErrorCount $RestoreProcess.ErrorCount -ExitCode 1 + return $UninstallProcess } else { Write-Log -Type "CHECK" -Object "Alteryx Server rollback completed successfully" Write-Log -Type "WARN" -Message "Check the logs to troubleshoot issue with upgrade" - Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Failed" -ExitCode 1 + Update-ProcessObject -ProcessObject $UninstallProcess -Status "Failed" -ExitCode 1 } } } else { @@ -137,6 +137,6 @@ function Update-Alteryx { } } End { - return $Uninstallprocess + return $UninstallProcess } } \ No newline at end of file From 0bab27506dc04652baa62491cd8ed9bb434d6462 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 23 Sep 2024 18:17:55 +0200 Subject: [PATCH 55/61] Add rollback option --- Deploy-Alteryx.ps1 | 114 ++++++++++++++++++++++- powershell/Invoke-RollbackAlteryx.ps1 | 124 ++++++++++++++++++++++++++ powershell/Uninstall-Alteryx.ps1 | 9 +- 3 files changed, 240 insertions(+), 7 deletions(-) create mode 100644 powershell/Invoke-RollbackAlteryx.ps1 diff --git a/Deploy-Alteryx.ps1 b/Deploy-Alteryx.ps1 index 8166226..3ac93b4 100644 --- a/Deploy-Alteryx.ps1 +++ b/Deploy-Alteryx.ps1 @@ -11,21 +11,22 @@ .PARAMETER Action The action parameter corresponds to the operation to perform. - Nineteen options are available: + Multiple options are available: - activate: activate the Alteryx application license - backup: backup the Alteryx application database - configure: configure the Alteryx application - deactivate: deactivate the Alteryx application license - download: download latest Alteryx application release + - help: display the help documentation - install: install the Alteryx application - - repair: repair the Alteryx application database - open: open the Alteryx application - patch: patch upgrade the Alteryx application - ping: check the status of the Alteryx application - repair: repair the Alteryx application database - restart: restart the Alteryx application - restore: restore a backup of the Alteryx application database + - rollback: restore a previous known state of the Alteryx application - setup: set-up the script configuration - show: display the script configuration - start: start the Alteryx application @@ -33,14 +34,116 @@ - uninstall: uninstall the Alteryx application - upgrade: upgrade the Alteryx application + .PARAMETER Version + The optional version parameter enables users to speficy a version at runtime to override the script configuration. + + .PARAMETER BackupPath + The optional back-up path paramater enables users to specify a back-up file location at runtime to override the script configuration. + + .PARAMETER Product + The optional product parameter enabels users to specify the product to manage. It defaults to Server. + + .PARAMETER LicenseKey + The optional license key paramater enables users to specify one or more license keys at runtime to override the script configuration. + .PARAMETER Unattended The unattended switch define if the script should run in silent mode without any user interaction. + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "setup" + + Start the configuration wizard to guide the user through the set-up of the alteryx-deploy script. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "show" + + Display the current script configuration back to the user. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "download" + + Download the latest version of the licensed Alteryx application from the Alteryx license portal. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "install" + + Start the installation process of the Alteryx application and its add-ons if configured. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "upgrade" + + Start the (major) upgrade process of the Alteryx application and its add-ons if configured. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "patch" + + Start the patch process of the Alteryx application. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "uninstall" + + Start the uninstallation process of the Alteryx application and all of its add-ons. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "activate" + + License the Alteryx application by registering the specified license keys through the Alteryx licensing system. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "deactivate" + + Deregister the specified license keys through the Alteryx licensing system. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "backup" + + Start the back-up process of the Alteryx database and all of the configuration files of the application. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "restore" + + Start the restoration process of the Alteryx database and all of the configuration files of the application from a back-up file. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "repair" + + Start the repair process of the Alteryx database. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "rollback" + + Start the rollback process of the Alteryx application back to a previous known state from a back-up file. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "start" + + Start the service powering the Alteryx application. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "stop" + + Stop the service powering the Alteryx application. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "restart" + + Restart the service powering the Alteryx application. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "ping" + + Check the status of the service powering the Alteryx application and the connectivity to the Gallery. + + .EXAMPLE + .\Deploy-Alteryx.ps1 -Action "open" + + Open the user interface of the Alteryx applciation. + .NOTES File name: Deploy-Alteryx.ps1 Author: Florian Carrier Creation date: 2021-06-13 - Last modified: 2024-09-20 + Last modified: 2024-09-23 Dependencies: - PowerShell Tool Kit (PSTK) - Alteryx PowerShell Module (PSAYX) @@ -71,14 +174,15 @@ Param ( "configure", "deactivate", "download", + "help", "install", "open", "patch", "ping", "repair", - "repair", "restart", "restore", + "rollback", "setup", "show", "start", @@ -284,6 +388,7 @@ Process { "configure" { $Process = Set-AlteryxConfiguration -Properties $Properties -Unattended:$Unattended } "deactivate" { $Process = Invoke-DeactivateAlteryx -Properties $Properties -Unattended:$Unattended } "download" { $Process = Invoke-DownloadAlteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } + "help" { $Process = Show-Help } "install" { $Process = Install-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } "repair" { $Process = Repair-Alteryx -Properties $Properties -Unattended:$Unattended } "open" { $Process = Open-Alteryx -Properties $Properties -Unattended:$Unattended } @@ -292,6 +397,7 @@ Process { "repair" { $Process = Repair-Alteryx -Properties $Properties -Unattended:$Unattended } "restart" { $Process = Invoke-RestartAlteryx -Properties $Properties -Unattended:$Unattended } "restore" { $Process = Invoke-RestoreAlteryx -Properties $Properties -Unattended:$Unattended } + "rollback" { $Process = Invoke-RollbackAlteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended } "setup" { $Process = Invoke-SetupScript -Properties $Properties -ScriptProperties $ScriptProperties } "show" { $Process = Show-Configuration -Properties $Properties -InstallationProperties $InstallationProperties } "start" { $Process = Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended } diff --git a/powershell/Invoke-RollbackAlteryx.ps1 b/powershell/Invoke-RollbackAlteryx.ps1 new file mode 100644 index 0000000..40bb84e --- /dev/null +++ b/powershell/Invoke-RollbackAlteryx.ps1 @@ -0,0 +1,124 @@ +function Invoke-RollbackAlteryx { + <# + .SYNOPSIS + Rollback Alteryx + + .DESCRIPTION + Rollback Alteryx Server to a previous (stable) known state + + .NOTES + File name: Invoke-RollbackAlteryx.ps1 + Author: Florian Carrier + Creation date: 2024-09-23 + Last modified: 2024-09-23 + #> + [CmdletBinding ( + SupportsShouldProcess = $true + )] + Param ( + [Parameter ( + Position = 1, + Mandatory = $true, + HelpMessage = "Properties" + )] + [ValidateNotNullOrEmpty ()] + [System.Collections.Specialized.OrderedDictionary] + $Properties, + [Parameter ( + Position = 2, + Mandatory = $true, + HelpMessage = "Installation properties" + )] + [ValidateNotNullOrEmpty ()] + [System.Collections.Specialized.OrderedDictionary] + $InstallationProperties, + [Parameter ( + HelpMessage = "Non-interactive mode" + )] + [Switch] + $Unattended + ) + Begin { + # Get global preference vrariables + Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState + # Log function call + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + # Process status + $RollbackProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name + # Clear error pipeline + $Error.Clear() + # Retrieve current version + Write-Log -Type "DEBUG" -Object "Retrieving current version" + if ($PSCmdlet.ShouldProcess("Alteryx version", "Retrieve")) { + # Check registry for installation path to avoid issues if directory has changed + $AlteryxVersion = Get-AlteryxVersion + Write-Log -Type "DEBUG" -Object $AlteryxVersion + $RollbackVersion = Select-String -InputObject $AlteryxVersion -Pattern "\d+\.\d+.\d+(.\d+)?" | ForEach-Object { $PSItem.Matches.Value } + } + } + Process { + $RollbackProcess = Update-ProcessObject -ProcessObject $RollbackProcess -Status "Running" + Write-Log -Type "CHECK" -Object "Starting Alteryx Server rollback from $RollbackVersion to $($Properties.Version)" + # ------------------------------------------------------------------------------ + # * Checks + # ------------------------------------------------------------------------------ + if ($Unattended -eq $false) { + # Ask for confirmation to uninstall + $ConfirmUninstall = Confirm-Prompt -Prompt "Are you sure that you want to rollback to version $($Properties.Version)?" + if ($ConfirmUninstall -eq $false) { + Write-Log -Type "WARN" -Message "Cancelling rollback" + $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Cancelled" + return $Uninstallprocess + } + } + # ------------------------------------------------------------------------------ + # * Uninstall + # ------------------------------------------------------------------------------ + $UninstallProperties = Copy-OrderedHashtable -Hashtable $Properties -Deep + $UninstallProperties.Version = $RollbackVersion + # Unistall existing Alteryx version + $UninstallProcess = Uninstall-Alteryx -Properties $UninstallProperties -InstallationProperties $InstallationProperties -Unattended:$Unattended + if ($UninstallProcess.Success -eq $false) { + Write-Log -Type "ERROR" -Message "Rollback process failed" + $RollbackProcess = Update-ProcessObject -ProcessObject $RollbackProcess -Status "Failed" -ErrorCount $UninstallProcess.ErrorCount -ExitCode $UninstallProcess.ExitCode + return $RollbackProcess + } + # ------------------------------------------------------------------------------ + # * Reinstall + # ------------------------------------------------------------------------------ + # Reinstall previous Alteryx version + $InstallProcess = Install-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended + if ($InstallProcess.Success -eq $false) { + Write-Log -Type "ERROR" -Message "Rollback process failed" + $RollbackProcess = Update-ProcessObject -ProcessObject $RollbackProcess -Status "Failed" -ErrorCount $InstallProcess.ErrorCount -ExitCode $InstallProcess.ExitCode + return $RollbackProcess + } + # ------------------------------------------------------------------------------ + # * Restore + # ------------------------------------------------------------------------------ + # Restore backup + $RestoreProcess = Invoke-RestoreAlteryx -Properties $Properties -Unattended:$Unattended + if ($RestoreProcess.Success -eq $false) { + Write-Log -Type "ERROR" -Message "Rollback process failed" + $RollbackProcess = Update-ProcessObject -ProcessObject $RollbackProcess -Status "Failed" -ErrorCount $RestoreProcess.ErrorCount -ExitCode 1 + return $RollbackProcess + } else { + Write-Log -Type "CHECK" -Object "Alteryx Server rollback completed successfully" + Write-Log -Type "WARN" -Message "Check the logs to troubleshoot issue with upgrade" + Update-ProcessObject -ProcessObject $RollbackProcess -Status "Failed" -ExitCode 1 + } + # ------------------------------------------------------------------------------ + # * Restart + # ------------------------------------------------------------------------------ + $StartProcess = Invoke-StartAlteryx -Properties $Properties -Unattended:$Unattended + if ($StartProcess.Success) { + Write-Log -Type "CHECK" -Message "Alteryx Service restart process complete" + $RollbackProcess = Update-ProcessObject -ProcessObject $RollbackProcess -Status "Completed" -Success $true + } else { + $RollbackProcess = Update-ProcessObject -ProcessObject $RollbackProcess -Status $StopProcess.Status -ErrorCount $StartProcess.ErrorCount -ExitCode $StartProcess.ExitCode + } + } + End { + return $RollbackProcess + } +} \ No newline at end of file diff --git a/powershell/Uninstall-Alteryx.ps1 b/powershell/Uninstall-Alteryx.ps1 index dd5b530..bdca7f0 100644 --- a/powershell/Uninstall-Alteryx.ps1 +++ b/powershell/Uninstall-Alteryx.ps1 @@ -16,7 +16,7 @@ function Uninstall-Alteryx { File name: Uninstall-Alteryx.ps1 Author: Florian Carrier Creation date: 2021-07-08 - Last modified: 2024-09-18 + Last modified: 2024-09-23 .LINK https://www.powershellgallery.com/packages/PSAYX @@ -69,11 +69,14 @@ function Uninstall-Alteryx { $ServerInstaller = "AlteryxInstallx64_.exe" } else { $ServerInstaller = "AlteryxServerInstallx64_.exe" - } + } } Process { $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Running" Write-Log -Type "INFO" -Message "Uninstallation of Alteryx Server $($Properties.Version)" + # ------------------------------------------------------------------------------ + # * Checks + # ------------------------------------------------------------------------------ if ($Unattended -eq $false) { # Ask for confirmation to uninstall $ConfirmUninstall = Confirm-Prompt -Prompt "Are you sure that you want to uninstall $($Properties.Product)?" @@ -82,6 +85,7 @@ function Uninstall-Alteryx { $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Cancelled" return $Uninstallprocess } else { + # TODO check if Alteryx is installed # Suggest backup $Backup = Confirm-Prompt -Prompt "Do you want to take a back-up of the database?" if ($Backup) { @@ -109,7 +113,6 @@ function Uninstall-Alteryx { # ------------------------------------------------------------------------------ # * Uninstall Alteryx Server # ------------------------------------------------------------------------------ - # TODO check if Alteryx is installed # Update file version number $ServerFileName = Set-Tags -String $ServerInstaller -Tags (Resolve-Tags -Tags $Tags -Prefix "<" -Suffix ">") $ServerPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $ServerFileName From 5889179299ac429552100c44636663735cceb315 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 23 Sep 2024 18:29:10 +0200 Subject: [PATCH 56/61] Add checks --- powershell/Invoke-RollbackAlteryx.ps1 | 15 ++++++ powershell/Update-Alteryx.ps1 | 71 ++++++++++++++------------- 2 files changed, 52 insertions(+), 34 deletions(-) diff --git a/powershell/Invoke-RollbackAlteryx.ps1 b/powershell/Invoke-RollbackAlteryx.ps1 index 40bb84e..4d9101f 100644 --- a/powershell/Invoke-RollbackAlteryx.ps1 +++ b/powershell/Invoke-RollbackAlteryx.ps1 @@ -117,6 +117,21 @@ function Invoke-RollbackAlteryx { } else { $RollbackProcess = Update-ProcessObject -ProcessObject $RollbackProcess -Status $StopProcess.Status -ErrorCount $StartProcess.ErrorCount -ExitCode $StartProcess.ExitCode } + # ------------------------------------------------------------------------------ + # * Checks + # ------------------------------------------------------------------------------ + if ($RollbackProcess.ErrorCount -eq 0) { + Write-Log -Type "CHECK" -Message "Alteryx $($Properties.Product) $($Properties.Version) installed successfully" + $RollbackProcess = Update-ProcessObject -ProcessObject $RollbackProcess -Status "Completed" -Success $true + } else { + if ($RollbackProcess.ErrorCount -eq 1) { + $ErrorCount = "one error" + } else { + $ErrorCount = "$($RollbackProcess.ErrorCount) errors" + } + Write-Log -Type "WARN" -Message "Alteryx $($Properties.Product) $($Properties.Version) was rolled back with $ErrorCount" + $RollbackProcess = Update-ProcessObject -ProcessObject $RollbackProcess -Status "Completed" + } } End { return $RollbackProcess diff --git a/powershell/Update-Alteryx.ps1 b/powershell/Update-Alteryx.ps1 index e0fe3cb..33413c0 100644 --- a/powershell/Update-Alteryx.ps1 +++ b/powershell/Update-Alteryx.ps1 @@ -44,7 +44,7 @@ function Update-Alteryx { # Log function call Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name # Process status - $UninstallProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name + $UpgradeProcess = New-ProcessObject -Name $MyInvocation.MyCommand.Name # Clear error pipeline $Error.Clear() # Retrieve current version @@ -59,7 +59,7 @@ function Update-Alteryx { $Properties.ActivateOnInstall = $Properties.ActivateOnUpgrade } Process { - $UninstallProcess = Update-ProcessObject -ProcessObject $UninstallProcess -Status "Running" + $UpgradeProcess = Update-ProcessObject -ProcessObject $UpgradeProcess -Status "Running" Write-Log -Type "CHECK" -Object "Starting Alteryx Server upgrade from $BackupVersion to $($Properties.Version)" # Check installation path $InstallDirectory = Get-AlteryxInstallDirectory @@ -76,8 +76,8 @@ function Update-Alteryx { $AlteryxService = Get-AlteryxUtility -Utility "Service" -Path $InstallationPath } else { Write-Log -Type "WARN" -Message "Upgrade cancelled by user" - $UninstallProcess = Update-ProcessObject -ProcessObject $UninstallProcess -Status "Cancelled" - return $UninstallProcess + $UpgradeProcess = Update-ProcessObject -ProcessObject $UpgradeProcess -Status "Cancelled" + return $UpgradeProcess } } else { # Retrieve Alteryx Service utility path @@ -93,50 +93,53 @@ function Update-Alteryx { $BackupProcess = Invoke-BackupAlteryx -Properties $BackUpProperties -Unattended:$Unattended if ($BackupProcess.Success -eq $false) { if (Confirm-Prompt -Prompt "Do you still want to proceed with the upgrade?") { - $UninstallProcess = Update-ProcessObject -ProcessObject $UninstallProcess -ErrorCount 1 + $UpgradeProcess = Update-ProcessObject -ProcessObject $UpgradeProcess -ErrorCount $BackupProcess.ErrorCount } else { - $UninstallProcess = Update-ProcessObject -ProcessObject $UninstallProcess -Status "Cancelled" -ErrorCount 1 - return $UninstallProcess + $UpgradeProcess = Update-ProcessObject -ProcessObject $UpgradeProcess -Status "Cancelled" -ErrorCount $BackupProcess.ErrorCount + return $UpgradeProcess } } # ------------------------------------------------------------------------------ # * Upgrade # ------------------------------------------------------------------------------ $InstallProcess = Install-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended - if ($InstallProcess.Success -eq $false) { - $UninstallProcess = Update-ProcessObject -ProcessObject $UninstallProcess -Status "Failed" -ErrorCount $InstallProcess.ErrorCount -ExitCode 1 - return $UninstallProcess + if ($InstallProcess.Success -eq $true) { + Write-Log -Type "CHECK" -Object "Alteryx Server upgrade completed successfully" + } else { + Write-Log -Type "ERROR" -Object "Upgrade process failed" + $UpgradeProcess = Update-ProcessObject -ProcessObject $UpgradeProcess -Status "Failed" -ErrorCount $InstallProcess.ErrorCount -ExitCode $InstallProcess.ExitCode + # ------------------------------------------------------------------------------ + # * Rollback + # ------------------------------------------------------------------------------ + $RollbackProcess = Invoke-RollbackAlteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended + if ($RollbackProcess.Success -eq $false) { + Write-Log -Type "ERROR" -Message "Rollback process failed" + $UpgradeProcess = Update-ProcessObject -ProcessObject $UpgradeProcess -Status "Failed" -ErrorCount $RollbackProcess.ErrorCount -ExitCode $RollbackProcess.ExitCode + return $UpgradeProcess + } } # ------------------------------------------------------------------------------ - # * Rollback + # * Checks # ------------------------------------------------------------------------------ - if ($Error.Count -gt 0) { - Write-Log -Type "ERROR" -Object "Upgrade process failed with $($Error.Count) errors" - Write-Log -Type "WARN" -Object "Restoring previous version ($BackupVersion)" - # Reinstall previous Alteryx version - $InstallProcess = Install-Alteryx -Properties $Properties -InstallationProperties $BackUpProperties -Unattended:$Unattended - if ($InstallProcess.Success -eq $false) { - Write-Log -Type "ERROR" -Message "Rollback process failed" - $UninstallProcess = Update-ProcessObject -ProcessObject $UninstallProcess -Status "Failed" -ErrorCount $InstallProcess.ErrorCount -ExitCode 1 - return $UninstallProcess + if ($UpgradeProcess.ErrorCount -eq 0) { + Write-Log -Type "CHECK" -Message "Alteryx $($Properties.Product) $($Properties.Version) upgraded successfully" + $UpgradeProcess = Update-ProcessObject -ProcessObject $UpgradeProcess -Status "Completed" -Success $true + } else { + if ($UpgradeProcess.ErrorCount -eq 1) { + $ErrorCount = "one error" } else { - # Restore backup - $RestoreProcess = Invoke-RestoreAlteryx -Properties $BackUpProperties -Unattended:$Unattended - if ($RestoreProcess.Success -eq $false) { - Write-Log -Type "ERROR" -Message "Rollback process failed" - $UninstallProcess = Update-ProcessObject -ProcessObject $UninstallProcess -Status "Failed" -ErrorCount $RestoreProcess.ErrorCount -ExitCode 1 - return $UninstallProcess - } else { - Write-Log -Type "CHECK" -Object "Alteryx Server rollback completed successfully" - Write-Log -Type "WARN" -Message "Check the logs to troubleshoot issue with upgrade" - Update-ProcessObject -ProcessObject $UninstallProcess -Status "Failed" -ExitCode 1 - } + $ErrorCount = "$($UpgradeProcess.ErrorCount) errors" + } + if ($null -eq $RollbackProcess) { + Write-Log -Type "WARN" -Message "Alteryx $($Properties.Product) $($Properties.Version) was upgraded with $ErrorCount" + $UpgradeProcess = Update-ProcessObject -ProcessObject $UpgradeProcess -Status "Completed" + } else { + Write-Log -Type "WARN" -Message "Alteryx $($Properties.Product) $($Properties.Version) upgraded process failed with $ErrorCount" + $UpgradeProcess = Update-ProcessObject -ProcessObject $UpgradeProcess -Status "Failed" -ExitCode 1 } - } else { - Write-Log -Type "CHECK" -Object "Alteryx Server upgrade completed successfully" } } End { - return $UninstallProcess + return $UpgradeProcess } } \ No newline at end of file From a01795e8ebbebacd2f069dfaead525eaa160cfba Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Tue, 24 Sep 2024 13:42:59 +0200 Subject: [PATCH 57/61] Change message type --- powershell/Invoke-RollbackAlteryx.ps1 | 2 +- powershell/Uninstall-Alteryx.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/powershell/Invoke-RollbackAlteryx.ps1 b/powershell/Invoke-RollbackAlteryx.ps1 index 4d9101f..676daba 100644 --- a/powershell/Invoke-RollbackAlteryx.ps1 +++ b/powershell/Invoke-RollbackAlteryx.ps1 @@ -58,7 +58,7 @@ function Invoke-RollbackAlteryx { } Process { $RollbackProcess = Update-ProcessObject -ProcessObject $RollbackProcess -Status "Running" - Write-Log -Type "CHECK" -Object "Starting Alteryx Server rollback from $RollbackVersion to $($Properties.Version)" + Write-Log -Type "NOTICE" -Object "Starting Alteryx Server rollback from $RollbackVersion to $($Properties.Version)" # ------------------------------------------------------------------------------ # * Checks # ------------------------------------------------------------------------------ diff --git a/powershell/Uninstall-Alteryx.ps1 b/powershell/Uninstall-Alteryx.ps1 index bdca7f0..5da175b 100644 --- a/powershell/Uninstall-Alteryx.ps1 +++ b/powershell/Uninstall-Alteryx.ps1 @@ -73,7 +73,7 @@ function Uninstall-Alteryx { } Process { $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -Status "Running" - Write-Log -Type "INFO" -Message "Uninstallation of Alteryx Server $($Properties.Version)" + Write-Log -Type "NOTICE" -Message "Uninstallation of Alteryx Server $($Properties.Version)" # ------------------------------------------------------------------------------ # * Checks # ------------------------------------------------------------------------------ From a8308ccea0712cce7dfddc29b3c206a31b9dc29a Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Tue, 24 Sep 2024 14:58:05 +0200 Subject: [PATCH 58/61] Fix back-up issue --- powershell/Uninstall-Alteryx.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powershell/Uninstall-Alteryx.ps1 b/powershell/Uninstall-Alteryx.ps1 index 5da175b..8d4879b 100644 --- a/powershell/Uninstall-Alteryx.ps1 +++ b/powershell/Uninstall-Alteryx.ps1 @@ -16,7 +16,7 @@ function Uninstall-Alteryx { File name: Uninstall-Alteryx.ps1 Author: Florian Carrier Creation date: 2021-07-08 - Last modified: 2024-09-23 + Last modified: 2024-09-24 .LINK https://www.powershellgallery.com/packages/PSAYX @@ -89,7 +89,7 @@ function Uninstall-Alteryx { # Suggest backup $Backup = Confirm-Prompt -Prompt "Do you want to take a back-up of the database?" if ($Backup) { - $BackupProcess = Invoke-BackupAlteryx -Properties $BackUpProperties -Unattended:$Unattended + $BackupProcess = Invoke-BackupAlteryx -Properties $Properties -Unattended:$Unattended if ($BackupProcess.Success -eq $false) { if (Confirm-Prompt -Prompt "Do you still want to proceed with the uninstallation?") { $Uninstallprocess = Update-ProcessObject -ProcessObject $Uninstallprocess -ErrorCount 1 From 47637aa4a7523b582bd8e8bc273980972ec9599f Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Mon, 7 Oct 2024 15:42:14 +0200 Subject: [PATCH 59/61] Fix backup file path --- powershell/Invoke-RestoreAlteryx.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powershell/Invoke-RestoreAlteryx.ps1 b/powershell/Invoke-RestoreAlteryx.ps1 index c023098..6343f88 100644 --- a/powershell/Invoke-RestoreAlteryx.ps1 +++ b/powershell/Invoke-RestoreAlteryx.ps1 @@ -136,7 +136,7 @@ function Invoke-RestoreAlteryx { if ($null -ne $BackupFile) { # Ask user confirmation on backup file if ($Unattended -eq $false) { - $Confirmation = Confirm-Prompt -Prompt "Do you want to restore backup from $BackupFile?" + $Confirmation = Confirm-Prompt -Prompt "Do you want to restore backup from $($BackupFile.FileName)?" if ($Confirmation -eq $false) { Write-Log -Type "WARN" -Message "Restore operation cancelled by user" $RestoreProcess = Update-ProcessObject -ProcessObject $RestoreProcess -Status "Cancelled" From 6028a9962828e0c221b91d905f5d76035570fefa Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Tue, 8 Oct 2024 13:26:05 +0200 Subject: [PATCH 60/61] Add sensitive data encryption Encrypt keys and tokens as well as support for downloading Intelligence Suite --- .gitignore | 1 + CHANGELOG.md | 31 ++++- README.md | 6 +- conf/default.ini | 2 +- powershell/Invoke-ActivateAlteryx.ps1 | 4 +- powershell/Invoke-DeactivateAlteryx.ps1 | 4 +- powershell/Invoke-DownloadAlteryx.ps1 | 168 +++++++++++------------- powershell/Invoke-RollbackAlteryx.ps1 | 8 +- powershell/Invoke-SetupScript.ps1 | 45 ++++--- 9 files changed, 148 insertions(+), 121 deletions(-) diff --git a/.gitignore b/.gitignore index 7e20868..970e6b8 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ tmp custom.ini *.token *.key +res/* \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ce2a7d4..f0ccad7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,39 @@ # Changelog -All notable changes to the [Alteryx deploy](https://github.com/Akaizoku/alteryx-deploy) project will be documented in this file. +All notable changes to the [`alteryx-deploy`](https://github.com/Akaizoku/alteryx-deploy) utility will be documented in this file. Roadmap and backlog are documented in the corresponding [GitHub project](https://github.com/users/Akaizoku/projects/4). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.0](https://github.com/Akaizoku/alteryx-deploy/releases/2.0.0) - 2024-10-08 + +Complete revamp to provide support for new installers (2022.3+), license portal API, as well as guardrails and usefull error handling. + +### Added + +- Invoke-DownloadAlteryx: Fetch releases from the Alteryx license portal +- Invoke-PatchAlteryx: Install patch upgrades +- Invoke-PingAlteryx: Check Server UI (Gallery) connectivity +- Invoke-RollbackAlteryx: Rollback to previous known stable state +- Invoke-SetupScript: Script configuration wizard +- Open-Alteryx: Open Alteryx (G)UI +- Repair-Alteryx: Repair embedded MongoDB database +- Set-AlteryxConfiguration: Configure Alteryx system settings +- Show-Help: Display script help documentation + +### Changed + +- Invoke-ActivateAlteryx: Improve process robustness +- Invoke-BackupAlteryx: Improve process robustness +- Invoke-DeactivateAlteryx: Deactivate licenses one-by-one +- Invoke-RestartAlteryx: Improve process robustness +- Invoke-RestoreAlteryx: Redesign process to improve robustness +- Invoke-StartAlteryx: Improve process robustness +- Invoke-StopAlteryx: Improve process robustness +- Uninstall-Alteryx: Improve process robustness +- Update-Alteryx: Add rollback in case of failure +- Various changes were made to configuration files, including encryption of sensitive information; Please use the `setup` command to configure the scripts. + ## [1.1.2](https://github.com/Akaizoku/alteryx-deploy/releases/1.1.2) - 2021-12-13 UX improvements diff --git a/README.md b/README.md index 74a516e..1050af3 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ -# Alteryx Deploy +# alteryx-deploy [![PSScriptAnalyzer](https://github.com/Akaizoku/alteryx-deploy/actions/workflows/scan.yml/badge.svg?branch=main)](https://github.com/Akaizoku/alteryx-deploy/actions/workflows/scan.yml) -```asci + `alteryx-deploy` is a small PowerShell utility for the automation of the deployment and maintenance of Alteryx. diff --git a/conf/default.ini b/conf/default.ini index ae93573..1a90c19 100644 --- a/conf/default.ini +++ b/conf/default.ini @@ -33,7 +33,7 @@ LicenseFile = license.key # License API refresh token file LicenseAPIFile = license.token # Server admin API key & secret -ServerAdminAPI = server.token +ServerAdminAPI = server.key [Misc.] # Installation language diff --git a/powershell/Invoke-ActivateAlteryx.ps1 b/powershell/Invoke-ActivateAlteryx.ps1 index 70d42c3..66bf3fa 100644 --- a/powershell/Invoke-ActivateAlteryx.ps1 +++ b/powershell/Invoke-ActivateAlteryx.ps1 @@ -16,7 +16,7 @@ function Invoke-ActivateAlteryx { File name: Invoke-ActivateAlteryx.ps1 Author: Florian Carrier Creation date: 2021-07-05 - Last modified: 2024-09-18 + Last modified: 2024-10-08 .LINK https://www.powershellgallery.com/packages/PSAYX @@ -79,7 +79,7 @@ function Invoke-ActivateAlteryx { $ActivateProcess = Update-ProcessObject -ProcessObject $ActivateProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 return $ActivateProcess } - $Properties.LicenseKey = @(Get-Content -Path $LicenseFilePath) + $Properties.LicenseKey = (ConvertFrom-SecureString -SecureString (ConvertTo-SecureString -String (Get-Content -Path $LicenseFilePath)) -AsPlainText) -split '[ ,]+' } Write-Log -Type "DEBUG" -Message $Properties.LicenseKey # Count keys diff --git a/powershell/Invoke-DeactivateAlteryx.ps1 b/powershell/Invoke-DeactivateAlteryx.ps1 index 44231ae..79fc2ea 100644 --- a/powershell/Invoke-DeactivateAlteryx.ps1 +++ b/powershell/Invoke-DeactivateAlteryx.ps1 @@ -16,7 +16,7 @@ function Invoke-DeactivateAlteryx { File name: Invoke-DeactivateAlteryx.ps1 Author: Florian Carrier Creation date: 2021-11-20 - Last modified: 2024-09-18 + Last modified: 2024-10-08 .LINK https://www.powershellgallery.com/packages/PSAYX @@ -106,7 +106,7 @@ function Invoke-DeactivateAlteryx { $DeactivateProcess = Update-ProcessObject -ProcessObject $DeactivateProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 return $DeactivateProcess } else { - $Properties.LicenseKey = @(Get-Content -Path $LicenseFilePath) + $Properties.LicenseKey = (ConvertFrom-SecureString -SecureString (ConvertTo-SecureString -String (Get-Content -Path $LicenseFilePath)) -AsPlainText) -split '[ ,]+' } } Write-Log -Type "DEBUG" -Message $Properties.LicenseKey diff --git a/powershell/Invoke-DownloadAlteryx.ps1 b/powershell/Invoke-DownloadAlteryx.ps1 index 2a4b34a..dd8a6fa 100644 --- a/powershell/Invoke-DownloadAlteryx.ps1 +++ b/powershell/Invoke-DownloadAlteryx.ps1 @@ -10,7 +10,7 @@ function Invoke-DownloadAlteryx { File name: Invoke-DownloadAlteryx.ps1 Author: Florian Carrier Creation date: 2024-09-04 - Last modified: 2024-09-23 + Last modified: 2024-10-08 #> [CmdletBinding ( SupportsShouldProcess = $true @@ -55,7 +55,7 @@ function Invoke-DownloadAlteryx { $RegistryKey = "HKLM:HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\SRC\Alteryx" # License API refresh token $LicenseAPIPath = Join-Path -Path $Properties.ResDirectory -ChildPath $Properties.LicenseAPIFile - $RefreshToken = (Get-Content -Path $LicenseAPIPath -Raw) -replace "`r|`n", "" + $RefreshToken = (ConvertFrom-SecureString -SecureString (ConvertTo-SecureString -String (Get-Content -Path $LicenseAPIPath)) -AsPlainText) -replace "`r|`n", "" # Placeholder $Skip = $false } @@ -75,10 +75,10 @@ function Invoke-DownloadAlteryx { return $DownloadProcess } } - if ($null -eq $Properties.AccountID) { + if ($null -eq $Properties.LicenseAccountID) { Write-Log -Type "ERROR" -Message "The AccountID parameter has not been configured" if (-Not $Unattended) { - $Properties.AccountID = Read-Host -Prompt "What is the ID of your account in the Alteryx license portal?" + $Properties.LicenseAccountID = Read-Host -Prompt "What is the ID of your account in the Alteryx license portal?" } else { Write-Log -Type "ERROR" -Message "Download process cannot proceed" $DownloadProcess = Update-ProcessObject -ProcessObject $DownloadProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 @@ -140,99 +140,81 @@ function Invoke-DownloadAlteryx { # ------------------------------------------------------------------------------ # Check if download should proceed if ($Skip -eq $false) { - # TODO improve and loop through installation properties - if ($PSCmdlet.ShouldProcess("Patch installer", "Check")) { - # Check upgrade step - if (Compare-Version -Version $TargetVersion -Operator "ne" -Reference $MajorVersion) { - # If major upgrade, download installer - Write-Log -Type "INFO" -Message "Downloading $($Release.Product) version $($Release.Version)" - } else { - # If minor or patch upgrade, download patch - Write-Log -Type "INFO" -Message "Downloading $($Release.Product) patch version $($Release.Version)" - $Release = Get-AlteryxLatestRelease -AccountID $Properties.LicenseAccountID -Token $AccessToken -ProductID $ProductID -Version $TargetVersion -Patch - } + $Products = [Ordered]@{ + "Server" = $ProductID + # "PredictiveTools" = "Predictive Tools" # Included within Server + "IntelligenceSuite" = "Alteryx Intelligence Suite" + # "DataPackages" = "Data Packages" # } - # ------------------------------------------------------------------------------ - # * Server/Designer - # ------------------------------------------------------------------------------ - if ($PSCmdlet.ShouldProcess($ProductID, "Download")) { - $DownloadEXE = $true - $DownloadPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $Release.FileName - # Check if file already exists - if (Test-Path -Path $DownloadPath) { - Write-Log -Type "WARN" -Message "$ProductID installation file already exist in source directory" - Write-Log -Type "DEBUG" -Message $DownloadPath - if ($Unattended -eq $false) { - $DownloadEXE = Confirm-Prompt "Do you want to redownload and overwrite the existing file?" - } else { - $DownloadEXE = $false - } - } - if ($DownloadEXE -eq $true) { - if (Test-Object -Path $Properties.SrcDirectory -NotFound) { - Write-Log -Type "INFO" -Message "Creating source directory $($Properties.SrcDirectory)" - New-Item -Path $DownloadPath -ItemType "Directory" | Out-Null - } - # Download file - try { - Invoke-WebRequest -Uri $Release.URL -OutFile $DownloadPath -UseBasicParsing - } catch { - Write-Log -Type "ERROR" -Message (Get-PowerShellError) - # Remove failed download file - Remove-Item -Path $DownloadPath -Force - } - # Check downloaded file - Write-Log -Type "DEBUG" -Message $DownloadPath - if (Test-Path -Path $DownloadPath) { - Write-Log -Type "CHECK" -Message "$ProductID download completed successfully" - } else { - Write-Log -Type "ERROR" -Message "Download failed" - $DownloadProcess = Update-ProcessObject -ProcessObject $DownloadProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 - } - } else { - Write-Log -Type "WARN" -Message "Skipping download of $ProductID version $($Release.Version)" - } - } - # ------------------------------------------------------------------------------ - # * Predictive Tools - # ------------------------------------------------------------------------------ - # Check if download should proceed - if ($InstallationProperties.PredictiveTools -eq $true) { - if ($PSCmdlet.ShouldProcess("Predictive Tools", "Download")) { - $DownloadR = $true - if ($Properties.Product -eq "Server") { - Write-Log -Type "INFO" -Message "Predictive Tools installer is packaged within the main installation file" - if ($Unattended -eq $false) { - $DownloadR = Confirm-Prompt -Prompt "Do you still want to download Predictive Tools separately?" + foreach ($Product in $Products.GetEnumerator()) { + if ($InstallationProperties.$($Product.Key) -eq $true) { + $ProductID = $Product.Value + if ($PSCmdlet.ShouldProcess($ProductID, "Download")) { + $DownloadEXE = $true + $FormattedVersion = "version" + if ($ProductID -in ("Alteryx Server", "Alteryx Designer")) { + # Check upgrade step + if (Compare-Version -Version $TargetVersion -Operator "eq" -Reference $MajorVersion) { + # If minor or patch upgrade, download patch + $Release = Get-AlteryxLatestRelease -AccountID $Properties.LicenseAccountID -Token $AccessToken -ProductID $ProductID -Version $TargetVersion -Patch + $FormattedVersion = "patch version" + } } else { - $DownloadR = $false + # Fetch latest release for add-ons + $Release = Get-AlteryxLatestRelease -AccountID $Properties.LicenseAccountID -Token $AccessToken -ProductID $ProductID -Version $TargetVersion + if ($null -eq $Release) { + $DownloadEXE = $false + } + } + $DownloadPath = Join-Path -Path $Properties.SrcDirectory -ChildPath $Release.FileName + # Check if file already exists + if (Test-Path -Path $DownloadPath) { + Write-Log -Type "WARN" -Message "$ProductID installation file already exist in source directory" + Write-Log -Type "DEBUG" -Message $DownloadPath + if ($Unattended -eq $false) { + $DownloadEXE = Confirm-Prompt "Do you want to redownload and overwrite the existing file?" + } else { + $DownloadEXE = $false + } + } + # Additional check for R + if ($ProductID -eq "Predictive Tools") { + if ($Properties.Product -eq "Server") { + Write-Log -Type "INFO" -Message "$ProductID installer is packaged within Server installation file" + } else { + Write-Log -Type "WARN" -Message "$ProductID download is not yet supported" + $DownloadEXE = $false + } + } + # Download process + if ($DownloadEXE -eq $true) { + Write-Log -Type "INFO" -Message "Downloading $($Release.Product) $FormattedVersion $($Release.Version)" + if (Test-Object -Path $Properties.SrcDirectory -NotFound) { + Write-Log -Type "INFO" -Message "Creating source directory $($Properties.SrcDirectory)" + New-Item -Path $DownloadPath -ItemType "Directory" | Out-Null + } + # Download file + try { + Invoke-WebRequest -Uri $Release.URL -OutFile $DownloadPath -UseBasicParsing + } catch { + Write-Log -Type "ERROR" -Message (Get-PowerShellError) + # Remove failed download file + Remove-Item -Path $DownloadPath -Force + } + # Check downloaded file + Write-Log -Type "DEBUG" -Message $DownloadPath + if (Test-Path -Path $DownloadPath) { + Write-Log -Type "CHECK" -Message "$ProductID download completed successfully" + } else { + Write-Log -Type "ERROR" -Message "Download failed" + $DownloadProcess = Update-ProcessObject -ProcessObject $DownloadProcess -Status "Failed" -ErrorCount 1 -ExitCode 1 + } + } else { + Write-Log -Type "WARN" -Message "Skipping download of $ProductID version $($Release.Version)" } } - if ($DownloadR = $true) { - # TODO download RInstaller - } - } - } - # ------------------------------------------------------------------------------ - # * Intelligence Suite - # ------------------------------------------------------------------------------ - if ($InstallationProperties.IntelligenceSuite -eq $true) { - if ($PSCmdlet.ShouldProcess("Intelligence Suite", "Download")) { - $DownloadIS = $true - if ($Unattended -eq $false) { - $DownloadIS = Confirm-Prompt -Prompt "Do you want to download Intelligence Suite?" - } - if ($DownloadIS -eq $true) { - # TODO download IS - } - } - } - # ------------------------------------------------------------------------------ - # * Data packages - # ------------------------------------------------------------------------------ - if ($InstallationProperties.DataPackages -eq $true) { - if ($PSCmdlet.ShouldProcess("Data Packages", "Download")) { - # TODO download data packages + } else { + Write-Log -Type "WARN" -Message "Skipping $ProductID by configuration" } } } else { diff --git a/powershell/Invoke-RollbackAlteryx.ps1 b/powershell/Invoke-RollbackAlteryx.ps1 index 676daba..8c1bb1e 100644 --- a/powershell/Invoke-RollbackAlteryx.ps1 +++ b/powershell/Invoke-RollbackAlteryx.ps1 @@ -74,13 +74,15 @@ function Invoke-RollbackAlteryx { # ------------------------------------------------------------------------------ # * Uninstall # ------------------------------------------------------------------------------ + # + # TODO back error $UninstallProperties = Copy-OrderedHashtable -Hashtable $Properties -Deep $UninstallProperties.Version = $RollbackVersion # Unistall existing Alteryx version $UninstallProcess = Uninstall-Alteryx -Properties $UninstallProperties -InstallationProperties $InstallationProperties -Unattended:$Unattended if ($UninstallProcess.Success -eq $false) { Write-Log -Type "ERROR" -Message "Rollback process failed" - $RollbackProcess = Update-ProcessObject -ProcessObject $RollbackProcess -Status "Failed" -ErrorCount $UninstallProcess.ErrorCount -ExitCode $UninstallProcess.ExitCode + $RollbackProcess = Update-ProcessObject -ProcessObject $RollbackProcess -Status "Failed" -ErrorCount $UninstallProcess.ErrorCount -ExitCode 1 return $RollbackProcess } # ------------------------------------------------------------------------------ @@ -88,9 +90,9 @@ function Invoke-RollbackAlteryx { # ------------------------------------------------------------------------------ # Reinstall previous Alteryx version $InstallProcess = Install-Alteryx -Properties $Properties -InstallationProperties $InstallationProperties -Unattended:$Unattended - if ($InstallProcess.Success -eq $false) { + if ($InstallProcess.Success -eq $false -And $InstallProcess.ExitCode -eq 1) { Write-Log -Type "ERROR" -Message "Rollback process failed" - $RollbackProcess = Update-ProcessObject -ProcessObject $RollbackProcess -Status "Failed" -ErrorCount $InstallProcess.ErrorCount -ExitCode $InstallProcess.ExitCode + $RollbackProcess = Update-ProcessObject -ProcessObject $RollbackProcess -Status "Failed" -ErrorCount $InstallProcess.ErrorCount -ExitCode 1 return $RollbackProcess } # ------------------------------------------------------------------------------ diff --git a/powershell/Invoke-SetupScript.ps1 b/powershell/Invoke-SetupScript.ps1 index cf157ca..c8024a2 100644 --- a/powershell/Invoke-SetupScript.ps1 +++ b/powershell/Invoke-SetupScript.ps1 @@ -10,7 +10,7 @@ function Invoke-SetupScript { File name: Invoke-SetupScript.ps1 Author: Florian Carrier Creation date: 2022-05-03 - Last modified: 2024-09-23 + Last modified: 2024-10-08 #> [CmdletBinding ( SupportsShouldProcess = $true @@ -129,18 +129,25 @@ function Invoke-SetupScript { $LicenseAPIPrompt = "License Portal API refresh token" $ConfigureLicenseAPI = $true if (Test-Path -Path $LicenseAPIPath) { - $RefreshAPIToken = Get-Content -Path $LicenseAPIPath - if ($RefreshAPIToken -notin ($null, "")) { - Write-Log -Type "WARN" -Message "License Portal API refresh token has already been configured" - Write-Log -Type "DEBUG" -Message $RefreshAPIToken - $ConfigureLicenseAPI = Confirm-Prompt -Prompt "Do you want to reconfigure the License Portal API refresh token?" + try { + $RefreshAPIToken = ConvertFrom-SecureString -SecureString (ConvertTo-SecureString -String (Get-Content -Path $LicenseAPIPath)) -AsPlainText + if ($RefreshAPIToken -notin ($null, "")) { + Write-Log -Type "WARN" -Message "License Portal API refresh token has already been configured" + Write-Log -Type "DEBUG" -Message $RefreshAPIToken + $ConfigureLicenseAPI = Confirm-Prompt -Prompt "Do you want to reconfigure the License Portal API refresh token?" + } + } + catch { + Write-Log -Type "DEBUG" -Message (Get-PowerShellError) + Write-Log -Type "WARN" -Message "Failed to read current License Portal API token" } } if ($ConfigureLicenseAPI) { - $LicenseAPIToken = (Read-Host -Prompt $LicenseAPIPrompt).Trim() - Write-Log -Type "DEBUG" -Message $LicenseAPIToken + $LicenseAPIToken = (Read-Host -Prompt $LicenseAPIPrompt).Trim() + $EncryptedLicenseAPIToken = ConvertFrom-SecureString -SecureString (ConvertTo-SecureString -String $LicenseAPIToken.ToString() -AsPlainText -Force) + # Write-Log -Type "DEBUG" -Message $EncryptedLicenseAPIToken Write-Log -Type "DEBUG" -Message $LicenseAPIPath - Set-Content -Path $LicenseAPIPath -Value $LicenseAPIToken -NoNewline -Force + Set-Content -Path $LicenseAPIPath -Value $EncryptedLicenseAPIToken -NoNewline -Force if (Test-Path -Path $LicenseAPIPath) { Write-Log -Type "CHECK" -Message "License Portal API refresh token saved successfully" } else { @@ -166,20 +173,22 @@ function Invoke-SetupScript { $APIKeys = Get-Content -Path $ServerAPIPath | ConvertFrom-JSON if ($APIKeys -notin ($null, "")) { Write-Log -Type "WARN" -Message "Server API keys have already been configured" - Write-Log -Type "DEBUG" -Message $APIKeys + # Write-Log -Type "DEBUG" -Message $APIKeys $ConfigureServerAPI = Confirm-Prompt -Prompt "Do you want to reconfigure Server API keys?" if ($ConfigureServerAPI) { $APIKeyPrompt = "$APIKeyPrompt (current $($APIKeys.Key))" $APISecretPrompt = "$APISecretPrompt (current $($APIKeys.Secret))" } } + } else { + $ConfigureServerAPI = Confirm-Prompt -Prompt "Do you want to configure Server API keys?" } if ($ConfigureServerAPI) { $ServerAPIKey = (Read-Host -Prompt $APIKeyPrompt).Trim() $ServerAPISecret = (Read-Host -Prompt $APISecretPrompt).Trim() $ServerAPIToken = [Ordered]@{ - "key" = $ServerAPIKey - "secret" = $ServerAPISecret + "key" = ConvertFrom-SecureString -SecureString (ConvertTo-SecureString -String $ServerAPIKey -AsPlainText -Force) + "secret" = ConvertFrom-SecureString -SecureString (ConvertTo-SecureString -String $ServerAPISecret -AsPlainText -Force) } | ConvertTo-JSON Write-Log -Type "DEBUG" -Message $ServerAPIToken Write-Log -Type "DEBUG" -Message $ServerAPIPath @@ -229,7 +238,7 @@ function Invoke-SetupScript { $LicenseFilePath = Join-Path -Path "$PSScriptRoot/.." -ChildPath "$($Properties.ResDirectory)/$($Properties.LicenseFile)" $ConfigureLicenseFile = $true if (Test-Path -Path $LicenseFilePath) { - $LicenseKeys = Get-Content -Path $LicenseFilePath + $LicenseKeys = ConvertFrom-SecureString -SecureString (ConvertTo-SecureString -String (Get-Content -Path $LicenseFilePath)) -AsPlainText if ($LicenseKeys -notin ($null, "")) { Write-Log -Type "WARN" -Message "License keys have already been configured" Write-Log -Type "DEBUG" -Message $LicenseKeys @@ -237,11 +246,12 @@ function Invoke-SetupScript { } } if ($ConfigureLicenseFile) { - $LicenseKeys = ((Read-Host -Prompt "Enter Alteryx license key(s)").Trim()) -split '[ ,]+' - Write-Log -Type "DEBUG" -Message $LicenseKeys + $LicenseKeys = (Read-Host -Prompt "Enter Alteryx license key(s)").Trim() try { + $EncryptedLicenseKeys = ConvertFrom-SecureString -SecureString (ConvertTo-SecureString -String $LicenseKeys -AsPlainText -Force) + Write-Log -Type "DEBUG" -Message $EncryptedLicenseKeys Write-Log -Type "DEBUG" $LicenseFilePath - Set-Content -Path $LicenseFilePath -Value $LicenseKeys -Force + Set-Content -Path $LicenseFilePath -Value $EncryptedLicenseKeys -Force } catch { Write-Log -Type "ERROR" -Message (Get-PowerShellError) Write-Log -Type "ERROR" -Message "License file could not be saved" @@ -259,8 +269,11 @@ function Invoke-SetupScript { # ------------------------------------------------------------------------------ # * Configure SMTP # ------------------------------------------------------------------------------ + # Write-Log -Type "INFO" -Message "Configuring SMTP settings" # TODO Configure SMTP settings # ------------------------------------------------------------------------------ + # * Checks + # ------------------------------------------------------------------------------ if ($SetupProcess.ErrorCount -eq 5) { # If all configuration failed Write-Log -Type "ERROR" -Message "Set-up wizard failed" From a020109333fba9304ca1214da5902c64e4f9f7b0 Mon Sep 17 00:00:00 2001 From: Florian Carrier Date: Tue, 8 Oct 2024 13:27:59 +0200 Subject: [PATCH 61/61] Update PSAYX version --- Deploy-Alteryx.ps1 | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Deploy-Alteryx.ps1 b/Deploy-Alteryx.ps1 index 3ac93b4..415985f 100644 --- a/Deploy-Alteryx.ps1 +++ b/Deploy-Alteryx.ps1 @@ -266,7 +266,7 @@ Begin { # Dependencies $Modules = [Ordered]@{ "PSTK" = "1.2.6" - "PSAYX" = "1.0.4" + "PSAYX" = "1.1.1" } # Load modules foreach ($Module in $Modules.GetEnumerator()) { diff --git a/README.md b/README.md index 1050af3..08a42cd 100644 --- a/README.md +++ b/README.md @@ -576,7 +576,7 @@ Only the first version supported is listed. Later releases should also be compat | [1.1.0] | [2021.3] | 5.0 | 1.2.5 | 1.0.1 | | [1.1.1] | [2021.3] | 5.0 | 1.2.5 | 1.0.1 | | [1.1.2] | [2021.3] | 5.0 | 1.2.5 | 1.0.1 | -| [2.0.0] | [2024.1] | 5.0 | 1.2.6 | 1.1.0 | +| [2.0.0] | [2024.1] | 5.0 | 1.2.6 | 1.1.1 | ## Known issues