powershelliis

How do I check if user 'IIS AppPool\MyAppPoolName' exists in powershell


I'm trying to automate some DB configuration for my developers. For development and testing, we're just using the ApplicationPoolIdentity service accounts (one of our test servers hates NETWORK SERVICE so that's not an option), so I need to configure databases to automatically grant permissions to the correct account for IIS. But developers are often only running the database script, not the database and web scripts.

Because of that, the IIS AppPool may not exist at the time they're running the DB script, which means that by extension the IIS AppPool\myAppPoolName user will not exist either. So when I attempt to grant them access to the local SQL database, they get an error.

So the question is, how do I check that these IIS AppPool service accounts exist in Powershell? I know how to confirm the existence of AD users, or local users, but these IIS apppool service accounts are in neither list. Where do they live? Is it a listing not accessible from Powershell?

I can do something dumb like just catching and handling the error during the permissions step, but I'd rather ask permission than forgiveness.


Solution

  • There is some misunderstanding, in that there never is a "user" [IIS AppPool\{AppPoolName}].

    [IIS AppPool\{AppPoolName}] is a "virtual account", & is completely 'unmanaged' by IIS/Windows, and as such is not available via normal means. I think they could have named it better, because the word "account" is a bit of a misnomer (in the traditional sense). It's really a "deterministic unmanaged SID", which windows will let you use in security contexts as if it 'were' an account/user.

    Aside/Details: Therefore, Microsoft/WindowsTeam does not have a process which keeps an easily accessible record of all of the "virtual account(s)" that have executed (as there is no 'creation', just 'usage'; a chicken with no egg). This is hack is possible due to the role of SIDs in Windows combined with the deterministic nature of the SIDs generated for the "virtual account in question". It's just a SID prefix based on the account class (i.e. [IIS AppPool\*] === S-1-5-82-*) combined with the UInt32 representation of the SHA-1 of the (lowercase, for IIS AppPool; uppercase, for other services) username.

    This is why, when creating permissions in MSSQL Server for an IIS AppPool, the documentation states:

    !!!DO NOT CLICK SEARCH!!!
    

    How to add the ApplicationPoolIdentity to a SQL Server Login https://learn.microsoft.com/en-us/archive/blogs/ericparvin/how-to-add-the-applicationpoolidentity-to-a-sql-server-login

    ... as you can't search (or verify) that it exists, because it only 'exists' when you're using it. So while there will be traces of a virtual account's existence (i.e. the traces it leaves behind as it's bound to an executing service {in logs}, in configuration files, & usually the permissions created on resources for it to be effective). The "deterministic unmanaged SID" only 'exists' at "run time" of the service (and most often will not have a user profile). For instance, if you create a new AppPool, but don't actually start it; there won't be a trace it was there (via icacls.exe, below). However, as the AppPool is running you will see the 'virtual account / user' in task manager for w3wp.exe, as well as the config entry.

    So now that that's "clear", let's dig into the question, "So the question is, how do I check that these IIS AppPool service accounts exist in Powershell?" .. because "{you} need to configure databases to automatically grant permissions to the correct account for IIS".

    Short Answer -- You Don't (& don't "need" to).

    Longer Answer -- If you're using MSSQL, you can follow the instructions above ("How to add the ApplicationPoolIdentity to a SQL Server Login") prior to even creating the Application Pool!

    If you're using some other resource (db, file, etc.), you can do the following to bind the SID to a local group, & then use the GUI to apply access to that group:

    #  PowerShell AS Admin  ->
    #  ADSI  ===  System.DirectoryServices.DirectoryEntry
    $group = [ADSI]"WinNT://$Env:ComputerName/{SomeSecGrpName},group"
    Write-Host $group.Path
    #  group  ===  WinNT://{ComputerName}/{SomeSecGrpName},group
    $newAppPoolName = "SomeAppPoolName"
    $ntAccount = New-Object System.Security.Principal.NTAccount("IIS APPPOOL\$newAppPoolName")
    Write-Host $ntAccount
    #  $ntAccount  ===  IIS APPPOOL\SomeAppPoolName
    $strSID = $ntAccount.Translate([System.Security.Principal.SecurityIdentifier])
    Write-Host $strSID
    #  $strSID  ===  S-1-5-82-1567671121-388969313-3181147451-2359319770-4988630401
    #  $strSID  -  note  -  not a valid SID above
    $user = [ADSI]"WinNT://$strSID"
    $group.Add($user.Path)
    

    ... then use the group "SomeSecGrpName".

    However, lets say you want to know if the IIS AppPool ever ran and/or you want an easy way to get access to the SID; which you can then use to secure items. You can do the following:

    Ensure Security Isolation for Web Sites https://learn.microsoft.com/en-us/iis/manage/configuring-security/ensure-security-isolation-for-web-sites

    icacls.exe c:\inetpub\temp\appPools\{SomeAppPoolName}\{SomeAppPoolName}.config /save {d:\SomeDirectory}\icacls_{SomeAppPoolName}_output.txt
    

    ... gets us a file, containing the SID to use for security permissions.