I like OneDrive. It allows me to keep my data secure and always synchronized. If things go wrong, I can always get it back. I use it for almost everything. Even for my PowerShell projects, which are committed to GitHub, so in theory, I shouldn't need that. But every once in a while, I make some stupid mistake and delete a file that has yet not been committed to GitHub, and that's where the OneDrive comes in handy. Quick restore, and we're back. Unfortunately, sometimes things aren't as I would expect them to work. For example, let's have a look at this nice list of markdown files that are documentation for my module called GPOZaurr.
Every time I would like to delete that content or anything from PowerShell it would throw me an error
Remove-Item : Access to the cloud file is denied
While I could understand the error if it was a file that is stored in the cloud, it's actually fully available on my drive, just synchronized to OneDrive. It wasn't always like that. It started happening a few months ago, so most likely some update caused it – or maybe it's the great Files On-Demand feature causing this issue. I don't know and I don't even want to go deep and test every possible combination where this happens. All I know is this impacts my scripts, as anything that is supposed to get deleted automatically and, for some reason, is stored on OneDrive gets hit with this error.
It seems the error only happens when trying to delete folders that contain those files.
Remove-Item -LiteralPath "C:\Support\GitHub\GpoZaurr\Docs" -Force -Recurse
It seems the problem comes from a directory, not the files themselves, so using a small workaround using Get-ChildItem to list and then delete all files helps to get rid of all files.
$Items = Get-ChildItem -LiteralPath "C:\Support\GitHub\GpoZaurr\Docs" -Recurse foreach ($Item in $Items) { Remove-Item -LiteralPath $Item.Fullname }
However retrying again deletion of a folder, even without files, still gives an error when using Remove-Item.
Remove-Item -LiteralPath "C:\Support\GitHub\GpoZaurr\Docs" -Force -Recurse
Remove-Item : Access to the cloud file is denied
At C:\Support\GitHub\GpoZaurr\Examples\Test.ps1:10 char:1
Did you know Remove-Item is not the only way to delete files and folders in PowerShell? Using Get-Item or Get-ChildItem, you're able to use Delete() method
$Item = Get-Item -LiteralPath "C:\Support\GitHub\GpoZaurr\Docs" $Item.Delete($true)
To my surprise, the following method worked without a problem. This means to fully delete the folder with all files in it, we can use:
$Items = Get-ChildItem -LiteralPath "C:\Support\GitHub\GpoZaurr\Docs" -Recurse foreach ($Item in $Items) { Remove-Item -LiteralPath $Item.Fullname } $Items = Get-Item -LiteralPath "C:\Support\GitHub\GpoZaurr\Docs" $Items.Delete($true)
Since we're already using the Delete() method for a folder, why not try to do the same for the whole thing?
$Items = Get-ChildItem -LiteralPath "C:\Support\GitHub\GpoZaurr\Docs" -Recurse foreach ($Item in $Items) { $Item.Delete() } $Items = Get-Item -LiteralPath "C:\Support\GitHub\GpoZaurr\Docs" $Items.Delete($true)
Finally, I wanted to have a quick and easy way to reuse my code
function Remove-ItemAlternative { <# .SYNOPSIS Removes all files and folders within given path .DESCRIPTION Removes all files and folders within given path. Workaround for Access to the cloud file is denied issue .PARAMETER Path Path to file/folder .PARAMETER SkipFolder Do not delete top level folder .EXAMPLE Remove-ItemAlternative -Path "C:\Support\GitHub\GpoZaurr\Docs" .EXAMPLE Remove-ItemAlternative -Path "C:\Support\GitHub\GpoZaurr\Docs" .NOTES General notes #> [cmdletbinding()] param( [alias('LiteralPath')][string] $Path, [switch] $SkipFolder ) if ($Path -and (Test-Path -LiteralPath $Path)) { $Items = Get-ChildItem -LiteralPath $Path -Recurse foreach ($Item in $Items) { if ($Item.PSIsContainer -eq $false) { try { $Item.Delete() } catch { Write-Warning "Remove-ItemAlternative - Couldn't delete $($Item.FullName), error: $($_.Exception.Message)" } } } $Items = Get-ChildItem -LiteralPath $Path -Recurse foreach ($Item in $Items) { try { $Item.Delete() } catch { Write-Warning "Remove-ItemAlternative - Couldn't delete $($Item.FullName), error: $($_.Exception.Message)" } } if (-not $SkipFolder) { $Item = Get-Item -LiteralPath $Path try { $Item.Delete($true) } catch { Write-Warning "Remove-ItemAlternative - Couldn't delete $($Item.FullName), error: $($_.Exception.Message)" } } } else { Write-Warning "Remove-ItemAlternative - Path $Path doesn't exists. Skipping. " } }function Remove-ItemAlternative { <# .SYNOPSIS Removes all files and folders within given path .DESCRIPTION Removes all files and folders within given path. Workaround for Access to the cloud file is denied issue .PARAMETER Path Path to file/folder .PARAMETER SkipFolder Do not delete top level folder .EXAMPLE Remove-ItemAlternative -Path "C:\Support\GitHub\GpoZaurr\Docs" .EXAMPLE Remove-ItemAlternative -Path "C:\Support\GitHub\GpoZaurr\Docs" .NOTES General notes #> [cmdletbinding()] param( [alias('LiteralPath')][string] $Path, [switch] $SkipFolder ) if ($Path -and (Test-Path -LiteralPath $Path)) { $Items = Get-ChildItem -LiteralPath $Path -Recurse foreach ($Item in $Items) { if ($Item.PSIsContainer -eq $false) { try { $Item.Delete() } catch { Write-Warning "Remove-ItemAlternative - Couldn't delete $($Item.FullName), error: $($_.Exception.Message)" } } } $Items = Get-ChildItem -LiteralPath $Path -Recurse foreach ($Item in $Items) { try { $Item.Delete() } catch { Write-Warning "Remove-ItemAlternative - Couldn't delete $($Item.FullName), error: $($_.Exception.Message)" } } if (-not $SkipFolder) { $Item = Get-Item -LiteralPath $Path try { $Item.Delete($true) } catch { Write-Warning "Remove-ItemAlternative - Couldn't delete $($Item.FullName), error: $($_.Exception.Message)" } } } else { Write-Warning "Remove-ItemAlternative - Path $Path doesn't exists. Skipping. " } }
It seems I have no other choice than use this alternative approach to delete files and folders from my OneDrive, at least until Microsoft fixes this issue. Hopefully, sooner rather than later. Keep in mind that this function above is fundamental, with minimal error handling. If you intend to use it, make sure to add some error handling yourself. It's supposed to be a workaround rather than a permanent solution.