13

I want to be able to set the IIS account for new websites to have modify permissions. I have the following script:

function Set-ModifyPermission ($directory, $username, $domain = 'IIS APPPOOL') {
    $inherit = [system.security.accesscontrol.InheritanceFlags]"ContainerInherit, ObjectInherit"
    $propagation = [system.security.accesscontrol.PropagationFlags]"None"
    $acl = Get-Acl $directory
    $user = New-Object System.Security.Principal.NTAccount($domain, $username )
    $accessrule = New-Object system.security.AccessControl.FileSystemAccessRule($user, "Modify", $inherit, $propagation, "Allow")
    $acl.AddAccessRule($accessrule)
    set-acl -aclobject $acl $directory
}

However, when I run it, I get errors like this:

Set-Acl : The trust relationship between this workstation and the primary domain failed.

I think this is because IIS APPPOOL isn't a real domain, but is a weird prefix on a kind-of-fake account. Is there a correct way to refer to that account so that I can make this work?

bdukes
  • 235
  • 1
  • 2
  • 9

5 Answers5

13

First of all, use Set-Acl like this, as the directory path is the first positional argument:

Set-Acl $directory $acl

Second, you should create the user object with only one argument:

$user = New-Object System.Security.Principal.NTAccount("$domain\\$username")

UPDATE: Seems that it won't accept the "IIS APPPOOL\AppPoolName" as an NTAccount identifier. Now, there are two ways to accomplish what you are trying to do:

  1. Create a new SID object with the AppPoolIdentities SID and translate it into an NTAccount, like this: http://iformattable.blogspot.com/2007/12/convert-sid-to-ntaccount-with.html, and you should be able to treat it like any other NTAccount object. If you still want to be able to pass domain/usernames for real accounts, built in some simple logic that defaults to the AppPool SID if username is "AweSomeAppPool" and domain is empty, just as an example.

  2. Use PowerShell to invoke icacls.exe, and use it to grant/revoke whatever permissions you want, like this (first normal icacls form command prompt, then powershell, notice the difference):

    icacls.exe test.txt /grant "IIS AppPool\DefaultAppPool":(OI)(CI)M

    cmd /c icacls test.txt /grant "IIS AppPool\DefaultAppPool:(OI)(CI)M"

If you go for the second option, be sure to test them manually first, i haven't had a chance to test these specific examples myself, but it should work

Mathias R. Jessen
  • 25,161
  • 4
  • 63
  • 95
  • Thanks for the help. Doing that, I get an exception calling `AddAccessRule`: "Some or all identity references could not be translated." Any ideas what that might be? – bdukes Dec 27 '11 at 22:59
  • Try to help me understand what you are trying to accomplish here. The thing is, that ApplicationPoolIdentities aren't "real" NT Accounts, they are more like a "virtual account" representation of the NETWORK SERVICE actually. Do you wan't to set permissions on local system resources or networked resources? Depending on your need, a different challenge arises :-) – Mathias R. Jessen Dec 27 '11 at 23:16
  • Local system resources. I'm trying to streamline setting/resetting permissions for local development websites that I setup. So, I'd unzip a website package to the file system, set it up in IIS, then run this command to give IIS modify permission. Or, run into a permission issue in the site, run this to make sure something I've added after the site was created has modify permission. – bdukes Dec 29 '11 at 14:52
  • Just added some hopefully useful options for you – Mathias R. Jessen Dec 29 '11 at 16:52
  • I was able to get `icacls` working great for me, thanks for the help! I ended up with the body of the function (same parameters as above) being `cmd /c icacls "$directory" /grant ("$domain\$username" + ':(OI)(CI)M') /t /c /q` (with `/t` to work recursively on the directory, `/c` to keep going after any errors, and `/q` to suppress success messages for each file). – bdukes Dec 29 '11 at 19:35
  • awesome, glad to hear it worked out well for you ;) – Mathias R. Jessen Dec 29 '11 at 19:36
5

The following works in Windows 2012 to get a SID for the IIS site. It requires the IIS Provider which uses the WebAdministration powershell module, but this article indicates it will work on Windows 2008R2.

$appPoolName = 'MyAppPool'
$appPoolSid = (Get-ItemProperty IIS:\AppPools\$appPool).applicationPoolSid
$identifier = New-Object System.Security.Principal.SecurityIdentifier $appPoolSid
$user = $identifier.Translate([System.Security.Principal.NTAccount])
bdukes
  • 235
  • 1
  • 2
  • 9
Justin Dearing
  • 1,037
  • 12
  • 33
  • I tried to use this approach (on Windows 8), but got this error: "Exception calling '`AddAccessRule`' with '1' argument(s): 'Some or all identity references could not be translated.'" – bdukes Aug 05 '13 at 17:00
  • Using the link from @Mathias R. Jessen's answer to translate the SID into a real `NTAccount` worked. – bdukes Aug 05 '13 at 17:20
  • I've updated the code in the answer to do the translation. Also, for those trying to take advantage of this, call `Import-Module WebAdministration` to get the IIS drive from the IIS provider. – bdukes Aug 05 '13 at 17:25
4

Something like this should do the trick for you. It should be able to resolve IIS APPPOOl\Anything as well...

function Set-AclOnPath
{
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string] $Path,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string] $DomainAccount
    )

    #Put whatever permission you want here
    $permission = $DomainAccount,"ReadAndExecute","Allow"
    $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $permission

    $acl = Get-Acl $Path
    $acl.SetAccessRule($accessRule)
    $acl | Set-Acl $Path
}
4

As of IIS 10/Windows 10/Server 2016, the WebAdministration module is deprecated and we're expected to use the new IISAdministration Powershell module instead. Here's how to get the application pool SID translated to the virtual user using the new module:

Import-Module IISAdministration
$manager = Get-IISServerManager
$appPoolName = 'MyAppPool'
$appPoolSid = $manager.ApplicationPools["$appPoolName"].RawAttributes['applicationPoolSid']
$identifier = New-Object System.Security.Principal.SecurityIdentifier $appPoolSid
$user = $identifier.Translate([System.Security.Principal.NTAccount])
Chris Doherty
  • 211
  • 1
  • 2
3

The following worked for me in Windows 2012, couldn't get the other examples working:

Import-Module WebAdministration

$appPoolName='MyAppPool'
$folderDirectory='C:\MyWebFolder'

$appPoolSid = (Get-ItemProperty IIS:\AppPools\$appPoolName).applicationPoolSid

Write-Output "App Pool User $appPoolSid"

$identifier = New-Object System.Security.Principal.SecurityIdentifier $appPoolSid
$user = $identifier.Translate([System.Security.Principal.NTAccount])

Write-Output "Translated User $user.Value"

$acl = Get-Acl $folderDirectory
$acl.SetAccessRuleProtection($True, $False)
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule($user, "FullControl", "ContainerInherit", ObjectInherit", "None", "Allow")
$acl.AddAccessRule($rule)
$acl | set-acl -path $folderDirectory
Stuggi
  • 3,506
  • 4
  • 19
  • 36
ChrisT
  • 31
  • 1
  • This also worked for me except one thing. This removed ALL other permissions. If this isn't what you want, comment out this line `$acl.SetAccessRuleProtection($True, $False)` as the last param here is PreserveInheritance. Thanks for posting this! – Kurtis Jul 03 '19 at 10:00