Public/system/Get-EnvironmentVariable.ps1
|
#Requires -Version 5.1 function Get-EnvironmentVariable { <# .SYNOPSIS Retrieves environment variables from local or remote computers .DESCRIPTION Returns environment variables organized by scope (Machine, User, Process). Machine and User scopes read from the registry for persistent values. Process scope uses the current runtime environment. Supports wildcard filtering by variable name. .PARAMETER ComputerName One or more computer names to query. Defaults to the local computer. Accepts pipeline input by value and by property name. .PARAMETER VariableName Optional wildcard filter on the variable name. Uses -like matching. For example, 'PATH' returns only the PATH variable per scope. .PARAMETER Scope Scope to query. Valid values: Machine, User, Process, All. Defaults to All. Process scope is only available for local queries. .PARAMETER Credential Optional PSCredential for authenticating to remote computers. Not used for local queries. .EXAMPLE Get-EnvironmentVariable Returns all environment variables from all scopes on the local computer. .EXAMPLE Get-EnvironmentVariable -ComputerName 'SRV01' -VariableName 'PATH' -Scope Machine Returns the Machine-scoped PATH variable from SRV01. .EXAMPLE 'SRV01', 'SRV02' | Get-EnvironmentVariable -VariableName 'TEMP*' Retrieves all TEMP-related variables from multiple servers via pipeline. .OUTPUTS PSWinOps.EnvironmentVariable Returns objects with ComputerName, Name, Value, Scope, and Timestamp. Results are sorted by Scope then by Name. .NOTES Author: Franck SALLET Version: 1.0.0 Last Modified: 2026-03-25 Requires: PowerShell 5.1+ / Windows only Requires: Remote registry or WinRM for remote Machine/User scopes .LINK https://github.com/k9fr4n/PSWinOps .LINK https://learn.microsoft.com/en-us/windows/win32/procthread/environment-variables #> [CmdletBinding()] [OutputType('PSWinOps.EnvironmentVariable')] param( [Parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [Alias('CN', 'Name', 'DNSHostName')] [string[]]$ComputerName = $env:COMPUTERNAME, [Parameter(Mandatory = $false, Position = 0)] [ValidateNotNullOrEmpty()] [string]$VariableName, [Parameter(Mandatory = $false)] [ValidateSet('Machine', 'User', 'Process', 'All')] [string]$Scope = 'All', [Parameter(Mandatory = $false)] [ValidateNotNull()] [System.Management.Automation.PSCredential] [System.Management.Automation.Credential()] $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { Write-Verbose -Message "[$($MyInvocation.MyCommand)] Starting with Scope=$Scope" $localNames = @($env:COMPUTERNAME, 'localhost', '.') $registryPaths = @{ Machine = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' User = 'HKCU:\Environment' } $scriptBlock = { param( [hashtable]$Paths, [string]$RequestedScope ) $results = [System.Collections.Generic.List[object]]::new() $scopesToQuery = if ($RequestedScope -eq 'All') { @('Machine', 'User') } else { @($RequestedScope) } foreach ($scopeName in $scopesToQuery) { if ($scopeName -eq 'Process') { continue } $path = $Paths[$scopeName] if (-not $path) { continue } try { $regItem = Get-Item -Path $path -ErrorAction Stop foreach ($valueName in $regItem.GetValueNames()) { if ([string]::IsNullOrEmpty($valueName)) { continue } $results.Add([PSCustomObject]@{ Name = $valueName Value = $regItem.GetValue($valueName, '', 'DoNotExpandEnvironmentNames') Scope = $scopeName }) } } catch { Write-Warning "Failed to read $scopeName environment: $_" } } $results } } process { foreach ($machine in $ComputerName) { Write-Verbose -Message "[$($MyInvocation.MyCommand)] Processing '$machine'" try { $isLocal = $localNames -contains $machine $displayName = if ($isLocal) { $env:COMPUTERNAME } else { $machine } $resultList = [System.Collections.Generic.List[object]]::new() if ($isLocal) { $rawEntries = & $scriptBlock -Paths $registryPaths -RequestedScope $Scope foreach ($entry in $rawEntries) { $resultList.Add($entry) } # Add Process scope if requested and local if ($Scope -eq 'All' -or $Scope -eq 'Process') { $envVars = [Environment]::GetEnvironmentVariables('Process') foreach ($key in $envVars.Keys) { $resultList.Add([PSCustomObject]@{ Name = $key Value = $envVars[$key] Scope = 'Process' }) } } } else { if ($Scope -eq 'Process') { Write-Warning -Message "[$($MyInvocation.MyCommand)] Process scope is not available for remote computers. Skipping '$machine'." continue } $invokeParams = @{ ComputerName = $machine ScriptBlock = $scriptBlock ArgumentList = @($registryPaths, $Scope) ErrorAction = 'Stop' } if ($Credential -ne [System.Management.Automation.PSCredential]::Empty) { $invokeParams['Credential'] = $Credential } $rawEntries = Invoke-Command @invokeParams foreach ($entry in $rawEntries) { $resultList.Add($entry) } } # Apply name filter and emit typed objects $resultList | Sort-Object -Property Scope, Name | ForEach-Object -Process { if ($PSBoundParameters.ContainsKey('VariableName') -and ($_.Name -notlike $VariableName)) { return } [PSCustomObject]@{ PSTypeName = 'PSWinOps.EnvironmentVariable' ComputerName = $displayName Name = $_.Name Value = $_.Value Scope = $_.Scope Timestamp = Get-Date -Format 'o' } } } catch { Write-Error -Message "[$($MyInvocation.MyCommand)] Failed on '${machine}': $_" continue } } } end { Write-Verbose -Message "[$($MyInvocation.MyCommand)] Completed" } } |