I'm trying to change the location of the %LOCALAPPDATA%
environment variable in PowerShell, but the change is not taking effect.
I want to set the LOCALAPPDATA
variable to a new directory (G:\AppData\Local
), but after following several methods, it still shows the default location (C:\Users\username\AppData\Local
) in PowerShell and other applications.
Set the environment variable using [System.Environment]::SetEnvironmentVariable()
:
[System.Environment]::SetEnvironmentVariable("LOCALAPPDATA", "G:\AppData\Local", "User")
Verified the change using echo $env:LOCALAPPDATA
:
Restarted Powershell:
While the paths of known (special) folders are reflected in environment variables, they cannot be changed that way.
Use SHSetKnownFolderPath
to change the location of known folders. It must be invoked via P/Invoke with the KNOWNFOLDERID
(GUID) of the target folder, which from PowerShell requires an Add-Type
call with ad hoc-compiled C# code.
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
) is discouraged and not officially supported, but still seems to work in practice as of Windows 11.%LOCALAPPDATA%
for the current user:(
Add-Type -NameSpace NS$PID -Name KnownFolderPath -PassThru -MemberDefinition @'
[DllImport("shell32.dll")]
public extern static int SHSetKnownFolderPath(ref Guid folderId, uint flags, IntPtr token, [MarshalAs(UnmanagedType.LPWStr)] string path);
'@
)::SHSetKnownFolderPath(
[ref] [guid] '{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}', # folder ID
0, # flags
[IntPtr]::Zero, # target the current user
'G:\AppData\Local' # new path
)
Note:
A return value of 0
indicates success.
The change takes effect:
$env:LOCALAPPDATA
.
Stop-Process -Name explorer -Force
Changing the location of a user-independent well-known folder (e.g., that of %PROGRAMDATA%
) requires elevation (running with administrative privileges)
Changing the location of a well-known folder for a different user requires obtaining an impersonation token for them via the LogonUser
WinAPI function (which would similarly have to be wrapped via P/Invoke in the Add-Type
call) and pass it instead of [IntPtr]::Zero
above; this too requires running with elevation.