Question on Update-PSUServer - appsettings.json overwritten

I always seem to run into an issue when I’ve tried to update Universal with Update-PSUServer. I’ve noticed that my appsettings.json is overwritten, is that supposed to happen when running Update-PSUServer?

The documentation says to simply run Update-PSUServer. I’m wondering if there are more detailed steps I should be taking when trying to apply an update via powershell?

Product: PowerShell Universal
Version: 3.5.2

Where are you editing the appsettings.json file? In C:\ProgramData\PowerShellUniversal?

The update function isn’t too complicated but maybe there is something we are missing and stomping on your settings.

function Update-PSUServer {
    <#
    .SYNOPSIS
    Update the PowerShell Universal server.
    
    .DESCRIPTION
    Update the PowerShell Universal server. This is a convenience function that will update the server for your platform. 
    
    .PARAMETER Path
    The path for the PowerShell Universal binaries. If not specified, the path will attempt to be resolved.
    
    .PARAMETER Version
    The version to upgrade to. 
    
    .PARAMETER LatestVersion
    Upgrade to the latest version. 
    
    .EXAMPLE
    Update-PSUServer
    #>
    [CmdletBinding(DefaultParameterSetName = "Version")]
    param(
        [Parameter()]
        [string]$Path,
        [Parameter(ParameterSetName = "Version")]
        [string]$Version = (Get-Module Universal).Version,
        [Parameter(ParameterSetName = "Latest")]
        [Switch]$LatestVersion,
        [Parameter()]
        [string]$IISWebsite
    )

    if ($platform -eq 'win7-x64' -and -not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
        throw 'You must be an administrator to update the Universal Server. Please run the command as an administrator.'
    }

    if ($IISWebsite -and ($IsLinux -or $IsMacOS)) {
        throw "IISWebsite is only supported on Windows."
    }

    if ($IISWebsite) {
        Import-Module WebAdministration -ErrorAction Stop
    }

    $platform = "win7-x64";
    if ($PSVersionTable.PSEdition -eq 'Core') {
        if ($IsLinux) {
            $platform = "linux-x64"
        }
        elseif ($IsMacOS) {
            $platform = "osx-x64"
        }
    }

    if (-not $Path -and -not $IISWebsite) {
        if ($PSVersionTable.PSEdition -eq 'Desktop' -or $IsWindows) {
            $ServerPath = Get-Command "Universal.Server.exe" -ErrorAction SilentlyContinue
        }
        else {
            $ServerPath = Get-Command "Universal.Server" -ErrorAction SilentlyContinue
        }

        if (-not $ServerPath) {
            throw "Unable to locate existing PowerShell Universal installation. Use the -Path parameter to specify the folder of the previous installation."
        }

        $Path = [System.IO.Path]::GetDirectoryName($ServerPath.Source)
    }

    if (-not $Path -and $IISWebsite) {
        $Path = (Get-Website -Name $IISWebsite).PhysicalPath
    }

    Write-Verbose "Upgrading server installed at $Path"

    if ($LatestVersion) {
        $Version = (Invoke-WebRequest https://imsreleases.blob.core.windows.net/universal/production/v3-version.txt).Content
    }

    Write-Verbose "Downloading version $Version"

    $Temp = [System.IO.Path]::GetTempPath()
    $Zip = (Join-Path $Temp "Universal.$Version.$platform.zip")
    Remove-Item $Zip -Force -ErrorAction SilentlyContinue

    if (($PSVersionTable.PSEdition -eq 'Desktop' -or $IsWindows) -and -not $IISWebsite) {
        Write-Verbose "Stopped PowerShellUniversal service"
        Stop-Service -Name 'PowerShellUniversal'
    }

    if ($IISWebsite) {
        $AppPool = (Get-Website -Name $IISWebsite).ApplicationPool
        Stop-Website -Name $IISWebsite
        Stop-WebAppPool -Name $AppPool
    }

    if ($IsLinux) {
        Write-Verbose "Stopped PowerShellUniversal service"
        systemctl stop PowerShellUniversal
        systemctl disable PowerShellUniversal
    }

    Remove-Item $Path -Force -Recurse
    Invoke-WebRequest "https://imsreleases.blob.core.windows.net/universal/production/$version/Universal.$platform.$Version.zip" -OutFile $Zip

    Write-Verbose "Download complete. Extracting to $Path"

    Expand-Archive -Path $Zip -DestinationPath $Path -Force
    Remove-Item $Zip -Force

    if (($PSVersionTable.PSEdition -eq 'Desktop' -or $IsWindows) -and -not $IISWebsite) {
        Get-ChildItem $Path -Recurse | Unblock-File
        Start-Service -Name 'PowerShellUniversal'
        Write-Verbose "Started PowerShellUniversal service"
    }

    if ($IISWebsite) {
        Get-ChildItem $Path -Recurse | Unblock-File
        Start-Website -Name $IISWebsite
    }

    if ($IsMacOS -or $IsLinux) {
        $ServerPath = Join-Path $Path "Universal.Server"
        /bin/chmod +x $ServerPath
    }

    if ($IsLinux) {
        Write-Verbose "Started PowerShellUniversal service"
        systemctl start PowerShellUniversal
        systemctl enable PowerShellUniversal
    }
}

I’ve been editing the AppSettings.json in C:\ProgramData\PowerShellUniversal\Server. Should I be copying that file to C:\ProgramData\PowershellUniversal instead?

If you move that file to the parent (C:\ProgramData\PowerShellUniversal) the cmdlet wont overwrite it and it will load that first. It actually will merge it with the Server folder one so you don’t need every option in there.

I have a different issue with Update-PSUServer. I am on Windows 2022, pwsh 7, PSUServer 3.5.2, running as a service.

When I use pwsh7 I forgot to set the proxy environment variables, so had no connection to the internet and Update blew away the UniversalServer. It also had difficulty removing the Universal Module.

No issue as I can re-install the latest version, but can you add some logic when Invoke-Webrequest does not reach the internet to avoid the extra work to get PSU back up?

PS C:\Users\jdavid.lab\AppData\Local\Temp> get-service powershell* | Start-Service
Start-Service: Service 'PowerShell Universal (PowerShellUniversal)' cannot be started due to the following error: Cannot start service 'PowerShellUniversal' on computer '.'.
PS C:\Users\jdavid.lab\AppData\Local\Temp>
PS C:\Windows\System32> update-psuserver -LatestVersion -Verbose
VERBOSE: Upgrading server installed at C:\ProgramData\PowerShellUniversal\Server
VERBOSE: GET with 0-byte payload
Invoke-WebRequest: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

VERBOSE: Downloading version 3.3.3
VERBOSE: Stopped PowerShellUniversal service
Remove-Item: Access to the path 'C:\ProgramData\PowerShellUniversal\Server\Modules\Microsoft.PowerShell.SecretManagement\1.1.1\Microsoft.PowerShell.SecretManagement.dll' is denied.

Remove-Item: The directory is not empty. : 'C:\ProgramData\PowerShellUniversal\Server\Modules\Microsoft.PowerShell.SecretManagement\1.1.1'

Remove-Item: The directory is not empty. : 'C:\ProgramData\PowerShellUniversal\Server\Modules\Microsoft.PowerShell.SecretManagement'

Remove-Item: Access to the path 'C:\ProgramData\PowerShellUniversal\Server\Modules\Microsoft.PowerShell.SecretStore\1.0.5\Microsoft.PowerShell.SecretStore.dll' is denied.

Remove-Item: The directory is not empty. : 'C:\ProgramData\PowerShellUniversal\Server\Modules\Microsoft.PowerShell.SecretStore\1.0.5'

Remove-Item: The directory is not empty. : 'C:\ProgramData\PowerShellUniversal\Server\Modules\Microsoft.PowerShell.SecretStore'

Remove-Item: Access to the path 'C:\ProgramData\PowerShellUniversal\Server\Modules\SecretManagement.JustinGrote.CredMan\1.0.0\SecretManagement.JustinGrote.CredMan.Extension\SecretManagement.JustinGrote.CredMan.Extension.dll' is denied.

Remove-Item: The directory is not empty. : 'C:\ProgramData\PowerShellUniversal\Server\Modules\SecretManagement.JustinGrote.CredMan\1.0.0\SecretManagement.JustinGrote.CredMan.Extension'

Remove-Item: The directory is not empty. : 'C:\ProgramData\PowerShellUniversal\Server\Modules\SecretManagement.JustinGrote.CredMan\1.0.0'

Remove-Item: The directory is not empty. : 'C:\ProgramData\PowerShellUniversal\Server\Modules\SecretManagement.JustinGrote.CredMan'

Remove-Item: Access to the path 'C:\ProgramData\PowerShellUniversal\Server\Modules\Universal\classes.dll' is denied.

## sections removed by jdavid

Remove-Item: Access to the path 'C:\ProgramData\PowerShellUniversal\Server\UniversalDashboard.dll' is denied.

Remove-Item: Access to the path 'C:\ProgramData\PowerShellUniversal\Server\UniversalLicensing.dll' is denied.

Remove-Item: The directory is not empty. : 'C:\ProgramData\PowerShellUniversal\Server'

VERBOSE: GET with 0-byte payload
Invoke-WebRequest: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

VERBOSE: Download complete. Extracting to C:\ProgramData\PowerShellUniversal\Server
Expand-Archive: The path 'C:\Users\jdavid.lab\AppData\Local\Temp\Universal.3.3.3.win7-x64.zip' either does not exist or is not a valid file system path.

Remove-Item: Cannot find path 'C:\Users\jdavid.lab\AppData\Local\Temp\Universal.3.3.3.win7-x64.zip' because it does not exist.

Start-Service: Service 'PowerShell Universal (PowerShellUniversal)' cannot be started due to the following error: Cannot start service 'PowerShellUniversal' on computer '.'.

VERBOSE: Started PowerShellUniversal service
PS C:\Windows\System32>```

Thanks, Adam! I figured that may be the case after your last reply.