Search code examples
c#windows.net-corewindows-services

How to allow Windows service to access file system?


I have a C# console application running as a Windows service. How can I allow it to access the file system?

Should I create an account for it? If so, I don't think I want a user account. (I noticed that other Windows services are run under accounts that don't show up under my user accounts.) If this is the right approach, how do I create one of these type of accounts?

But whenever I Google this, I just seem to find pages for creating regular user accounts.


Solution

  • A Windows Service created in .NET typically looks like this:

    IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddHostedService<MyBackgroundWorker>();
    })
    .UseWindowsService()
    .Build();
    
    host.Run();
    

    Where MyBackgroundWorker is a BackgroundService that does its work in ExecuteAsync(). Or one can register various services that the host will run for you.

    The UseWindowsService(), from Microsoft.Extensions.Hosting.WindowsServices, makes the program tell Windows' Service Control Manager (SCM) that yes, this process is in fact hosting one Windows Service.

    The installation

    Now when you deploy this service somewhere, say C:\MyCoolService, it has to be made known to the SCM. One usually uses sc.exe for this:

    sc.exe create MyCoolService binPath= "C:\MyCoolService\MyCoolService.exe"
    

    Not specifying a user account (using the obj= argument) defaults to the built-in LocalSystem account, which can do about everything on your machine. It can access any directory, it can represent the machine on the network, it is a bad default.

    Anyhow, we now have a .NET application running as a Windows Service, blissfully running our MyBackgroundWorker implementation in the background.

    The permissions

    There's nothing special about Windows Service users, apart from the built-in part of some of them. You could let your service run as LocalSystem, having access to about everything on your system, or you could let it run as a lesser-privileged account LocalService, which can access about nothing.

    Or you could create a Windows (Active Directory or local) user and have your service run as that user. It can then access whatever that user can access, using Access Control Lists and whatnot.

    The problem

    As you explained in comments, you use Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) to obtain the path to write to. When running as LocalSystem, that returns an empty string, because the LocalSystem user does not have a My Documents folder. Who would read those documents anyway?

    And what happens when you use that empty string to build a path to write files to? You write relative to the current directory.

    What is the current directory for a Windows Service when not specified otherwise? C:\Windows\system32. The LocalSystem user can and will happily write there.

    That's where your files are.