5

I know this question was already asked, but I couldn't find the solution so far.

What I'm trying to do is uninstall a windows service and delete the folder with the windows service using C#.

Windows service uninstall

    public static void Uninstall(string exeFilename)
    {
        var commandLineOptions = new string[1] { "/LogFile=uninstall.log" };

        if (!Directory.Exists(exeFilename)) return;

        var fileNames = Directory.GetFiles(exeFilename);
        var serviceFile = fileNames.FirstOrDefault(f => f.EndsWith(".exe"));
        var serviceFileName = Path.GetFileName(serviceFile);
        var serviceName = Path.GetFileNameWithoutExtension(serviceFile);

        var serviceExists = ServiceController.GetServices().Any(s => s.ServiceName == serviceName);

        if (!serviceExists) return;

        var installer =
            new AssemblyInstaller($"{exeFilename}\\{serviceFileName}", commandLineOptions)
            {
                UseNewContext = true
            };

        installer.Uninstall(null);
        installer.Dispose();
    }

Folder and files delete

    public static void DeleteFolder(string folderPath)
    {
        if(!Directory.Exists(folderPath)) return;
        
        try
        {
            foreach (var folder in Directory.GetDirectories(folderPath))
            {
                DeleteFolder(folder);
            }

            foreach (var file in Directory.GetFiles(folderPath))
            {
                var pPath = Path.Combine(folderPath, file);
                File.SetAttributes(pPath, FileAttributes.Normal);
                File.Delete(file);
            }

            Directory.Delete(folderPath);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
    }

Error that I get

Access to the path 'c:\services\x\x.exe' is denied.

 at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
 at System.IO.File.InternalDelete(String path, Boolean checkHost)
 at System.IO.File.Delete(String path)

This error occurs randomly. The .exe file is not readonly, sometimes the files get deleted.

Does anyone know what's wrong?

ThomasArdal
  • 4,999
  • 4
  • 33
  • 73
Gerald Hughes
  • 5,771
  • 20
  • 73
  • 131
  • My first guess would be the exe file is running. Is the service stopped? – Cleptus Jul 14 '21 at 11:04
  • @Cleptus I was thinking the same, but not sure how to fix this. Yes the service is stopped – Gerald Hughes Jul 14 '21 at 11:12
  • Where is `DeleteFolder` called in relation to `Uninstall`? – Kit Jul 16 '21 at 13:05
  • Make sure you dont have any instances of mmc.exe running too, eg, the services window, computer management etc. This process can stop the service from fully uninstalling and it will be marked for deletion instead of actually uninstalled. – WraithNath Jul 20 '21 at 10:23
  • I guess this is a problem with how windows services are uninstalled. Sometimes they are like in a pending state for a while before they are removed from the system. Try and implement it so when it fails it would wait for some time and then retry. I had problems with services before that doesn't get uninstalled instantly. – dennis_ler Jul 23 '21 at 08:51

4 Answers4

5

Stopping a Windows service does not equate to exiting a process. An executable can house multiple Windows services (it's essentially the physical shell for the services).

So what you're running into, it looks like, is that the service likely stopped just fine, and uninstall can proceed and the deletion of files can proceed, but only up until the point where it reaches the executable, which hasn't yet had a chance to exit.

Stopping, exiting, uninstalling are all asynchronous and need time to complete before moving to the next step.

What you have to do is follow this formula

  1. Ensure your code is running with elevated privileges if you can; if you can't you may run into Access Denied. You can also try changing the ownership of the target executable.
  2. Stop or ensure the service is stopped. If there are multiple services, stop all of them.
  3. Wait for stop to actually occur. It's not always immediate.
  4. Call the Uninstall().
  5. Wait some amount of time. Check to see if the process is running. If it is you will call Process.Kill() (see an implementation below).
  6. Finally, you can call the DeleteFolder() for which your implementation looks adequate to me.

Exiting the Process

Write a method that looks something like this. You might want to tweak it.

void Exit(Process p)
{
    for (int i = 0; i <= 5; i++)
    {
        // doesn't block
        if (p.HasExited) return;

        // doesn't block; pass true to terminate children (if any)
        p.Kill(true);

        // wait 5 seconds then try again
        Thread.Sleep(5000);
    }
}

After all that you should be good to go.

Kit
  • 20,354
  • 4
  • 60
  • 103
1

Is the service stopped / executable stopped and does the program have Administrator access? If you don't have administrator access, refer to: How do I force my .NET application to run as administrator? to run as administrator. When uninstalling a program, administrator permissions are almost always required. If this still fails, you are not the owner of the file and you must change the owner to yourself or Administrators. You can do this programatically here: Getting / setting file owner in C#

Ethan
  • 160
  • 2
  • 10
0

I think you have to stop the service first. try using

sc stop <service name>

to stop the service. Then uninstall should work. try using installutil.exe if your uninstall code does not work. It can give your error output also. The exe cannot be deleted if it is currently executing so make sure exe is not executing when you try to delete it.

Jin Thakur
  • 2,711
  • 18
  • 15
0

You can use setup project, it generates the uninstaller automatically and gives you a range of possibilities with it.

Example of the service installer

You must download the addon in the market place