CarlR
CarlR

Reputation: 1768

How to configure 32-bit IIS websites or applications using PowerShell cmdlets

I am trying to change the location of the ASP.NET temporary files so that I can clean them up during the release of a new version.

Because it is very hard to find the location of the ASP.NET temporary files for a specific website, application of virtual directory under the C:\Windows\Microsoft.NET\Framework C:\Windows\Microsoft.NET\Framework64 locations I decided it would be easier just to move the files to a specific location on the disk which can then be cleaned.

You can do this by modifying the tempDirectory attribute in the system.web/compilation configuration section.

We have our server build and release processes automated therefore this looked straightforward to add the code to the configuration and release scripts.

However during testing I found that the location of 32-bit applications does not change.

The code I am using is:

Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT' -location 'MyWebSite' -filter 'system.web/compilation' -name 'tempDirectory' -value 'E:\Temporary ASP.NET Files\MyWebSite' -Clr v2.0

This code works without errors and writes an entry into the root web.config file at: C:\Windows\Microsoft.NET\Framework64\v2.0.50727\CONFIG\web.config.

e.g.

<location path="MyWebSite">
  <system.web>
    <compilation tempDirectory="E:\Temporary ASP.NET Files\MyWebSite" />
  </system.web>
</location>

Note that without the -Clr v2.0 parameter, the value would be written to the CLR 4.0 configuration file at C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\web.config.

You can see the entry in IIS Configuration Editor as well:IIS Configuration Editor showing temporary path specified

The problem is the application pool is set to "Enable 32-Bit Applications" and therefore this property is ignored.

If I manually move the location element shown above from C:\Windows\Microsoft.NET\Framework64\v2.0.50727\CONFIG\web.config to C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\web.config

The change works and indeed the ASP.NET temporary files move to this location specified when the compilation of the website occurs.

The question is not about ASP.NET temporary files, it is a more general question on how are you meant to configure 32-bit applications in PowerShell or indeed in IIS? There seems to be no way to do it which I find incredible. There are plenty of 32-bit applications around which still need to be configured.

Also please note that I have chosen to use the root web.config to store this value for good reasons:

  1. ApplicationHost.config cannot store system.web configuration
  2. The location of the temporary files is not something that is known at design time and is determined by the hosting server configuration. Therefore this setting cannot be specified in the web.config file for the application itself.

Upvotes: 0

Views: 3534

Answers (2)

CarlR
CarlR

Reputation: 1768

After experimentation, using some information from the answer provided here and an offline conversation I can say conclusively that it is not possible to edit 32-bit root web.config files using the Microsoft WebAdministration PowerShell cmdlets.

It seems that the cmdlets are hard coded to only look at the 64-bit versions of the configuration files. IIS Manager behaves the same way. Why this is the case is inexplicable to me.

I also found a lot of problems using some of the cmdlets for editing 64 bit Clr 2.0 websites and applications. The Clr parameter is not present on all the cmdlets and even in the ones where it is it does not seem to always work.

Therefore I decided to abandon the WebAdministration cmdlets and use the 'Microsoft.Web.Administration.dll' assembly and the Microsoft.Web.Administration.ServerManager object directly.

The following are some of the functions I wrote which might be helpful:

    function Get-MWAConfigObjects
    {
        <#
                .SYNOPSIS
                Returns object to manage IIS configuration in root web.config
                .DESCRIPTION
                The objects returned allow viewing or editing or configuration. Parameters open the appropriate version, either 32 or 64 bit for the appropriate version of the ManagedRunTime. https://msdn.microsoft.com/en-us/library/microsoft.web.administration.servermanager(v=vs.90).aspx
Ensure that you call CommitChanges to save any changes made.
                .EXAMPLE
                $MWA = Get-MWAConfigObjects -ManagedRunTimeVersion v2.0 -Architecture 32               $MWA.Configuration.GetSection('system.web/compilation','MyWebSite/MyApplication').SetAttributeValue('tempDirectory', 'C:\NewPath')
                $MWA.ServerManager.CommitChanges()             
        #>
        [cmdletbinding(positionalbinding = $false)]
        param(
            [Parameter(Mandatory = $True)][string][ValidateSet('v2.0','v4.0')] $ManagedRunTimeVersion,
            [Parameter(Mandatory = $True)][string][ValidateSet(32,64)] $Architecture
        )
    
        $assemblyPath = $(Join-Path -Path $([System.Environment]::GetFolderPath('System')) -ChildPath $(Join-Path -Path 'inetsrv' -ChildPath 'Microsoft.Web.Administration.dll'))
        If (Test-Path -Path $assemblyPath -PathType Leaf)
        {
            $null = [System.Reflection.Assembly]::LoadFrom($assemblyPath)
            $iis = New-Object -TypeName Microsoft.Web.Administration.ServerManager
            $wcm = New-Object -TypeName Microsoft.Web.Administration.WebConfigurationMap -ArgumentList $(Get-ConfigFilePath -Type machine -ManagedRunTimeVersion $ManagedRunTimeVersion -Architecture $Architecture), $(Get-ConfigFilePath -Type web -ManagedRunTimeVersion $ManagedRunTimeVersion -Architecture $Architecture)
            $configuration = $iis.GetWebConfiguration($wcm, $null)
        
            $object = New-Object -TypeName PSObject
            $object | Add-Member -MemberType NoteProperty -Name ServerManager -Value $iis
            $object | Add-Member -MemberType NoteProperty -Name Configuration -Value $configuration
            Write-Output -InputObject  $object
        }
        else
        {
            Throw "Cannot validate existence of required assembly 'Microsoft.Web.Administration.dll' at ""$assemblyPath"""
        }
    }

    function Get-ConfigFilePath
    {
        [CmdletBinding(PositionalBinding = $false)]
        param
        (
            [Parameter(Mandatory = $True)][string][ValidateSet('web','machine')] $Type, 
            [Parameter(Mandatory = $True)][string][ValidateSet('v2.0','v4.0')] $ManagedRunTimeVersion, 
            [Parameter(Mandatory = $True)][string][ValidateSet(32,64)] $Architecture
        )
        
        $ErrorActionPreference = 'stop'
    
        switch ($ManagedRunTimeVersion)
        {
            'v2.0'
            {
                switch ($Architecture)
                {
                    32
                    {
                        $path = $(Join-Path -Path $([System.Environment]::GetFolderPath('Windows')) -ChildPath "Microsoft.NET\Framework\v2.0.50727\CONFIG\$Type.config")
                        break
                    }
                    64
                    {
                        $path = $(Join-Path -Path $([System.Environment]::GetFolderPath('Windows')) -ChildPath  "Microsoft.NET\Framework64\v2.0.50727\CONFIG\$Type.config")
                        break
                    }
                }
    
                break;
            }
            'v4.0'
            {
                switch ($Architecture)
                {
                    32
                    {
                        $path = $(Join-Path -Path $([System.Environment]::GetFolderPath('Windows')) -ChildPath "Microsoft.NET\Framework\v4.0.30319\CONFIG\$Type.config")
                        break
                    }
                    64
                    {
                        $path = $(Join-Path -Path $([System.Environment]::GetFolderPath('Windows')) -ChildPath  "Microsoft.NET\Framework64\v4.0.30319\CONFIG\$Type.config")
                        break
                    }
                }
    
                break;
            }
        }
    
        If (Test-Path -Path $path -PathType Leaf)
        {
            Write-Output -InputObject $path
        }
        else
        {
            Throw "Cannot validate configuration file at path ""$path"""
        }
    }

Upvotes: 0

Jeong Hwan Kim
Jeong Hwan Kim

Reputation: 116

there are two workarounds.

  1. Use 32 bit appcmd.exe. Here is the example.

%windir%\syswow64\cmd.exe %windir%\syswow64\inetsrv\appcmd.exe set config -section:appSettings /+"[key='test',value='test']" /commit:webroot /clr:4.0

  1. Use MWA directly on powershell. Here is the example.

$iis = new-object Microsoft.Web.Administration.ServerManager $wcm = New-Object -TypeName Microsoft.Web.Administration.WebConfigurationMap -ArgumentList "C:\Windows\Microsoft.NET\Framework\v4.0.30319\CONFIG\machine.config","C:\Windows\Microsoft.NET\Framework\v4.0.30319\CONFIG\web.config" $iis.GetWebConfiguration($wcm, $null).GetSection("appSettings").SetAttributeValue("file", "test3") $iis.CommitChanges()

Upvotes: 1

Related Questions