You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
PowerShell doesn't delete file in $env:TEMP if account contains a cyrillic char #21070
If a user account contains a Cyrillic char in its name, PowerShell is unable to remove any file in $env:TEMP folder with command Remove-Item "$env:TEMP\1.txt" -Force.
The issue cannot be reproduced with $env:LOCALAPPDATA and $env:APPDATA.
Added on 16.01.2024
It turned out, if a username has the first capital letter Тест (not тест), the bug cannot be reproduced!
Expected behavior
File should be removed.
Actual behavior
Remove-Item: An object at the specified path C:\Users\FF6D~1 does not exist.
Error details
PS C:\Users\тест> get-errorException : Type : System.Management.Automation.PSArgumentException ErrorRecord : Exception : Type :System.Management.Automation.ParentContainsErrorRecordException Message : An object at the specified path C:\Users\FF6D~1 doesnot exist. HResult : -2146233087 CategoryInfo : InvalidArgument: (:) [],ParentContainsErrorRecordException FullyQualifiedErrorId : Argument Message : An object at the specified path C:\Users\FF6D~1 does notexist. ParamName : path TargetSite : Name : NormalizeThePath DeclaringType : Microsoft.PowerShell.Commands.FileSystemProvider MemberType : Method Module : System.Management.Automation.dll Source : System.Management.Automation HResult : -2147024809 StackTrace : atMicrosoft.PowerShell.Commands.FileSystemProvider.NormalizeThePath(Stringbasepath, Stack`1 tokenizedPathStack) at Microsoft.PowerShell.Commands.FileSystemProvider.NormalizeRelativePathHelper(String path, String basePath)CategoryInfo : InvalidArgument: (:) [Remove-Item],PSArgumentExceptionFullyQualifiedErrorId :Argument,Microsoft.PowerShell.Commands.RemoveItemCommandInvocationInfo : MyCommand : Remove-Item ScriptLineNumber : 1 OffsetInLine : 1 HistoryId : 1 Line : Remove-Item "$env:TEMP\1.txt" -Force Statement : Remove-Item "$env:TEMP\1.txt" -Force PositionMessage : At line:1 char:1 + Remove-Item "$env:TEMP\1.txt" -Force + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ InvocationName : Remove-Item CommandOrigin : InternalScriptStackTrace : at <ScriptBlock>, <No file>: line 1
Environment data
Name Value
---------
PSVersion 7.4.1
PSEdition Core
GitCommitId 7.4.1
OS Microsoft Windows 10.0.22631
Platform Win32NT
PSCompatibleVersions {1.0,2.0,3.0,4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
changed the title [-]PowerShell doesn't delete file in $env:TEMP in account contains cyrillic chars[/-][+]PowerShell doesn't delete file in $env:TEMP if account contains cyrillic chars[/+]on Jan 14, 2024
changed the title [-]PowerShell doesn't delete file in $env:TEMP if account contains cyrillic chars[/-][+]PowerShell doesn't delete file in $env:TEMP if account contains a cyrillic char[/+]on Jan 14, 2024
I encountered a similar issue with a coworker. His name is JT, two consecutive capital letters, and he was encountering the exact same issue trying to delete a file in the temp directory. We applied the workaround described above and were able to get past it.
Root cause located — the character set is a red herring
I reproduced this on Windows 11 (build 26200) + PowerShell 7.6.6 and traced it to a single
length heuristic in FileSystemProvider.NormalizeThePath. The trigger is not Cyrillic
characters, and not non-ASCII characters at all. It is 8.3 short names that expand to a shorter long name.
Minimal reproduction — pure ASCII, no special account name required
# long name is 1 char, short name is 3 chars$d="$env:TEMP\a"New-Item-ItemType Directory -Force -Path $d|Out-Null
fsutil file setshortname "$d""A~1"Set-Content"$env:TEMP\A~1\p.txt"-Value x
Remove-Item"$env:TEMP\A~1\p.txt"-Force
# Remove-Item: An object at the specified path C:\Users\<user>\AppData\Local\Temp\A~1 does not exist.Test-Path"$env:TEMP\A~1\p.txt"# True — the file is still there
The same thing with a non-ASCII name (the shape from the original report):
$d="$env:TEMP\测试目录"# long: 4 charsNew-Item-ItemType Directory -Force -Path $d|Out-Null
fsutil file setshortname "$d""CESHI~1"# short: 7 charsSet-Content"$env:TEMP\CESHI~1\p.txt"-Value x
Remove-Item"$env:TEMP\CESHI~1\p.txt"-Force
# Remove-Item: An object at the specified path ...\Temp\CESHI~1 does not exist.
The exact condition
long name
short name
resolved FullName
shorter than input?
Remove-Item
a
A~1
a (1)
yes (3 → 1)
❌ fails
测试目录
CESHI~1
测试目录 (4)
yes (7 → 4)
❌ fails
abcdefghij
ABCDEF~1
abcdefghij (10)
no (8 → 10)
✅ works
asciiProbe
ASCIPR~1
asciiProbe (10)
no (8 → 10)
✅ works
It fails iff len(resolved long name) < len(short name). Non-ASCII account names are the
common real-world trigger only because a 4-character UTF-16 name like тест almost always gets
a longer ASCII short name (FF6D~1). That also explains the "capitalized Тест does not
reproduce" observation in the thread — what matters is the resulting short/long name lengths,
not the casing.
Only Remove-Item is affected
Path component is a short name longer than its long name (CESHI~1 → 测试目录):
call
result
Test-Path
✅
Get-Item
✅
Remove-Item <path>
❌ "does not exist"
Remove-Item -LiteralPath <path>
❌ "does not exist"
Remove-Item 'p.txt' after Set-Location <short>
❌ "does not exist"
Get-Item <path> | Remove-Item
✅
[System.IO.File]::Delete(<path>)
✅
cmd /c del <path>
✅
The filesystem, the .NET BCL, cmd.exe and PowerShell's own Get-Item all resolve the short
name correctly. Only Remove-Item's path normalization fails.
Root cause
src/System.Management.Automation/namespaces/FileSystemProvider.cs, NormalizeThePath(string basepath, Stack<string> tokenizedPathStack) — the guard at L5688:
currentPath=MakePath(currentPath,childName);varfsinfo=GetFileSystemInfo(currentPath,outbool_);if(fsinfo!=null){// This might happen if you've passed a child name of two or more dots,// which the .NET APIs treat as the parent directoryif(fsinfo.FullName.Length<currentPath.Length)// ← L5688{throwPSTraceSource.NewArgumentException("path",FileSystemProviderStrings.ItemDoesNotExist,currentPath);}// Expand the short file nameif(fsinfo.Name.Length>=childName.Length){childName=fsinfo.Name;}}
The guard is a heuristic meant to catch a child token such as .... that the .NET APIs treated
as a parent directory reference — in that case fsinfo.FullName points at an ancestor and is
therefore "shorter". It assumes a shorter FullName can only mean an ancestor.
An 8.3 short name breaks that assumption. GetFileSystemInfo returns a DirectoryInfo, whose FullName is the expanded long name. When the long name is shorter in characters than the
short name, the guard fires and reports ItemDoesNotExist for an item that exists and is
exactly the one requested:
Note that the next statement in the same block already performs short-name expansion
correctly and correctly declines to expand when the long name is shorter — the L5688 guard runs
first and never gives it the chance.
Suggested fix
The guard needs to distinguish "this is an ancestor due to over-normalization" from "this is the
same item, spelled with a short name". A short-name expansion keeps the same number of path
components; an over-normalized path has fewer. So comparing component counts (or comparing
against the expanded currentPath) instead of raw character lengths would be immune to this.
Assigning currentPath = fsinfo.FullName before the comparison would also make it meaningful,
since fsinfo.FullName is already the correctly resolved path.
A regression test can be built with the a / A~1 pair above — no non-ASCII characters, no
locale or account-name dependence.
Environment
Windows 11 build 26200, NTFS with 8.3 short-name generation enabled
PowerShell 7.6.6 (stable)
Verified with fsutil file setshortname on directories under $env:TEMP
Reacted by Thomas Lee, Michael Klement and Dmitry Nefedov
Confirming the root cause analysis above (len(long name) < len(short name)) with a real-world, pure-ASCII trigger and
two additional observations that may help scope the fix.
Environment: PowerShell 7.6.6, Windows 11 (build 26200), NTFS with 8.3 names enabled.
Real-world trigger without any special characters: a domain account of the form f.lastname (a dot in the name).
Windows gives the profile folder an 8.3 alias like F12AB~1.XYZ and sets TEMP/TMP to the short form
(C:\Users\F12AB~1.XYZ\AppData\Local\Temp). The long name (f.lastname, 10 chars) is shorter than the short name
(F12AB~1.XYZ, 11 chars), so every path under $env:TEMP hits the bug.
1. Move-Item is affected as well, not only Remove-Item:
call (path under the 8.3 profile alias)
result
Test-Path -LiteralPath
✅
Get-Item -LiteralPath
✅
Copy-Item -LiteralPath
✅
Move-Item -LiteralPath
❌ An object at the specified path C:\Users\F12AB~1.XYZ does not exist.
Remove-Item -LiteralPath
❌ same error, FullyQualifiedErrorId: Argument,Microsoft.PowerShell.Commands.RemoveItemCommand
2. It depends on the current location's drive: with the current location on the same drive as the target
(Set-Location C:\), Move-Item/Remove-Item fail; with the current location on another drive
(Set-Location D:\), the identical calls succeed. This presumably steers which branch of the path normalization runs.
Repro (uses GetShortPathName instead of fsutil file setshortname, so it needs no admin rights; it reproduces
whenever $env:TEMP itself is in the problematic 8.3 form):
Workarounds we use: expand the path first — [IO.Path]::GetFullPath($p) already returns the long form on
.NET 8, also for not-yet-existing files — or call [IO.File]::Move/Delete directly.
Activity
[-]PowerShell doesn't delete file in $env:TEMP in account contains cyrillic chars[/-][+]PowerShell doesn't delete file in $env:TEMP if account contains cyrillic chars[/+][-]PowerShell doesn't delete file in $env:TEMP if account contains cyrillic chars[/-][+]PowerShell doesn't delete file in $env:TEMP if account contains a cyrillic char[/+]michael-o commentedon Jan 14, 2024
After more than 30 years Windows still cannot get the 8.3 limitation and Unicode straight...
mklement0 commentedon Jan 14, 2024
The bug also affects Windows PowerShell, and switching from the (positionally implied)
-Pathparameter to-LiteralPathdoesn't make a difference.It's not a fundamental problem, however, given the following workaround:
farag2 commentedon Jan 14, 2024
Use the same workaround in my module.
237dmitry commentedon Jan 14, 2024
Intersting, does this work?
PS. Use utf-8 as system wide locale, 2024 already.
farag2 commentedon Jan 14, 2024
It works in CMD.
237dmitry commentedon Jan 14, 2024
I am about pwsh
farag2 commentedon Jan 14, 2024
тестmeanstestin Russian. It's a VM in Hyper-V.237dmitry commentedon Jan 14, 2024
Ok, I thought it might be possible using PSDrive
temp:this would worknot
temp\1.txtbuttemp:\1.txtfarag2 commentedon Jan 14, 2024
I will until the bug will be fixed properly. I'm OK to use now
Get-Item $env:TEMP\1.txt | Remove-Itemin the code.mklement0 commentedon Jan 14, 2024
Dmitry Nefedov (@farag2), a tip for future issues:
Given the comments above, the bug seems to come down to this:
Remove-Item...TEMPenvironment variable.cmd.exe's internaldelcommand does not have this problemTemp:drive works fineRemove-Item $env:USERPROFILE\AppData\Local\Temp\1.txt, given that$env:USERPROFILEdoes not use an 8.3 pathfarag2 commentedon Jan 16, 2024
It turned out, if a username has the first capital letter
Тест(notтест), the bug cannot be reproduced!farag2 commentedon Jan 23, 2024
jascott1717 commentedon Feb 16, 2024
I encountered a similar issue with a coworker. His name is JT, two consecutive capital letters, and he was encountering the exact same issue trying to delete a file in the temp directory. We applied the workaround described above and were able to get past it.
farag2 commentedon Feb 23, 2024
farag2 commentedon May 25, 2024
farag2 commentedon Oct 31, 2024
farag2 commentedon Jan 16, 2025
farag2 commentedon Jan 25, 2025
farag2 commentedon May 17, 2025
farag2 commentedon Oct 21, 2025
farag2 commentedon May 10, 2026
The issue still persists in PowerShell 7.7.0-preview.1.
haigou-web commentedon Oct 6, 2026
Root cause located — the character set is a red herring
I reproduced this on Windows 11 (build 26200) + PowerShell 7.6.6 and traced it to a single
length heuristic in
FileSystemProvider.NormalizeThePath. The trigger is not Cyrilliccharacters, and not non-ASCII characters at all. It is 8.3 short names that expand to a
shorter long name.
Minimal reproduction — pure ASCII, no special account name required
The same thing with a non-ASCII name (the shape from the original report):
The exact condition
FullNameRemove-ItemaA~1a(1)测试目录CESHI~1测试目录(4)abcdefghijABCDEF~1abcdefghij(10)asciiProbeASCIPR~1asciiProbe(10)It fails iff
len(resolved long name) < len(short name). Non-ASCII account names are thecommon real-world trigger only because a 4-character UTF-16 name like
тестalmost always getsa longer ASCII short name (
FF6D~1). That also explains the "capitalizedТестdoes notreproduce" observation in the thread — what matters is the resulting short/long name lengths,
not the casing.
Only
Remove-Itemis affectedPath component is a short name longer than its long name (
CESHI~1→测试目录):Test-PathGet-ItemRemove-Item <path>Remove-Item -LiteralPath <path>Remove-Item 'p.txt'afterSet-Location <short>Get-Item <path> | Remove-Item[System.IO.File]::Delete(<path>)cmd /c del <path>The filesystem, the .NET BCL,
cmd.exeand PowerShell's ownGet-Itemall resolve the shortname correctly. Only
Remove-Item's path normalization fails.Root cause
src/System.Management.Automation/namespaces/FileSystemProvider.cs,NormalizeThePath(string basepath, Stack<string> tokenizedPathStack)— the guard at L5688:The guard is a heuristic meant to catch a child token such as
....that the .NET APIs treatedas a parent directory reference — in that case
fsinfo.FullNamepoints at an ancestor and istherefore "shorter". It assumes a shorter
FullNamecan only mean an ancestor.An 8.3 short name breaks that assumption.
GetFileSystemInforeturns aDirectoryInfo, whoseFullNameis the expanded long name. When the long name is shorter in characters than theshort name, the guard fires and reports
ItemDoesNotExistfor an item that exists and isexactly the one requested:
Note that the next statement in the same block already performs short-name expansion
correctly and correctly declines to expand when the long name is shorter — the L5688 guard runs
first and never gives it the chance.
Suggested fix
The guard needs to distinguish "this is an ancestor due to over-normalization" from "this is the
same item, spelled with a short name". A short-name expansion keeps the same number of path
components; an over-normalized path has fewer. So comparing component counts (or comparing
against the expanded
currentPath) instead of raw character lengths would be immune to this.Assigning
currentPath = fsinfo.FullNamebefore the comparison would also make it meaningful,since
fsinfo.FullNameis already the correctly resolved path.A regression test can be built with the
a/A~1pair above — no non-ASCII characters, nolocale or account-name dependence.
Environment
fsutil file setshortnameon directories under$env:TEMPgitnol commentedon Oct 8, 2026
Confirming the root cause analysis above (
len(long name) < len(short name)) with a real-world, pure-ASCII trigger andtwo additional observations that may help scope the fix.
Environment: PowerShell 7.6.6, Windows 11 (build 26200), NTFS with 8.3 names enabled.
Real-world trigger without any special characters: a domain account of the form
f.lastname(a dot in the name).Windows gives the profile folder an 8.3 alias like
F12AB~1.XYZand setsTEMP/TMPto the short form(
C:\Users\F12AB~1.XYZ\AppData\Local\Temp). The long name (f.lastname, 10 chars) is shorter than the short name(
F12AB~1.XYZ, 11 chars), so every path under$env:TEMPhits the bug.1.
Move-Itemis affected as well, not onlyRemove-Item:Test-Path -LiteralPathGet-Item -LiteralPathCopy-Item -LiteralPathMove-Item -LiteralPathAn object at the specified path C:\Users\F12AB~1.XYZ does not exist.Remove-Item -LiteralPathFullyQualifiedErrorId: Argument,Microsoft.PowerShell.Commands.RemoveItemCommand2. It depends on the current location's drive: with the current location on the same drive as the target
(
Set-Location C:\),Move-Item/Remove-Itemfail; with the current location on another drive(
Set-Location D:\), the identical calls succeed. This presumably steers which branch of the path normalization runs.Repro (uses
GetShortPathNameinstead offsutil file setshortname, so it needs no admin rights; it reproduceswhenever
$env:TEMPitself is in the problematic 8.3 form):Workarounds we use: expand the path first —
[IO.Path]::GetFullPath($p)already returns the long form on.NET 8, also for not-yet-existing files — or call
[IO.File]::Move/Deletedirectly.