使用$ site | Set-Item不会将更改保存回IIS站点

Kie*_*ies 8 powershell iis-7 powershell-2.0

我正在编写一些自动脚本来使用PowerShell在服务器上创建/更新IIS站点.

目的是让一个配置对象可以由一个脚本处理,以完成所有繁重的工作.

我的配置HashTable如下所示:

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

然后我的脚本使用配置来处理每个应用程序池和网站:

 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 
    }      
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,该过程实际上是相同的(除了项目路径和正在创建的类型).如果我开始工作,这当然会被重构!

我写了一个叫做的函数Set-PropertiesFromHash.这基本上将哈希表展平为属性路径:

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"))            
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

scriptblockelse子句中创建将导致执行$on.ProcessModel.IdentityType = $properties.IdentityType(每个循环中的属性对象是最后找到的HashTable值,因此这确实分配了正确的值)

问题

还在?谢谢!

以上所有工作与应用程序池的预期一样,但对网站完全失败.为什么这只对网站失败?

我知道我可以使用,Set-ItemProperty但这里的目的是允许配置对象驱动正在设置的属性.

一个更简单的例子详述如下:

# 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"
Run Code Online (Sandbox Code Playgroud)

之后Set-Item被调用,然后将物品检索再次$ap有更新的值,但$site不包含更新后的值.

我正在使用PowerShell v2和IIS7

部分解决方案...更多的解决方案

我改成Set-PropertiesFromHash工作如下:

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这让我现在继续.但是我的原始问题仍然存在.

为什么$site | Set-Item网站失败?

Web*_*ing 1

这似乎有效

(gi IIS:\sites\site1).physicalpath
(gi IIS:\sites\site1).physicalpath = "C:\sites\anothersite"
(gi IIS:\sites\site1).physicalpath
Run Code Online (Sandbox Code Playgroud)