IIS Web Deploy permissions (with PowerShell)

Web Deploy is a great way to publish websites if you use Windows + IIS hosting, especially inside company’s infrastructure.

Why do I like it:

  • It can be used from Visual Studio as well as from commandline - this means developers can publish right from VS, without any additional tools, but also script and commandline freaks like me can automate it
  • It only syncs modified files - if you have low bandwith, deploy often or have large sites - it beats other methods that require full package to be deployed every time
  • Active Directory can be used for authentication

Allowing a user to publish with Web Deploy

The goal is to allow non-administrator user to publish IIS website using Web Deploy.

There are two parts here:

  1. Add IIS Manager permissions
  2. Add File System permissions

If you like clicking through it, see Installing and Configuring Web Deploy on IIS 8.0 or Later. Remember that you should also add appropriate permissions to site’s physical folder or else the user won’t be able to publish any files.

If you want to do it from commandline, here’s a snippet for setting IIS Manager permissions:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Management") 
[Microsoft.Web.Management.Server.ManagementAuthorization]::Grant($username, "$site", $false) 

Then, use Set-Acl to set physical path permissions. Here’s a full script:

<#
.SYNOPSIS

adds ACL rules to specific path. it's a helper wrapper for Set-ACL from Microsoft.PowerShell.Security   

#>

function set-acl2(
[Parameter(Mandatory=$true)] $path, 
[Parameter(Mandatory=$true)] [System.Security.AccessControl.FileSystemRights] $rights, 
[Parameter(Mandatory=$true)] $user,
[System.Security.AccessControl.InheritanceFlags]  $InheritanceFlag = [System.Security.AccessControl.InheritanceFlags]::None,
 [System.Security.AccessControl.PropagationFlags] $PropagationFlag = [System.Security.AccessControl.PropagationFlags]::None
) {
    $colRights = $rights

    $PropagationFlag = [System.Security.AccessControl.PropagationFlags]::None 

    $objType =[System.Security.AccessControl.AccessControlType]::Allow 

    $objUser = New-Object System.Security.Principal.NTAccount($user) 

    $objACE = New-Object System.Security.AccessControl.FileSystemAccessRule ($objUser, $colRights, $InheritanceFlag, $PropagationFlag, $objType) 

    $objACL = (Get-Item $path).GetAccessControl('Access')#(Get-ACL $path).GetAccessControl('Access')
    $objACL.AddAccessRule($objACE) 

    Set-ACL -Path $path -AclObject $objACL
}

<#

.SYNOPSIS 
Allows the specified user to publish website through webdeploy

#>    
function allow-iiswebdeploy {
param(
    [Parameter(Mandatory=$true)] $username,
    [Parameter(Mandatory=$true)] $site,
    [Switch][bool] $isgroup
)

    ipmo webadministration


    $iissite = get-item "iis:\sites\$site" -ErrorAction Stop

    if ($iissite -eq $null) { throw "site '$site' not found" }

    # add  IIS Manager Users and Permissions
    # from: https://blogs.iis.net/carlosag/adding-iis-manager-users-and-permissions-using-powershell

    [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Management") 
    [Microsoft.Web.Management.Server.ManagementAuthorization]::Grant($username, "$site", $isgroup) 

    # grant file system permissions!

    $dir = $iissite.physicalPath
    
    set-acl2 -path $dir -rights CreateFiles,Delete,Modify,CreateDirectories,ReadAndExecute -user $username -InheritanceFlag ObjectInherit,ContainerInherit 
}

Just call:

PS> allow-iiswebdeploy -username "MYDOMAIN\user" -site "Default Web Site"

And that’s it! Note that site’s physical path is obtained directly from IIS.

Resources

https://www.iis.net/learn/publish/using-web-deploy/web-deploy-powershell-cmdlets