利用Powershell在IIS上自动化部署网站

本文主要讲如何通过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脚本。也请各位大牛多多指教,指出本文中的不足和错误的地方。

时间: 2024-10-07 11:01:59

利用Powershell在IIS上自动化部署网站的相关文章

IIS上架设https网站证书处理备忘

1. 免费SSL证书申请 https://www.startssl.com 教程:http://hxs.fd.fj.cn/?action=show&id=13 2. 证书转换 申请到的证书有两个关键文件(适用于openssl文本格式), xxx.key & xxx.crt,要在IIS上安装需要转换成pfx格式,转换命令: openssl pkcs12 -export -out server.pfx -inkey xxx.key -in xxx.crt 3. 证书安装 在IIS中,打开“服务

利用Fabric+Capistrano实现Python自动化部署

Fabric是一个用于应用(批量)部署和系统(批量)管理的Python库和命令行工具,关于Fabric的介绍请参考:http://www.fabfile.org/. Capistrano是一个用Ruby语言编写的远程服务器自动化和部署工具,关于Capistrano的介绍请参考:http://capistranorb.com/. 本文仅使用Python语言和部分Linux或Windows系统命令,借助Fabric模块和Capistrano的部署思路,实现在Linux平台和Windows平台的自动化

利用jenkins做项目的自动化部署

最近领导要求上海本地的项目需要使用进jenkins实现自动化部署,以便可以直接将项目移交给运维的同学,减轻开发的工作量.记录下这次爬坑的过程. 一.前言 Jenkins是基于Java开发的一种持续集成工具,用于监控持续重复的工作,功能包括: 1.持续的软件版本发布/测试项目. 2.监控外部调用执行的工作. 上面是我从百科上down下来的,老实说没看懂,这是个什么玩意啊?其实以我现在的理解和应用,最多的便是部署了,其他功能待研究╮(╯_╰)╭ 撸主目前在上海一个不知名国企打工,我们现在项目的发布流

利用powershell script每个月定期从microsoft download网站上抓补丁

This artical will be published in English also: http://www.cnblogs.com/LarryAtCNBlog/p/4026695.html 本人所在的公司对于安全性要求较高,除了平时各种内网加密外网firewall之外,对于server所使用的OS也要求更新到最新的security级别的补丁. 但是样本数量一多就总有些是打不上补丁的,这可能由于各种各样如update配置错误,SCCM/WSUS抽风,加上第3方扫描补丁软件的2X机制和se

Asp.net Core IIS上安装部署

安装IIS:"控制面板" > "程序" > "程序和功能" > "打开或关闭 Windows 功能". 安装 .NET Core Windows Server 托管捆绑包. 在托管系统上安装 .NET Core Windows Server 托管捆绑包. 捆绑包可安装 .NET Core 运行时..NET Core 库和ASP.NET Core模块. 该模块创建 IIS 与 Kestrel 服务器之间的反向代

ASP.NET Core部署系列一:发布到IIS上

前言: 当构建一个ASP.NET Core应用程序并且计划将其运行在IIS中时,你会发现Core应用程序和之前版本的ASP.NET程序在IIS中的运行方式是完全不一样的.与ASP.NET时代不同,ASP.NET Core不再是由IIS工作进程(w3wp.exe)托管,而是使用自托管Web服务器(Kestrel)运行,IIS则是作为反向代理的角色转发请求到Kestrel不同端口的ASP.NET Core程序中,随后就将接收到的请求推送至中间件管道中去,处理完你的请求和相关业务逻辑之后再将HTTP响

利用Powershell自动部署asp.net mvc网站项目 (一)

这一篇中我们会写一些关于自动化部署的代码.我们会使用 Powershell 书写这类代码. 你将发现这篇文章中涉及的东西非常具体,有的要求甚至相当苛刻且可能不具有通用性.这是因为部署从来都是跟环境打交道,部署过程中协作的组建太多,相互之间的交集不可能太大.可能唯一能够通用的是自动化部署的基本原则(只是这篇文章的基本原则): 每一次自动化部署结束之后,应用程序都会有相同的初始状态. 自动化部署的机器非常干净,只有相应的 Windows Server 系统和 .NET Framework.尤其是,不

IIS上部署MVC网站,打开后ExtensionlessUrlHandler-Integrated-4.0解决办法

IIS上部署MVC网站,打开后ExtensionlessUrlHandler-Integrated-4.0解决方法 IIS上部署MVC网站,打开后500错误:处理程序“ExtensionlessUrlHandler-Integrated-4.0”在其模块列表中有一个错误模块“ManagedPipelineHandler” 解决方法如下: 以管理员运行下面的命令注册: 32位机器: C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regii

IIS上部署MVC网站,打开后ExtensionlessUrlHandler-4.0

IIS上部署MVC网站,打开后ExtensionlessUrlHandler-Integrated-4.0解决方法IIS上部署MVC网站,打开后500错误 IS上部署MVC网站,打开后ExtensionlessUrlHandler-Integrated-4.0解决方法 IIS上部署MVC网站,打开后500错误:处理程序“ExtensionlessUrlHandler-Integrated-4.0”在其模块列表中有一个错误模块“ManagedPipelineHandler” 解决方法如下: 以管理