Private/Environment/Send-EnvironmentChange.ps1

function Send-EnvironmentChange {
    <#
    .SYNOPSIS
    Tells the open programs, such as Explorer, that the environment variables of the user changed.

    .DESCRIPTION
    Programs read the environment when they start. Explorer passes its own copy to the
    terminals it opens, so without this notice they keep the old Path until the next logon.

    .EXAMPLE
    Send-EnvironmentChange

    .LINK
    https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-sendmessagetimeoutw

    .LINK
    https://learn.microsoft.com/windows/win32/winmsg/wm-settingchange
    #>

    [CmdletBinding()]
    param()

    $isNotifierLoaded = [bool] ('WinPlaybook.EnvironmentNotifier' -as [type])
    if (-not $isNotifierLoaded) {
        $declaration = @(
            '[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]'
            'public static extern IntPtr SendMessageTimeout('
            ' IntPtr window,'
            ' uint message,'
            ' UIntPtr unusedParameter,'
            ' string changedSetting,'
            ' uint flags,'
            ' uint timeoutMilliseconds,'
            ' out UIntPtr result'
            ');'
        ) -join [Environment]::NewLine
        Add-Type -Namespace 'WinPlaybook' -Name 'EnvironmentNotifier' -MemberDefinition $declaration
    }

    $result = [UIntPtr]::Zero
    [WinPlaybook.EnvironmentNotifier]::SendMessageTimeout(
        [IntPtr] 0xffff,   # HWND_BROADCAST: every top-level window
        0x1A,              # WM_SETTINGCHANGE
        [UIntPtr]::Zero,   # not used by this message
        'Environment',     # the setting that changed
        2,                 # SMTO_ABORTIFHUNG
        200,               # wait per window, in milliseconds
        [ref] $result
    ) | Out-Null
}