Windows 模块开发演练
在本节中,我们将逐步介绍 Ansible Windows 模块的开发、测试和调试。
由于 Windows 模块是用 PowerShell 编写的,并且需要在 Windows 主机上运行,因此本指南与通常的开发演练指南有所不同。
本节涵盖的内容
Windows 环境设置
与可以在运行 Ansible 的主机上运行的 Python 模块开发不同,Windows 模块需要为 Windows 主机编写和测试。虽然可以从 Microsoft 下载 Windows 的评估版,但这些镜像通常需要进一步修改才能被 Ansible 使用。设置 Windows 主机以便 Ansible 可以使用的最简单方法是使用 Vagrant 设置虚拟机。Vagrant 可用于下载称为“镜像”的现有操作系统镜像,然后将其部署到 VirtualBox 等虚拟机管理程序。这些镜像可以离线创建和存储,也可以从名为 Vagrant Cloud 的中央存储库下载。
本指南将使用 packer-windoze 存储库创建的 Vagrant 镜像,这些镜像也已上传到 Vagrant Cloud。要了解有关如何创建这些镜像的更多信息,请访问 GitHub 存储库并查看 README
文件。
在开始之前,必须安装以下程序(有关安装说明,请参阅 Vagrant 和 VirtualBox 文档)
Vagrant
VirtualBox
在虚拟机中创建 Windows 服务器
要创建单个 Windows Server 2016 实例,请运行以下命令:
vagrant init jborean93/WindowsServer2016
vagrant up
这将从 Vagrant Cloud 下载 Vagrant 镜像,将其添加到主机上的本地镜像,然后在 VirtualBox 中启动该实例。首次启动时,Windows 虚拟机将运行 sysprep 过程,然后自动创建一个 HTTP 和 HTTPS WinRM 侦听器。Vagrant 将在侦听器上线后完成其过程,之后 Ansible 可以使用该虚拟机。
创建 Ansible 清单
以下 Ansible 清单文件可用于连接到新创建的 Windows 虚拟机:
[windows]
WindowsServer ansible_host=127.0.0.1
[windows:vars]
ansible_user=vagrant
ansible_password=vagrant
ansible_port=55986
ansible_connection=winrm
ansible_winrm_transport=ntlm
ansible_winrm_server_cert_validation=ignore
注意
端口 55986
由 Vagrant 自动转发到已创建的 Windows 主机,如果这与现有的本地端口冲突,则 Vagrant 将自动随机使用另一个端口并在输出中显示。
创建的操作系统基于设置的镜像。可以使用以下镜像:
主机上线后,可以通过 127.0.0.1:3389
上的 RDP 访问它,但端口可能因冲突而异。要删除主机,请运行 vagrant destroy --force
,Vagrant 将自动删除虚拟机以及与该虚拟机关联的任何其他文件。
虽然这在单个 Windows 实例上测试模块时很有用,但这些主机在不修改的情况下无法与基于域的模块一起使用。ansible-windows 中的 Vagrantfile 可用于创建可在 Ansible 中使用的测试域环境。此存储库包含三个文件,Ansible 和 Vagrant 都使用这些文件来在域环境中创建多个 Windows 主机。这些文件是:
Vagrantfile
:读取inventory.yml
的清单设置并配置所需主机的 Vagrant 文件inventory.yml
:包含所需主机和其他连接信息,例如 IP 地址和转发端口main.yml
:Vagrant 调用的 Ansible 剧本,用于配置域控制节点并将子主机加入域
默认情况下,这些文件将创建以下环境:
在 Windows Server 2016 上运行的单个 AD 域控制器
五个加入该域的每个主要 Windows Server 版本的子主机
DNS 名称为
domain.local
的域每个主机上的本地管理员帐户,用户名为
vagrant
,密码为vagrant
域管理员帐户
[email protected]
,密码为VagrantPass1
如果需要,可以通过更改 inventory.yml
文件中的变量 domain_*
来修改域名称和帐户。还可以通过更改 domain_children
键下定义的主机来修改清单文件以配置更多或更少的服务器。主机变量 ansible_host
是将分配给 VirtualBox 主机专用网络适配器的私有 IP,而 vagrant_box
是将用于创建虚拟机的镜像。
配置环境
要按原样配置环境,请运行以下命令:
git clone https://github.com/jborean93/ansible-windows.git
cd vagrant
vagrant up
注意
Vagrant 按顺序配置每个主机,因此这可能需要一些时间才能完成。如果在设置域的 Ansible 阶段发生任何错误,请运行 vagrant provision
以重新运行该步骤。
与使用 Vagrant 设置单个 Windows 实例不同,这些主机也可以使用 IP 地址直接访问,也可以通过转发端口访问。通过主机专用网络适配器访问它更容易,因为使用了普通协议端口,例如 RDP 仍然通过 3389
。在无法使用主机专用网络 IP 解析主机的情况下,可以使用以下转发端口通过 127.0.0.1
访问以下协议:
RDP
:295xxSSH
:296xxWinRM HTTP
:297xxWinRM HTTPS
:298xxSMB
:299xx
将xx
替换为清单文件中的条目号,该条目号从域控制器启动时的00
开始递增。例如,在默认的inventory.yml
文件中,SERVER2012R2
的HTTPS上的WinRM通过端口29804
转发,因为它是在domain_children
中的第四个条目。
Windows 新模块开发
创建新模块时,需要记住以下几点
模块代码位于 Powershell (.ps1) 文件中,而文档包含在同名的 Python (.py) 文件中。
避免在模块中使用
Write-Host/Debug/Verbose/Error
,并将需要返回的内容添加到$module.Result
变量中。要使模块失败,请调用
$module.FailJson("failure message here")
,可以将异常或ErrorRecord设置为第二个参数以获得更具描述性的错误消息。您可以将异常或ErrorRecord作为第二个参数传递给
FailJson("failure", $_)
以获得更详细的输出。大多数新模块在合并到 Ansible 主代码库之前都需要检查模式和集成测试。
避免对大型代码块使用 try/catch 语句,而应将其用于单个调用,以便错误消息更具描述性。
使用 try/catch 语句时,尝试捕获特定异常。
除非必要,否则避免使用 PSCustomObjects。
在
./lib/ansible/module_utils/powershell/
中查找常用函数,并使用其中的代码,而不是重复工作。这些可以通过添加行#Requires -Module *
来导入,其中 * 是要导入的文件名,并在通过 Ansible 运行时自动包含在发送到 Windows 目标的模块代码中。除了 PowerShell 模块实用程序外,C# 模块实用程序也存储在
./lib/ansible/module_utils/csharp/
中,如果存在行#AnsibleRequires -CSharpUtil *
,则会在模块执行中自动导入。C# 和 PowerShell 模块实用程序实现相同目标,但 C# 允许开发人员实现低级任务,例如调用 Win32 API,并且在某些情况下速度更快。
确保代码在 Windows Server 2016 及更高版本上可在 Powershell v5.1 及更高版本下运行;如果需要更高的最小 Powershell 或操作系统版本,请确保文档清楚地反映这一点。
Ansible 在严格模式版本 2.0 下运行模块。请务必通过在开发脚本顶部放置
Set-StrictMode -Version 2.0
来启用该模式进行测试。如果可能,优先使用本机 PowerShell cmdlet 而不是可执行文件调用。
使用完整的 cmdlet 名称而不是别名,例如使用
Remove-Item
而不是rm
。使用带参数的 cmdlet,例如使用
Remove-Item -Path C:\temp
而不是Remove-Item C:\temp
。
一个非常基本的 Powershell 模块win_environment包含 Powershell 模块的最佳实践。它演示了如何实现检查模式和差异支持,还在满足特定条件时向用户显示警告。
一个稍微高级一点的模块是win_uri,它还展示了如何使用不同的参数类型(bool、str、int、list、dict、path)和参数的选择,如何使模块失败以及如何处理异常。
作为新的AnsibleModule
包装器的一部分,输入参数是根据参数规范定义和验证的。以下选项可以在参数规范的根级别设置。
mutually_exclusive
:列表的列表,其中内部列表包含不能一起设置的模块选项。no_log
:阻止模块向 Windows 事件日志发出任何日志。options
:字典,其中键是模块选项,值是该选项的规范。required_by
:字典,如果设置了键指定的选项,则必须设置值指定的选项。required_if
:列表的列表,其中内部列表包含 3 个或 4 个元素;第一个元素是要检查其值的模块选项。
第二个元素是第一个元素指定的选项的值,如果匹配,则运行所需的if检查。
第三个元素是匹配时所需的模块选项列表。
可选的第四个元素是一个布尔值,它声明第三个元素中的所有模块选项是否都是必需的(默认值:
$false
)或只有一个($true
)。
required_one_of
:列表的列表,其中内部列表包含必须至少设置一个的模块选项。required_together
:列表的列表,其中内部列表包含必须一起设置的模块选项。supports_check_mode
:模块是否支持检查模式,默认为$false
。
模块的实际输入选项在options
值中作为字典设置。此字典的键是模块选项名称,而值是该模块选项的规范。每个规范都可以设置以下选项。
aliases
:模块选项的别名列表。choices
:模块选项的有效值列表,如果type=list
,则每个列表值都针对选项进行验证,而不是列表本身。default
:如果未设置,则为模块选项的默认值。deprecated_aliases
:定义已弃用别名及其将被移除的版本的哈希表列表。每个条目都必须包含键name
和collection_name
,以及version
或date
。elements
:当type=list
时,这将设置每个列表值的类型,值与type
相同。no_log
:在module_invocation
返回值中返回之前,将对输入值进行清理。removed_in_version
:声明何时移除已弃用的模块选项,如果设置,则会向最终用户显示警告。removed_at_date
:声明何时(YYYY-MM-DD)移除已弃用的模块选项,如果设置,则会向最终用户显示警告。removed_from_collection
:声明将从哪个集合中移除已弃用的模块选项;如果指定了removed_in_version
和removed_at_date
中的一个,则必须指定。required
:如果未设置模块选项,则会失败。type
:模块选项的类型,如果未设置,则默认为str
。有效类型为;bool
:布尔值。dict
:字典值,如果输入是 JSON 或 key=value 字符串,则将其转换为字典。float
:浮点数或Single值。int
:Int32 值。json
:字符串,如果输入是字典,则将其转换为 JSON 字符串。list
:值列表,elements=<type>
如果设置,可以转换单个列表值类型。如果elements=dict
,则定义options
,将根据参数规范验证值。当输入是字符串时,字符串将按,
分割,任何空格都将被修剪。path
:字符串,其中类似%TEMP%
的值根据环境值进行扩展。如果输入值以\\?\
开头,则不运行扩展。raw
:Ansible 传递的值不会进行任何转换。sid
:将 Windows 安全标识符值或 Windows 帐户名称转换为SecurityIdentifier值。str
:值将转换为字符串。
当type=dict
或type=list
且elements=dict
时,还可以为该模块选项设置以下键。
apply_defaults
:如果True
,则该值基于该键的options
规范默认值;如果False
,则为 null。仅当用户未定义模块选项且type=dict
时有效。mutually_exclusive
:与根级别的mutually_exclusive
相同,但针对子字典中的值进行验证。options
:与根级别的options
相同,但包含子选项的有效选项。required_if
:与根级别的required_if
相同,但针对子字典中的值进行验证。required_by
:与根级别的required_by
相同,但会针对子字典中的值进行验证。required_together
:与根级别的required_together
相同,但会针对子字典中的值进行验证。required_one_of
:与根级别的required_one_of
相同,但会针对子字典中的值进行验证。
模块类型也可以是一个委托函数,它将值转换为模块选项所需的值。例如,以下代码片段显示了如何创建一个自定义类型来创建一个UInt64
值。
$spec = @{
uint64_type = @{ type = [Func[[Object], [UInt64]]]{ [System.UInt64]::Parse($args[0]) } }
}
$uint64_type = $module.Params.uint64_type
如有疑问,请查看其他一些核心模块,了解其实现方式。
有时,Windows 提供多种方法来完成一项任务;编写模块时,应优先考虑此顺序。
原生 PowerShell cmdlet,例如
Remove-Item -Path C:\temp -Recurse
.NET 类,例如
[System.IO.Path]::GetRandomFileName()
通过
New-CimInstance
cmdlet 的 WMI 对象通过
New-Object -ComObject
cmdlet 的 COM 对象对原生可执行文件的调用,例如
Secedit.exe
PowerShell 模块支持 PowerShell 内置的#Requires
选项的一个小子集,以及由#AnsibleRequires
指定的某些 Ansible 特定要求。这些语句可以放置在脚本中的任何位置,但最常见的是靠近顶部。它们用于更轻松地声明模块的要求,而无需编写任何检查。每个requires
语句都必须独占一行,但一个脚本中可以有多个requires语句。
这些是在 Ansible 模块中可以使用的检查。
#Requires -Module Ansible.ModuleUtils.<module_util>
:在 Ansible 2.4 中添加,指定要加载的 module_util 以进行模块执行。#Requires -Version x.y
:在 Ansible 2.5 中添加,指定模块所需 PowerShell 的版本。如果此要求未满足,则模块将失败。#AnsibleRequires -PowerShell <module_util>
:在 Ansible 2.8 中添加,类似于#Requires -Module
,它指定要加载的 module_util 以进行模块执行。#AnsibleRequires -CSharpUtil <module_util>
:在 Ansible 2.8 中添加,指定要加载的 C# module_util 以进行模块执行。#AnsibleRequires -OSVersion x.y
:在 Ansible 2.5 中添加,指定模块所需的 OS 构建版本,如果不满足此要求,则会失败。实际的 OS 版本是从[Environment]::OSVersion.Version
派生的。#AnsibleRequires -Become
:在 Ansible 2.5 中添加,强制 exec 运行程序使用become
运行模块,这主要用于绕过 WinRM 限制。如果未指定ansible_become_user
,则使用SYSTEM
帐户。
#AnsibleRequires -PowerShell
和#AnsibleRequires -CSharpUtil
支持更多功能,例如:
导入集合中包含的 util(在 Ansible 2.9 中添加)
通过相对名称导入 util(在 Ansible 2.10 中添加)
通过在导入声明中添加-Optional来指定 util 是可选的(在 Ansible 2.12 中添加)。
有关更多详细信息,请参见以下示例。
# Imports the PowerShell Ansible.ModuleUtils.Legacy provided by Ansible itself
#AnsibleRequires -PowerShell Ansible.ModuleUtils.Legacy
# Imports the PowerShell my_util in the my_namesapce.my_name collection
#AnsibleRequires -PowerShell ansible_collections.my_namespace.my_name.plugins.module_utils.my_util
# Imports the PowerShell my_util that exists in the same collection as the current module
#AnsibleRequires -PowerShell ..module_utils.my_util
# Imports the PowerShell Ansible.ModuleUtils.Optional provided by Ansible if it exists.
# If it does not exist then it will do nothing.
#AnsibleRequires -PowerShell Ansible.ModuleUtils.Optional -Optional
# Imports the C# Ansible.Process provided by Ansible itself
#AnsibleRequires -CSharpUtil Ansible.Process
# Imports the C# my_util in the my_namespace.my_name collection
#AnsibleRequires -CSharpUtil ansible_collections.my_namespace.my_name.plugins.module_utils.my_util
# Imports the C# my_util that exists in the same collection as the current module
#AnsibleRequires -CSharpUtil ..module_utils.my_util
# Imports the C# Ansible.Optional provided by Ansible if it exists.
# If it does not exist then it will do nothing.
#AnsibleRequires -CSharpUtil Ansible.Optional -Optional
对于可选的 require 语句,模块代码需要验证 util 是否已导入,然后再尝试使用它。这可以通过检查 util 提供的函数或类型是否存在来完成。
虽然#Requires -Module
和#AnsibleRequires -PowerShell
都可以用于加载 PowerShell 模块,但建议使用#AnsibleRequires
。这是因为#AnsibleRequires
支持集合模块 util、按相对 util 名称导入以及可选 util 导入。
C# 模块 util 可以通过在脚本顶部添加using Ansible.<module_util>;
行(与所有其他 using 语句一起)来引用其他 C# util。
Windows 模块实用程序
与 Python 模块一样,PowerShell 模块也提供许多模块实用程序,这些实用程序在 PowerShell 中提供辅助函数。可以通过在 PowerShell 模块中添加以下行来导入这些 module_utils:
#Requires -Module Ansible.ModuleUtils.Legacy
这将导入位于./lib/ansible/module_utils/powershell/Ansible.ModuleUtils.Legacy.psm1
的 module_util,并启用对其所有函数的调用。从 Ansible 2.8 开始,Windows 模块 util 也可以用 C# 编写,并存储在lib/ansible/module_utils/csharp
中。可以通过在 PowerShell 模块中添加以下行来导入这些 module_utils:
#AnsibleRequires -CSharpUtil Ansible.Basic
这将导入位于./lib/ansible/module_utils/csharp/Ansible.Basic.cs
的 module_util,并自动加载执行进程中的类型。C# 模块 util 可以相互引用并一起加载,方法是在 util 顶部的 using 语句中添加以下行:
using Ansible.Become;
可以在 C# 文件中设置特殊的注释来控制编译参数。以下注释可以添加到脚本中:
//AssemblyReference -Name <assembly dll> [-CLR [Core|Framework]]
:在编译期间要引用的程序集 DLL,可选的-CLR
标志也可以用来声明是在 .NET Core、Framework 或两者下运行时引用(如果省略)。//NoWarn -Name <error id> [-CLR [Core|Framework]]
:在编译代码时要忽略的编译器警告 ID,可选的-CLR
与上面相同。可以在编译器错误中找到警告列表。
此外,还定义了以下预处理器符号:
CORECLR
:当 PowerShell 通过 .NET Core 运行时,存在此符号。WINDOWS
:当 PowerShell 在 Windows 上运行时,存在此符号。UNIX
:当 PowerShell 在 Unix 上运行时,存在此符号。
这些标志的组合有助于使模块 util 能够在 .NET Framework 和 .NET Core 上互操作,以下是一个实际示例。
#if CORECLR
using Newtonsoft.Json;
#else
using System.Web.Script.Serialization;
#endif
//AssemblyReference -Name Newtonsoft.Json.dll -CLR Core
//AssemblyReference -Name System.Web.Extensions.dll -CLR Framework
// Ignore error CS1702 for all .NET types
//NoWarn -Name CS1702
// Ignore error CS1956 only for .NET Framework
//NoWarn -Name CS1956 -CLR Framework
以下是与 Ansible 打包的 module_utils 列表以及它们的常规描述。
ArgvParser:用于将参数列表转换为符合 Windows 参数解析规则的转义字符串的实用程序。
CamelConversion:用于将 camelCase 字符串/列表/字典转换为 snake_case 的实用程序。
CommandUtil:用于执行 Windows 进程并将 stdout/stderr 和 rc 作为单独的对象返回的实用程序。
FileUtil:扩展了
Get-ChildItem
和Test-Path
以处理特殊文件(如C:\pagefile.sys
)的实用程序。Legacy:Ansible 模块的一般定义和辅助实用程序。
LinkUtil:用于创建、删除和获取符号链接、联接点和硬链接信息的实用程序。
SID:用于将用户或组转换为 Windows SID,反之亦然的实用程序。
有关任何特定模块实用程序及其要求的更多详细信息,请参见Ansible 模块实用程序源代码。
PowerShell 模块实用程序可以存储在标准 Ansible 发行版之外,用于自定义模块。自定义 module_utils 放在 playbook 或角色目录根文件夹中的名为module_utils
的文件夹中。
C# 模块实用程序也可以存储在标准 Ansible 发行版之外,用于自定义模块。与 PowerShell util 一样,它们存储在名为module_utils
的文件夹中,文件名必须以扩展名.cs
结尾,以Ansible.
开头,并以 util 中定义的命名空间命名。
以下示例是一个角色结构,其中包含两个名为Ansible.ModuleUtils.ModuleUtil1
和Ansible.ModuleUtils.ModuleUtil2
的 PowerShell 自定义 module_utils,以及一个包含命名空间Ansible.CustomUtil
的 C# util。
meta/
main.yml
defaults/
main.yml
module_utils/
Ansible.ModuleUtils.ModuleUtil1.psm1
Ansible.ModuleUtils.ModuleUtil2.psm1
Ansible.CustomUtil.cs
tasks/
main.yml
每个 PowerShell module_util 必须至少包含一个已使用Export-ModuleMember
在文件末尾导出的函数。例如:
Export-ModuleMember -Function Invoke-CustomUtil, Get-CustomInfo
Windows playbook 模块测试
您可以使用 Ansible playbook 测试模块。例如
在任何目录中创建一个 playbook
touch testmodule.yml
。在同一目录中创建一个 inventory 文件
touch hosts
。使用连接到 Windows 主机(s)所需的变量填充 inventory 文件。
将以下内容添加到新的 playbook 文件中
---
- name: test out windows module
hosts: windows
tasks:
- name: test out module
win_module:
name: test name
运行 playbook
ansible-playbook -i hosts testmodule.yml
这对于查看 Ansible 如何端到端运行新模块非常有用。下面显示了其他可能的模块测试方法。
Windows 调试
目前只能在 Windows 主机上调试模块。这在开发新模块或实现错误修复时非常有用。以下是设置此项需要遵循的一些步骤
将模块脚本复制到 Windows 服务器
将文件夹
./lib/ansible/module_utils/powershell
和./lib/ansible/module_utils/csharp
复制到上述脚本的同一目录在模块代码中任何
#Requires -Module
行的开头添加一个额外的#
,这仅适用于以#Requires -Module
开头的任何行将以下内容添加到复制到服务器的模块脚本的开头
# Set $ErrorActionPreference to what's set during Ansible execution
$ErrorActionPreference = "Stop"
# Set the first argument as the path to a JSON file that contains the module args
$args = @("$($pwd.Path)\args.json")
# Or instead of an args file, set $complex_args to the pre-processed module args
$complex_args = @{
_ansible_check_mode = $false
_ansible_diff = $false
path = "C:\temp"
state = "present"
}
# Import any C# utils referenced with '#AnsibleRequires -CSharpUtil' or 'using Ansible.;
# The $_csharp_utils entries should be the context of the C# util files and not the path
Import-Module -Name "$($pwd.Path)\powershell\Ansible.ModuleUtils.AddType.psm1"
$_csharp_utils = @(
[System.IO.File]::ReadAllText("$($pwd.Path)\csharp\Ansible.Basic.cs")
)
Add-CSharpType -References $_csharp_utils -IncludeDebugInfo
# Import any PowerShell modules referenced with '#Requires -Module`
Import-Module -Name "$($pwd.Path)\powershell\Ansible.ModuleUtils.Legacy.psm1"
# End of the setup code and start of the module code
#!powershell
您可以根据模块需要向 $complex_args
添加更多参数,或通过具有以下结构的 JSON 文件定义模块选项:
{
"ANSIBLE_MODULE_ARGS": {
"_ansible_check_mode": false,
"_ansible_diff": false,
"path": "C:\\temp",
"state": "present"
}
}
可以使用多种 IDE 来调试 PowerShell 脚本,其中两个最流行的是:
为了能够查看 Ansible 传递给模块的参数,请遵循以下步骤。
在 Ansible 命令前加上
ANSIBLE_KEEP_REMOTE_FILES=1
以指定 Ansible 应保留服务器上的 exec 文件。使用 Ansible 用于执行模块的同一用户帐户登录到 Windows 服务器。
导航到
%TEMP%\..
。它应该包含一个以ansible-tmp-
开头的文件夹。在此文件夹中,打开模块的 PowerShell 脚本。
在此脚本中,
$json_raw
下有一个原始 JSON 脚本,其中包含module_args
下的模块参数。这些参数可以手动分配给在调试脚本中定义的$complex_args
变量,或者放入args.json
文件中。
Windows 单元测试
目前,Ansible CI 没有运行 PowerShell 模块单元测试的机制。
Windows 集成测试
Ansible 模块的集成测试通常编写为 Ansible 角色。这些测试角色位于 ./test/integration/targets
中。您必须首先设置测试环境,并为 Ansible 配置一个测试清单以连接。
在此示例中,我们将设置一个测试清单以连接到两个主机并运行 win_stat 的集成测试
运行命令
source ./hacking/env-setup
来准备环境。创建
./test/integration/inventory.winrm.template
的副本,并将其命名为inventory.winrm
。填写
[windows]
下的条目,并设置连接到主机所需的变量。安装所需的 Python 模块 以支持 WinRM 和已配置的身份验证方法。
要执行集成测试,请运行
ansible-test windows-integration win_stat
;您可以将win_stat
替换为您要测试的角色。
这将执行当前为此角色定义的所有测试。您可以使用 -v
参数设置详细程度,就像使用 ansible-playbook 一样。
在为新模块开发测试时,建议在检查模式下测试一次场景,在非检查模式下测试两次。这确保检查模式不会进行任何更改,但会报告更改,并且第二次运行是幂等的,不会报告更改。例如
- name: remove a file (check mode)
win_file:
path: C:\temp
state: absent
register: remove_file_check
check_mode: true
- name: get result of remove a file (check mode)
win_command: powershell.exe "if (Test-Path -Path 'C:\temp') { 'true' } else { 'false' }"
register: remove_file_actual_check
- name: assert remove a file (check mode)
assert:
that:
- remove_file_check is changed
- remove_file_actual_check.stdout == 'true\r\n'
- name: remove a file
win_file:
path: C:\temp
state: absent
register: remove_file
- name: get result of remove a file
win_command: powershell.exe "if (Test-Path -Path 'C:\temp') { 'true' } else { 'false' }"
register: remove_file_actual
- name: assert remove a file
assert:
that:
- remove_file is changed
- remove_file_actual.stdout == 'false\r\n'
- name: remove a file (idempotent)
win_file:
path: C:\temp
state: absent
register: remove_file_again
- name: assert remove a file (idempotent)
assert:
that:
- not remove_file_again is changed
Windows 通信和开发支持
加入 Ansible 论坛 并使用 windows 标签来讨论 Ansible 的 Windows 开发。