Windows file permissions¶
Windows implements file-level security through access control lists. Windows provides the
icacls utility to query and set permissions at the command line.
icacls C:\PythonEnvs\Example /grant "nt service\my_service":(OI)(CI)RX
Let’s break this down:
C:\PythonEnvs\Example- The folder you want to change permissions on
/grant- Grant rights additively
"nt service\my_service"- The name of the virtual service account
(OI)(CI)- Applies the grant recursively to this folder, subfolders, and files
RX- Grants Read and Execute access
Inherited folder permissions are specified as:
- OI - Object inherit - This folder and files (no inheritance to subfolders)
- CI - Container inherit - This folder and subfolders
- IO - Inherit only - The ACE does not apply to the current file/directory
These can also be combined:
- (OI)(CI) this folder, subfolders, and files
- (OI)(CI)(IO) subfolders and files only
- (CI)(IO) subfolders only
- (OI) (IO) files only
BUILTIN\Administrators:(OI)(CI)F means that both files and subfolders will inherit ‘F’ (Full Control)
(CI)R means folders will inherit ‘R’ (Read folders only = List permission)
SS64 has a good reference for the
Many Windows admin tasks require the wonderful Sysinternals tools, written by Mark Russinonvich. The first thing I do on a new Windows server is download the Sysinternals Suite and put it on the system path. For this troubleshooting section, I’ll be using the
Whenever a service is not working, it’s helpful to try running it by hand, in the same user account and environment that the service is trying to run in. As far as I know, there is no way to run commands manually as a virtual service account (
NT SERVICE\my_service). Put another way, there is no equivalent of
su - <user> that can be used for virtual service accounts. However, we can approximate it. We can use
psexec to run commands as the LocalService account (
NT AUTHORITY\LocalService). It’s far from perfect, but if we can get it working under the LocalService account, chances are we can then get it working under a virtual service account.
Let’s look at some steps we can take to investigate permissions problems. First, open a new admin command prompt. On Windows 8 and newer, “Win-x then a” is a quick way to open an admin command prompt.
Here’s how to execute a single command, under the LocalService account.
psexec -u "NT AUTHORITY\LocalService" C:\PythonEnvs\Example\Scripts\pip freeze
-u option tells
psexec what user to run as. The rest of the line is the command that you want
psexec to run. Notice that we pass the full path to the
pip inside the virtualenv.
pip freeze prints a list of the packages that are installed.
If you get a “Couldn’t install PSEXESVC service” error, try running
psexec as administrator.
Here’s another example. We’re telling Python to import the pyodbc module, and print “ok” if it succeeds.
psexec -u "NT AUTHORITY\LocalService" C:\PythonEnvs\Example\Scripts\python -c "import odbc; print 'ok'"
Here’s how to start a new interactive shell in a new window, running as the LocalService user.
psexec -u "NT AUTHORITY\LocalService" -i cmd /k
It should look something like this.
In the screenshot above, I have used the
whoami command to show that, in the new console window, we are running as
If you want to start a new interactive session as a different user, but stay in your current command window, omit the
-i argument to
psexec -u "NT AUTHORITY\LocalService" cmd /k
Since Windows does not print the username in the shell prompt, it can be hard to know what user you are running as. Use the
whoami command to see the current user.
whoami /all command shows a lot of useful information about the user, groups and privileges.
Two things to keep in mind when using
psexec to troubleshoot. One, it must be called from an admin command prompt (Win-x then a). Two, you can not use
psexec to run commands as a virtual service account.
When I’m setting up Windows service, I configure it to run under the LocalService account at first, and I use
psexec to track down any permissions problems. Then I switch the service over to a virtual service account. I grant the virtual service account the same privileges that I granted to the LocalService account.
You may find that the virtual service accounts you’re using to run the services don’t have permission to handle zip files. This may be due to a policy restriction set by your network administrator. The LocalService account may have the same restriction.
This is why, when I’m installing pyodbc, I have to pass the
--always-unzip option to
easy_install installs it as a zip file, and the virtual service account doesn’t have permission to read it.
Another example: on Windows, distutils packages source distributions as zip files. Let’s say for example you’re running python’s simpleHTTPServer as a Windows service (using nssm), running it as account
nt service\package_server. You can visit http://localhost:8000 and you get a nice file listing. However, if you try to download one of the zip files, you get a 404. Assigning permissions for
nt service\package_server doesn’t work - the permissions apply to folders and text files but they don’t apply to zip files through inheritance. It only works if you assign read permission specifically for the zip file itself.
Here’s a command to specifically assign permissions for a zip file
icacls "C:\PackageServer\www\downloads\My_Package-0.0.1.zip" /grant "nt service\package_server":R
By your leave¶
We’ve come to the end of Part 3. The virtual service account under which the service is running has been assigned the permissions it needs.
Note that these commands can be used for any service you are running on Windows, not only those using Twisted or NSSM.
Thanks for following along, and find me on Twitter at @christianmlong if you have any suggestions or fixes.