Powershell and Machine Level Environment Variables

Hi,

I am currently having an issue that I hope you may have come across before.

I am working on an application installation powershell script that sets a few machine level environment variables. The issue I am having as it seems that they behave like they are not being persisted so when the next step of the deployment runs to install the application it shows they are there via powershell, but the application fails to see them present when they start.

I have tried to set them via the Environment powershell form as well as directly added via registry keys. All of the steps seem to run fine, but the resulting installation is broken.

Any help is appreciated.

Step 1: Add machine level environment variables.
$sRabbitDeployDrive = “C:”
#[Environment]::SetEnvironmentVariable(“RABBITMQ_BASE”, “$($sRabbitDeployDrive)\RabbitMQ_Data”, “Machine”)
Set-ItemProperty -Path “HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment” -Name RABBITMQ_BASE -Value “$($sRabbitDeployDrive)\RabbitMQ_Data”
#[Environment]::SetEnvironmentVariable(“RABBITMQ_CONFIG_FILE”, “$($sRabbitDeployDrive)\RabbitMQ_Data\rabbitmq”, “Machine”)
Set-ItemProperty -Path “HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment” -Name RABBITMQ_CONFIG_FILE -Value "$($sRabbitDeployDrive)\RabbitMQ_Data\rabbitmq"
Set-ItemProperty -Path “HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment” -Name RABBITMQ_CONSOLE_LOG -Value “new”

$sERLangBaseNum = $sERLangEXEList.Name -replace “otp_win64_”,""
$sERLangBaseNum = $sERLangBaseNum -replace “.exe”,""
$sERLangNewPath = “$($sRabbitDeployDrive)\Program Files\ERLang_$($sERLangBaseNum)”
#[Environment]::SetEnvironmentVariable(“ERLANG_HOME”, $sERLangNewPath, “Machine”)
Set-ItemProperty -Path “HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment” -Name ERLANG_HOME -Value “$sERLangNewPath”

18:09:01 Info | PowerShell Version 2 in use.
18:09:01 Info | Windows OS Version Microsoft Windows Server 2008 R2 Standard in use.
18:09:01 Info | PowerShell Script Path: C:_Installs\RabbitMQ_Install
18:09:01 Info | ******************************************************************************
18:09:01 Info | This PowerShell script is setup to install ERLang/RabbitMQ for cluster nodes
18:09:01 Info | ******************************************************************************
18:09:01 Info | Execution started on: 02/02/2016 18:09:01
18:09:01 Info | Creating RABBITMQ_BASE environment variable (Machine)
18:09:01 Info | Creating RABBITMQ_CONFIG_FILE environment variable (Machine)
18:09:01 Info | Creating RABBITMQ_CONSOLE_LOG environment variable (Machine)
18:09:01 Info | New RabbitMQ Data Path: C:\RabbitMQ_Data
18:09:01 Info | New RabbitMQ Config Path: C:\RabbitMQ_Data\rabbitmq
18:09:01 Info | New RabbitMQ Console Log Rollover: new
18:09:01 Info | Creating ERLANG_HOME environment variable (Machine)
18:09:01 Info | New ERLANG_HOME Path: C:\Program Files\ERLang_18.2.1

Step 2: Install Erlang runtime
$sERLangVersionNewM = [Environment]::GetEnvironmentVariable(“ERLANG_HOME”,“Machine”)
Write-Host “New ERLANG_HOME Path (Machine): $sERLangVersionNewM”
$sERLangBaseNum = $sERLangEXEList.Name -replace “otp_win64_”,""
$sERLangBaseNum = $sERLangBaseNum -replace “.exe”,""
$sERLangNewPath = “$($sRabbitDeployDrive)\Program Files\ERLang_$($sERLangBaseNum)”
## /S (Silent) - /D (Install to specified path)
$sCommandTemp = “/S /D=$($sERLangNewPath)”

## Start up background process to handle the installation of ERLang runtime
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = $($sERLangEXEList.psobject.properties['FullName'].Value)
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = $sCommandTemp
Write-Host "EXE: $($pinfo.FileName)"
Write-Host "Execute Command Args: $($pinfo.Arguments)"
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$p.WaitForExit()
$stdout = $p.StandardOutput.ReadToEnd().Trim()
Write-Host "stdout: $stdout"
Write-Host "exit code: $($p.ExitCode)"

18:09:03 Info | New ERLANG_HOME Path: C:\Program Files\ERLang_18.2.1

Step 3: Install RabbitMQ
$sRabbitMQBaseM = [Environment]::GetEnvironmentVariable(“RABBITMQ_BASE”,“Machine”)
$sRabbitMQConfigM = [Environment]::GetEnvironmentVariable(“RABBITMQ_CONFIG_FILE”,“Machine”)
$sRabbitMQConLogM = [Environment]::GetEnvironmentVariable(“RABBITMQ_CONSOLE_LOG”,“Machine”)
$sERLangVersionNewM = [Environment]::GetEnvironmentVariable(“ERLANG_HOME”,“Machine”)
Write-Host "New RabbitMQ Base Path (Machine): $sRabbitMQBaseM"
Write-Host "New RabbitMQ Config Path (Machine): $sRabbitMQConfigM"
Write-Host "New RabbitMQ Console Log Rollover (Machine): $sRabbitMQConLogM"
Write-Host “New ERLANG_HOME Path (Machine): $sERLangVersionNewM”

18:09:05 Info | New RabbitMQ Data Path: C:\RabbitMQ_Data
18:09:05 Info | New RabbitMQ Config Path: C:\RabbitMQ_Data\rabbitmq
18:09:05 Info | New RabbitMQ Console Log Rollover: new
18:09:05 Info | New ERLANG_HOME Path: C:\Program Files\ERLang_18.2.1

<< Install rabbitmq using same method as erlang >>

Hi!

Thanks for getting in touch. I’ve done a bit of research into the behaviour you’re seeing, and I’ve built a sample project on our demo server that creates and logs environment variables.

It has two steps that illustrate the resultant behaviour:

  1. Create an Environment Variable (at the Machine scope) called RABBITMQ_BASE
  2. Read the Environment Variable (from the Machine scope) and log it out

The result I’m seeing is that:

Step 1
Tentacle.exe creates a child process of Calamari.exe which eventually creates another child process of PowerShell.exe

  • Get-ChildItem Env: - the variable is not available - which makes sense because the Environment is cached from the parent process (Tentacle.exe) when the child process (Calamari.exe and PowerShell.exe) starts up.
  • [Environment]::GetEnvironmentVariable("...", "Machine") - the variable is available since this overload reads from the registry

Step 2
This will be another instance of Calamari.exe which starts a further child process of PowerShell.exe

  • Get-ChildItem Env: - the variable is still not available - I believe this is because the parent process (Tentacle.exe) is still the same.
  • [Environment]::GetEnvironmentVariable("...", "Machine") - the variable is available since this overload reads from the registry

What this says to me is that if your application is started as a child process from the deployment process, Tentacle.exe->Calamari.exe->PowerShell.exe->Your.exe, the environment will have been cached when Tentacle.exe started. However, if your application process is started as an independent process, like a Windows Service, it should get a new/fresh set of the Environment variables upon starting. (One trick I’ve seen to achieve this is to set a scheduled task to start the executable)

I know this is a long response, but does this sound about right to you? Does it help solve the problem for your situation, or perhaps you could give me some more context?

Useful background information
PowerShell and Environment Variables: https://technet.microsoft.com/en-us/library/ff730964.aspx
Can you reload Environment Variables in-process: http://stackoverflow.com/questions/1363626/reload-environment-variables-in-c-sharp-after-launch

Hope that helps!
Mike

Hi Michael,

I have attempted again and I still have the same issues. There is something that OD is holding in the environment that doesn’t let go. If I run the installation a second time, it will complete successfully.

When I have some more time I will see if I can narrow down where it’s failing.

Thanks.

Hi!

Thanks for getting back to me. If you do end up getting more time it might be quicker and easier for us to schedule a support call. This way we can see exactly what’s happening in the context of your deployment.

https://calendly.com/octopusdeploy/supportcall

Otherwise I look forward to hearing from you soon.

Hope that helps!
Mike