Search code examples
powershellfile-permissionsaccess-control

How do I check in PowerShell if a service has read access to a certain folder?


So far, I know to do the following:

  1. Determine the service logon account - (Get-WmiObject -Query "SELECT StartName FROM win32_service where name = 'mssqlserver'").StartName
  2. Get accounts that have read access to the folder - accesschk -q -d $env:TEMP

But this leads me nowhere:

PS C:\> (Get-WmiObject -Query "SELECT StartName FROM win32_service where name = 'mssqlserver'").StartName
LocalSystem
PS C:\> accesschk -q -d $env:TEMP
c:\Users\MKHARI~1\AppData\Local\Temp
  RW NT AUTHORITY\SYSTEM
  RW BUILTIN\Administrators
  RW DAYFORCE\mkharitonov
PS C:\> accesschk LocalSystem -q -d $env:TEMP

Accesschk v5.2 - Reports effective permissions for securable objects
Copyright (C) 2006-2014 Mark Russinovich
Sysinternals - www.sysinternals.com

  Error looking up account: LocalSystem:
  The operation completed successfully.
PS C:\> accesschk "DAYFORCE\mkharitonov" -q -d $env:TEMP
RW c:\Users\MKHARI~1\AppData\Local\Temp
PS C:\>

The AccessChk does not seem to recognize LocalSystem. Also, if I run it with an account belonging to the BUILTIN\Administrators, it does not seem to acknowledge the access.

Does it mean AccessChk is not suitable for this or am I using it wrong? Is there a way to do it at all without actually trying to access the folder under the account in question?

When PowerShell is running not as administrator:

PS C:\> $service = Get-WmiObject -EnableAllPrivileges Win32_Service | Where-Object {$_.Name -eq "MSSQLSERVER"}
PS C:\> '{0:x}' -f $service.GetSecurityDescriptor().ReturnValue
80070522
PS C:\>

Which corresponds to A required privilege is not held by the client. The command works OK when the PowerShell is running as administrator. Ideally, I would like a solution that does not require elevation.


Solution

  • localsystem uses the token of nt authority\System, so this command line will work (you will need to map the localsystem to system in code):

    accesschk.exe system -q -d $env:temp
    

    I have created a snippet to fetch the proper name and pass it to accesschk (tested in PowerShell v5 and requires elevated access):

    $service = Get-WmiObject -EnableAllPrivileges Win32_Service | Where-Object {$_.Name -eq "wlidsvc"}
     $desc = (($service.GetSecurityDescriptor()).Descriptor).owner
     $desc.Domain + "\"+$desc.name | %{.\accesschk.exe $_ -q -d $env:temp}
    

    $desc.Domain + "\"+$desc.name will return NT AUTHORITY\SYSTEM instead of localsystem

    PS: The script can be optimized