Windows 模块开发指南
在本节中,我们将介绍如何开发、测试和调试 Ansible Windows 模块。
由于 Windows 模块是用 Powershell 编写的,并且需要在 Windows 主机上运行,因此本指南与常规开发指南有所不同。
本节涵盖内容
Windows 环境设置
与可以在运行 Ansible 的主机上直接测试的 Python 模块开发不同,Windows 模块需要针对 Windows 主机进行编写和测试。虽然可以从微软下载 Windows 评估版,但这些镜像通常在不经进一步修改的情况下无法直接供 Ansible 使用。设置 Windows 主机以使其可供 Ansible 使用的最简单方法是使用 Vagrant 设置虚拟机。Vagrant 可用于下载现有的操作系统镜像(称为 boxes),然后将其部署到像 VirtualBox 这样的虚拟机管理程序中。这些 box 可以离线创建并存储,也可以从名为 Vagrant Cloud 的中央仓库下载。
本指南将使用 packer-windoze 仓库创建的 Vagrant box,这些 box 也已上传到 Vagrant Cloud。要了解有关这些镜像如何创建的更多信息,请访问 GitHub 仓库并查看 README 文件。
在开始之前,必须安装以下程序(请查阅 Vagrant 和 VirtualBox 文档以获取安装说明)
Vagrant
VirtualBox
在虚拟机中创建 Windows 服务器
要创建一个单独的 Windows Server 2016 实例,请运行以下命令
vagrant init jborean93/WindowsServer2016
vagrant up
这将从 Vagrant Cloud 下载 Vagrant box,并将其添加到本地主机上,然后在 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 将自动随机使用另一个端口,并将其显示在输出中。
所创建的操作系统基于镜像集。可以使用以下镜像
当主机在线时,您可以通过 RDP 在 127.0.0.1:3389 上访问它,但端口可能会根据是否存在冲突而有所不同。要删除该主机,请运行 vagrant destroy --force,Vagrant 将自动删除虚拟机及其关联的所有文件。
虽然这在测试单个 Windows 实例上的模块时非常有用,但如果不进行修改,这些主机无法与基于域的模块配合使用。ansible-windows 中的 Vagrantfile 可用于创建在 Ansible 中使用的测试域环境。该仓库包含三个文件,Ansible 和 Vagrant 使用它们在域环境中创建多个 Windows 主机。这些文件是
Vagrantfile:读取inventory.yml的清单设置并配置所需主机的 Vagrant 文件inventory.yml:包含所需的各个主机以及 IP 地址和转发端口等连接信息main.yml:由 Vagrant 调用的 Ansible Playbook,用于配置域控节点并将从属主机加入域
默认情况下,这些文件将创建以下环境
一个运行在 Windows Server 2016 上的单 AD 域控制器
五个已加入该域的、涵盖主要 Windows Server 版本的从属主机
一个 DNS 名称为
domain.local的域每个主机上有一个用户名为
vagrant、密码为vagrant的本地管理员帐户一个密码为
VagrantPass1的域管理员帐户vagrant-domain@domain.local
如果需要,可以通过更改 inventory.yml 文件中的 domain_* 变量来修改域名和帐户。也可以通过更改 domain_children 键下定义的主机来修改清单文件,以增加或减少服务器数量。主机变量 ansible_host 是分配给 VirtualBox 仅主机(host-only)网络适配器的私有 IP,而 vagrant_box 是用于创建虚拟机的 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 的 WinRM over HTTPS 通过端口 29804 转发,因为它是 domain_children 中的第四个条目。
Windows 新模块开发
创建新模块时,有几点需要牢记
模块代码位于 Powershell (.ps1) 文件中,而文档则包含在同名的 Python (.py) 文件中
避免在模块中使用
Write-Host/Debug/Verbose/Error,应将需要返回的内容添加到$module.Result变量中要使模块失败,请调用
$module.FailJson("failure message here"),可以将 Exception 或 ErrorRecord 设置为第二个参数以获得更具描述性的错误消息您可以将异常或 ErrorRecord 作为第二个参数传递给
FailJson("failure", $_)以获得更详细的输出大多数新模块在合并到 Ansible 主代码库之前需要检查模式(check mode)和集成测试
避免在大型代码块上使用 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 或 OS 版本,请确保文档清晰地反映了这一点
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 模块的最佳实践。它演示了如何实现检查模式和差异支持(diff-support),并在满足特定条件时向用户显示警告。
一个更高级一点的模块是 win_uri,它额外展示了如何使用不同的参数类型(bool, str, int, list, dict, path)和参数选择项,以及如何使模块失败和处理异常。
作为新的 AnsibleModule 包装器的一部分,输入参数基于参数规范(argument spec)进行定义和验证。可以在参数规范的根级别设置以下选项
mutually_exclusive:一个列表的列表,其中内部列表包含不能同时设置的模块选项no_log:阻止模块向 Windows 事件日志发出任何日志options:一个字典,其中键是模块选项,值是该选项的规范required_by:一个字典,如果设置了由键指定的选项,则必须设置由值指定的选项required_if:一个列表的列表,其中内部列表包含 3 或 4 个元素;第一个元素是用于检查值的模块选项
第二个元素是第一个元素指定的选项的值,如果匹配,则运行 required if 检查
第三个元素是当上述匹配时所需的模块选项列表
可选的第四个元素是一个布尔值,说明是否需要第三个元素中的所有模块选项(默认:
$false)或仅需其中一个($true)
required_one_of:一个列表的列表,其中内部列表包含必须至少设置其中一个的模块选项required_together:一个列表的列表,其中内部列表包含必须一起设置的模块选项supports_check_mode:模块是否支持检查模式,默认情况下这是$false
模块的实际输入选项以字典形式设置在 options 值内。该字典的键是模块选项名称,值是该模块选项的规范。每个规范都可以设置以下选项
aliases:模块选项的别名列表choices:模块选项的有效值列表,如果type=list,则每个列表值都会根据选择项进行验证,而不是列表本身default:如果未设置,模块选项的默认值deprecated_aliases:一个哈希表列表,定义已弃用的别名以及它们将被删除的版本。每个条目必须包含键name和collection_name,以及version或dateelements:当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-CimInstancecmdlet 的 WMI 对象通过
New-Object -ComObjectcmdlet 的 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 版本派生自[Environment]::OSVersion.Version。#AnsibleRequires -Become:Ansible 2.5 新增,强制 exec 运行器使用become运行模块,这主要用于绕过 WinRM 限制。如果未指定ansible_become_user,则使用SYSTEM帐户。
#AnsibleRequires -PowerShell 和 #AnsibleRequires -CSharpUtil 支持更多功能,例如
导入集合中包含的实用程序(Ansible 2.9 新增)
按相对名称导入实用程序(Ansible 2.10 新增)
通过在导入声明中添加 -Optional 来指定实用程序是可选的(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 语句,模块代码需要负责在尝试使用实用程序之前验证其是否已导入。这可以通过检查实用程序提供的函数或类型是否存在来完成。
虽然 #Requires -Module 和 #AnsibleRequires -PowerShell 都可以用于加载 PowerShell 模块,但建议使用 #AnsibleRequires。这是因为 #AnsibleRequires 支持集合模块工具、按相对工具名称导入以及可选的工具导入。
C# 模块工具可以通过在脚本顶部与其他 using 语句一起添加 using Ansible.<module_util>; 行来引用其他 C# 工具。
Windows 模块工具
与 Python 模块一样,PowerShell 模块也提供了许多在 PowerShell 中提供辅助功能的模块工具。这些 module_utils 可以通过向 PowerShell 模块添加以下行来导入
#Requires -Module Ansible.ModuleUtils.Legacy
这将导入 ./lib/ansible/module_utils/powershell/Ansible.ModuleUtils.Legacy.psm1 处的 module_util 并启用其所有函数的调用。截至 Ansible 2.8,Windows 模块工具也可以用 C# 编写并存储在 lib/ansible/module_utils/csharp 中。这些 module_utils 可以通过向 PowerShell 模块添加以下行来导入
#AnsibleRequires -CSharpUtil Ansible.Basic
这将导入 ./lib/ansible/module_utils/csharp/Ansible.Basic.cs 处的 module_util 并自动在执行进程中加载类型。C# 模块工具可以相互引用,并通过在工具顶部的 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 上运行时,此符号存在
这些标志的组合有助于使模块工具在 .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 工具一样,它们存储在名为 module_utils 的文件夹中,并且文件名必须以 .cs 扩展名结尾,以 Ansible. 开头,并以工具中定义的命名空间命名。
下面的示例是一个角色结构,其中包含两个名为 Ansible.ModuleUtils.ModuleUtil1、Ansible.ModuleUtils.ModuleUtil2 的 PowerShell 自定义 module_utils,以及一个包含命名空间 Ansible.CustomUtil 的 C# 工具
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。在同一目录中创建清单文件
touch hosts。使用连接到 Windows 主机所需的变量填充清单文件。
将以下内容添加到新的 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替换为您要测试的角色。
这将执行为该角色定义的所有当前测试。您可以像使用 ansible-playbook 一样使用 -v 参数设置详细程度。
在开发新模块的测试时,建议在检查模式下测试场景一次,在非检查模式下测试两次。这确保检查模式不会进行任何更改但会报告更改,以及第二次运行是幂等的且不会报告更改。例如
- 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 标签进行有关 Windows Ansible 开发的讨论。