常见的云服务启动任务Common Cloud Service startup tasks

本文提供了一些可能需要在云服务中执行的常见启动任务示例。This article provides some examples of common startup tasks you may want to perform in your cloud service. 角色启动之前,可以使用启动任务执行操作。You can use startup tasks to perform operations before a role starts. 可能需要执行的操作包括安装组件、注册 COM 组件、设置注册表项或启动长时间运行的进程。Operations that you might want to perform include installing a component, registering COM components, setting registry keys, or starting a long running process.

请参阅本文以了解启动任务的工作方式,特别是如何创建定义启动任务的条目。See this article to understand how startup tasks work, and specifically how to create the entries that define a startup task.

备注

启动任务不适用于虚拟机,只适用于云服务 Web 角色和辅助角色。Startup tasks are not applicable to Virtual Machines, only to Cloud Service Web and Worker roles.

在角色启动之前定义环境变量Define environment variables before a role starts

如果需要为特定任务定义环境变量,则可以在 任务 元素内使用 环境 元素。If you need environment variables defined for a specific task, use the Environment element inside the Task element.

<ServiceDefinition name="MyService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
    <WorkerRole name="WorkerRole1">
        ...
        <Startup>
            <Task commandLine="Startup.cmd" executionContext="limited" taskType="simple">
                <Environment>
                    <Variable name="MyEnvironmentVariable" value="MyVariableValue" />
                </Environment>
            </Task>
        </Startup>
    </WorkerRole>
</ServiceDefinition>

此外,变量还可以使用有效 Azure XPath 值引用有关部署的内容。Variables can also use a valid Azure XPath value to reference something about the deployment. 请不要使用 value 属性,而是定义 RoleInstanceValue 子元素。Instead of using the value attribute, define a RoleInstanceValue child element.

<Variable name="PathToStartupStorage">
    <RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/LocalResources/LocalResource[@name='StartupLocalStorage']/@path" />
</Variable>

使用 AppCmd.exe 配置 IIS 启动Configure IIS startup with AppCmd.exe

AppCmd.exe 命令行工具在 Azure 上启动时可用于管理 IIS 设置。The AppCmd.exe command-line tool can be used to manage IIS settings at startup on Azure. AppCmd.exe 对要在 Azure 上的启动任务中使用的配置设置提供方便的命令行访问。AppCmd.exe provides convenient, command-line access to configuration settings for use in startup tasks on Azure. 使用 AppCmd.exe,可以为应用程序和站点添加、修改或删除网站设置。Using AppCmd.exe, Website settings can be added, modified, or removed for applications and sites.

但是,在使用 AppCmd.exe 作为启动任务时有几点需要注意:However, there are a few things to watch out for in the use of AppCmd.exe as a startup task:

  • 启动任务在重新启动之间可以运行多次。Startup tasks can be run more than once between reboots. 例如,当角色回收时。For instance, when a role recycles.
  • 如果多次执行 AppCmd.exe 操作,则可能会生成错误。If a AppCmd.exe action is performed more than once, it may generate an error. 例如,尝试将某个节添加到 Web.config 中两次会生成错误。For example, attempting to add a section to Web.config twice could generate an error.
  • 如果启动任务返回非零退出代码或 errorlevel,则为失败。Startup tasks fail if they return a non-zero exit code or errorlevel. 例如,当 AppCmd.exe 生成了错误时。For example, when AppCmd.exe generates an error.

比较明智的做法是在调用 AppCmd.exe 之后检查 errorlevel,如果使用 .cmd 文件包装对 AppCmd.exe 的调用,则很容易做到这一点 。It is a good practice to check the errorlevel after calling AppCmd.exe, which is easy to do if you wrap the call to AppCmd.exe with a .cmd file. 如果检测到已知的 errorlevel 响应,可以将其忽略,或将其返回。If you detect a known errorlevel response, you can ignore it, or pass it back.

AppCmd.exe 返回的 errorlevel 在 winerror.h 文件中列出,并且还可以在 MSDN 上查看。The errorlevel returned by AppCmd.exe are listed in the winerror.h file, and can also be seen on MSDN.

管理错误级别的示例Example of managing the error level

此示例将 JSON 的压缩节和压缩条目添加到 Web.config 文件,其中包含错误处理和日志记录。This example adds a compression section and a compression entry for JSON to the Web.config file, with error handling and logging.

此处显示了 ServiceDefinition.csdef 文件的相关部分,其中包括将 executionContext 属性设为 elevated 以为 AppCmd.exe 提供足够的权限来更改 Web.config 文件中的设置:The relevant sections of the ServiceDefinition.csdef file are shown here, which include setting the executionContext attribute to elevated to give AppCmd.exe sufficient permissions to change the settings in the Web.config file:

<ServiceDefinition name="MyService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
    <WorkerRole name="WorkerRole1">
        ...
        <Startup>
            <Task commandLine="Startup.cmd" executionContext="elevated" taskType="simple" />
        </Startup>
    </WorkerRole>
</ServiceDefinition>

Startup.cmd 批处理文件使用 AppCmd.exe 将 JSON 的压缩部分和压缩条目添加到 Web.config 文件 。The Startup.cmd batch file uses AppCmd.exe to add a compression section and a compression entry for JSON to the Web.config file. 使用 VERIFY.EXE 命令行程序将预期的 errorlevel 183 设为零。The expected errorlevel of 183 is set to zero using the VERIFY.EXE command-line program. 意外的 errorlevel 将记录到 StartupErrorLog.txt 中。Unexpected errorlevels are logged to StartupErrorLog.txt.

REM   *** Add a compression section to the Web.config file. ***
%windir%\system32\inetsrv\appcmd set config /section:urlCompression /doDynamicCompression:True /commit:apphost >> "%TEMP%\StartupLog.txt" 2>&1

REM   ERRORLEVEL 183 occurs when trying to add a section that already exists. This error is expected if this
REM   batch file were executed twice. This can occur and must be accounted for in an Azure startup
REM   task. To handle this situation, set the ERRORLEVEL to zero by using the Verify command. The Verify
REM   command will safely set the ERRORLEVEL to zero.
IF %ERRORLEVEL% EQU 183 VERIFY > NUL

REM   If the ERRORLEVEL is not zero at this point, some other error occurred.
IF %ERRORLEVEL% NEQ 0 (
    ECHO Error adding a compression section to the Web.config file. >> "%TEMP%\StartupLog.txt" 2>&1
    GOTO ErrorExit
)

REM   *** Add compression for json. ***
%windir%\system32\inetsrv\appcmd set config  -section:system.webServer/httpCompression /+"dynamicTypes.[mimeType='application/json; charset=utf-8',enabled='True']" /commit:apphost >> "%TEMP%\StartupLog.txt" 2>&1
IF %ERRORLEVEL% EQU 183 VERIFY > NUL
IF %ERRORLEVEL% NEQ 0 (
    ECHO Error adding the JSON compression type to the Web.config file. >> "%TEMP%\StartupLog.txt" 2>&1
    GOTO ErrorExit
)

REM   *** Exit batch file. ***
EXIT /b 0

REM   *** Log error and exit ***
:ErrorExit
REM   Report the date, time, and ERRORLEVEL of the error.
DATE /T >> "%TEMP%\StartupLog.txt" 2>&1
TIME /T >> "%TEMP%\StartupLog.txt" 2>&1
ECHO An error occurred during startup. ERRORLEVEL = %ERRORLEVEL% >> "%TEMP%\StartupLog.txt" 2>&1
EXIT %ERRORLEVEL%

添加防火墙规则Add firewall rules

实际上,Azure 中有两个防火墙。In Azure, there are effectively two firewalls. 第一个防火墙控制虚拟机与外界之间的连接。The first firewall controls connections between the virtual machine and the outside world. 此防火墙由 ServiceDefinition.csdef 文件中的 EndPoints 元素控制。This firewall is controlled by the EndPoints element in the ServiceDefinition.csdef file.

第二个防火墙控制虚拟机与该虚拟机中的进程之间的连接。The second firewall controls connections between the virtual machine and the processes within that virtual machine. 可以通过 netsh advfirewall firewall 命令行工具控制此防火墙。This firewall can be controlled by the netsh advfirewall firewall command-line tool.

Azure 将为角色中启动的进程创建防火墙规则。Azure creates firewall rules for the processes started within your roles. 例如,启动服务或程序时,Azure 会自动创建必要的防火墙规则以允许该服务与 Internet 进行通信。For example, when you start a service or program, Azure automatically creates the necessary firewall rules to allow that service to communicate with the Internet. 但是,如果创建的服务由角色外部的进程(例如,COM+ 服务或 Windows 计划任务)启动,则将需要手动创建防火墙规则以允许访问该服务。However, if you create a service that is started by a process outside your role (like a COM+ service or a Windows Scheduled Task), you need to manually create a firewall rule to allow access to that service. 可以通过使用启动任务来创建这些防火墙规则。These firewall rules can be created by using a startup task.

创建防火墙规则的启动任务的 executionContext 必须为 elevated,则为失败。A startup task that creates a firewall rule must have an executionContext of elevated. 将以下启动任务添加到 ServiceDefinition.csdef 文件。Add the following startup task to the ServiceDefinition.csdef file.

<ServiceDefinition name="MyService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
    <WorkerRole name="WorkerRole1">
        ...
        <Startup>
            <Task commandLine="AddFirewallRules.cmd" executionContext="elevated" taskType="simple" />
        </Startup>
    </WorkerRole>
</ServiceDefinition>

若要添加防火墙规则,必须在启动批处理文件中使用相应的 netsh advfirewall firewall 命令。To add the firewall rule, you must use the appropriate netsh advfirewall firewall commands in your startup batch file. 在此示例中,启动任务对 TCP 端口 80 具有安全性和加密要求。In this example, the startup task requires security and encryption for TCP port 80.

REM   Add a firewall rule in a startup task.

REM   Add an inbound rule requiring security and encryption for TCP port 80 traffic.
netsh advfirewall firewall add rule name="Require Encryption for Inbound TCP/80" protocol=TCP dir=in localport=80 security=authdynenc action=allow >> "%TEMP%\StartupLog.txt" 2>&1

REM   If an error occurred, return the errorlevel.
EXIT /B %errorlevel%

阻止特定 IP 地址Block a specific IP address

可以通过修改 IIS web.config 文件来限制某个 Azure Web 角色对一组指定的 IP 地址的访问权限。You can restrict an Azure web role access to a set of specified IP addresses by modifying your IIS web.config file. 还需要使用一个用于解锁 ApplicationHost.config 文件的 ipSecurity 部分的命令文件 。You also need to use a command file which unlocks the ipSecurity section of the ApplicationHost.config file.

若要解锁 ApplicationHost.config 文件的 ipSecurity 部分,请先创建角色启动时运行的命令文件 。To do unlock the ipSecurity section of the ApplicationHost.config file, create a command file that runs at role start. 在 Web 角色的根级别创建一个名为 startup 的文件夹,然后在该文件夹中创建一个名为 startup.cmd 的批处理文件 。Create a folder at the root level of your web role called startup and, within this folder, create a batch file called startup.cmd. 将此文件添加到 Visual Studio 项目并将属性设置为“始终复制” 以确保此文件包括在包中。Add this file to your Visual Studio project and set the properties to Copy Always to ensure that it is included in your package.

将以下启动任务添加到 ServiceDefinition.csdef 文件。Add the following startup task to the ServiceDefinition.csdef file.

<ServiceDefinition name="MyService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
    <WebRole name="WebRole1">
        ...
        <Startup>
            <Task commandLine="startup.cmd" executionContext="elevated" />
        </Startup>
    </WebRole>
</ServiceDefinition>

将此命令添加到 startup.cmd 文件:Add this command to the startup.cmd file:

@echo off
@echo Installing "IPv4 Address and Domain Restrictions" feature 
powershell -ExecutionPolicy Unrestricted -command "Install-WindowsFeature Web-IP-Security"
@echo Unlocking configuration for "IPv4 Address and Domain Restrictions" feature 
%windir%\system32\inetsrv\AppCmd.exe unlock config -section:system.webServer/security/ipSecurity

此任务将导致每次初始化 Web 角色时都运行 startup.cmd 批处理文件,确保所需的 ipSecurity 部分处于解锁状态。 This task causes the startup.cmd batch file to be run every time the web role is initialized, ensuring that the required ipSecurity section is unlocked.

最后,修改 web 角色的 web.config 文件的 system.webServer 节 以添加被授予访问权限的 IP 地址列表,如下面的示例所示:Finally, modify the system.webServer section your web role’s web.config file to add a list of IP addresses that are granted access, as shown in the following example:

此示例配置 允许 所有 IP(两个已定义的 IP 除外)访问服务器This sample config allows all IPs to access the server except the two defined

<system.webServer>
    <security>
    <!--Unlisted IP addresses are granted access-->
    <ipSecurity>
        <!--The following IP addresses are denied access-->
        <add allowed="false" ipAddress="192.168.100.1" subnetMask="255.255.0.0" />
        <add allowed="false" ipAddress="192.168.100.2" subnetMask="255.255.0.0" />
    </ipSecurity>
    </security>
</system.webServer>

此示例配置 拒绝 所有 IP(两个已定义的 IP 除外)访问服务器。This sample config denies all IPs from accessing the server except for the two defined.

<system.webServer>
    <security>
    <!--Unlisted IP addresses are denied access-->
    <ipSecurity allowUnlisted="false">
        <!--The following IP addresses are granted access-->
        <add allowed="true" ipAddress="192.168.100.1" subnetMask="255.255.0.0" />
        <add allowed="true" ipAddress="192.168.100.2" subnetMask="255.255.0.0" />
    </ipSecurity>
    </security>
</system.webServer>

创建 PowerShell 启动任务Create a PowerShell startup task

Windows PowerShell 脚本不能直接从 ServiceDefinition.csdef 文件调用,但它们可以从启动批处理文件中调用。Windows PowerShell scripts cannot be called directly from the ServiceDefinition.csdef file, but they can be invoked from within a startup batch file.

默认情况下,PowerShell 不会运行未签名的脚本。PowerShell (by default) does not run unsigned scripts. 除非为脚本签名,否则需要将 PowerShell 配置为运行未签名的脚本。Unless you sign your script, you need to configure PowerShell to run unsigned scripts. 若要运行未签名的脚本,ExecutionPolicy 必须设置为 Unrestricted 。To run unsigned scripts, the ExecutionPolicy must be set to Unrestricted. 使用的 ExecutionPolicy 设置基于 Windows PowerShell 的版本。The ExecutionPolicy setting that you use is based on the version of Windows PowerShell.

REM   Run an unsigned PowerShell script and log the output
PowerShell -ExecutionPolicy Unrestricted .\startup.ps1 >> "%TEMP%\StartupLog.txt" 2>&1

REM   If an error occurred, return the errorlevel.
EXIT /B %errorlevel%

如果使用的是运行 PowerShell 2.0 或 1.0 的来宾 OS,则可强制运行版本 2,如果不可用,则使用版本 1。If you're using a Guest OS that is runs PowerShell 2.0 or 1.0 you can force version 2 to run, and if unavailable, use version 1.

REM   Attempt to set the execution policy by using PowerShell version 2.0 syntax.
PowerShell -Version 2.0 -ExecutionPolicy Unrestricted .\startup.ps1 >> "%TEMP%\StartupLog.txt" 2>&1

REM   If PowerShell version 2.0 isn't available. Set the execution policy by using the PowerShell
IF %ERRORLEVEL% EQU -393216 (
   PowerShell -Command "Set-ExecutionPolicy Unrestricted" >> "%TEMP%\StartupLog.txt" 2>&1
   PowerShell .\startup.ps1 >> "%TEMP%\StartupLog.txt" 2>&1
)

REM   If an error occurred, return the errorlevel.
EXIT /B %errorlevel%

通过启动任务在本地存储中创建文件Create files in local storage from a startup task

可以使用本地存储资源来存储应用程序稍后将访问的启动任务创建的文件。You can use a local storage resource to store files created by your startup task that is accessed later by your application.

若要创建本地存储资源,请将 LocalResources 部分添加到 ServiceDefinition.csdef 文件,然后添加 LocalStorage 子元素。To create the local storage resource, add a LocalResources section to the ServiceDefinition.csdef file and then add the LocalStorage child element. 为本地存储资源指定唯一名称,并为启动任务指定合适大小。Give the local storage resource a unique name and an appropriate size for your startup task.

若要在启动任务中使用本地存储资源,需要创建一个环境变量以引用本地存储资源位置。To use a local storage resource in your startup task, you need to create an environment variable to reference the local storage resource location. 然后,启动任务和应用程序将能够在本地存储资源中读取和写入文件。Then the startup task and the application are able to read and write files to the local storage resource.

在此处显示 ServiceDefinition.csdef 文件的相关节:The relevant sections of the ServiceDefinition.csdef file are shown here:

<ServiceDefinition name="MyService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
  <WorkerRole name="WorkerRole1">
    ...

    <LocalResources>
      <LocalStorage name="StartupLocalStorage" sizeInMB="5"/>
    </LocalResources>

    <Startup>
      <Task commandLine="Startup.cmd" executionContext="limited" taskType="simple">
        <Environment>
          <Variable name="PathToStartupStorage">
            <RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/LocalResources/LocalResource[@name='StartupLocalStorage']/@path" />
          </Variable>
        </Environment>
      </Task>
    </Startup>
  </WorkerRole>
</ServiceDefinition>

例如,这个 Startup.cmd 批处理文件使用 PathToStartupStorage 环境变量在本地存储位置中创建文件 MyTest.txt 。As an example, this Startup.cmd batch file uses the PathToStartupStorage environment variable to create the file MyTest.txt on the local storage location.

REM   Create a simple text file.

ECHO This text will go into the MyTest.txt file which will be in the    >  "%PathToStartupStorage%\MyTest.txt"
ECHO path pointed to by the PathToStartupStorage environment variable.  >> "%PathToStartupStorage%\MyTest.txt"
ECHO The contents of the PathToStartupStorage environment variable is   >> "%PathToStartupStorage%\MyTest.txt"
ECHO "%PathToStartupStorage%".                                          >> "%PathToStartupStorage%\MyTest.txt"

REM   Exit the batch file with ERRORLEVEL 0.

EXIT /b 0

可以从 Azure SDK 中使用 GetLocalResource 方法访问本地存储文件夹。You can access local storage folder from the Azure SDK by using the GetLocalResource method.

string localStoragePath = Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.GetLocalResource("StartupLocalStorage").RootPath;

string fileContent = System.IO.File.ReadAllText(System.IO.Path.Combine(localStoragePath, "MyTestFile.txt"));

在模拟器或云中运行Run in the emulator or cloud

与在计算模拟器中运行时相比,可以让启动任务在云中运行时执行不同的步骤。You can have your startup task perform different steps when it is operating in the cloud compared to when it is in the compute emulator. 例如,仅当在模拟器中运行时,才可能需要使用 SQL 数据的新副本。For example, you may want to use a fresh copy of your SQL data only when running in the emulator. 或者,可能需要为云做一些性能优化,而在模拟器中运行时不需要做这些优化。Or you may want to do some performance optimizations for the cloud that you don't need to do when running in the emulator.

可以通过在 ServiceDefinition.csdef 文件中创建一个环境变量来实现在计算模拟器中和云中执行不同操作的能力。This ability to perform different actions on the compute emulator and the cloud can be accomplished by creating an environment variable in the ServiceDefinition.csdef file. 然后,在启动任务中针对某个值测试该环境变量。You then test that environment variable for a value in your startup task.

若要创建环境变量,请添加 变量/RoleInstanceValue 元素并创建 /RoleEnvironment/Deployment/@emulated 的 XPath 值。To create the environment variable, add the Variable/RoleInstanceValue element and create an XPath value of /RoleEnvironment/Deployment/@emulated. 在计算模拟器中运行时,%ComputeEmulatorRunning% 环境变量的值为 true,而在云中运行时,该值为 falseThe value of the %ComputeEmulatorRunning% environment variable is true when running on the compute emulator, and false when running on the cloud.

<ServiceDefinition name="MyService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
  <WorkerRole name="WorkerRole1">

    ...

    <Startup>
      <Task commandLine="Startup.cmd" executionContext="limited" taskType="simple">
        <Environment>
          <Variable name="ComputeEmulatorRunning">
            <RoleInstanceValue xpath="/RoleEnvironment/Deployment/@emulated" />
          </Variable>
        </Environment>
      </Task>
    </Startup>

  </WorkerRole>
</ServiceDefinition>

该任务现在可以使用 %ComputeEmulatorRunning% 环境变量根据角色是在云中还是在模拟器中运行来执行不同的操作。The task can now check the %ComputeEmulatorRunning% environment variable to perform different actions based on whether the role is running in the cloud or the emulator. 下面是用于检查该环境变量的 .cmd shell 脚本。Here is a .cmd shell script that checks for that environment variable.

REM   Check if this task is running on the compute emulator.

IF "%ComputeEmulatorRunning%" == "true" (
    REM   This task is running on the compute emulator. Perform tasks that must be run only in the compute emulator.
) ELSE (
    REM   This task is running on the cloud. Perform tasks that must be run only in the cloud.
)

检测到任务已运行Detect that your task has already run

该角色可能会无需重新启动即可回收,从而不会导致启动任务重新运行。The role may recycle without a reboot causing your startup tasks to run again. 没有标志来指示任务已在宿主 VM 上运行。There is no flag to indicate that a task has already run on the hosting VM. 可能有一些任务它们运行多次无关紧要。You may have some tasks where it doesn't matter that they run multiple times. 但是,也可能会遇到需要阻止任务运行多次的情况。However, you may run into a situation where you need to prevent a task from running more than once.

检测任务是否已运行的最简单方式是在任务成功时在 %TEMP% 文件夹中创建一个文件,并在任务开始时查找该文件。The simplest way to detect that a task has already run is to create a file in the %TEMP% folder when the task is successful and look for it at the start of the task. 下面是可执行该操作的示例 cmd shell 脚本。Here is a sample cmd shell script that does that for you.

REM   If Task1_Success.txt exists, then Application 1 is already installed.
IF EXIST "%PathToApp1Install%\Task1_Success.txt" (
  ECHO Application 1 is already installed. Exiting. >> "%TEMP%\StartupLog.txt" 2>&1
  GOTO Finish
)

REM   Run your real exe task
ECHO Running XYZ >> "%TEMP%\StartupLog.txt" 2>&1
"%PathToApp1Install%\setup.exe" >> "%TEMP%\StartupLog.txt" 2>&1

IF %ERRORLEVEL% EQU 0 (
  REM   The application installed without error. Create a file to indicate that the task
  REM   does not need to be run again.

  ECHO This line will create a file to indicate that Application 1 installed correctly. > "%PathToApp1Install%\Task1_Success.txt"

) ELSE (
  REM   An error occurred. Log the error and exit with the error code.

  DATE /T >> "%TEMP%\StartupLog.txt" 2>&1
  TIME /T >> "%TEMP%\StartupLog.txt" 2>&1
  ECHO  An error occurred running task 1. Errorlevel = %ERRORLEVEL%. >> "%TEMP%\StartupLog.txt" 2>&1

  EXIT %ERRORLEVEL%
)

:Finish

REM   Exit normally.
EXIT /B 0

任务最佳做法Task best practices

以下是在配置 web 角色或辅助角色的任务时应遵循的一些最佳做法。Here are some best practices you should follow when configuring task for your web or worker role.

始终记录启动活动Always log startup activities

Visual Studio 未提供用于单步调试批处理文件的调试器,因此最好在批处理文件操作中尽可能多地获取数据。Visual Studio does not provide a debugger to step through batch files, so it's good to get as much data on the operation of batch files as possible. 记录批处理文件的输出(stdout 和 stderr),以便在尝试调试和修复批处理文件时使用该信息 。Logging the output of batch files, both stdout and stderr, can give you important information when trying to debug and fix batch files. 若要记录 %TEMP% 环境变量指向的目录中 StartupLog.txt 文件的 stdout 和 stderr ,请将文本 >> "%TEMP%\\StartupLog.txt" 2>&1 添加到要记录的特定行的末尾。To log both stdout and stderr to the StartupLog.txt file in the directory pointed to by the %TEMP% environment variable, add the text >> "%TEMP%\\StartupLog.txt" 2>&1 to the end of specific lines you want to log. 例如,若要在 %PathToApp1Install% 目录中执行 setup.exe,请执行以下操作:For example, to execute setup.exe in the %PathToApp1Install% directory:

"%PathToApp1Install%\setup.exe" >> "%TEMP%\StartupLog.txt" 2>&1

要简化 xml,可以创建一个包装器 cmd 文件,使该文件调用所有启动任务以及日志记录并确保每个子任务共享相同的环境变量。To simplify your xml, you can create a wrapper cmd file that calls all of your startup tasks along with logging and ensures each child-task shares the same environment variables.

你可能会发现在每个启动任务的末尾都使用 >> "%TEMP%\StartupLog.txt" 2>&1 很是恼人。You may find it annoying though to use >> "%TEMP%\StartupLog.txt" 2>&1 on the end of each startup task. 可以通过创建一个包装器来处理日志记录以强制执行任务日志记录。You can enforce task logging by creating a wrapper that handles logging for you. 此包装器调用要运行的实际批处理文件。This wrapper calls the real batch file you want to run. 来自目标批处理文件的任何输出都会重定向到 Startuplog.txt 文件。Any output from the target batch file will be redirected to the Startuplog.txt file.

以下示例展示了如何重定向来自某个启动批处理文件的所有输出。The following example shows how to redirect all output from a startup batch file. 在此示例中,ServerDefinition.csdef 文件创建一个调用 logwrap.cmd 的启动任务。In this example, the ServerDefinition.csdef file creates a startup task that calls logwrap.cmd. logwrap.cmd 调用 Startup2.cmd ,并将所有输出都重定向到 %TEMP% \StartupLog.txtlogwrap.cmd calls Startup2.cmd, redirecting all output to %TEMP%\StartupLog.txt.

ServiceDefinition.cmd:ServiceDefinition.cmd:

<Startup>
    <Task commandLine="logwrap.cmd startup2.cmd" executionContext="limited" taskType="simple" />
</Startup>

logwrap.cmd:logwrap.cmd:

@ECHO OFF

REM   logwrap.cmd calls passed in batch file, redirecting all output to the StartupLog.txt log file.

ECHO [%date% %time%] == START logwrap.cmd ============================================== >> "%TEMP%\StartupLog.txt" 2>&1
ECHO [%date% %time%] Running %1 >> "%TEMP%\StartupLog.txt" 2>&1

REM   Call the child command batch file, redirecting all output to the StartupLog.txt log file.
START /B /WAIT %1 >> "%TEMP%\StartupLog.txt" 2>&1

REM   Log the completion of child command.
ECHO [%date% %time%] Done >> "%TEMP%\StartupLog.txt" 2>&1

IF %ERRORLEVEL% EQU 0 (

   REM   No errors occurred. Exit logwrap.cmd normally.
   ECHO [%date% %time%] == END logwrap.cmd ================================================ >> "%TEMP%\StartupLog.txt" 2>&1
   ECHO.  >> "%TEMP%\StartupLog.txt" 2>&1
   EXIT /B 0

) ELSE (

   REM   Log the error.
   ECHO [%date% %time%] An error occurred. The ERRORLEVEL = %ERRORLEVEL%.  >> "%TEMP%\StartupLog.txt" 2>&1
   ECHO [%date% %time%] == END logwrap.cmd ================================================ >> "%TEMP%\StartupLog.txt" 2>&1
   ECHO.  >> "%TEMP%\StartupLog.txt" 2>&1
   EXIT /B %ERRORLEVEL%

)

Startup2.cmd:Startup2.cmd:

@ECHO OFF

REM   This is the batch file where the startup steps should be performed. Because of the
REM   way Startup2.cmd was called, all commands and their outputs will be stored in the
REM   StartupLog.txt file in the directory pointed to by the TEMP environment variable.

REM   If an error occurs, the following command will pass the ERRORLEVEL back to the
REM   calling batch file.

ECHO [%date% %time%] Some log information about this task
ECHO [%date% %time%] Some more log information about this task

EXIT %ERRORLEVEL%

StartupLog.txt 文件中的示例输出:Sample output in the StartupLog.txt file:

[Mon 10/17/2016 20:24:46.75] == START logwrap.cmd ============================================== 
[Mon 10/17/2016 20:24:46.75] Running command1.cmd 
[Mon 10/17/2016 20:24:46.77] Some log information about this task
[Mon 10/17/2016 20:24:46.77] Some more log information about this task
[Mon 10/17/2016 20:24:46.77] Done 
[Mon 10/17/2016 20:24:46.77] == END logwrap.cmd ================================================ 

提示

StartupLog.txt 文件位于 C:\Resources\temp\{role identifier}\RoleTemp 文件夹中。The StartupLog.txt file is located in the C:\Resources\temp\{role identifier}\RoleTemp folder.

为启动任务适当地设置 executionContextSet executionContext appropriately for startup tasks

为启动任务适当地设置权限。Set privileges appropriately for the startup task. 有时启动任务必须以提升的权限运行,即使角色以普通权限运行,也是如此。Sometimes startup tasks must run with elevated privileges even though the role runs with normal privileges.

executionContext 属性将设置启动任务的权限级别。The executionContext attribute sets the privilege level of the startup task. 使用 executionContext="limited" 意味着启动任务具有与角色相同的权限级别。Using executionContext="limited" means the startup task has the same privilege level as the role. 使用 executionContext="elevated" 意味着启动任务具有管理员权限,这会允许启动任务执行管理员任务,而无需向角色授予管理员权限。Using executionContext="elevated" means the startup task has administrator privileges, which allows the startup task to perform administrator tasks without giving administrator privileges to your role.

需要提升的权限的启动任务示例是使用 AppCmd.exe 配置 IIS 的启动任务。An example of a startup task that requires elevated privileges is a startup task that uses AppCmd.exe to configure IIS. AppCmd.exe 需要 executionContext="elevated"AppCmd.exe requires executionContext="elevated".

使用适当的 taskTypeUse the appropriate taskType

taskType 属性决定了执行启动任务的方式。The taskType attribute determines the way the startup task is executed. 有三个值:simple、background 和 foreground 。There are three values: simple, background, and foreground. background 和 foreground 任务以异步方式启动,simple 任务以同步方式执行(一次一个)。The background and foreground tasks are started asynchronously, and then the simple tasks are executed synchronously one at a time.

使用 simple 启动任务,可以设置顺序,让任务按照它们在 ServiceDefinition.csdef 文件中的列出顺序运行。With simple startup tasks, you can set the order in which the tasks run by the order in which the tasks are listed in the ServiceDefinition.csdef file. 如果 simple 任务以非零退出代码结束,则启动过程将停止,并且角色不会启动。If a simple task ends with a non-zero exit code, then the startup procedure stops and the role does not start.

background 启动任务和 foreground 启动任务之间的区别在于 foreground 任务使角色一直运行,直到 foreground 任务结束为止 。The difference between background startup tasks and foreground startup tasks is that foreground tasks keep the role running until the foreground task ends. 这也意味着,如果 foreground 任务挂起或崩溃,角色将不会回收,直到 foreground 任务被强制关闭 。This also means that if the foreground task hangs or crashes, the role will not recycle until the foreground task is forced closed. 因此,对于异步启动任务建议使用 background 任务,除非需要 foreground 任务的功能 。For this reason, background tasks are recommended for asynchronous startup tasks unless you need that feature of the foreground task.

以 EXIT /B 0 结束批处理文件End batch files with EXIT /B 0

仅当每个 simple 启动任务的 errorlevel 均为零时,角色才会启动。The role will only start if the errorlevel from each of your simple startup task is zero. 并非所有程序都正确设置 errorlevel (退出代码),因此如果一切正常运行,批处理文件应以 EXIT /B 0 结束。Not all programs set the errorlevel (exit code) correctly, so the batch file should end with an EXIT /B 0 if everything ran correctly.

在启动批处理文件的末尾缺少 EXIT /B 0 是角色未启动的常见原因。A missing EXIT /B 0 at the end of a startup batch file is a common cause of roles that do not start.

备注

我发现当使用 /B 参数时,嵌套的批处理文件多次挂起。I've noticed that nested batch files sometimes hang when using the /B parameter. 如果另一个批处理文件调用当前批处理文件(例如当使用日志包装器时),你可能希望确保此挂起问题不再发生。You may want to make sure that this hang problem does not happen if another batch file calls your current batch file, like if you use the log wrapper. 在本例中,可以省略 /B 参数。You can omit the /B parameter in this case.

启动任务应多次运行Expect startup tasks to run more than once

并非所有角色回收都包括重新启动,但所有角色回收都包括运行所有启动任务。Not all role recycles include a reboot, but all role recycles include running all startup tasks. 这意味着启动任务必须能够在重新启动之间运行多次而不出现任何问题。This means that startup tasks must be able to run multiple times between reboots without any problems. 这在 前面部分中进行了讨论。This is discussed in the preceding section.

使用本地存储来存储必须在角色中访问的文件Use local storage to store files that must be accessed in the role

如果要在启动任务期间复制或创建随后可由角色访问的文件,则该文件必须放置在本地存储中。If you want to copy or create a file during your startup task that is then accessible to your role, then that file must be placed in local storage. 请参阅 前面部分See the preceding section.

后续步骤Next steps

查看云服务模型和包Review the cloud service model and package

详细了解任务的工作方式。Learn more about how Tasks work.

创建和部署云服务包。Create and deploy your cloud service package.