標籤:
本文主要講如何通過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 $registryPathif($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。
#檢查系統是否是64bitfunction Is64Bit { [IntPtr]::Size -eq 8 }#註冊或啟用ISAPIfunction 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 $appPoolNameif($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].fullnameCopy-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:\sitesif((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指令碼。也請各位大牛多多指教,指出本文中的不足和錯誤的地方。
利用Powershell在IIS上自動化部署網站