我如何在 powershell 中验证 IIS web.config

how do i validate an IIS web.config in powershell

不幸的是,在 IIS 中,如果您在 wwwroot\web.config 和 wwwroot\myapp\web.config 中定义相同的设置,某些类型的设置将相互冲突,从而导致 500.19 错误。

例如允许的动词:

<security>
    <requestFiltering>
        <verbs allowUnlisted="false">
            <add verb="HEAD" allowed="true" />
            <add verb="POST" allowed="true" />
            <add verb="GET" allowed="true" />
        </verbs>
    </requestFiltering>
</security>

此外,不幸的是,PowerShell Set-WebConfiguration 在进行更改之前不会对此进行验证,一旦损坏,您将无法删除错误的配置。

我需要一种方法来验证配置 before/after 更改,以便我可以回滚它或采取行动。

我找到了这个解决方案:https://serverfault.com/questions/708079/is-there-a-cmd-tool-to-check-a-web-config-file-for-validity 但是它只验证 SYNTAX 失败或仅验证非常重要的配置问题。

它不检测其他过滤器路径的冲突: 例如无法添加唯一键属性 'verb' 设置为 'HEAD'

类型 'add' 的重复集合条目

我发现解决这个问题的方法是创建一个读取 web.config 的函数,通过解析 xml 编译过滤器列表,然后为每个过滤器执行 get-webconfiguration,过滤器将 return 一些东西,什么都没有(如果没有要读取的设置)或异常(我们关心的)

代码:

function Test-IISWebAppConfigIsValid
{
    param (
        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineBYPropertyName=$true)]
        [string]$AppName,
        [string]$SiteName='Default Web Site'
    )
    process 
    {
        $Result = @{
            IsValid=$false;
            SiteName=$SiteName
            AppName=$AppName
        }
        try
        {
            $result.Add("FileInfo",(Get-WebConfigFile -PSPath "IIS:\Sites$SiteName$AppName"))
            $Result.Add("FileExists",$result.FileInfo.Exists)
            $result.Add("IsXML",$False)
            #load the web.config
            [xml]$ConfigXML =  $result.FileInfo | Get-Content
            $result.IsXML = $true

            #find all the elements in the config file
            $Elements = $ConfigXML.SelectNodes("//node()[name() != 'add' and name() != 'remove' and name() != 'clear']") 
    
            #extract the filters from the xpath by finding all the configured elements
            $FilterList = @()
            foreach ($el in $Elements)
            {
                $FilterStack = @()
                $tempel = $el
                while ($tempel.ParentNode -and $tempel -ne $ConfigXML.DocumentElement -and $tempel -ne $ConfigXML)
                {
                    $name = $tempel.get_name()
                    if ($tempel.NodeType -eq 'Element')
                    {
                        $FilterSTack += $name
                    }
                    $tempel = $tempel.ParentNode
                }
                if ($FilterStack.Count -gt 0) {
                    [array]::Reverse($FilterStack)
                    $FilterList += "/"+[string]::Join("/",$FilterStack)
                }
            }

            $Result.Add("FilterList", ($FilterList | Sort-Object -Unique))

            #load the configuration for each xpath
            if (($result.FilterList | Measure-Object).Count -gt 0) {
                Get-WebConfiguration -PSPath "IIS:\Sites$SiteName$AppName" -Filter $result.FilterList | Out-Null
            }
            $result.IsValid=$true
        }
        catch [System.Exception]
        {
            $result.Add("Exception",$_.Exception)
        }
        finally
        {
            write-output ([PSCustomObject]$result)
        }
    }#process
}#function Test-IISWebAppConfigIsValid

'myapp1','myapp2' | Test-IISWebAppConfigIsValid |ft -Property AppName,FileExists,IsValid,Exception -AutoSize

输出:

AppName FileExists IsValid Exception                                                                                                                                  
------- ---------- ------- ---------                                                                                                                                  
myapp1        True   False System.Runtime.InteropServices.COMException (0x800700B7): Filename: \?\C:\inetpub\wwwroot\myapp1\web.config...                               
myapp2        True    True