Skip to content

Add Update-Environment cmdlet#27360

Open
Hi-doki wants to merge 18 commits into
PowerShell:masterfrom
Hi-doki:master
Open

Add Update-Environment cmdlet#27360
Hi-doki wants to merge 18 commits into
PowerShell:masterfrom
Hi-doki:master

Conversation

@Hi-doki
Copy link
Copy Markdown

@Hi-doki Hi-doki commented Apr 26, 2026

PR Summary

Adds a new Update-Environment cmdlet to Microsoft.PowerShell.Management to pull and merge the process environment from the Machine and User registry targets.

PR Context

Previously, users needed to restart their shell to inherit updated/created environment variables, which can be quite irritating, especially if the user has set temporary environment variables in their session. This cmdlet safely pulls the newly created or updated environment variables without the need to restart the shell.

PR Checklist

Adds a new Update-Environment cmdlet to Microsoft.PowerShell.Management
to sync process environment from the machine and user registry targets.

Previously, users needed to restart their shell to inherit
updated/created environment variables. This cmdlet safely pulls the
newly created or updated environment variables without the need to
restart the shell.
@Hi-doki Hi-doki requested a review from a team as a code owner April 26, 2026 23:46
@Hi-doki
Copy link
Copy Markdown
Author

Hi-doki commented Apr 26, 2026

@microsoft-github-policy-service agree

Copilot AI review requested due to automatic review settings May 1, 2026 22:53
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Update-Environment cmdlet to Microsoft.PowerShell.Management intended to refresh the current process environment from the persisted Machine/User environment values.

Changes:

  • Added UpdateEnvironmentCommand cmdlet implementation in the Management commands assembly.
  • Exported Update-Environment from the Windows and Unix Microsoft.PowerShell.Management module manifests.
  • Added Pester tests validating basic variable behavior and user-scope refresh.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 8 comments.

File Description
src/Microsoft.PowerShell.Commands.Management/commands/management/UpdateEnvironmentCommand.cs Implements the new Update-Environment cmdlet and merging logic.
src/Modules/Windows/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 Exports Update-Environment on Windows.
src/Modules/Unix/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 Exports Update-Environment on Unix (currently problematic).
test/powershell/Modules/Microsoft.PowerShell.Management/Update-Environment.Tests.ps1 Adds tests for ignored variables and user-target refresh behavior.

Comment on lines +51 to +86

if (updateAll || Machine.IsPresent)
{
WriteVerbose("Updating Machine environment variables...");
UpdateFromTarget(EnvironmentVariableTarget.Machine);
}

if (updateAll || User.IsPresent)
{
WriteVerbose("Updating User environment variables...");
UpdateFromTarget(EnvironmentVariableTarget.User);
}

if (updateAll || (Machine.IsPresent && User.IsPresent))
{
FixListVariable("Path");
FixListVariable("PSModulePath");
}
}

private void FixListVariable(string variableName)
{
string machineVal = Environment.GetEnvironmentVariable(variableName, EnvironmentVariableTarget.Machine);
string userVal = Environment.GetEnvironmentVariable(variableName, EnvironmentVariableTarget.User);

if (!string.IsNullOrEmpty(machineVal) && !string.IsNullOrEmpty(userVal))
{
string combinedValue = machineVal + Path.PathSeparator + userVal;
string processVal = Environment.GetEnvironmentVariable(variableName, EnvironmentVariableTarget.Process);

if (!string.Equals(combinedValue, processVal, StringComparison.OrdinalIgnoreCase))
{
Environment.SetEnvironmentVariable(variableName, combinedValue, EnvironmentVariableTarget.Process);
WriteVerbose($"Merged User and Machine values for {variableName}");
}
}
Comment on lines +78 to +88
string combinedValue = machineVal + Path.PathSeparator + userVal;
string processVal = Environment.GetEnvironmentVariable(variableName, EnvironmentVariableTarget.Process);

if (!string.Equals(combinedValue, processVal, StringComparison.OrdinalIgnoreCase))
{
Environment.SetEnvironmentVariable(variableName, combinedValue, EnvironmentVariableTarget.Process);
WriteVerbose($"Merged User and Machine values for {variableName}");
}
}
}

Comment on lines +112 to +116
WriteVerbose($"Added {target} variable: {key} = '{value}'");
}
else
{
WriteVerbose($"Updated {target} variable: {key} from '{currentValue}' to '{value}'");
{
// A list of variables that should never be overwritten
// by static Machine or User registry reads.
private static readonly HashSet<string> _ignoredVariables = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

Describe "Update-Environment" -Tag "CI" {
Comment on lines +12 to +16
Update-Environment

# Assert
$env:USERNAME | Should -BeExactly $originalUsername
}
Comment on lines +64 to +68
if (updateAll || (Machine.IsPresent && User.IsPresent))
{
FixListVariable("Path");
FixListVariable("PSModulePath");
}
Hi-doki and others added 5 commits May 2, 2026 17:00
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

Comment on lines +9 to +18
# Snapshot the CI runner's environment to restore after all tests execute
BeforeAll {
$script:originalPath = $env:PATH
$script:originalUser = $env:USERNAME
}

AfterAll {
$env:PATH = $script:originalPath
$env:USERNAME = $script:originalUser
}
Comment on lines +15 to +16
[Cmdlet(VerbsData.Update, "Environment")]
public class UpdateEnvironmentCommand : PSCmdlet
…ribute and improving test structure for environment variable management
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

Comment on lines +40 to +66
Context "Variable merging and blocklist" {
It "Should not overwrite ignored dynamic variables like USERNAME" {
# Act
Update-Environment

# Assert
$env:USERNAME | Should -BeExactly $script:originalUser
}

It "Should successfully pull new variables from the User target" {
# Arrange
$testKey = "TEST_UPDATE_ENV_VAR_$(Get-Random)"
$testValue = "HelloWorld"

# Set a new environment variable in the User registry target
[Environment]::SetEnvironmentVariable($testKey, $testValue, "User")

try {
# Ensure the current process does not have it yet
[Environment]::GetEnvironmentVariable($testKey, "Process") | Should -BeNullOrEmpty

# Act - Run cmdlet
Update-Environment -User

# Assert - The process should now have the variable
(Get-Item -Path "Env:\$testKey").Value | Should -BeExactly $testValue
}
Remove-Item -Path "Env:\$testKey" -ErrorAction SilentlyContinue
}
}

Comment on lines +108 to +136
string processVal = Environment.GetEnvironmentVariable(variableName, EnvironmentVariableTarget.Process);
List<string> mergedSegments = new List<string>();
HashSet<string> seenSegments = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

if (includeMachine)
{
string machineVal = Environment.GetEnvironmentVariable(variableName, EnvironmentVariableTarget.Machine);
AppendUniqueListSegments(mergedSegments, seenSegments, machineVal);
}

if (includeUser)
{
string userVal = Environment.GetEnvironmentVariable(variableName, EnvironmentVariableTarget.User);
AppendUniqueListSegments(mergedSegments, seenSegments, userVal);
}

int registrySegmentCount = mergedSegments.Count;

// Preserve entries that exist only in the current process value
AppendUniqueListSegments(mergedSegments, seenSegments, processVal);

string mergedValue = string.Join(Path.PathSeparator.ToString(), mergedSegments);

if (!string.Equals(mergedValue, processVal, StringComparison.OrdinalIgnoreCase))
{
// Verify the user confirms the action if -Confirm or -WhatIf was supplied
if (ShouldProcess($"Environment Variable: {variableName}", $"Update to: {mergedValue}"))
{
Environment.SetEnvironmentVariable(variableName, mergedValue, EnvironmentVariableTarget.Process);
Comment on lines +153 to +166
IDictionary envVars = Environment.GetEnvironmentVariables(target);

foreach (DictionaryEntry entry in envVars)
{
string key = (string)entry.Key;
string value = (string)entry.Value;

if (s_ignoredVariables.Contains(key))
{
continue;
}

string currentValue = Environment.GetEnvironmentVariable(key, EnvironmentVariableTarget.Process);

…mpty segments and improving test cases for variable merging and -WhatIf behavior
@Hi-doki
Copy link
Copy Markdown
Author

Hi-doki commented May 2, 2026

I have updated the PR description to clarify this cmdlet only pulls and merges newly created/updated variables, rather than syncing (which can mean the removal of environment variables). Removing variables from active processes automatically can potentially cause unexpected instability for the user during an active session.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

…ancing tests for variable merging and blocklist behavior
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

/// <summary>
/// Implements the Update-Environment cmdlet.
/// </summary>
[Cmdlet(VerbsData.Update, "Environment", SupportsShouldProcess = true)]
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Update-Environment is not in PowerShell yet, there is no official Microsoft Docs page for it yet. I have left this out for now until there is documentation for it.

Comment on lines +54 to +64
if (updateMachine)
{
WriteVerbose("Updating Machine environment variables...");
UpdateFromTarget(EnvironmentVariableTarget.Machine);
}

if (updateUser)
{
WriteVerbose("Updating User environment variables...");
UpdateFromTarget(EnvironmentVariableTarget.User);
}
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since these strings are mainly for debugging, I am leaving them hardcoded for now, unless strongly required by maintainers.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

@daxian-dbw daxian-dbw added WG-Cmdlets general cmdlet issues WG-NeedsReview Needs a review by the labeled Working Group labels May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

WG-Cmdlets general cmdlet issues WG-NeedsReview Needs a review by the labeled Working Group

Projects

Status: Queue

Development

Successfully merging this pull request may close these issues.

4 participants