Handling Path Too Long Exception with New-PSDrive - powershell

I am recursing a deep folder structure in order to retreive all folder paths like so:
$subFolders = Get-ChildItem $rootFolder -Recurse -Directory -ErrorVariable folderErrors | Select-Object -ExpandProperty FullName
NOTE: $rootFolder in my case is a network share. i.e. "\\server\DeptDir$\somefolder"
The $folderErrors variable is correctly capturing all the FileTooLong exceptions so I want to create new PSDrives using the long Paths in order to recurse those long paths.
So I create a new PSDrive using this cmdlet:
new-psdrive -Name "long1" -PSProvider FileSystem -Root $folderErrors[0].CategoryInfo.TargetName
However, after creating a new PSDrive I am still getting PathTooLong Exceptions.
PS C:\>> cd long1:
PS long1:\>> dir
dir : The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.
At line:1 char:1
+ dir
+ ~~~
+ CategoryInfo : ReadError: (\\svr01\Dep...\Fibrebond ECO\:String) [Get-ChildItem], PathTooLongException
+ FullyQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand
I see no other way around this problem. Am I doing something incorrectly? Why is the new PSDrive throwing PathTooLong when I am creating a drive at the location where the path is too long?
Thanks

There is a local policy that is now available since Windows anniversary update.
Requirements are :
Windows Management Framework 5.1
.Net Framework 4.6.2 or more recent
Windows 10 / Windows server 2016 (Build 1607 or newer)
This policy can be enabled using the following snippet.
#GPEdit location: Configuration>Administrative Templates>System>FileSystem
Set-ItemProperty 'HKLM:\System\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -value 1
Otherwise, you can actually get to the paths longer than 260 characters by making your call to the unicode version of Windows API.
There's a catch though.
This work only in Powershell 5.1 minimum.
From there, instead of making your call the standard way:
get-childitem -Path 'C:\Very long path' -Recurse
You will need to use the following prefix:
\\?\
Example
get-childitem -LiteralPath '\\?\C:\Very long path' -Recurse
For UNC path, this is slightly different, the prefix being \\?\UNC\ instead of \\
get-childitem -LiteralPath '\\?\UNC\127.0.0.1\c$\Very long path\' -Recurse
Important
When calling Get-ChildItem unicode version, you should use the -LiteralPath parameter instead of Path
From Microsoft documentation
-LiteralPath
Specifies a path to one or more locations. Unlike the -Path parameter, the value of the -LiteralPath parameter is used exactly as it is typed. No characters are interpreted as wildcards. If the path includes escape characters, enclose them in single quotation marks. Single quotation marks tell Windows PowerShell not to interpret any characters as escape sequences.
source
Example
(get-childitem -LiteralPath '\\?\UNC\127.0.0.1\This is a folder$' -Recurse) |
ft #{'n'='Path length';'e'={$_.FullName.length}}, FullName
output
Here is the actual functional test I made to create the very long repository, query it to produce the output above and confirm I could create repository with more than 260 characters and view them.
Function CreateVeryLongPath([String]$Root,[Switch]$IsUNC,$FolderName = 'Dummy Folder',$iterations = 200) {
$Base = '\\?\'
if ($IsUNC) {$Base = '\\?\UNC\'}
$CurrentPath = $Base + $Root + $FolderName + '\'
For ($i=0;$i -le $iterations;$i++) {
New-Item -Path $CurrentPath -Force -ItemType Directory | Out-Null
$currentPath = $CurrentPath + $FolderName + '\'
}
}
Function QueryVeryLongPath([String]$Root,[Switch]$IsUNC) {
$Base = '\\?\'
if ($IsUNC) {$Base = '\\?\UNC\';$Root = $Root.substring(2,$Root.Length -2)}
$BasePath = $Base + $Root
Get-ChildItem -LiteralPath $BasePath -Recurse | ft #{'n'='Length';'e'={$_.FullName.Length}},FullName
}
CreateVeryLongPath -Root 'C:\__tmp\' -FolderName 'This is a folder'
QueryVeryLongPath -Root 'C:\__tmp\Dummy Folder11\'
#UNC - tested on a UNC share path
CreateVeryLongPath -Root '\\ServerName\ShareName\' -FolderName 'This is a folder' -IsUNC
QueryVeryLongPath -Root '\\ServerName\ShareName\' -IsUNC
Worth to mention
During my research, I saw people mentioning using RoboCopy then parse its output. I am not particularly fond of this approach so I won't elaborate on it.
(edit: Years later, I discovered that Robocopy is part of Windows and not some third-party utility. I guess that would be an ok approach too, although I prefer a pure Powershell solution)
I also saw AlphaFS being mentionned a couple of time which is a library that allows to overcome the 260 characters limitation too. It is open sourced on Github and there's even a (I did not test it though) Get-AlphaFSChildItem built on it available on Technet here
Other references
Long Paths in .Net
Naming Files, Paths, and Namespaces

Related

I want to take the output of Get-PSDrive to get the drive letter of all drives and do a search for ISO's and use the path from the Get-PSDrive

I am trying to use Get-PSDrive to put all the drive letters used by disks into a string that returns each letter (That works)
I am having problems using the $ISODeviceLetter variable to use it as a path to search all drives for .ISO files.
$ISODeviceLetter = Get-PSDrive | Select-Object -ExpandProperty 'Name' | Select-String -Pattern '^[a-z]:$'
$ISOLocation = Get-ChildItem -Path $ISODeviceLetter -Recurse -Include *.ISO
This is the error I get:
Get-ChildItem : Cannot find path 'C:\Users\Administrator\C' because it does not exist.
At line:1 char:16
+ ... OLocation = Get-ChildItem -Path $ISODeviceLetter -Recurse -Include *. ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\Users\Administrator\C:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
I see by the error the get-childitem is using the default location which is the C:\Users\Administrator.
The desired output is to pass $ISODriveLetter as the Path for all drives on the server "C:","D:","E:", so all the drives can be searched for .ISO files.
Thanks ahead of time for the help.
The issue is that when referencing drives, they have to be distinguished using a colon (:) to disambiguate the drive from a regular folder/file:
Use the Foreach-Object command to append the Colon to each drive letter returned.
Changed the filter from -Include to -Filter, to speed up the process as -Filter is implemented by the FileSystemProvider, and you're also not looking for multiple files.
Added -File switch for a more efficient query as well, since an .ISO extension is associated to a file.
$ISODeviceLetter = [array](Get-PSDrive |
Where-Object -FilterScript {$_.Name -match "^.$"}).Foreach{
$_.Name + ':'
}
$ISOLocation = Get-ChildItem -Path $ISODeviceLetter -File -Recurse -Filter *.ISO
Bonus:
You can use Simplified Syntax to achieve the same results as above for better readability:
$ISODeviceLetter = (Get-PSDrive).Where{$_.Name -match "^.$"} |
Select -exp Name | Foreach Insert -ArgumentList 1,':'
Only real "downside" of this is, that you're using the pipeline even more. Even though it may not affect the speed in your return for this example, other time sensitive tasks can take quite a performance hit using the pipeline.

Rename file before copy to certain folder

I´m a newbie still and learning to create PowerShell scripts to make Life in IT easier.
At present I´m trying to build a script, which runs a certain Microsoft tool, scanning defined network shares in a csv file and creating an JSON output file.
Now as the pattern of this file is always the same like "Report_Username_Hostname.vba.JSON", I would like to append either the scanned directory name or even a range of numbers, fe. "Report_Username_Hostname(100).vba.JSON" or "Report_Username_Hostname(sharename).vba.JSON"
This is neccessaray as after this renaming step, I upload this and other files within this folder to another folder on different server to upload them into a Database.
I planned to run this script in in many different locations on most automatic level and they all copy the their collected files to just one upload folder.
I already tried several options I found somewhere in the deep of the Internet, but I only came to the point where the file was renamed to 0 or similar, but not to expected result.
The Powershell script doing the work is this:
$PSpath = 'C:\temp\FileRemediation\Scripts\'
$Rpath = $PSpath +'..\Reports\1st'
$localshare = $PSpath +'..\temp\1st'
$csvinputs = Import-Csv $PSpath\fileremediation_1st.csv
$uploadshare = '\\PGC2EU-WFSFR01.eu1.1corp.org\upload\'
# This section checks if the folder for scan reports is availabe and if not will create necessary folder.
If(!(test-path $Rpath))
{
New-Item -ItemType Directory -Force -Path $Rpath
}
If(!(test-path $localshare))
{
New-Item -ItemType Directory -Force -Path $localshare
}
Set-Location $Rpath
# This section reads input from configuration file and starts Ms ReadinessReportCreator to scan shares in configuration file.
ForEach($csvinput in $csvinputs)
{
$uncshare = $csvinput.sharefolder
$Executeable = Start-Process "C:\Program Files (x86)\Microsoft xxx\xxx.exe" `
-Argumentlist "-p ""$uncshare""", "-r", "-t 10000", "-output ""$localshare"""`
-Wait
Get-ChildItem -Path $localshare -Filter '*.JSON' | Rename-Item -NewName {$_.FullName+$uncshare}
}
# This section copies the output *.JSON file of the xxx to the share, where I they will be uploaded to DB.
Get-ChildItem -Path $localshare -Filter '*.JSON' | Where {$_.Length -ge 3} | move-item -Destination '$uploadshare'
the fileremediation_1st.csv looks like
sharefolder
\\server\sharename
Can someone please help me on this, I don´t have a clue what I´m doing wrong.
Thank you!
Current error I get is
Rename-Item : Cannot rename the specified target, because it
represents a path or device name. At
C:\temp\FileRemediation\scripts\fileremediation_V2_1st.ps1:28 char:55
+ ... share -Filter '*.JSON' | Rename-Item -NewName {$_.FullName+$uncshare}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Rename-Item], PSArgumentException
+ FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.RenameItemCommand
As said before, I would also be fine with a dedicated range of numbers, which is append to the file name "Report_Username_Hostname(100).vba.JSON"
The perfect world would be if I could split the \server\sharename from csv file and append the sharename to my filename.
I think the issue is with:
Rename-Item -NewName {$_.FullName+$uncshare}
Your input file (Get-ChildItem) path is:
$PSpath = 'C:\temp\FileRemediation\Scripts\'
$localshare = $PSpath +'..\temp\1st'
The Rename-Item uses $_.FullName which resolves to something like this:
C:\temp\FileRemediation\Scripts\..\temp\1st\MyFile.JSON
The variables then contain:
$_.FullName = C:\temp\FileRemediation\Scripts\..\temp\1st\MyFile.JSON
$uncshare = "\\server\sharename"
So Your Rename-Item ... $_.FullName+$uncshare will try to rename it to:
C:\temp\FileRemediation\Scripts\..\temp\1st\MyFile.JSON\\server\sharename
Which is not a valid path.

Get-ChildItem and wildcards and filtering

I have two different ways of getting files with a wildcard pattern:
Get-ChildItem "$ActivityLogDirectory/*.csv"
and
Get-ChildItem "$ActivityLogDirectory" -Filter *.csv
I prefer to use the latter instead of the former because the former (Get-ChildItem "$ActivityLogDirectory/*.csv") has, on occasion, given me a permission denied error.
They both appear to return the same results, but when I try to compress the resulting files with this command:
Compress-Archive -Update -Path $CsvFiles -DestinationPath C:\Users\admin\Downloads\foo.zip
the former succeeds while the latter fails with the following error:
Compress-Archive : The path 'rgb dev automation store a_1-1_2194_20181120.csv'
either does not exist or is not a valid file system path.
At line:1 char:1
+ Compress-Archive -Update -Path $CsvFiles -DestinationPath C:\Users\ad ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (rgb dev automat...94_20181120.csv:String) [Compress-Archive], InvalidOperationException
+ FullyQualifiedErrorId : ArchiveCmdletPathNotFound,Compress-Archive
So what's the difference between these two ways of getting a listing of files using wildcards? Or perhaps asked another way, why does using -Filter *.csv cause the Compress-Archive cmdlet to fail?
The reason you're seeing different behavior is the - obscurely situational - stringification behavior of the objects output by Get-ChildItem:
This answer details when Get-ChildItem output happens to stringify to a mere filename vs. a full path, and it so happens that Get-ChildItem "$ActivityLogDirectory" -Filter *.csv stringifies to mere filenames.
The workaround is to explicitly stringify the objects as their full paths via their FullName property (PSv3+ syntax):
$CsvFiles = (Get-ChildItem "$ActivityLogDirectory" -Filter *.csv).FullName
If you are running this from a shell with the location of the folder where the CSV files are located then this will work. What you are doing by passing the $CsvFiles variable into Compress-Archive is trying to run against the file name in the current context. To fix this pass the full path $CsvFiles.FullName:
$Csvfiles = (Get-Childitem $ActivityLogDirectory -Filter *.csv)
Compress-Archive -Update -Path $Csvfiles.fullname -DestinationPath C:\Users\admin\Downloads\foo.zip

Powershell can't copy existing file

Have a strange issue crop up last week and can't find a solution. I have a modified version of this script: http://technet.microsoft.com/en-us/magazine/2009.07.heyscriptingguy.aspx running my log backups across 500 servers. Last week, 6 servers in the EMEA region decided that they didn't want to allow the files to be copied over.
The script processes one script a time and is failing with the copy-item cmdlet. The file does exist on the remote server. Take a look at the output below:
PS C:\> BackUpAndClearEventLogsDebug.ps1 -computers bud1s001 -LogsArchive "\\srv1s001\d$\Log_Backups\Test"
+ Processing bud1s001
This is the Backupeventlogs function and we're about to copy \\bud1s001\c$\Windows\temp\bud1s001\Application.evt
This is the Copyeventlogs function and we're about to copy \\bud1s001\c$\Windows\temp\bud1s001\Application.evt
Copy-Item : Cannot find path '\\bud1s001\c$\Windows\temp\bud1s001\Application.evt' because it does not exist.
At C:\Sched\LOG_BACKUPS\BackUpAndClearEventLogsDebug.ps1:132 char:2
+ Copy-Item -path $path -dest "$LogsArchive\$folder"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (\\bud1s001\c$\W...Application.evt:String) [Copy-Item], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.CopyItemCommand
PS C:\> ls \\bud1s001\c$\Windows\temp\bud1s001\Application.evt
Directory: \\bud1s001\c$\Windows\temp\bud1s001
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2/17/2014 10:17 AM 5242836 Application.evt
If I set the variables in an interactive shell I can run the copy-item cmd with no problems. If I use the same arguments but not variables I can copy the files. It is only when run within the script that the failure happens.
I've tried running under different accounts, all of which are administrators. I changed the -path argument to -LiteralPath with no change. I've added output to make sure that the object isn't getting its value changed and everything looks good. The servers that are failing could have different language settings since they are not in the US, but the variable looks good. Only having issues with Windows 2003 servers, not issues with 2008 servers.
I'm out of ideas, open to suggestions.
Here is the exact function from the script with calling argument
Copy-EventLogsToArchive -path $path -Folder $Folder
Function Copy-EventLogsToArchive($path, $folder)
{
Write-Host " "
write-host "This is the Copyeventlogs function and we're about to copy $path"
Copy-Item -path $path -dest "$LogsArchive\$folder"
} # end Copy-EventLogsToArchive
Have you tried using Test-Path to verify the existence of the target file path, before calling Copy-Item?
Function Copy-EventLogsToArchive
{
[CmdletBinding()]
param ( [string] $Path, [string] $folder)
Write-Host -Object "`nThis is the Copyeventlogs function and we're about to copy $path";
if (Test-Path -Path $Path) {
Copy-Item -Path $Path -Destination "$LogsArchive\$folder";
}
} # end Copy-EventLogsToArchive
Copy-EventLogsToArchive -Path $Path -Folder $Folder;
The behavior you are describing is rather odd. How about bypassing the Copy-Item cmdlet, and going straight to the .NET Framework to copy the file?
[System.IO.File]::Copy($Path, "$LogsArchive\$Folder");
Side note: You should generally put your function calls after the function definition in PowerShell. If you make a change to the function definition, but your function call occurs before the definition, then your old function definition will be called when you execute the script.

Delete directory regardless of 260 char limit

I'm writing a simple script to delete USMT migration folders after a certain amount of days:
## Server List ##
$servers = "Delorean","Adelaide","Brisbane","Melbourne","Newcastle","Perth"
## Number of days (-3 is over three days ago) ##
$days = -3
$timelimit = (Get-Date).AddDays($days)
foreach ($server in $servers)
{
$deletedusers = #()
$folders = Get-ChildItem \\$server\USMT$ | where {$_.psiscontainer}
write-host "Checking server : " $server
foreach ($folder in $folders)
{
If ($folder.LastWriteTime -lt $timelimit -And $folder -ne $null)
{
$deletedusers += $folder
Remove-Item -recurse -force $folder.fullname
}
}
write-host "Users deleted : " $deletedusers
write-host
}
However I keep hitting the dreaded Remove-Item : The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.
I've been looking at workarounds and alternatives but they all revolve around me caring what is in the folder.
I was hoping for a more simple solution as I don't really care about the folder contents if it is marked for deletion.
Is there any native Powershell cmdlet other than Remove-Item -recurse that can accomplish what I'm after?
I often have this issue with node projects. They nest their dependencies and once git cloned, it's difficult to delete them. A nice node utility I came across is rimraf.
npm install rimraf -g
rimraf <dir>
Just as CADII said in another answer: Robocopy is able to create paths longer than the limit of 260 characters. Robocopy is also able to delete such paths. You can just mirror some empty folder over your path containing too long names in case you want to delete it.
For example:
robocopy C:\temp\some_empty_dir E:\temp\dir_containing_very_deep_structures /MIR
Here's the Robocopy reference to know the parameters and various options.
I've created a PowerShell function that is able to delete a long path (>260) using the mentioned robocopy technique:
function Remove-PathToLongDirectory
{
Param(
[string]$directory
)
# create a temporary (empty) directory
$parent = [System.IO.Path]::GetTempPath()
[string] $name = [System.Guid]::NewGuid()
$tempDirectory = New-Item -ItemType Directory -Path (Join-Path $parent $name)
robocopy /MIR $tempDirectory.FullName $directory | out-null
Remove-Item $directory -Force | out-null
Remove-Item $tempDirectory -Force | out-null
}
Usage example:
Remove-PathToLongDirectory c:\yourlongPath
This answer on SuperUser solved it for me: https://superuser.com/a/274224/85532
Cmd /C "rmdir /S /Q $myDir"
I learnt a trick a while ago that often works to get around long file path issues. Apparently when using some Windows API's certain functions will flow through legacy code that can't handle long file names. However if you format your paths in a particular way, the legacy code is avoided. The trick that solves this problem is to reference paths using the "\\?\" prefix. It should be noted that not all API's support this but in this particular case it worked for me, see my example below:
The following example fails:
PS D:\> get-childitem -path "D:\System Volume Information\dfsr" -hidden
Directory: D:\System Volume Information\dfsr
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a-hs 10/09/2014 11:10 PM 834424 FileIDTable_2
-a-hs 10/09/2014 8:43 PM 3211264 SimilarityTable_2
PS D:\> Remove-Item -Path "D:\System Volume Information\dfsr" -recurse -force
Remove-Item : The specified path, file name, or both are too long. The fully qualified file name must be less than 260
characters, and the directory name must be less than 248 characters.
At line:1 char:1
+ Remove-Item -Path "D:\System Volume Information\dfsr" -recurse -force
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (D:\System Volume Information\dfsr:String) [Remove-Item], PathTooLongExcepti
on
+ FullyQualifiedErrorId : RemoveItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
PS D:\>
However, prefixing the path with "\\?\" makes the command work successfully:
PS D:\> Remove-Item -Path "\\?\D:\System Volume Information\dfsr" -recurse -force
PS D:\> get-childitem -path "D:\System Volume Information\dfsr" -hidden
PS D:\>
If you have ruby installed, you can use Fileman:
gem install fileman
Once installed, you can simply run the following in your command prompt:
fm rm your_folder_path
This problem is a real pain in the neck when you're developing in node.js on Windows, so fileman becomes really handy to delete all the garbage once in a while
This is a known limitation of PowerShell. The work around is to use dir cmd (sorry, but this is true).
http://asysadmin.tumblr.com/post/17654309496/powershell-path-length-limitation
or as mentioned by AaronH answer use \?\ syntax is in this example to delete build
dir -Include build -Depth 1 | Remove-Item -Recurse -Path "\\?\$($_.FullName)"
If all you're doing is deleting the files, I use a function to shorten the names, then I delete.
function ConvertTo-ShortNames{
param ([string]$folder)
$name = 1
$items = Get-ChildItem -path $folder
foreach ($item in $items){
Rename-Item -Path $item.FullName -NewName "$name"
if ($item.PSIsContainer){
$parts = $item.FullName.Split("\")
$folderPath = $parts[0]
for ($i = 1; $i -lt $parts.Count - 1; $i++){
$folderPath = $folderPath + "\" + $parts[$i]
}
$folderPath = $folderPath + "\$name"
ConvertTo-ShortNames $folderPath
}
$name++
}
}
I know this is an old question, but I thought I would put this here in case somebody needed it.
There is one workaround that uses Experimental.IO from Base Class Libraries project. You can find it over on poshcode, or download from author's blog. 260 limitation is derived from .NET, so it's either this, or using tools that do not depend on .NET (like cmd /c dir, as #Bill suggested).
Combination of tools can work best, try doing a dir /x to get the 8.3 file name instead. You could then parse out that output to a text file then build a powershell script to delete the paths that you out-file'd. Take you all of a minute. Alternatively you could just rename the 8.3 file name to something shorter then delete.
For my Robocopy worked in 1, 2 and 3
First create an empty directory lets say c:\emptydir
ROBOCOPY c:\emptydir c:\directorytodelete /purge
rmdir c:\directorytodelete
This is getting old but I recently had to work around it again. I ended up using 'subst' as it didn't require any other modules or functions be available on the PC this was running from. A little more portable.
Basically find a spare drive letter, 'subst' the long path to that letter, then use that as the base for GCI.
Only limitation is that the $_.fullname and other properties will report the drive letter as the root path.
Seems to work ok:
$location = \\path\to\long\
$driveLetter = ls function:[d-z]: -n | ?{ !(test-path $_) } | random
subst $driveLetter $location
sleep 1
Push-Location $driveLetter -ErrorAction SilentlyContinue
Get-ChildItem -Recurse
subst $driveLetter /D
That command is obviously not to delete files but can be substituted.
PowerShell can easily be used with AlphaFS.dll to do actual file I/O stuff
without the PATH TOO LONG hassle.
For example:
Import-Module <path-to-AlphaFS.dll>
[Alphaleonis.Win32.Filesystem.Directory]::Delete($path, $True)
Please see at Codeplex: https://alphafs.codeplex.com/ for this .NET project.
I had the same issue while trying to delete folders on a remote machine.
Nothing helped but... I found one trick :
# 1:let's create an empty folder
md ".\Empty" -erroraction silentlycontinue
# 2: let's MIR to the folder to delete : this will empty the folder completely.
robocopy ".\Empty" $foldertodelete /MIR /LOG+:$logname
# 3: let's delete the empty folder now:
remove-item $foldertodelete -force
# 4: we can delete now the empty folder
remove-item ".\Empty" -force
Works like a charm on local or remote folders (using UNC path)
Adding to Daniel Lee's solution,
When the $myDir has spaces in the middle it gives FILE NOT FOUND errors considering set of files splitted from space. To overcome this use quotations around the variable and put powershell escape character to skip the quatations.
PS>cmd.exe /C "rmdir /s /q <grave-accent>"$myDir<grave-accent>""
Please substitute the proper grave-accent character instead of <grave-accent>
SO plays with me and I can't add it :). Hope some one will update it for others to understand easily
Just for completeness, I have come across this a few more times and have used a combination of both 'subst' and 'New-PSDrive' to work around it in various situations.
Not exactly a solution, but if anyone is looking for alternatives this might help.
Subst seems very sensitive to which type of program you are using to access the files, sometimes it works and sometimes it doesn't, seems to be the same with New-PSDrive.
Any thing developed using .NET out of the box will fail with paths too long. You will have to move them to 8.3 names, PInVoke (Win32) calls, or use robocopy