佈建第二部 Web Sites 控制器

 

適用於: Windows Azure Pack

Windows Azure Pack: Web Sites 最多可有兩個 Web Sites 控制站。如果要使用高可用性,極力建議您採用此上限值並佈建第二部 Web Sites 控制器。您可以使用下列提供的指令碼達成此目的:

OnStartSecondaryController.cmd

HostingBootstrapperBootstrapper.ps1

OnStartSecondaryController.ps1

Common.ps1

  • OnStartSecondaryController.cmd:在您所準備的 Windows 2012 伺服器或虛擬機器上,安裝 WebPlatform Installer (Web PI)。接下來,其會依序呼叫 HostingBootstrapperBootstrapper 及 OnStartSecondaryController 指令碼,完成次要控制器的佈建工作。必要項目包括 SQL Server 及控制器的系統管理認證,供設定時使用。

  • HostingBootstrapperBootstrapper.ps1:呼叫 Program Files\Microsoft\Web Platform Installer\WebpiCmd.exe,以安裝第二部 Web Sites 控制器。其程序和安裝主要控制站相同,但會指定命令列參數 /SuppressPostFinish,中斷入口網站設定。

  • OnStartSecondaryController.ps1:從主要控制站複製組態資料到次要控制器,包括 SystemCoreSiteRuntime 金鑰,以及主控與資源計量連接字串。完成後,其會啟動 WebFarmService。

  • Common.ps1:提供 OnStartSecondaryController.ps1 指令碼的支援函數。

System_CAPS_important重要事項

這些指令碼需要主要控制器啟用 Windows 遠端管理 (WinRM)。

  1. 將指令碼檔案複製到擔任次要控制器之伺服器上的資料夾。

  2. 將 WebPlatformInstaller.msi 檔案複製到指令碼所在的資料夾。此為必要步驟,因為 OnStartSecondaryController.cmd 指令碼會自動安裝 Web PI。

  3. 以系統管理員權限執行 OnStartSecondaryController.cmd,並提供下表所列的參數。您必須具備系統管理權限,如此才能透過 Web PI 自動化作業安裝適當的產品,同時主要控制站也才能透過 WinRM 進行存取。

    System_CAPS_note注意事項

    在 WORKGROUP 案例中,您可能需要啟用主要控制站的 WinRM,或是手動執行 OnStartSecondaryController.cmd 指令碼中的命令。

OnStartSecondaryController.cmd -feed %Feed% -webSitesInstanceName %WebSitesInstanceName% -sqlservername %DatabaseServerName% -sqlsysadmin %DatabaseSysAdminAccount% -sqlsysadminpwd %DatabaseSysAdminPassword% -controllerAdminUserName %ControllerAdminUserName% -controllerAdminPassword %ControllerAdminPassword%

參數名稱

說明

附註

feed

選擇是否要指定 Web PI 摘要,在安裝控制器時使用。

如果未指定此參數,將會使用預設的 Web PI 主要摘要。

webSitesInstanceName

用為資料庫物件的字首

必須符合所安裝之資料庫的名稱字首。

sqlservername

SQL Server 執行個體的名稱

sqlsysadmin

SQL Server 系統管理使用者帳戶的名稱

必須是系統管理伺服器角色的成員。

sqlsysadminpwd

SQL Server 系統管理使用者帳戶的密碼

controllerAdminUserName

要佈建之 Web Farm Framework (WFF) 系統管理員帳戶的名稱

這如果是網域帳戶,將會加入本機的 Administrators 群組。

如果伺服器位於 WORKGROUP,而使用者不存在,其會嘗試建立該使用者,並將其加入本機的 Administrators 群組。

controllerAdminPassword

要佈建之 WFF 系統管理員帳戶的密碼

@echo off
echo Starting OnStartSecondaryController.cmd

rem ---------------------------------------------
rem Initialize Variables
rem ---------------------------------------------
    set POWERSHELL=%windir%\System32\WindowsPowerShell\v1.0\powershell.exe

    set FEED=
    set INSTANCE_NAME=
    set SQL_SERVERNAME=
    set SQL_SYSADMIN=
    set SQL_SYSADMINPWD=
    set CONTROLLER_ADMIN_USERNAME=
    set CONTROLLER_ADMIN_PASSWORD=

rem ---------------------------------------------
rem Parse command line parameters
rem ---------------------------------------------
:parse_param
    set PARAM_MATCHED=0
    if "%1"=="" (
        goto :parse_param_completed
    )

    if /I "%1"=="-feed" (
        set FEED=%2
        shift
        set PARAM_MATCHED=1
    )

    if /I "%1"=="-webSitesInstanceName" (
        set INSTANCE_NAME=%2
        shift
        set PARAM_MATCHED=1
    )

    if /I "%1"=="-sqlservername" (
        set SQL_SERVERNAME=%2
        shift
        set PARAM_MATCHED=1
    )

    if /I "%1"=="-sqlsysadmin" (
        set SQL_SYSADMIN=%2
        shift
        set PARAM_MATCHED=1
    )

    if /I "%1"=="-sqlsysadminpwd" (
        set SQL_SYSADMINPWD=%2
        shift
        set PARAM_MATCHED=1
    )

    if /I "%1"=="-controllerAdminUserName" (
        set CONTROLLER_ADMIN_USERNAME=%2
        shift
        set PARAM_MATCHED=1
    )

    if /I "%1"=="-controllerAdminPassword" (
        set CONTROLLER_ADMIN_PASSWORD=%2
        shift
        set PARAM_MATCHED=1
    )

    if "%PARAM_MATCHED%"=="0" (
       echo Parameter %1 was not matched
       exit 1
    )

    shift
    goto :parse_param
:parse_param_completed

rem -----------------------------------------------------------------------
rem Provision Controller
rem ------------------------------------------------------------------------

    echo Installing WebPlatformInstaller.
    start /wait %windir%\system32\msiexec.exe /qn /i WebPlatformInstaller.msi /l %SystemDrive%\WebPlatformInstaller.log
    if errorlevel 1 (
        echo WebPlatform Installer installation failed. See log at %SystemDrive%\WebPlatformInstaller.log for more details.
        exit 1
    )

    echo WebPlatformInstaller setup completed successfully.

    echo Enabling remote desktop access.
    start /wait cscript %windir%\system32\scregedit.wsf /ar 0
    if errorlevel 1 (
        echo Enabling remote desktop failed.
        exit 1
    )

    echo Remote desktop access has been enabled successfully.

    if exist StrongNameHijack.msi (

        echo Installing StrongNameHijack...
        start /wait %windir%\system32\msiexec.exe /qn /i StrongNameHijack.msi /l %SystemDrive%\StrongNameHijack.log
        if errorlevel 1 (
            echo "StrongNameHijack installation failed. See log at %SystemDrive%\StrongNameHijack.log for more details."
            exit 1
        )

        echo StrongNameHijack setup completed successfully.

        net stop msiserver & net start msiserver
    )

    echo Starting HostingBootstrapperBootstrapper.ps1

    if "%FEED%"=="" (
        %POWERSHELL% -ExecutionPolicy Unrestricted -File HostingBootstrapperBootstrapper.ps1
    ) else (
        %POWERSHELL% -ExecutionPolicy Unrestricted -File HostingBootstrapperBootstrapper.ps1 -mainFeed "%FEED%"
    )

    if errorlevel 1 (
        echo HostingBootstrapperBootstrapper.ps1 failed.
        exit 1
    )

    echo HostingBootstrapperBootstrapper.ps1 completed successfully.

    echo Starting OnStartSecondaryController.ps1

    %POWERSHELL% -ExecutionPolicy Unrestricted -File OnStartSecondaryController.ps1 -webSitesInstanceName "%INSTANCE_NAME%" -sqlservername "%SQL_SERVERNAME%" -sqlsysadmin "%SQL_SYSADMIN%" -sqlsysadminpwd "%SQL_SYSADMINPWD%" -controllerAdminUserName "%CONTROLLER_ADMIN_USERNAME%" -controllerAdminPassword "%CONTROLLER_ADMIN_PASSWORD%"
    if errorlevel 1 (
        echo OnStartSecondaryController.ps1 failed.
        exit 1
    )

    echo OnStartSecondaryController.ps1 completed successfully.

echo OnStartSecondaryController.cmd completed successfully.

exit 0

# PowerShell script to setup Web Sites Controller using WebPI.
# Copyright (c) Microsoft Corporation. All rights reserved.

Param
(
    [string] $boostrapperProductId = "HostingPrimaryControllerBootstrapper_v2",
    [string] $mainFeed = "",
    [string] $customFeed = ""
)

# Change Error Action to Stop
$ErrorActionPreference="Stop"

Function BootstrapBootstrapper ()
{
    $WebPiCmd = [System.Environment]::ExpandEnvironmentVariables("%ProgramW6432%\Microsoft\Web Platform Installer\WebpiCmd.exe")
    $WebPiLog = [System.Environment]::ExpandEnvironmentVariables("%SystemDrive%\HostingPrimaryControllerBootstrapper.log")

    If ($mainFeed -eq "")
    {
        Invoke-Command -ScriptBlock { & $WebPiCmd /Install /Products:$boostrapperProductId /AcceptEula /SuppressReboot /SuppressPostFinish /Log:$WebPiLog }
    }
    Else
    {
        If ($customFeed -eq "")
        {
            Invoke-Command -ScriptBlock { & $WebPiCmd /Install /Products:$boostrapperProductId /AcceptEula /SuppressReboot /SuppressPostFinish /XML:$mainFeed /Log:$WebPiLog }
        }
        Else
        {
            Invoke-Command -ScriptBlock { & $WebPiCmd /Install /Products:$boostrapperProductId /AcceptEula /SuppressReboot /SuppressPostFinish /XML:$mainFeed /Feeds:$customFeed /Log:$WebPiLog }
        }
    }

    If ($lastexitcode -ne $Null -And $lastexitcode -ne 0)
    {
        Exit $lastexitcode
    }
}

# Entry Point
BootstrapBootstrapper

# PowerShell script to setup a Web Sites secondary controller.
# Copyright (c) Microsoft Corporation. All rights reserved.

Param
(
    [string] $webSitesInstanceName,
    [string] $sqlservername,
    [string] $sqlsysadmin,
    [string] $sqlsysadminpwd,
    [string] $controllerAdminUserName,
    [string] $controllerAdminPassword
)

# Init Global Variables
$cnstr = "server=$($sqlservername);database=Hosting;uid=$($sqlsysadmin);pwd=$($sqlsysadminpwd);"

# Load common script file
$startDir = "."
$common = [System.IO.Path]::Combine($startDir, "Common.ps1")
. $common

Function Get-PrimaryController()
{
    Try
    {
        $siteManager = New-Object Microsoft.Web.Hosting.SiteManager $cnstr
        $primaryController = $siteManager.Controllers.GetPrimaryController([Microsoft.Web.Hosting.PlatformOptions]::VirtualMachineManager)

        Return $primaryController.MachineName;
    }
    Finally
    {
        If($siteManager -ne $Null)
        {
            $siteManager.Dispose()
        }
    }
}

Function Test-PrimaryController()
{
    Try
    {
        $PrimaryController = Get-PrimaryController

        Return $PrimaryController -ne $Null
    }
    Catch [Microsoft.Web.Hosting.WebHostingObjectNotFoundException]
    {
        Write-Host "$(Get-Date): Primary Controller NOT Ready"

        Return $False;
    }
}

Function WaitForPrimaryControllerToBeReady()
{
    $WaitIndex=0;
    $MaxWait=15
    $WaitInterval=60000

    Write-Host "$(Get-Date): Waiting for Primary Controller to be ready"

    $valid = Test-PrimaryController
    If ($valid -eq $False)
    {
        While ($WaitIndex -lt $MaxWait -and $valid -eq $False)
        {
            [System.Threading.Thread]::Sleep($WaitInterval);
            $WaitIndex = $WaitIndex + 1
            $valid = Test-PrimaryController
        }
    }

    If ($valid -eq $False)
    {
        Throw New-Object [System.Exception] "Primary Controller NOT ready. Timed out waiting."
    }

    Write-Host "$(Get-Date): Primary Controller is Ready"
}

Function Copy-SystemCoreKeyFromPrimaryController([string] $PrimaryController)
{
    Write-Host "$(Get-Date): Copy SystemCore key"

    $remoteCommand = {
        Add-PSSnapIn WebHostingSnapIn
        Get-WebSitesConfig -Type SecurityKey -SymmetricKeyName SystemCore
    }

    $SystemCoreKey = Invoke-Command -ComputerName $PrimaryController -ScriptBlock $remoteCommand
    Set-WebSitesConfig -Type SecurityKey -SymmetricKeyName SystemCore -SymmetricKey $SystemCoreKey -Force
}

Function Copy-SiteRuntimeKeyFromPrimaryController([string] $PrimaryController)
{
    Write-Host "$(Get-Date): Copy SiteRuntime key"

    $remoteCommand = {
        Add-PSSnapIn WebHostingSnapIn
        Get-WebSitesConfig -Type SecurityKey -SymmetricKeyName SiteRuntime
    }

    $SiteRuntimeKey  = Invoke-Command -ComputerName $PrimaryController -ScriptBlock $remoteCommand
    Set-WebSitesConfig -Type SecurityKey -SymmetricKeyName SiteRuntime -SymmetricKey $SiteRuntimeKey -Force
}

Function Copy-HostingConnectionStringFromPrimaryController([string] $PrimaryController)
{
    Write-Host "$(Get-Date): Copy hosting connection string"

    $remoteCommand = {
        Add-PSSnapIn WebHostingSnapIn
        [Microsoft.Web.Hosting.SiteManager]::GetDefaultConnectionString()
    }

    $HostingCnStr  = Invoke-Command -ComputerName $PrimaryController -ScriptBlock $remoteCommand
    Set-WebSitesConnectionString -Type Hosting -ConnectionString $HostingCnStr
}

Function Copy-MeteringConnectionStringFromPrimaryController([string] $PrimaryController)
{
    Write-Host "$(Get-Date): Copy metering connection string"

    $remoteCommand = {
        Add-PSSnapIn WebHostingSnapIn
        [Microsoft.Web.Hosting.SiteManager]::GetMeteringConnectionString()
    }

    $computerName = [Microsoft.Web.Hosting.Common.NetworkHelper]::GetComputerName([Microsoft.Web.Hosting.Common.ComputerNameFormat]::DnsFullyQualified)

    $MeteringCnStr  = Invoke-Command -ComputerName $PrimaryController -ScriptBlock $remoteCommand    
    Set-WebSitesConnectionString -Type Metering -ConnectionString $MeteringCnStr -ServerName $computerName
}

Function OnStartSecondaryController()
{
    Try
    {
        Write-Host "$(Get-Date): Starting OnStartSecondaryController()" -ForegroundColor Green

        Add-PSSnapin WebHostingSnapin

        ConfigureRoleAdministrator $controllerAdminUserName $controllerAdminPassword

        WaitForHostingDatabaseToBeReady $cnstr
        WaitForPrimaryControllerToBeReady

        $PrimaryController = Get-PrimaryController
        Copy-SystemCoreKeyFromPrimaryController $PrimaryController
        Copy-SiteRuntimeKeyFromPrimaryController $PrimaryController
        Copy-HostingConnectionStringFromPrimaryController $PrimaryController
        Copy-MeteringConnectionStringFromPrimaryController $PrimaryController

        Start-Service WebFarmService

        Write-Host "$(Get-Date): OnStartSecondaryController completed successfully" -ForegroundColor Green
    }
    Catch [System.Exception]
    {
        Write-Host "$(Get-Date): Exception encountered while executing OnStartSecondaryController:" -ForegroundColor Red
        Write-Host $_ -ForegroundColor Red

        Write-Host "$(Get-Date): Exiting OnStartSecondaryController.ps1" -ForegroundColor Red
        Exit -1
    }
}

# Entry Point
OnStartSecondaryController

# PowerShell Web Sites common script.
# Copyright (c) Microsoft Corporation. All rights reserved.

Function LoadHostingFramework()
{
    $mwhc = Get-Item ".\Microsoft.Web.Hosting.Common.dll"
    [void] [System.Reflection.Assembly]::LoadFrom($mwhc.FullName)
    Write-Host "$(Get-Date): Microsoft.Web.Hosting.Common assembly was successfully loaded from: $mwhc"

    $mwh  = Get-Item ".\Microsoft.Web.Hosting.dll"
    [void] [System.Reflection.Assembly]::LoadFrom($mwh.FullName)
    Write-Host "$(Get-Date): Microsoft.Web.Hosting assembly was successfully loaded from: $mwh"
}

Function IsHostingDatabaseReady([string] $cnstr)
{
    Try
    {
        $siteManager = New-Object Microsoft.Web.Hosting.SiteManager $cnstr
        $siteManager.TestConnection([Microsoft.Web.Hosting.PlatformOptions]::VirtualMachineManager)

        Return $true;
    }
    Catch [Exception]
    {
        Write-Host "$(Get-Date): Hosting Database NOT Ready"

        Return $false;
    }
    Finally
    {
        If($siteManager -ne $Null)
        {
            $siteManager.Dispose()
        }
    }
}

Function WaitForHostingDatabaseToBeReady ([string] $cnstr)
{
    $WaitIndex=0;
    $MaxWait=120
    $WaitInterval=60000

    Write-Host "$(Get-Date): Waiting for Hosting Database to be ready"

    $ready = IsHostingDatabaseReady $cnstr
    If($ready -ne $true)
    {
    While ($WaitIndex -lt $MaxWait -and $ready -ne $true)
        {
            [System.Threading.Thread]::Sleep($WaitInterval);
            $WaitIndex = $WaitIndex + 1
            $ready = IsHostingDatabaseReady $cnstr
        }
    }

    If ($ready -ne $true)
    {
        Throw New-Object [System.Exception] "Hosting Database NOT ready. Timed out waiting."
    }

    Write-Host "$(Get-Date): Hosting Database is Ready"
}

Function ConfigureRoleAdministrator([string] $roleadminusr, [string] $roleadminpwd)
{
    $isDomain = $false

    # Identify if user is a domain user account
    $values = $roleadminusr.Split('\');
    If ($values.Length -eq 1)
    {
        $domain = $env:COMPUTERNAME
        $username = $values[0]
    }
    ElseIf ($values.Length -eq 2)
    {
        If ([String]::Equals($values[0], ".") -Or
            [String]::Equals($values[0], [Environment]::MachineName, [StringComparison]::OrdinalIgnoreCase))
        {
            $isDomain = $false
            $domain = $env:COMPUTERNAME
            $username = $values[1]
        }
        Else
        {
            $isDomain = $true
            $domain = $values[0]
            $username = $values[1]
        }
    }
    Else
    {
        Throw New-Object ArgumentException "Invalid user name" "roleadminusr"
    }

    # Create user if specified user is not a domain account
    if ($isDomain -eq $false)
    {
        Try
        {
            $computer = [ADSI]"WinNT://$env:COMPUTERNAME"
            $user = $computer.Create("User", $username)
            $user.setpassword($roleadminpwd)
            $user.SetInfo()
        }
        Catch [System.Runtime.InteropServices.COMException]
        {
            # User already exists
            If ($_.Exception.ErrorCode -eq -2147022672)
            {
                Write-Host "$(Get-Date): User $domain\$username already exits."
                Write-Host "$(Get-Date): Updating password for User $domain\$username."
                $user = [ADSI]("WinNT://$env:COMPUTERNAME/$username,user")
                $user.setpassword($roleadminpwd)
                $user.SetInfo()
            }
            Else
            {
                Write-Host "$(Get-Date): Error creating user $domain\$username." -ForegroundColor Red

                Throw
            }
        }
    }

    # Add user to local administrators group

    #first translate the "Administrators" name to the name based on locale (make well known SID -> Name translation)

    $administratorsSID = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")
    $administratorsGroupName = $administratorsSID.Translate([System.Security.Principal.NTAccount]).Value

    # retrieve the short name eg in german translate VORDEFINIERT\Administratoren ->Administratoren
    # the translation should always return fully qualified name equivalent to BUILTIN\Administrators

    $localizedAdministratorsGroupName=$administratorsGroupName.Split("\\")[1]

    $adminGroup = [ADSI]("WinNT://$env:COMPUTERNAME/$localizedAdministratorsGroupName,group")

    Try
    {
        If ($isDomain -eq $true)
        {
            $adminGroup.add("WinNT://$domain/$username,user")
        }
        Else
        {
            $adminGroup.add("WinNT://$env:COMPUTERNAME/$username,user")
        }
    }
    Catch [System.Runtime.InteropServices.COMException]
    {
        If ($_.Exception.ErrorCode -eq -2147023518) # ERROR_MEMBER_IN_ALIAS 1378 (0x562)
        {
            Write-Host "$(Get-Date): User $domain\$username is already member of Administrators group."
        }
        Else
        {
            Write-Host "$(Get-Date): Error adding user $domain\$username to Administrators group." -ForegroundColor Red

            Throw
        }
    }
}
顯示: