Getting OneDrive files dehydrated can be a challenge, especially with multiuser environments like AVD or legacy RDS. For some reason Microsoft haven’t provided proper tooling for this and finding how to do it can also be challenging.
There is for example this tool that can do the cleanups for you:
OneDrive Clean-Up for Azure Virtual Desktop | ITProCloud Blog
But if you are as paranoid as I, you won’t easily trust to binary blobs that someone else has created and sharing at Internet. Note that I’m not in any way saying that above site cannot be trusted, very likely it can be.
I have come up with a PowerShell script, main part of that I got from a collegue (likely he got that somewhere else) and other part that I improved with help of ChatGPT (since I’m a bit lazy when I can utilize tools). The script runs inside the user session and is very suitable to be used for example as logoff script:
$Code = @' using System;[FlagsAttribute] public enum FileAttributesEx : uint { Readonly = 0x00000001, Hidden = 0x00000002, System = 0x00000004, Directory = 0x00000010, Archive = 0x00000020, Device = 0x00000040, Normal = 0x00000080, Temporary = 0x00000100, SparseFile = 0x00000200, ReparsePoint = 0x00000400, Compressed = 0x00000800, Offline = 0x00001000, NotContentIndexed = 0x00002000, Encrypted = 0x00004000, IntegrityStream = 0x00008000, Virtual = 0x00010000, NoScrubData = 0x00020000, EA = 0x00040000, Pinned = 0x00080000, Unpinned = 0x00100000, U200000 = 0x00200000, RecallOnDataAccess = 0x00400000, U800000 = 0x00800000, U1000000 = 0x01000000, U2000000 = 0x02000000, U4000000 = 0x04000000, U8000000 = 0x08000000, U10000000 = 0x10000000, U20000000 = 0x20000000, U40000000 = 0x40000000, U80000000 = 0x80000000 } '@ # Check if the type 'FileAttributesEx' already exists before adding it if (-not ([System.Management.Automation.PSTypeName]'FileAttributesEx').Type) { Add-Type $Code } # Escape OneDrive path to handle special characters $escapedOneDrivePath = [System.Management.Automation.WildcardPattern]::Escape($env:OneDrive) # Create a DirectoryInfo object for the OneDrive path $oneDriveDirectory = New-Object System.IO.DirectoryInfo $escapedOneDrivePath # Get list of files $files = $oneDriveDirectory.GetFiles("*.*", "AllDirectories") | Where-Object {!$_.PSIsContainer} foreach ($file in $files) { # Get file attributes $attributes = [FileAttributesEx]$file.Attributes # Check file attributes if (($attributes -band [FileAttributesEx]::Unpinned) -eq 0 -or ($attributes -band [FileAttributesEx]::Offline) -eq 0 -and ($attributes -band [FileAttributesEx]::RecallOnDataAccess) -eq 0) { # Apply changes to the file attrib.exe $file.FullName +U -P /S } }
Nothing prevents you to use Group Policy and schedule it as a task that runs for users, but personally I think it is good enough to run it only during the logoff. This way it will not affect to the user session at all since it happens when user has stopped his/her work.
To set the Group Policy logoff script just open GPMC and select existing or create new GPO. In the User Configuration side go to Policies -> Windows Settings -> Scripts (Logon/Logoff). Open the Logoff settings and add the script to PowerShell tab. If you aren’t using SYSVOL for storage location and using a normal file share instead, remember to give suitable user group or Authenticated Users read+execute permissions to it.
Please note that running PowerShell scripts as logon or logoff scripts can be tricky unless you use code signing or allow PowerShell scripts to run as ExecutionPolicy set to Bypass. However bypassing the execution policy is not advisable… If you cannot use code signing and run it as a trusted script, you can create legacy .cmd file as wrapper for PowerShell which I think is slightly better than just allowing all unsigned scripts to run. Your wrapper.cmd needs to have only one row:
powershell -WindowStyle Hidden -NonInteractive -NoProfile -ExecutionPolicy Bypass -File "OneDrive_Dehydration_Single_User.ps1"
You can include full UNC path of the PS1 file in the script. And if you use wrapper, add it to Scripts tab of Logoff scripts window, not PowerShell Scripts.
Also remember that User Configuration GPOs need to be located to the same OU where user accounts are, unless you are setting GPO Loopback Processing as Merge or Replace mode. But since you likely are a professional admin, you have already done this and likely set this as “replace” to prevent GPOs from user account OU to hassle with your precious AVD/RDS environment, meaning only user policies from the same OU as the servers are processed.
Microsoft’s documentation about Logon/Logoff scripts:
Why not just using Storage Sense for this?
Well… The simple answer is that it does not work well with multiuser environments. You of course want to have Storage Sense settings configured so that some temporary file cleanups and similar would happen, but for dehydrating OneDrive files my experiences are not very great with AVD/RDS environments.
I have even tried to run it with very aggressive schedule in forced way by having a scheduled task in computer configuration running as BUILTIN\Users:
cleanmgr.exe /autocleanstoragesense /d %systemdrive%
But even the cleanup starts and looks to be running as expected when followed with Process Explorer, still the OneDrive file dehydration is not working as expected. However Storage Sense should work just fine with normal single user computers without any extra scheduled tasks if your settings are correct.