5

First, a bunch of background:

I'm working on prepping about 20 laptops for an educational program in a prison. This environment has some... special challenges. One of these is students (prisoners) are not permitted under any circumstances to have anything even marginally resembling email or electronic messaging access.

This means they cannot have Microsoft Accounts at all and will not have access to an AD domain or Entra Identity; only local accounts will do (and removing the MS Account nags will be a separate question), and group policy/system center/intune/other MDM management is off the table.

It also means they cannot have One Drive anywhere on the computer. If a student were to manage to get One Drive open and connected, they could use it to create a shared folder to someone outside the prison and exchange messages by dropping in text files.

Yes, we really have to be that careful, and finding out after the fact we failed to get this right involves the kind of penalties I don't want to think about.

It further does not matter the OneDrive service will be blocked on the prison network. The machines will be inspected before delivery, and my understanding talking to other organizations that finding One Drive will cause them to fail inspection.

An additional aspect of the situation is there is no real on-site tech support. My current understanding (which could still be wrong) is the education coordinator in the prison is given a local admin account and detailed instructions on how to open Computer Management and create a new local user with a distinct password for each student (also known to the coordinator). So I need this to work as the default experience for new users.

Again, I have a batch of these, with the potential need to add more on the horizon. I do know I always start from a fresh/clean Windows installation, and right now they are all the same make/model. But I also know it's doubtful the next batch will be the same brand, so I can't count on the systems looking exactly the same. This isn't the only weird/extra thing I need to do for these machines, so I would really like this to be scripted, such that the process will be repeatable.

In short (too late), I'm highly motivated to ensure OneDrive really is totally gone from these systems in a repeatable way; it's likely I'll even have the final script run nightly as a scheduled task, to protect against accidental re-install. It really does need to be for all users, including users not yet created, and it's more than just the usual, "Boo hoo, I don't like OneDrive, why do I have to put up with it?" whining.

So far I have this:

# Make sure OneDrive isn't later changed to be a Windows Store app
Get-AppxPackage -AllUsers "*OneDrive*" | Remove-AppxPackage -AllUsers

But really OneDrive uses any of five possible locations:

Windows\System, Windows\System32, Windows\SysWOW64, Program Files, and Program Files (x86)

Need to check all five

if (Test-Path "C:\Windows\System\OneDriveSetup.exe") { start -wait -filepath "C:\Windows\System\OneDriveSetup.exe" -argumentlist "/uninstall","/qn" } if (Test-Path "C:\Windows\System32\OneDriveSetup.exe") { start -wait -filepath "C:\Windows\System32\OneDriveSetup.exe" -argumentlist "/uninstall","/qn" } if (Test-Path "C:\Windows\SysWOW64\OneDriveSetup.exe") { start -wait -filepath "C:\Windows\SysWOW64\OneDriveSetup.exe" -argumentlist "/uninstall","/qn" }

Program Files locations also have a version number subfolder that may change over time

if (Test-path "C:\Program Files\Microsoft OneDrive") { $folder = (get-childitem "C:\Program Files\Microsoft OneDrive").Name | ?{ $_ -match "^\d{2}." } # can be several folders. Only one will have the uninstaller $folder | % { if (Test-Path "C:\Program Files\Microsoft OneDrive$\OneDriveSetup.exe") { $path = "C:\Program Files\Microsoft OneDrive$\OneDriveSetup.exe" start -wait -filepath $path -argumentlist "/uninstall","/qn" } } } if (Test-path "C:\Program Files (x86)\Microsoft OneDrive") { $folder = (get-childitem "C:\Program Files (x86)\Microsoft OneDrive").Name | ?{ $_ -match "^\d{2}." } # can be several folders. Only one will have the uninstaller $folder | % { if (Test-Path "C:\Program Files (x86)\Microsoft OneDrive$\OneDriveSetup.exe") { $path = "C:\Program Files (x86)\Microsoft OneDrive$\OneDriveSetup.exe" start -wait -filepath $path -argumentlist "/uninstall","/qn" } } }

Also look in WinSXS

$ods = get-childitem "C:\Windows\WinSxS\amd64_microsoft-windows-onedrive-setup*" if ($ods) { $path = "C:\Windows\WinSxS$($ods.Name)*.*" # Don't need to uninstall; just remove files. But also need to take ownership first takeown /F $path /A | Out-Null icacls $path /grant Administrators:M | Out-Null remove-item -path $path -force }

I include this script to show what is already done, and not because I need any help with code (and this is why I'm here at Super User instead of on Stack Overflow).

I further have the ability elsewhere in my script to easily add changes to the default user profile registry hive and local machine:

reg load HKU\default c:\users\default\ntuser.dat
reg import .\DefaultRegistryFixes.reg
reg unload HKU\default

The result is anything in that DefaultRegistryFixes.reg file can reference HKEY_USERS\default and it will be written into the registry settings given to new users. The file currently has about 40 registry edits. Nothing there yet has anything to do with OneDrive, as I really need OneDrive to be fully removed, and not just disabled. However, anything I can do here to also disable OneDrive is good, since I want additionally protect against a system update putting OneDrive back on the computer, and if a registry change is the only way to stop it running for a new user I am prepared.


And now, finally, my problem:

After all this, I see OneDrive is gone from the initial admin account I use to run the script. But if I then create a new local user and login, I see One Drive running in the system tray. Task Manager shows the .exe file is living in that user's (brand new) App Data folder.

What am I missing, that One Drive is still running on the system when I add a new user, even after removing it from these other locations? And how can I remove it finally once and for good?

Joel Coehoorn
  • 28,637

1 Answers1

3

I now have things so I believe OneDrive is fully removed using a script and reg file. The script:

Write-Host "Removing OneDrive"

First make our registry tweaks. To do this, we need the default user's hive loaded

reg load HKU\default c:\users\default\ntuser.dat

Now, before importing changes, look for the OneDrive Personal installer location (we'll need it later)

Also, KHU isn't available by default, so check that, too

if ((Get-PSDrive -PSProvider Registry).Name -notcontains 'HKU') { New-PSDrive HKU Registry HKEY_USERS | Out-Null $removeHKU = $true } $odp = (Get-ItemProperty -path 'HKU:\default\SOFTWARE\Microsoft\Windows\CurrentVersion\Run').OneDriveSetup if ($removeHKU) { Remove-PSDrive -Name "HKU" }

Import our registry changes

This removes the command to install OneDrive again from the default user template

reg import .\DefaultRegistryFixes.reg reg unload HKU\default

Done with registry

Make sure OneDrive isn't later changed to be a Windows Store app

Get-AppxPackage -AllUsers "OneDrive" | Remove-AppxPackage -AllUsers

OneDrive is installed in one or more of five possible locations:

Windows\System, Windows\System32, Windows\SysWOW64, Program Files, and Program Files (x86)

Need to check all five

First, the Windows locations

if (Test-Path "C:\Windows\System\OneDriveSetup.exe") { start -wait -filepath "C:\Windows\System\OneDriveSetup.exe" -argumentlist "/uninstall","/qn" } if (Test-Path "C:\Windows\System32\OneDriveSetup.exe") { start -wait -filepath "C:\Windows\System32\OneDriveSetup.exe" -argumentlist "/uninstall","/qn" } if (Test-Path "C:\Windows\SysWOW64\OneDriveSetup.exe") { start -wait -filepath "C:\Windows\SysWOW64\OneDriveSetup.exe" -argumentlist "/uninstall","/qn" }

Then Program Files.

These locations also have a version number subfolder that may change over time

So we need extra steps to find that folder

if (Test-path "C:\Program Files\Microsoft OneDrive") { $folder = (get-childitem "C:\Program Files\Microsoft OneDrive").Name | ?{ $_ -match "^\d{2}." } # can be several folders. Only one will have the uninstaller $folder | % { if (Test-Path "C:\Program Files\Microsoft OneDrive$\OneDriveSetup.exe") { $path = "C:\Program Files\Microsoft OneDrive$\OneDriveSetup.exe" start -wait -filepath $path -argumentlist "/uninstall","/qn" } } } if (Test-path "C:\Program Files (x86)\Microsoft OneDrive") { $folder = (get-childitem "C:\Program Files (x86)\Microsoft OneDrive").Name | ?{ $_ -match "^\d{2}." } # can be several folders. Only one will have the uninstaller $folder | % { if (Test-Path "C:\Program Files (x86)\Microsoft OneDrive$\OneDriveSetup.exe") { $path = "C:\Program Files (x86)\Microsoft OneDrive$\OneDriveSetup.exe" start -wait -filepath $path -argumentlist "/uninstall","/qn" } } }

Now look in WinSXS for the setup file backup

$ods = get-childitem "C:\Windows\WinSxS\amd64_microsoft-windows-onedrive-setup*" if ($ods) { $path = "C:\Windows\WinSxS$($ods.Name)*.*" # Don't need to uninstall. Just remove the files. But also need to take ownership first takeown /F $path /A | Out-Null icacls $path /grant Administrators:M | Out-Null remove-item -path $path -force | out-null }

And finally clean up installer program found earlier in the registry

if ($odp) { $odp = $odp.Replace(" /thfirstsetup", "") # remove command line argument takeown /F $odp /A | Out-Null icacls $odp /grant Administrators:M | Out-Null remove-item $odp | out-null }

The registry file:

Windows Registry Editor Version 5.00

[HKEY_USERS\default\SOFTWARE\Microsoft\Windows\CurrentVersion\Run] "OneDriveSetup"=-

[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run] "OneDriveSetup"=- "OneDrive"=-

Remember, script has loaded the default user hive specially for this .reg file to be effective.

This successfully removes OneDrive from a new system, and I no longer see it running after creating a new user. If there are other users on the system already created, still more work will be needed. But that's not my situation at this time.


But I'm not done.

I expect the above script will be effective for a month or three, but then a Windows Update will eventually patch the installer and default registry. This isn't even Microsoft trying too hard to push their own products. It's just a natural result of the servicing platform doing it's thing, either after patching a CVE or when a new version is available as part of an annual feature update.

So, to prevent OneDrive from coming back, this code (and some other things) will also be included as a recurring scheduled task. Then, when OneDrive eventually comes back it will just get pulled again. That should stop it appearing for new users, which is a rarer event. I'm also looking into additional registry tweaks I can use to make it less aggressive during the potential period of up to about a day where it may exist on a system, so it doesn't end up installed in a user's AppData folder.

As another measure, I'm considering changing the script code to write placeholder files over top of the existing OneDriveSetup.exe files, with custom access control lists that do not permit write access to SYSTEM or TRUSTED INSTALLER principals. But I'm worried this would break and force rollbacks for larger Updates, leaving systems in an unsecured state, and so that's not in the current plan.

Finally, we may also make manual security policy tweaks on each system, to block the installers from running. But since I haven't seen a way to make that scriptable/repeatable, I'm saving it as a last resort.

Joel Coehoorn
  • 28,637