From 1a7fced58adbd9ef682e4f297620288e0e88551d Mon Sep 17 00:00:00 2001 From: Romuald Lemesle Date: Fri, 6 Mar 2026 17:17:25 +0100 Subject: [PATCH 1/3] [agent] chore(PSScriptAnalyzer): add PSScriptAnalyzer on CI --- .circleci/config.yml | 8 +++++++ .../windows/agent-installer-service-user.ps1 | 18 +++++++-------- .../windows/agent-installer-session-user.ps1 | 22 +++++++++---------- installer/windows/agent-installer.ps1 | 16 +++++++------- .../windows/agent-upgrade-service-user.ps1 | 8 +++---- .../windows/agent-upgrade-session-user.ps1 | 20 ++++++++--------- installer/windows/agent-upgrade.ps1 | 14 ++++++------ 7 files changed, 57 insertions(+), 49 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index dfc21b58..5df38ad5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,6 +22,10 @@ jobs: # Run checks - run: cargo check - run: cargo fmt -- --check + - run: + name: Lint PowerShell installer scripts (PSScriptAnalyzer) + shell: powershell.exe + command: .\installer\windows\Run-Lint.ps1 - run: cargo build --release - run: cargo test --release - run: | @@ -108,6 +112,10 @@ jobs: $env:PATH = "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\Llvm\ARM64\bin;" + $env:PATH; # Run checks - run: $env:PATH = "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\Llvm\ARM64\bin;" + $env:PATH; Invoke-Expression '& "$env:USERPROFILE\.cargo\bin\cargo" check' + - run: + name: Lint PowerShell installer scripts (PSScriptAnalyzer) + shell: powershell.exe + command: .\installer\windows\Run-Lint.ps1 - run: git config --global --unset url.ssh://git@github.com.insteadOf - run: git config --global url.ssh://git@github.com.insteadOf https://github.com/ - run: $env:PATH = "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\Llvm\ARM64\bin;" + $env:PATH; Invoke-Expression '& "$env:USERPROFILE\.cargo\bin\cargo" build --release' diff --git a/installer/windows/agent-installer-service-user.ps1 b/installer/windows/agent-installer-service-user.ps1 index 49e09c62..e82f0871 100644 --- a/installer/windows/agent-installer-service-user.ps1 +++ b/installer/windows/agent-installer-service-user.ps1 @@ -55,11 +55,11 @@ if ($installDir -like ".\*" -or $installDir -like ".\*") { # Combine the profile path with the install directory $fullInstallPath = Join-Path $profilePath $installDir -echo "Resolved installation path: $fullInstallPath" +Write-Output "Resolved installation path: $fullInstallPath" # Can't install the OpenAEV agent in System32 location because NSIS 64 exe $location = Get-Location -if ($location -like "*C:\Windows\System32*") { cd C:\ } +if ($location -like "*C:\Windows\System32*") { Set-Location C:\ } switch ($env:PROCESSOR_ARCHITECTURE) { "AMD64" {$architecture = "x86_64"; Break} @@ -73,18 +73,18 @@ switch ($env:PROCESSOR_ARCHITECTURE) } } if ([string]::IsNullOrEmpty($architecture)) { throw "Architecture $env:PROCESSOR_ARCHITECTURE is not supported yet, please create a ticket in openaev github project" } -echo "Downloading and installing OpenAEV Agent..." +Write-Output "Downloading and installing OpenAEV Agent..." try { Invoke-WebRequest -Uri "${OPENAEV_URL}/api/agent/package/openaev/windows/${architecture}/service-user" -OutFile "agent-installer-service-user.exe"; # Use the resolved full installation path ./agent-installer-service-user.exe /S ~OPENAEV_URL="${OPENAEV_URL}" ~ACCESS_TOKEN="${OPENAEV_TOKEN}" ~UNSECURED_CERTIFICATE=${OPENAEV_UNSECURED_CERTIFICATE} ~WITH_PROXY=${OPENAEV_WITH_PROXY} ~SERVICE_NAME="${OPENAEV_SERVICE_NAME}" ~INSTALL_DIR="$fullInstallPath" ~USER="$User" ~PASSWORD="$Password" | Out-Null; - echo "OpenAEV agent has been successfully installed" + Write-Output "OpenAEV agent has been successfully installed" } catch { - echo "Installation failed" - echo "Note: PowerShell 7 or higher is recommended. If the issue persists, consider upgrading." - echo $_ + Write-Output "Installation failed" + Write-Output "Note: PowerShell 7 or higher is recommended. If the issue persists, consider upgrading." + Write-Output $_ } finally { Start-Sleep -Seconds 2 - rm -force ./agent-installer-service-user.exe; - if ($location -like "*C:\Windows\System32*") { cd C:\Windows\System32 } + Remove-Item -Force ./agent-installer-service-user.exe; + if ($location -like "*C:\Windows\System32*") { Set-Location C:\Windows\System32 } } \ No newline at end of file diff --git a/installer/windows/agent-installer-session-user.ps1 b/installer/windows/agent-installer-session-user.ps1 index d4ff7c8f..419069f7 100644 --- a/installer/windows/agent-installer-session-user.ps1 +++ b/installer/windows/agent-installer-session-user.ps1 @@ -1,7 +1,7 @@ [Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls12; # Can't install the OpenAEV agent in System32 location because NSIS 64 exe $location = Get-Location -if ($location -like "*C:\Windows\System32*") { cd C:\ } +if ($location -like "*C:\Windows\System32*") { Set-Location C:\ } switch ($env:PROCESSOR_ARCHITECTURE) { "AMD64" {$architecture = "x86_64"; Break} @@ -15,7 +15,7 @@ switch ($env:PROCESSOR_ARCHITECTURE) } } if ([string]::IsNullOrEmpty($architecture)) { throw "Architecture $env:PROCESSOR_ARCHITECTURE is not supported yet, please create a ticket in openaev github project" } -function Sanitize-UserName { +function ConvertTo-SafeUserName { param( [Parameter(Mandatory = $true)] [string]$UserName @@ -26,7 +26,7 @@ function Sanitize-UserName { } $BasePath = "${OPENAEV_INSTALL_DIR}"; $User = whoami; -$SanitizedUser = Sanitize-UserName -UserName $user; +$SanitizedUser = ConvertTo-SafeUserName -UserName $user; $isElevated = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if ($isElevated) { $AgentName = "OAEVAgent-Session-Administrator-$SanitizedUser" @@ -37,19 +37,19 @@ $InstallDir = $BasePath + "\" + $AgentName; $AgentPath = $InstallDir + "\openaev-agent.exe"; try { - echo "Stop existing agent"; + Write-Output "Stop existing agent"; Get-Process | Where-Object { $_.Path -eq "$AgentPath" } | Stop-Process -Force; - echo "Downloading and installing OpenAEV Agent..."; + Write-Output "Downloading and installing OpenAEV Agent..."; Invoke-WebRequest -Uri "${OPENAEV_URL}/api/agent/package/openaev/windows/${architecture}/session-user" -OutFile "agent-installer-session-user.exe"; ./agent-installer-session-user.exe /S ~OPENAEV_URL="${OPENAEV_URL}" ~ACCESS_TOKEN="${OPENAEV_TOKEN}" ~UNSECURED_CERTIFICATE=${OPENAEV_UNSECURED_CERTIFICATE} ~WITH_PROXY=${OPENAEV_WITH_PROXY} ~SERVICE_NAME="${OPENAEV_SERVICE_NAME}" ~INSTALL_DIR="$BasePath"; - echo "OpenAEV agent has been successfully installed" + Write-Output "OpenAEV agent has been successfully installed" } catch { - echo "Installation failed" - echo "Note: PowerShell 7 or higher is recommended. If the issue persists, consider upgrading." - echo $_ + Write-Output "Installation failed" + Write-Output "Note: PowerShell 7 or higher is recommended. If the issue persists, consider upgrading." + Write-Output $_ } finally { Start-Sleep -Seconds 2 - rm -force ./agent-installer-session-user.exe; - if ($location -like "*C:\Windows\System32*") { cd C:\Windows\System32 } + Remove-Item -Force ./agent-installer-session-user.exe; + if ($location -like "*C:\Windows\System32*") { Set-Location C:\Windows\System32 } } \ No newline at end of file diff --git a/installer/windows/agent-installer.ps1 b/installer/windows/agent-installer.ps1 index 62e9a273..ac00ae04 100644 --- a/installer/windows/agent-installer.ps1 +++ b/installer/windows/agent-installer.ps1 @@ -3,7 +3,7 @@ $isElevatedPowershell = ([Security.Principal.WindowsPrincipal] [Security.Princip if ($isElevatedPowershell -like "False") { throw "PowerShell 'Run as Administrator' is required for installation" } # Can't install the OpenAEV agent in System32 location because NSIS 64 exe $location = Get-Location -if ($location -like "*C:\Windows\System32*") { cd C:\ } +if ($location -like "*C:\Windows\System32*") { Set-Location C:\ } switch ($env:PROCESSOR_ARCHITECTURE) { "AMD64" {$architecture = "x86_64"; Break} @@ -18,17 +18,17 @@ switch ($env:PROCESSOR_ARCHITECTURE) } if ([string]::IsNullOrEmpty($architecture)) { throw "Architecture $env:PROCESSOR_ARCHITECTURE is not supported yet, please create a ticket in openaev github project" } -echo "Downloading and installing OpenAEV Agent..." +Write-Output "Downloading and installing OpenAEV Agent..." try { Invoke-WebRequest -Uri "${OPENAEV_URL}/api/agent/package/openaev/windows/${architecture}/service" -OutFile "openaev-installer.exe"; ./openaev-installer.exe /S ~OPENAEV_URL="${OPENAEV_URL}" ~ACCESS_TOKEN="${OPENAEV_TOKEN}" ~UNSECURED_CERTIFICATE=${OPENAEV_UNSECURED_CERTIFICATE} ~WITH_PROXY=${OPENAEV_WITH_PROXY} ~SERVICE_NAME="${OPENAEV_SERVICE_NAME}" ~INSTALL_DIR="${OPENAEV_INSTALL_DIR}" | Out-Null; - echo "OpenAEV agent has been successfully installed" + Write-Output "OpenAEV agent has been successfully installed" } catch { - echo "Installation failed" - echo "Note: PowerShell 7 or higher is recommended. If the issue persists, consider upgrading." - echo $_ + Write-Output "Installation failed" + Write-Output "Note: PowerShell 7 or higher is recommended. If the issue persists, consider upgrading." + Write-Output $_ } finally { Start-Sleep -Seconds 2 - rm -force ./openaev-installer.exe; - if ($location -like "*C:\Windows\System32*") { cd C:\Windows\System32 } + Remove-Item -Force ./openaev-installer.exe; + if ($location -like "*C:\Windows\System32*") { Set-Location C:\Windows\System32 } } diff --git a/installer/windows/agent-upgrade-service-user.ps1 b/installer/windows/agent-upgrade-service-user.ps1 index 3c431303..9408209f 100644 --- a/installer/windows/agent-upgrade-service-user.ps1 +++ b/installer/windows/agent-upgrade-service-user.ps1 @@ -12,7 +12,7 @@ switch ($env:PROCESSOR_ARCHITECTURE) } } -function Sanitize-UserName { +function ConvertTo-SafeUserName { param( [Parameter(Mandatory = $true)] [string]$UserName @@ -26,7 +26,7 @@ if ([string]::IsNullOrEmpty($architecture)) { throw "Architecture $env:PROCESSOR $BasePath = "${OPENAEV_INSTALL_DIR}"; $User = whoami; -$SanitizedUser = Sanitize-UserName -UserName $user; +$SanitizedUser = ConvertTo-SafeUserName -UserName $user; $ServiceName = "${OPENAEV_SERVICE_NAME}"; $AgentName = "$ServiceName-$SanitizedUser"; @@ -46,7 +46,7 @@ Invoke-WebRequest -Uri "${OPENAEV_URL}/api/agent/executable/openaev/windows/${ar sc.exe stop $AgentName; -rm -force $AgentPath; -mv $AgentUpgradedPath $AgentPath; +Remove-Item -Force $AgentPath; +Move-Item $AgentUpgradedPath $AgentPath; sc.exe start $AgentName; \ No newline at end of file diff --git a/installer/windows/agent-upgrade-session-user.ps1 b/installer/windows/agent-upgrade-session-user.ps1 index debccac2..65bf43dc 100644 --- a/installer/windows/agent-upgrade-session-user.ps1 +++ b/installer/windows/agent-upgrade-session-user.ps1 @@ -12,7 +12,7 @@ switch ($env:PROCESSOR_ARCHITECTURE) } } if ([string]::IsNullOrEmpty($architecture)) { throw "Architecture $env:PROCESSOR_ARCHITECTURE is not supported yet, please create a ticket in openaev github project" } -function Sanitize-UserName { +function ConvertTo-SafeUserName { param( [Parameter(Mandatory = $true)] [string]$UserName @@ -23,7 +23,7 @@ function Sanitize-UserName { } $BasePath = "${OPENAEV_INSTALL_DIR}"; $User = whoami; -$SanitizedUser = Sanitize-UserName -UserName $user; +$SanitizedUser = ConvertTo-SafeUserName -UserName $user; $isElevated = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if ($isElevated) { $AgentName = "${OPENAEV_SERVICE_NAME}-Administrator-$SanitizedUser" @@ -67,18 +67,18 @@ $AgentPath = $AgentPath -replace "OAEV", "OBAS" Get-Process | Where-Object { $_.Path -eq "$AgentPath" } | Stop-Process -Force; $UninstallDir = "${OPENAEV_INSTALL_DIR}" -replace "openaev", "openbas" $UninstallDir = "${OPENAEV_INSTALL_DIR}" -replace "OAEV", "OBAS" -rm -force "${UninstallDir}/openbas.ico" -rm -force "${UninstallDir}/openbas_agent_kill.ps1" -rm -force "${UninstallDir}/openbas_agent_start.ps1" -rm -force "${UninstallDir}/openbas-agent.exe" -rm -force "${UninstallDir}/openbas-agent-config.toml" -rm -force "${UninstallDir}/uninstall.exe" +Remove-Item -Force "${UninstallDir}/openbas.ico" +Remove-Item -Force "${UninstallDir}/openbas_agent_kill.ps1" +Remove-Item -Force "${UninstallDir}/openbas_agent_start.ps1" +Remove-Item -Force "${UninstallDir}/openbas-agent.exe" +Remove-Item -Force "${UninstallDir}/openbas-agent-config.toml" +Remove-Item -Force "${UninstallDir}/uninstall.exe" if ($isElevated) { schtasks.exe /End /TN "$AgentName" schtasks.exe /Delete /TN "$AgentName" /F } else { Remove-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -Name "$AgentName" } -rm -force ./openaev-installer.ps1 +Remove-Item -Force ./openaev-installer.ps1 } -rm -force ./openaev-installer-session-user.exe; \ No newline at end of file +Remove-Item -Force ./openaev-installer-session-user.exe; diff --git a/installer/windows/agent-upgrade.ps1 b/installer/windows/agent-upgrade.ps1 index 72ab5f21..5bceb68f 100644 --- a/installer/windows/agent-upgrade.ps1 +++ b/installer/windows/agent-upgrade.ps1 @@ -33,12 +33,12 @@ Invoke-WebRequest -Uri "${OPENAEV_URL}/api/agent/installer/openaev/windows/servi sc.exe stop "${OPENAEV_SERVICE_NAME}" $UninstallDir = "${OPENAEV_INSTALL_DIR}" -replace "openaev", "openbas" $UninstallDir = "${OPENAEV_INSTALL_DIR}" -replace "OAEV", "OBAS" -rm -force "${UninstallDir}/openbas.ico" -rm -force "${UninstallDir}/openbas_agent_kill.ps1" -rm -force "${UninstallDir}/openbas-agent.exe" -rm -force "${UninstallDir}/openbas-agent-config.toml" -rm -force "${UninstallDir}/uninstall.exe" +Remove-Item -Force "${UninstallDir}/openbas.ico" +Remove-Item -Force "${UninstallDir}/openbas_agent_kill.ps1" +Remove-Item -Force "${UninstallDir}/openbas-agent.exe" +Remove-Item -Force "${UninstallDir}/openbas-agent-config.toml" +Remove-Item -Force "${UninstallDir}/uninstall.exe" sc.exe delete "${OPENAEV_SERVICE_NAME}" -rm -force ./openaev-installer.ps1 +Remove-Item -Force ./openaev-installer.ps1 } -rm -force ./openaev-installer.exe; \ No newline at end of file +Remove-Item -Force ./openaev-installer.exe; From 839f0f57f4e822e20adfeee1b25c16b16dbca79f Mon Sep 17 00:00:00 2001 From: Romuald Lemesle Date: Fri, 6 Mar 2026 17:28:45 +0100 Subject: [PATCH 2/3] [agent] chore(PSScriptAnalyzer): add PSScriptAnalyzer on CI --- installer/windows/Run-Lint.ps1 | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 installer/windows/Run-Lint.ps1 diff --git a/installer/windows/Run-Lint.ps1 b/installer/windows/Run-Lint.ps1 new file mode 100644 index 00000000..8e2755b7 --- /dev/null +++ b/installer/windows/Run-Lint.ps1 @@ -0,0 +1,29 @@ +$ErrorActionPreference = 'Stop' + +# Ensure NuGet provider is available (required for Install-Module on fresh machines / CI runners) +if (-not (Get-PackageProvider -Name NuGet -ListAvailable -ErrorAction SilentlyContinue)) { + Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope CurrentUser | Out-Null +} + +# Install PSScriptAnalyzer if not already present, then load it +$analyzer = Get-Module -ListAvailable -Name PSScriptAnalyzer | Select-Object -First 1 + +if (-not $analyzer) { + Write-Host "Installing PSScriptAnalyzer ..." -ForegroundColor Yellow + Install-Module -Name PSScriptAnalyzer -Force -SkipPublisherCheck -Scope CurrentUser +} + +Import-Module PSScriptAnalyzer -Force + +# Lint all installer scripts +$settings = Join-Path $PSScriptRoot 'PSScriptAnalyzerSettings.psd1' +$results = Invoke-ScriptAnalyzer -Path "$PSScriptRoot\*.ps1" -Recurse -Settings $settings + +if ($results) { + $results | Format-Table -AutoSize + Write-Host "$($results.Count) issue(s) found." -ForegroundColor Red + exit 1 +} else { + Write-Host "No issues found." -ForegroundColor Green +} + From 45f6ff27d9be872d149a356202bccbf231fe5a65 Mon Sep 17 00:00:00 2001 From: Romuald Lemesle Date: Fri, 6 Mar 2026 17:47:31 +0100 Subject: [PATCH 3/3] [agent] chore(PSScriptAnalyzer): add PSScriptAnalyzer on CI --- installer/windows/PSScriptAnalyzerSettings.psd1 | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 installer/windows/PSScriptAnalyzerSettings.psd1 diff --git a/installer/windows/PSScriptAnalyzerSettings.psd1 b/installer/windows/PSScriptAnalyzerSettings.psd1 new file mode 100644 index 00000000..8761f628 --- /dev/null +++ b/installer/windows/PSScriptAnalyzerSettings.psd1 @@ -0,0 +1,11 @@ +# PSScriptAnalyzer settings for the Windows installer scripts. +# Rules excluded here are intentional choices, not oversights: +# - Write-Host is used deliberately for interactive console output during installation. +# - $Password must remain [string] because the NSIS installer expects plain-text input. +@{ + ExcludeRules = @( + 'PSAvoidUsingWriteHost', + 'PSAvoidUsingPlainTextForPassword' + ) +} +