Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using $site | Set-Item does not save changes back to IIS site

I'm in the process of writing some automated scripts to create/update IIS sites on a server using PowerShell.

The aim is to have a configuration object that can then be handled by a single script to do all the heavy lifting.

My config HashTable looks like this:

$config = @{
    AppPools = (
        @{
            Name="AppPool1"
            Properties = @{
                Enable32BitAppOnWin64=$true
                ManagedRuntimeVersion="v4.0"
                ProcessModel = @{
                    IdentityType = "NetworkService"
                }
            }
        }
    )
    Websites = (
        @{
            Name="Site1"
            Properties = @{
                PhysicalPath = "C:\sites\site1"
                ApplicationPool = "AppPool1"
            }
        }
    )    
}

My script then uses the config to process each application pool and web site:

 Import-Module WebAdministration

 $config.AppPools | 
    % {
        $poolPath = "IIS:\AppPools\$($_.Name)"
        
        # Create if not exists
        if(-not(Test-Path $poolPath)){ New-WebAppPool $_.Name }            
        
        # Update the properties from the config
        $pool = Get-Item $poolPath
        Set-PropertiesFromHash $pool $_.Properties
        $pool | Set-Item            
    }
        
 $config.Websites | 
    %{        
        $sitePath = "IIS:\Sites\$($_.Name)"
            
        # Create if not exists
        if(-not(Test-Path $sitePath)){ New-WebSite $_.Name -HostHeader $_.Name }
            
        # Update the properties from the config
        $site = Get-Item $sitePath
        Set-PropertiesFromHash $site $_.Properties
        $site | Set-Item 
    }      

As you can see the process is virtually identical (apart from the item paths and type being created). This will of course be refactored if I get things working!

I've written a function called Set-PropertiesFromHash. This basically flattens the hash table to a property path:

Function Set-PropertiesFromHash{
    Param(
        [Parameter(Mandatory=$true, HelpMessage="The object to set properties on")]        
        $on,
        [Parameter(Mandatory=$true, HelpMessage="The HashTable of properties")]
        [HashTable]$properties,
        [Parameter(HelpMessage="The property path built up")]
        $path
    )
    foreach($key in $properties.Keys){
        if($properties.$key -is [HashTable]){
            Set-PropertiesFromHash $on $properties.$key ($path,$key -join '.')
        } else {            
            & ([scriptblock]::Create( "`$on$path.$key = `$properties.$key"))            
        }
    }
}

The created scriptblock in the else clause will result in the execution of $on.ProcessModel.IdentityType = $properties.IdentityType (the properties object in each loop is the last found HashTable value so this does assign the correct value)

The Question

Still here? Thanks!

All of the above works just as expected for application pools but fails completely for websites. Why is this failing only for websites?

I know I can use Set-ItemProperty but the aim here is to allow the config object to drive the properties that are being set.

A simpler example is detailed below:

# Setting an app pool property this way works as expected
$ap = gi IIS:\apppools\apppool1
$ap.enable32BitAppOnWin64 # returns False
$ap.enable32BitAppOnWin64 = $true
$ap | Set-Item
$ap = gi IIS:\apppools\apppool1
$ap.enable32BitAppOnWin64 # returns True

# Setting a website property this way fails silently
$site = gi IIS:\sites\site1
$site.physicalpath # returns "C:\sites\site1"
$site.physicalpath = "C:\sites\anothersite"
$site | Set-Item
$site = gi IIS:\sites\site1
$site.physicalpath # returns "C:\sites\site1"

After Set-Item is called and then the items are retrieved again $ap has the updated value but $site does not contain the updated value.

I'm using PowerShell v2 and IIS7

Partial Resolution ... more of a work around

I've changed Set-PropertiesFromHash to work as follows:

Function Set-PropertiesFromHash{
    Param(
        [Parameter(Mandatory=$true, HelpMessage="The object to set properties on")]        
        $on,
        [Parameter(Mandatory=$true, HelpMessage="The HashTable of properties")]
        [HashTable]$properties,
        [Parameter(HelpMessage="The property path built up")]
        $pathParts = @()
    )
    foreach($key in $properties.Keys){        
        if($properties.$key -is [HashTable]){
            Set-PropertiesFromHash $on $properties.$key ($pathParts + $key)
        } else {                  
            $path = ($pathParts + $key) -join "."
            Set-ItemProperty $on $path $properties.$key
        }
    }
}

Which has allowed me to continue for now. However my original question still stands.

Why does $site | Set-Item fail for sites?

like image 765
Kieranties Avatar asked Oct 26 '12 12:10

Kieranties


1 Answers

This seems to work

(gi IIS:\sites\site1).physicalpath
(gi IIS:\sites\site1).physicalpath = "C:\sites\anothersite"
(gi IIS:\sites\site1).physicalpath
like image 73
Webplanet TFS Consulting Avatar answered Nov 15 '22 04:11

Webplanet TFS Consulting