.NET Environment Variables Not Applied (Windows)

🔍 Problem

You’ve instrumented a .NET application using the SeaLights agent, but the expected environment variables (e.g., SL_*) are not being applied to the profiler process. This can lead to missing tags, incorrect configuration, or the profiler not activating.

Additionally, when defining variables using PowerShell, values may not appear immediately in the current session or may not propagate to background processes such as IIS or Windows Services.

⚠️ Cause

The environment variables may not be defined at the correct scope level for the profiler process to inherit them as Windows supports multiple levels of environment variables:

  • Machine-level: Available system-wide to all users and processes.

  • User-level: Available to all processes launched by a specific user.

  • Process-level (Session): Available only to the current shell or script session and its child processes.

When the same variable is defined at multiple levels, Windows resolves it using the following priority order:

Process-level > User-level > Machine-level

This means a variable set in the current session will override any user or machine-level definitions. However, suppose your profiler is launched as a service or from a different context (e.g., IIS, Windows Service). In that case, it may not inherit session-level variables at all — and will rely on user or machine-level definitions.

Common issues:

  • PowerShell changes are persisted to the registry, but not applied to the current $env: session unless reloaded manually

  • Services (e.g., IIS) may not inherit session/user-level variables

  • Manual testing may work if variables are set at process level but fail in automated execution or services

🩺Diagnose

Use the following PowerShell function to log all SL_* environment variables across the three key levels — Machine, User, and Process — to help diagnose where the variable is (or isn’t) defined.

function Get-SLEnvVarsAllLevels {
    param (
        [string]$OutputFilePath = "$(Get-Location)\sl_env_vars_all_levels.txt"
    )

    # Clear the file if it exists
    if (Test-Path $OutputFilePath) { Clear-Content $OutputFilePath }

    # Helper function to write to console and file
    function Write-And-Log {
        param ($text)
        Write-Output $text
        Add-Content -Path $OutputFilePath -Value $text
    }

    # Machine-level
    Write-And-Log "`n=== Machine-level Environment Variables ==="
    $machineVars = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
    $machineVars.PSObject.Properties | Where-Object { $_.Name -like 'SL_*' } | ForEach-Object {
        Write-And-Log "$($_.Name)=$($_.Value)"
    }

    # User-level
    Write-And-Log "`n=== User-level Environment Variables ==="
    $userVars = Get-ItemProperty -Path "HKCU:\Environment"
    $userVars.PSObject.Properties | Where-Object { $_.Name -like 'SL_*' } | ForEach-Object {
        Write-And-Log "$($_.Name)=$($_.Value)"
    }

    # Process-level
    Write-And-Log "`n=== Process-level (Session) Environment Variables ==="
    Get-ChildItem Env: | Where-Object { $_.Name -like 'SL_*' } | ForEach-Object {
        Write-And-Log "$($_.Name)=$($_.Value)"
    }
}

▶️ Usage:

Get-SLEnvVarsAllLevels -OutputFilePath "C:\Logs\env_debug.txt"

This will:

  • Print all SL_* variables to the console.

  • Save them to a file for inspection or sharing with support.


Solution

Use the following script to:

  • Set environment variables at the Machine level (persisted in registry)

  • Make them immediately available to the current PowerShell session ($env: scope)

$vars = @{
    "SL_SESSION_TOKENFILE" = "your-agent-token-file"
    "SL_SESSION_LABID"      = "your-lab-id"
    "SL_LOGDIR"  = "my-logging-directory"
}

# Set at Machine level and apply in current session
$vars.GetEnumerator() | ForEach-Object {
    [Environment]::SetEnvironmentVariable($_.Key, $_.Value, "Machine")
    $env[$_.Key] = $_.Value
}

Write-Host "✅ Machine-level environment variables have been set and applied in current session."

If needed, replace "Machine" with "User" to define variables at the user level instead, or duplicate the logic to support both scopes.

  • If your application runs as a Windows Service, ensure the environment variables are set at the Machine level.

  • For IIS-hosted apps, consider setting variables via Application Pool identity or system-wide.

📢Broadcast Environment Change (Optional)

The script above updates the current session, but other running apps (like explorer.exe, new command prompts, etc.) may still use cached values.

To notify the operating system that environment variables have changed:

Advanced Option: Broadcast Update

Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;

public class NativeMethods {
    [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
    public static extern IntPtr SendMessageTimeout(
        IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam,
        uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);
}
"@

[void][NativeMethods]::SendMessageTimeout(
    [IntPtr]0xFFFF,      # HWND_BROADCAST
    0x1A,                # WM_SETTINGCHANGE
    [UIntPtr]::Zero,     
    "Environment",
    0x0002,              # SMTO_ABORTIFHUNG
    100,
    [ref]([UIntPtr]::Zero)
)

Write-Host "Environment change broadcast sent to system."

This is useful in GUI environments or when other non-PowerShell apps need to immediately receive the updated environment without reboot.

Last updated

Was this helpful?