本文主要講如何通過Powershell在IIS上自動化部署ASP.NET網站,而不涉及Powershell的基本語法,如果沒有Powershell基礎的同學也可以把本文作為學習Powershell的基石,通過學習本文中的腳本再去查閱具體的語法,可能會達到事半功倍的效果。
一般我們建立網站大致需要以下幾個步驟:
1、安裝.NET Framework
2、安裝了IIS
3、注冊、啟用ISAPI和CGI限制
4、建立網站
5、設置默認首頁、身份驗證、設置MIME類型
6、綁定域名或IP地址
7、設置權限
8、設置防火牆入站規則
功能介紹
該功能主要是將站點文件夾、Powershell腳本文件、.NET Framework安裝程序、Powershell升級程序放在同一個文件夾下,以管理員身份運行腳本文件,腳本自動安裝.NET Framework和升級Powershell並將站點文件拷貝到網站目錄下,最終建立一個網站。
接下來我們就講講如果通過Powershell實現上面的步驟:
安裝.NET Framework
首先檢查是否已經安裝了.NET Framework,如果沒有再安裝。目前我知道的有兩種方式可以判斷是否已經安裝了.NET Framework,一種是檢查注冊表,一種是檢查安裝路徑(有點不靠譜),在本文中我將通過注冊表來檢查是否已經安裝了.NET Framework。.NET Framework的注冊表路徑在“HKLM:\SOFTWARE\Microsoft\NET Framework Setup\”,所以可以通過以下代碼來實現:
test-path "HKLM:\SOFTWARE\Microsoft\NET Framework Setup\"
但是上面的代碼只能檢查.NET Framework的安裝情況,並不知道是安裝了哪個版本,所以還需要配合下面的代碼:
$version = gci 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP'| sort pschildname -desc | select -fi 1 -exp pschildname
gci是Get-ChildItem的縮寫,srot是Sort-Object的縮寫,可以通過運行Get-Help Get-ChildItem -Detailed來查看該函數的詳細信息,其他函數只要替換掉Get-ChilItem就可以了。具體的代碼如下所示:
function CheckFramework { try { $exists = test-path "HKLM:\SOFTWARE\Microsoft\NET Framework Setup\" if($exists -eq $false) { return $false } else { $version = gci 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP'| sort pschildname -desc | select -fi 1 -exp pschildname if($version -ge "v4.0") { return $true } else { return $false } } } catch { Write-Error $_.Exception.Message } }
檢查后就是安裝.NET Framework,調用安裝程序是通過Start-Process函數來實現的,只需找出文件夾下的exe文件,並調用Start-Process函數即可:
Write-Progress "正在安裝.NET Framework" "請稍候……" Get-ChildItem $PSScriptRoot -Filter *.exe | %{start -wait $_ -ArgumentList "/quiet"}
Write-Progress "completed" "completed" -Completed
Write-Progress是顯示進度條信息,$PSScriptRoot是獲取當前腳本所在的路徑。-ArgumentList參數表示該安裝過程是以靜默安裝的方式進行,如果沒有該參數就會顯示具體的安裝過程。接下來是升級Powershell到4.0版本,因為后面的腳本是基於4.0來寫的。
升級Powershell
在升級之前同樣是先檢查Powershell的版本,如果已經是4.0版本了就沒有必要再重新更新一次了。升級Powershell的方式跟安裝.NET Framework的方式是一樣的,只是在升級完成時系統會自動重啟以完成升級,也可以在安裝后不自動重啟,只需在-ArgumentList參數里使用"/quiet /norestart"即可,但是本文中的腳本是會自動重啟。如果你的腳本不是基於4.0版本的就可以設置為不自動重啟了。那么,如何讓系統重啟后自動執行當前的腳本呢?你可能會想到注冊表,沒錯,本文就是通過寫注冊表的方式來實現,如果已經是4.0版本的話就可以用另外一種方式來實現了,具體的代碼如下:
#Register-ScheduledJob只能在3.0以后使用 #$scriptPath = $MyInvocation.ScriptName #$trigger = New-JobTrigger -AtStartup -RandomDelay 00:01:00 #Register-ScheduledJob -Trigger $trigger -FilePath $scriptPatp -Name UpgradePowershell $registryValue = "{0}\system32\WindowsPowerShell\v1.0\powershell.exe {1}" -f $env:windir,$MyInvocation.ScriptName $registryPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\RunOnce" $exists = Test-Path $registryPath if($exists -eq $false) { New-Item $registryPath } New-ItemProperty "$registryPath" Upgrade -PropertyType String -Value "$registryValue"
注釋的代碼就是另外一種實現方式,但是只能在3.0以后的版本中使用。在HKCU下是沒有RunOnce這個項的,所以需要先判斷該注冊表路徑是否存在,在HKLM下的話就有RunOnce路徑了。RunOnce表示只會執行一次,執行完后該注冊信息就會被刪除。
安裝IIS
在安裝調用安裝IIS的方法之前需要先使用下面的代碼引入ServerManager模塊,否則沒有辦法調用具體的函數:
Import-Module servermanager
添加功能和角色主要用Add-WindowsFeature -name,name參數是功能或角色的名稱,如果不知道具體功能和角色的名稱可以用Get-WindowsFeature來獲取相關角色或功能的名稱:
$features = get-windowsfeature web-* foreach($item in $features) { if($item.installed -eq $false) { Write-Host "安裝:$item.displayname" $item | add-windowsfeature } }
首先獲取以web-開頭的所有角色和功能,逐個判斷是否已經安裝,沒有安裝的再進行安裝。
注冊、啟用ISAPI和CGI限制
在運行注冊命令之前先判斷是否已經注冊,如果注冊了判斷是否已經啟用。在Powershell注冊ISAPI和在命令提示符中注冊是差不多的,都是要以管理員身份身份運行。如果是直接運行aspnet_regiis.exe的全路徑的話,Powershell和cmd中的命令是一樣的,即:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -i
如果是先切換到aspnet_regiis.exe的目錄下,在cmd下可以直接運行aspnet_regiis.exe -i,在Powershell下則需要運行./aspnet_regiis.exe -i,否則Powershell無法識別aspnet_regiis.exe -i命令。通過下面的腳本獲取是否已經注冊和啟用,並賦值給$isapiConfiguration變量:
$isapiConfiguration = get-webconfiguration "/system.webServer/security/isapiCgiRestriction/add[@path='$isapiPath']/@allowed"
$isapiPath是一個變量,存放isapi的全路徑。如果變量$isapiConfiguration等於null的話說明尚未注冊isapi,如果變量不等於null,並且$isapiConfiguration.Value等於false的話說明未啟用isapi。
#檢查系統是否是64bit function Is64Bit { [IntPtr]::Size -eq 8 } #注冊或啟用ISAPI function RegisterAndEnableIsapi { $is64Bit = Is64Bit $isapiPath="" if($is64Bit) { $isapiPath ="$env:windir\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" } else { $isapiPath ="$env:windir\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" } $isapiConfiguration = get-webconfiguration "/system.webServer/security/isapiCgiRestriction/add[@path='$isapiPath']/@allowed" if($isapiConfiguration -eq $null) { write-host "IIS尚未注冊aspnet_isapi.dll" $tmpPath="" if($is64Bit) { $tmpPath = "$env:windir\Microsoft.NET\Framework64\v4.0.30319\" } else { $tmpPath = "$env:windir\Microsoft.NET\Framework\v4.0.30319\" } set-location $tmpPath .\aspnet_regiis.exe -i $isapiConfiguration = get-webconfiguration "/system.webServer/security/isapiCgiRestriction/add[@path='$isapiPath']/@allowed" } if($isapiConfiguration.Value -eq $false) { write-host "IIS已經注冊過aspnet_isapi.dll,但未啟用" set-webconfiguration "/system.webServer/security/isapiCgiRestriction/add[@path='$isapiPath']/@allowed" -value true if(Is64Bit) { set-webconfiguration "/system.webServer/security/isapiCgiRestriction/add[@path='$env:windir\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll']/@allowed" -value true } Write-Host "isapi已啟用" } else { write-host "IIS已經注冊過aspnet_isapi.dll,且已啟用" } }
創建應用程序池
在新建應用程序池和新建網站之前需要先引入“WebAdministration”模塊,否則會出現下面的錯誤:
該模塊在2.0版本下是沒有的,所以要升級到4.0版本。
由於我們手動建立網站的時候會自動創建應用程序池,只需要設置應用程序池的相關屬性就可以,但用Powershell腳本新建網站的時候是不會自動創建應用程序池的,所以我們需要先創建好應用程序池,在創建網站的時候將其指向到新建的應用程序池。
set-location iis:\AppPools $existsAppPool = test-path $appPoolName if($existsAppPool -eq $false) { $appPool = new-item $appPoolName #設置標識:LocalService=1;LocalSystem=2;NewworkService=3;ApplicationPoolIdentity=4 $appPool.ProcessModel.IdentityType=4 #設置.NET Framework 版本 $appPool.managedRuntimeVersion="v4.0" #設置托管管道模式:集成=0;經典=1 $appPool.ManagedPipelineMode=0 $appPool.startMode="AlwaysRunning" #設置啟用32位應用程序 false=0;true=1 $appPool.enable32BitAppOnWin64=0 $appPool | set-item } else { write-error "應用程序池已經存在" }
創建網站
因為動態壓縮功能只要有安裝,在新建網站的時候會自動啟用,所以有需要啟用動態內容壓縮功能的話就需要檢查該功能是否已經安裝。
#安裝動態內容壓縮功能 function EnableGZip { $check = get-windowsfeature web-dyn-compression if($check.installed -eq $false) { add-windowsfeature web-dyn-compression } }
檢查網站目錄是否存在,如果不存在就新建一個目錄並設置權限,如果要關聯的目錄不存在的話就會出現下面的錯誤:
#設置權限 function SetSecurity($name,$path) { $acl= get-acl $path $ar = new-object System.Security.AccessControl.FileSystemAccessRule("$name","ReadAndExecute","ContainerInherit,ObjectInherit","None","Allow") $acl.SetAccessRule($ar) set-acl $acl -path $path } function CheckDirectory($path) { $existsPath=test-path $path if($existsPath -eq $false) { write-host "【$path】目錄不存在,新建該目錄" new-item -path $path -type directory } #設置network service用戶的權限 Write-Progress "正在設置目錄權限,請稍候……" SetSecurity "network service" $path SetSecurity "everyone" $path Write-Progress "completed" -Completed }
$name是“組或用戶名”,$path是站點路徑。
將當前文件夾下的站點文件拷貝到站點目錄下,由於拷貝文件可能會比較耗時,所以使用了進度條顯示拷貝進度,如果不使用進度條的話就只要兩條語句就可以完成:
$siteFilePath = (get-childitem $psscriptroot | ?{$_.psiscontainer})[0].fullname Copy-Item "$siteFilePath\*" $sitePath -Force -Recurse
使用進度條的方式:
#將腳本文件所在目錄下的文件夾下的文件全部拷貝到站點目錄下 function CopyFiles { $siteFilePath = (get-childitem $psscriptroot | ?{$_.psiscontainer})[0].fullname $files=Get-ChildItem "$siteFilePath\*" $count = $files.Length for($i=0;$i -lt $count;$i++) { $copied = $i+1; Copy-Item $files[$i] $sitePath -Force -Recurse $percentage = $copied/$count $msg = "已拷貝:{0:p0}" -f $percentage Write-Progress -Activity "正在拷貝文件到:【$sitePath】目錄" -Status $msg -PercentComplete ($percentage*100) } Write-Progress "拷貝結束" -Completed }
上述准備工作做完之后就是建立網站了
set-location iis:\sites if((test-path $siteName) -eq $true) { write-error "站點已經存在"; } else { #新建站點 new-website $siteName -physicalpath $sitepath #綁定域名 new-webbinding -name $siteName -host $hostname -port 80 -protocol http #獲取本機IP $ojbItem = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE -ComputerName . $ipaddress = $ojbItem.IPAddress[0] #綁定IP地址和端口 new-webbinding -name $siteName -ip $ipaddress -port $port -protocol http #設置應用程序池 set-itemproperty $siteName -name applicationpool -value $appPoolName #啟用Forms身份驗證 $config = get-webconfiguration system.web/authentication $siteName $config.mode="Forms" $config|set-webconfiguration system.web/authentication #啟用匿名身份驗證 Set-WebConfigurationProperty -Filter system.webServer/security/authentication/anonymousAuthentication -PSPath MACHINE/WEBROOT/APPHOST -Location $siteName -Name Enabled -Value $true }
如果有開啟防火牆的話還需要添加入站規則
function AddFirewallRule($name,$tcpPorts,$appName = $null,$serviceName = $null) { try { $fw = New-Object -ComObject hnetcfg.fwpolicy2 $rule = New-Object -ComObject HNetCfg.FWRule $rule.Name = $name if ($appName -ne $null) { $rule.ApplicationName = $appName } if ($serviceName -ne $null) { $rule.serviceName = $serviceName } $rule.Protocol = 6 #NET_FW_IP_PROTOCOL_TCP $rule.LocalPorts = $tcpPorts $rule.Enabled = $true $rule.Grouping = "@firewallapi.dll,-23255" $rule.Profiles = 7 # all $rule.Action = 1 # NET_FW_ACTION_ALLOW $rule.EdgeTraversal = $false $fw.Rules.Add($rule) Write-Host "防火牆入站規則添加成功" } catch { Write-Error $_.Exception.Message } }
創建虛擬目錄的比較簡單,但是也需要檢查虛擬目錄的路徑是否存在,設置虛擬目錄的權限
new-item "$siteName\$name" -type virtualdirectory -physicalpath $path
如果有需要還可以添加MIME類型
#添加擴展名 $mime為哈希表類型 如$mimes = @{".a"="application/stream";".b"="application/stream";".c"="application/stream";} function AddMime($mime) { try { if($mimes -eq $null -or $mimes.count -le 0) { return } foreach($item in $mimes.Keys) { Write-Host "添加MIME類型:$item" $extension = get-webconfigurationproperty //staticcontent -name collection | ?{$_.fileExtension -eq $item} if($extension -ne $null) { write-host "該擴展名已經存在" } else { add-webconfigurationproperty //staticcontent -name collection -value @{fileExtension=$item;mimeType=$mimes[$item]} } } Write-Host "MIME類型添加完成" } catch { Write-Error $_.Exception.Message } }
測試網站
#請求接口 function GetRequest($url) { $request = [System.Net.HttpWebRequest]::Create($url) $response = [System.Net.HttpWebResponse]$request.GetResponse() $code = [System.Int32]$response.StatusCode $response.Close() $response.Dispose() Write-Host $code }
測試網站是通過調用.NET Framework的相關函數來實現的。
以上就是用Powershell腳本自動化部署網站的全部過程,可能還有遺落的功能沒有實現。如果你對自動化部署網站有興趣的話可以自己實現一個Powershell腳本。也請各位大牛多多指教,指出本文中的不足和錯誤的地方。