Microsoft.Web.Administration not saving changes to a site's custom log fields collection

119 views Asked by At

I'm trying to use the Microsoft.Web.Administration API to configure a site's custom log fields. Here's my code:

$serverManager = [Microsoft.Web.Administration.ServerManager]::New()
$config = $serverManager.GetApplicationHostConfiguration()
$sitesSection = $config.GetSection("system.applicationHost/sites")
$siteElement = $sitesSection.GetCollection() | Where-Object { $_.GetAttributeValue('name') -eq $name }

$logFileElement = $siteElement.GetChildElement("logFile")
$customFieldsElement = $logFileElement.GetChildElement("customFields")
$customFieldsCollection = $customFieldsElement.GetCollection()

$logFileElement.SetAttributeValue('Period', 'Hourly')

$addElement = $customFieldsCollection.CreateElement("add")
$addElement["logFieldName"] = "ContosoField"
$addElement["sourceName"] = "ContosoSource"
$addElement["sourceType"] = "ServerVariable"
$customFieldsCollection.Add($addElement)

$serverManager.CommitChanges()

However, after calling CommitChanges, the applicationHost.config file doesn't show the custom log fields:

<site name="Clear-CIisCollectiono4adlbez.w4u" id="4">
    <application path="/">
        <virtualDirectory path="/" physicalPath="C:\InetPub\0" />
    </application>
    <bindings>
        <binding protocol="http" bindingInformation="*:63001:" />
    </bindings>
    <logFile />
</site>

I can add the configuration via the IIS Manager UI.

This is part of an automated test that creates a new site every time the test runs. The first run, the test fails because the custom log field configuration is missing. But on subsequent runs it fails because it thinks the website already has the custom log field in its collection (i.e. the Microsoft.Web.Administration API is somehow caching the collection and applying it to the next site I create).

I've tried using $serverManager.Sites.LogFile object directly, and get the same behavior.

After a little bit of research, we discovered that Microsoft.Web.Administration is adding the custom log fields to the first site in applicationHost.config that doesn't have any custom log fields.

I can get appcmd.exe to eventually save the changes. It also will change the first website but sometimes it doesn't.

C:\Windows\System32\inetsrv\appcmd.exe set config -section:system.applicationHost/sites /+"[name='${name}'].logFile.customFields.[logFieldName='ContosoField',sourceName='ContosoSource',sourceType='ServerVariable']" /commit:apphost

Calling CommitChanges multiple times doesn't work.

Anyone know of any workarounds or fixes for this behavior?

2

There are 2 answers

1
DrJay On

try committing changes for each site individually, immediately after making changes.

Perform operations on the first site $serverManager.CommitChanges()

Create a new site and perform operations on it ...

Commit changes for the new site $serverManager.CommitChanges()

Update.

Sorry, must learn to read the question.

Hopefully for security you’ve substituted the actual site with $name. If you have, then apologies. But, sometimes it’s the simplest things.

0
Eldar On

Well, according to documentation the GetApplicationHostConfiguration() method "Returns a Configuration object for the default ApplicationHost.config file."

So this part: automated test that creates a new site every time the test runs may be cached and the newly added site's configuration is not reflected to ApplicationHost.config file. But you can directly use Sites collection to modify your site directly :

$site = $serverManager.Sites | Where-Object { $_.Name -eq $name }

if ($site -ne $null) {
    $logFile = $site.LogFile

    # Here we modify the $logfile
    $logFile.Period = LoggingRolloverPeriod.Hourly
    $logFile.Enabled = $true

    $addElement = $logFile.CustomFields.CreateNewElement("add")
    $addElement["logFieldName"] = "ContosoField"
    $addElement["sourceName"] = "ContosoSource"
    $addElement["sourceType"] = "ServerVariable"

    $serverManager.CommitChanges()

    Write-Host "OK"
} else {
    Write-Host "No such '$name' found."
}