Search code examples
powershelliisurl-rewrite-moduledsc

Adding Inbound Rewrite Rule in DSC script does not work


As the title says I'm configuring Rewrite rules for Reverse Proxy functionality with:

  • IIS 8.5
  • Windows Server 2012R2
  • URL Rewrite 2.1
  • Application Request Routing 3.0
  • Powershell 5.1

For this I'm using Powershell DSC, setting the configuration in a Script Resource. This works perfectly fine for the outbound rules, but the inbound rule does not get created, nor does it give an error/warning. When trying to set properties on it (on the 3 lines after), a warning does show saying it can't find the inbound rule, btw also showing the correctly used variable name). In IIS Management Console it is also not visible (and yes, I've used F5 on it).

I'm using the command as generated from IIS itself, which is equal to everything I see online, including StackOverflow. This particular problem is not easy to find, so I must be missing something very trivial. I've already tried:

  • running the Script under different credentials
  • using a hardcoded name instead of the variable
  • using URL Rewrite 2.0
  • restarting IIS
  • rebooting server

The ONLY way I got the command working is if it's executed as a single command in (elevated) Powershell (marked below by >>>>).

Then the script itself. (for reference, one outbound rule is added too):

SetScript = {
            Write-Verbose "Checking if inbound rewrite rule is present..."

            $inbound = (Get-WebConfiguration -Filter "//System.webServer/rewrite/rules" -PSPath "IIS:\Sites\$using:frontendSiteName").Collection | Where-Object {$_.Name -eq "$using:inboundRuleName"}

            if($inbound -eq $null) {
                Write-Verbose "Inbound rewrite rule not present, configuring..."

        >>>>    Add-WebConfigurationProperty -Filter "//System.webServer/rewrite/rules" -Name "." -Value @{name=$using:inboundRuleName;stopProcessing="True"} -PSPath "IIS:\Sites\$using:frontendSiteName"
                Set-WebConfigurationProperty -Filter "//System.webServer/rewrite/rules/rule[@name='$using:inboundRuleName']/match" -Name "url" -Value "^api/(.*)" -PSPath "IIS:\Sites\$using:frontendSiteName"
                Set-WebConfigurationProperty -Filter "//System.webServer/rewrite/rules/rule[@name='$using:inboundRuleName']/action" -Name "type" -Value "Rewrite" -PSPath "IIS:\Sites\$using:frontendSiteName"
                Set-WebConfigurationProperty -Filter "//System.webServer/rewrite/rules/rule[@name='$using:inboundRuleName']/action" -Name "url" -Value "http://localhost:8000/api/{R:1}" -PSPath "IIS:\Sites\$using:frontendSiteName"

                Write-Verbose "Inbound rewrite rule configured"
            }

            Write-Verbose "Checking if outbound HTML rule is present..."

            $outboundHTML = (Get-WebConfiguration -Filter "//System.webServer/rewrite/outboundRules" -PSPath "IIS:\Sites\$using:frontendSiteName").Collection | Where-Object {$_.Name -eq "$using:outboundHTMLRuleName"}

            if($outboundHTML -eq $null) {
                Write-Verbose "Outbound HTML rule not present, configuring..."

                Add-WebConfigurationProperty -Filter "//System.webServer/rewrite/outboundRules/preConditions" -Name "." -Value @{name='IsHTML'} -PSPath "IIS:\Sites\$using:frontendSiteName"
                Add-WebConfigurationProperty -Filter "//System.webServer/rewrite/outboundRules/preConditions/preCondition[@name='IsHTML']" -Name "." -Value @{input='{RESPONSE_CONTENT_TYPE}';pattern='^text/html'} -PSPath "IIS:\Sites\$using:frontendSiteName"

                Add-WebConfigurationProperty -Filter "//System.webServer/rewrite/outboundRules" -Name "." -Value @{name=$using:outboundHTMLRuleName;preCondition='IsHTML'} -PSPath "IIS:\Sites\$using:frontendSiteName"
                Set-WebConfigurationProperty -Filter "//System.webServer/rewrite/outboundRules/rule[@name='$using:outboundHTMLRuleName']/match" -Name "filterByTags" -Value "A" -PSPath "IIS:\Sites\$using:frontendSiteName"
                Set-WebConfigurationProperty -Filter "//System.webServer/rewrite/outboundRules/rule[@name='$using:outboundHTMLRuleName']/match" -Name "pattern" -Value "^/(.*)" -PSPath "IIS:\Sites\$using:frontendSiteName"

                Add-WebConfigurationProperty -Filter "//System.webServer/rewrite/outboundRules/rule[@name='$using:outboundHTMLRuleName']/conditions" -Name "." -Value @{input='{URL}';pattern='^/api/.*'} -PSPath "IIS:\Sites\$using:frontendSiteName"

                Set-WebConfigurationProperty -Filter "//System.webServer/rewrite/outboundRules/rule[@name='$using:outboundHTMLRuleName']/action" -Name "type" -Value "Rewrite" -PSPath "IIS:\Sites\$using:frontendSiteName"
                Set-WebConfigurationProperty -Filter "//System.webServer/rewrite/outboundRules/rule[@name='$using:outboundHTMLRuleName']/action" -Name "value" -Value "/{C:1}/{R:1}" -PSPath "IIS:\Sites\$using:frontendSiteName"

                Write-Verbose "Outbound HTML rewrite rule configured"
            }
}

I hope someone knows why this is happening, as I'm getting pretty frustrated trying to solve this.


Solution

  • Alright, after trying a lot more (like using the newer xScript resource instead of Script and trying to put that 1 failing command in an Invoke-Command Scriptblock) I have found the solution.

    Solution: In Powershell, or at least for IIS configuration, there are 2 ways to pass the location to the command. The very known one is -PSPath, but there is also -Location. When performing the command solo (and with the other commands), what simply works is passint -PSPath "IIS:\Sites\SITENAME" to the command. How I got it to work for that command in my script now is: -PSPath "IIS:\Sites" -Location "SITENAME".

    The fact that I need to use this workaround seems to me this is a bug in the Powershell-to-IIS conversion (or in just the Rewrite-module). If I'm wrong, please correct me! Anyway, my issue is solved and I hope this answer helps someone else with this problem in the future. Thank you to the people that looked at my question and gave it some thought :)