预期状态配置

什么是预期状态配置?

预期状态配置或 DSC 是 PowerShell 中内置的工具,可用于通过代码定义 Windows 主机设置。DSC 的总体目标与 Ansible 相同,只是执行方式不同。从 Ansible 2.4 开始,添加了 win_dsc 模块,可用于在与 Windows 主机交互时利用现有的 DSC 资源。

有关 DSC 的更多详细信息,请参阅 DSC 概述

主机要求

要使用 win_dsc 模块,Windows 主机必须安装 PowerShell v5.0 或更高版本。所有支持的主机都可以升级到 PowerShell v5。

满足 PowerShell 要求后,使用 DSC 就像使用 win_dsc 模块创建任务一样简单。

为什么要使用 DSC?

DSC 和 Ansible 模块有一个共同的目标,即定义和确保资源的状态。因此,诸如 DSC 文件资源 和 Ansible win_file 之类的资源可用于实现相同的结果。决定使用哪个取决于场景。

在 Ansible 模块上使用 DSC 资源的理由

  • 主机不支持 PowerShell v5.0,或者无法轻松升级

  • DSC 资源未提供 Ansible 模块中存在的特性。例如,win_regedit 可以管理 REG_NONE 属性类型,而 DSC Registry 资源则无法管理

  • DSC 资源对检查模式的支持有限,而某些 Ansible 模块则具有更好的检查

  • DSC 资源不支持差异模式,而某些 Ansible 模块则支持

  • 自定义资源需要在主机上预先执行其他安装步骤才能运行,而 Ansible 模块内置于 Ansible 中

  • DSC 资源中存在错误,而 Ansible 模块可以正常工作

在 Ansible 模块上使用 DSC 资源的理由

  • Ansible 模块不支持 DSC 资源中存在的特性

  • 没有可用的 Ansible 模块

  • 现有 Ansible 模块中存在错误

最终,使用 DSC 还是 Ansible 模块执行任务并不重要;重要的是任务能够正确执行,并且剧本仍然可读。如果您对 DSC 比 Ansible 更熟悉,并且它能完成工作,只需对该任务使用 DSC 即可。

如何使用 DSC?

win_dsc 模块接受各种选项,因此它会根据要管理的资源进行更改。可以在 资源 中找到内置资源的列表。

注册表 资源为例,这是 Microsoft 文档中的 DSC 定义

Registry [string] #ResourceName
{
    Key = [string]
    ValueName = [string]
    [ Ensure = [string] { Enable | Disable }  ]
    [ Force =  [bool]   ]
    [ Hex = [bool] ]
    [ DependsOn = [string[]] ]
    [ ValueData = [string[]] ]
    [ ValueType = [string] { Binary | Dword | ExpandString | MultiString | Qword | String }  ]
}

在定义任务时,resource_name 必须设置为正在使用的 DSC 资源 - 在这种情况下,resource_name 应设置为 Registrymodule_version 可以引用已安装的 DSC 资源的特定版本;如果留空,它将默认为最新版本。其他选项是用于定义资源的参数,例如 KeyValueName。虽然任务中的选项不区分大小写,但建议保持大小写不变,因为它更便于区分 DSC 资源选项和 Ansible 的 win_dsc 选项。

这是上面提到的 DSC 注册表资源的 Ansible 任务版本

- name: Use win_dsc module with the Registry DSC resource
  win_dsc:
    resource_name: Registry
    Ensure: Present
    Key: HKEY_LOCAL_MACHINE\SOFTWARE\ExampleKey
    ValueName: TestValue
    ValueData: TestData

从 Ansible 2.8 开始,win_dsc 模块会自动使用 DSC 定义验证 Ansible 中的输入选项。这意味着如果选项名称不正确、缺少必填选项或值不是有效选择,Ansible 将会失败。使用 3 或更高(-vvv)的详细程度级别运行 Ansible 时,返回值将包含根据指定的 resource_name 确定的可能的调用选项。以下是上面 Registry 任务的调用输出示例

changed: [2016] => {
    "changed": true,
    "invocation": {
        "module_args": {
            "DependsOn": null,
            "Ensure": "Present",
            "Force": null,
            "Hex": null,
            "Key": "HKEY_LOCAL_MACHINE\\SOFTWARE\\ExampleKey",
            "PsDscRunAsCredential_password": null,
            "PsDscRunAsCredential_username": null,
            "ValueData": [
                "TestData"
            ],
            "ValueName": "TestValue",
            "ValueType": null,
            "module_version": "latest",
            "resource_name": "Registry"
        }
    },
    "module_version": "1.1",
    "reboot_required": false,
    "verbose_set": [
        "Perform operation 'Invoke CimMethod' with following parameters, ''methodName' = ResourceSet,'className' = MSFT_DSCLocalConfigurationManager,'namespaceName' = root/Microsoft/Windows/DesiredStateConfiguration'.",
        "An LCM method call arrived from computer SERVER2016 with user sid S-1-5-21-3088887838-4058132883-1884671576-1105.",
        "[SERVER2016]: LCM:  [ Start  Set      ]  [[Registry]DirectResourceAccess]",
        "[SERVER2016]:                            [[Registry]DirectResourceAccess] (SET) Create registry key 'HKLM:\\SOFTWARE\\ExampleKey'",
        "[SERVER2016]:                            [[Registry]DirectResourceAccess] (SET) Set registry key value 'HKLM:\\SOFTWARE\\ExampleKey\\TestValue' to 'TestData' of type 'String'",
        "[SERVER2016]: LCM:  [ End    Set      ]  [[Registry]DirectResourceAccess]  in 0.1930 seconds.",
        "[SERVER2016]: LCM:  [ End    Set      ]    in  0.2720 seconds.",
        "Operation 'Invoke CimMethod' complete.",
        "Time taken for configuration job to complete is 0.402 seconds"
    ],
    "verbose_test": [
        "Perform operation 'Invoke CimMethod' with following parameters, ''methodName' = ResourceTest,'className' = MSFT_DSCLocalConfigurationManager,'namespaceName' = root/Microsoft/Windows/DesiredStateConfiguration'.",
        "An LCM method call arrived from computer SERVER2016 with user sid S-1-5-21-3088887838-4058132883-1884671576-1105.",
        "[SERVER2016]: LCM:  [ Start  Test     ]  [[Registry]DirectResourceAccess]",
        "[SERVER2016]:                            [[Registry]DirectResourceAccess] Registry key 'HKLM:\\SOFTWARE\\ExampleKey' does not exist",
        "[SERVER2016]: LCM:  [ End    Test     ]  [[Registry]DirectResourceAccess] False in 0.2510 seconds.",
        "[SERVER2016]: LCM:  [ End    Set      ]    in  0.3310 seconds.",
        "Operation 'Invoke CimMethod' complete.",
        "Time taken for configuration job to complete is 0.475 seconds"
    ]
}

invocation.module_args 键显示了实际设置的值以及未设置的其他可能值。不幸的是,这不会显示 DSC 属性的默认值,只会显示 Ansible 任务中设置的值。任何 *_password 选项都将在输出中被屏蔽,以确保安全性;如果存在任何其他敏感的模块选项,请在任务中设置 no_log: True,以阻止所有任务输出被记录。

属性类型

每个 DSC 资源属性都与一个类型相关联。Ansible 将尝试在执行期间将定义的选项转换为正确的类型。对于 [string][bool] 之类的简单类型,这是一个简单的操作,但对于 [PSCredential] 或数组(如 [string[]])之类的复杂类型,则需要遵循一定的规则。

PSCredential

[PSCredential] 对象用于以安全方式存储凭据,但 Ansible 无法通过 JSON 序列化它。要设置 DSC PSCredential 属性,该参数的定义应包含两个条目,分别以 _username_password 作为后缀,分别用于用户名和密码。例如

PsDscRunAsCredential_username: '{{ ansible_user }}'
PsDscRunAsCredential_password: '{{ ansible_password }}'

SourceCredential_username: AdminUser
SourceCredential_password: PasswordForAdminUser

注意

在 Ansible 2.8 之前的版本中,您应该在 Ansible 的任务定义中设置 no_log: true,以确保任何使用的凭据都不会存储在任何日志文件或控制台输出中。

在 DSC 资源 MOF 定义中,使用 EmbeddedInstance("MSFT_Credential") 定义 [PSCredential]

CimInstance 类型

DSC 使用 [CimInstance] 对象来存储基于该资源定义的自定义类的字典对象。在 YAML 中定义接受 [CimInstance] 的值与在 YAML 中定义字典相同。例如,要在 Ansible 中定义 [CimInstance]

# [CimInstance]AuthenticationInfo == MSFT_xWebAuthenticationInformation
AuthenticationInfo:
  Anonymous: false
  Basic: true
  Digest: false
  Windows: true

在上面的示例中,CIM 实例是 MSFT_xWebAuthenticationInformation 类的表示形式。此类接受四个布尔变量,AnonymousBasicDigestWindows[CimInstance] 中要使用的键取决于它所表示的类。请阅读资源文档以确定可以使用的键以及每个键值的类型。类定义通常位于 <resource name>.schema.mof 中。

哈希表类型

[HashTable] 对象也是一个字典,但它没有严格的键集需要定义。就像一个 [CimInstance],将其定义为 YAML 中的普通字典值。一个 [HashTable] 在 DSC 资源 MOF 定义中使用 EmbeddedInstance("MSFT_KeyValuePair") 定义。

数组

简单类型数组,例如 [string[]][UInt32[]],可以定义为列表或逗号分隔的字符串,然后将其转换为其类型。建议使用列表,因为 win_dsc 模块在将值传递给 DSC 引擎之前不会手动解析这些值。例如,要在 Ansible 中定义一个简单类型数组,

# [string[]]
ValueData: entry1, entry2, entry3
ValueData:
- entry1
- entry2
- entry3

# [UInt32[]]
ReturnCode: 0,3010
ReturnCode:
- 0
- 3010

复杂类型数组,例如 [CimInstance[]](字典数组),可以像这个示例一样定义

# [CimInstance[]]BindingInfo == MSFT_xWebBindingInformation
BindingInfo:
- Protocol: https
  Port: 443
  CertificateStoreName: My
  CertificateThumbprint: C676A89018C4D5902353545343634F35E6B3A659
  HostName: DSCTest
  IPAddress: '*'
  SSLFlags: 1
- Protocol: http
  Port: 80
  IPAddress: '*'

以上示例是一个包含两个 MSFT_xWebBindingInformation 类值的数组。在定义 [CimInstance[]] 时,请务必阅读资源文档,了解定义中要使用哪些键。

日期时间

[DateTime] 对象是一个 DateTime 字符串,表示以 ISO 8601 日期时间格式表示的日期和时间。[DateTime] 字段的值应在 YAML 中用引号引起来,以确保字符串被正确序列化到 Windows 主机。以下是在 Ansible 中定义 [DateTime] 值的示例

# As UTC-0 (No timezone)
DateTime: '2019-02-22T13:57:31.2311892+00:00'

# As UTC+4
DateTime: '2019-02-22T17:57:31.2311892+04:00'

# As UTC-4
DateTime: '2019-02-22T09:57:31.2311892-04:00'

以上所有值都等于 2019 年 2 月 22 日下午 1:57:31.2311892 UTC 日期时间。

以其他用户身份运行

默认情况下,DSC 以 SYSTEM 帐户而不是 Ansible 用于运行模块的帐户来运行每个资源。这意味着根据用户配置文件动态加载的资源,例如 HKEY_CURRENT_USER 注册表配置单元,将在 SYSTEM 配置文件下加载。参数 PsDscRunAsCredential 是可以为每个 DSC 资源设置的参数,并强制 DSC 引擎在其他帐户下运行。由于 PsDscRunAsCredential 的类型为 PSCredential,因此它使用 _username_password 后缀定义。

以 Registry 资源类型为例,以下是如何定义一个任务来访问 Ansible 用户的 HKEY_CURRENT_USER 配置单元

- name: Use win_dsc with PsDscRunAsCredential to run as a different user
  win_dsc:
    resource_name: Registry
    Ensure: Present
    Key: HKEY_CURRENT_USER\ExampleKey
    ValueName: TestValue
    ValueData: TestData
    PsDscRunAsCredential_username: '{{ ansible_user }}'
    PsDscRunAsCredential_password: '{{ ansible_password }}'
  no_log: true

自定义 DSC 资源

DSC 资源不限于来自 Microsoft 的内置选项。可以安装自定义模块来管理通常不可用的其他资源。

查找自定义 DSC 资源

您可以使用 PSGallery 查找自定义资源,以及有关如何在 Windows 主机上安装它们的文档。

还可以使用 Find-DscResource cmdlet 查找自定义资源。例如

# Find all DSC resources in the configured repositories
Find-DscResource

# Find all DSC resources that relate to SQL
Find-DscResource -ModuleName "*sql*"

注意

由 Microsoft 开发的以 x 开头的 DSC 资源表示该资源是实验性的,并且不提供支持。

安装自定义资源

在主机上安装 DSC 资源有三种方法

  • 使用 Install-Module cmdlet 手动安装

  • 使用 win_psmodule Ansible 模块

  • 手动保存模块并将其复制到其他主机

以下是如何使用 win_psmodule 安装 xWebAdministration 资源的示例

- name: Install xWebAdministration DSC resource
  win_psmodule:
    name: xWebAdministration
    state: present

安装完成后,win_dsc 模块将能够通过引用 resource_name 选项来使用该资源。

上述前两种方法仅在主机能够访问互联网时有效。当主机无法访问互联网时,必须先在另一个能够访问互联网的主机上使用上述方法安装模块,然后将其复制到其他主机。要将模块保存到本地文件路径,可以运行以下 PowerShell cmdlet

Save-Module -Name xWebAdministration -Path C:\temp

这将在 C:\temp 中创建一个名为 xWebAdministration 的文件夹,可以将其复制到任何主机。为了让 PowerShell 看到这个离线资源,必须将其复制到 PSModulePath 环境变量中设置的目录中。在大多数情况下,路径 C:\Program Files\WindowsPowerShell\Module 是通过该变量设置的,但是可以使用 win_path 模块添加其他路径。

示例

解压缩 zip 文件

- name: Extract a zip file
  win_dsc:
    resource_name: Archive
    Destination: C:\temp\output
    Path: C:\temp\zip.zip
    Ensure: Present

创建目录

- name: Create file with some text
  win_dsc:
    resource_name: File
    DestinationPath: C:\temp\file
    Contents: |
        Hello
        World
    Ensure: Present
    Type: File

- name: Create directory that is hidden is set with the System attribute
  win_dsc:
    resource_name: File
    DestinationPath: C:\temp\hidden-directory
    Attributes: Hidden,System
    Ensure: Present
    Type: Directory

与 Azure 交互

- name: Install xAzure DSC resources
  win_psmodule:
    name: xAzure
    state: present

- name: Create virtual machine in Azure
  win_dsc:
    resource_name: xAzureVM
    ImageName: a699494373c04fc0bc8f2bb1389d6106__Windows-Server-2012-R2-201409.01-en.us-127GB.vhd
    Name: DSCHOST01
    ServiceName: ServiceName
    StorageAccountName: StorageAccountName
    InstanceSize: Medium
    Windows: true
    Ensure: Present
    Credential_username: '{{ ansible_user }}'
    Credential_password: '{{ ansible_password }}'

设置 IIS 网站

- name: Install xWebAdministration module
  win_psmodule:
    name: xWebAdministration
    state: present

- name: Install IIS features that are required
  win_dsc:
    resource_name: WindowsFeature
    Name: '{{ item }}'
    Ensure: Present
  loop:
  - Web-Server
  - Web-Asp-Net45

- name: Setup web content
  win_dsc:
    resource_name: File
    DestinationPath: C:\inetpub\IISSite\index.html
    Type: File
    Contents: |
      <html>
      <head><title>IIS Site</title></head>
      <body>This is the body</body>
      </html>
    Ensure: present

- name: Create new website
  win_dsc:
    resource_name: xWebsite
    Name: NewIISSite
    State: Started
    PhysicalPath: C:\inetpub\IISSite\index.html
    BindingInfo:
    - Protocol: https
      Port: 8443
      CertificateStoreName: My
      CertificateThumbprint: C676A89018C4D5902353545343634F35E6B3A659
      HostName: DSCTest
      IPAddress: '*'
      SSLFlags: 1
    - Protocol: http
      Port: 8080
      IPAddress: '*'
    AuthenticationInfo:
      Anonymous: false
      Basic: true
      Digest: false
      Windows: true

另请参阅

Ansible 剧本

剧本简介

Ansible 提示和技巧

剧本的提示和技巧

Windows 模块列表

Windows 特定模块列表,所有模块都在 PowerShell 中实现

用户邮件列表

有问题吗?加入 Google 群组!

实时聊天

如何加入 Ansible 聊天频道