mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-05-08 14:22:46 +00:00
Relocating extras into lib/ansible/modules/ after merge
This commit is contained in:
committed by
Matt Clay
parent
c65ba07d2c
commit
011ea55a8f
206
lib/ansible/modules/windows/win_acl.ps1
Normal file
206
lib/ansible/modules/windows/win_acl.ps1
Normal file
@@ -0,0 +1,206 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Copyright 2015, Phil Schwartz <schwartzmx@gmail.com>
|
||||
# Copyright 2015, Trond Hindenes
|
||||
# Copyright 2015, Hans-Joachim Kliemeck <git@kliemeck.de>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
# win_acl module (File/Resources Permission Additions/Removal)
|
||||
|
||||
|
||||
#Functions
|
||||
Function UserSearch
|
||||
{
|
||||
Param ([string]$accountName)
|
||||
#Check if there's a realm specified
|
||||
|
||||
$searchDomain = $false
|
||||
$searchDomainUPN = $false
|
||||
$SearchAppPools = $false
|
||||
if ($accountName.Split("\").count -gt 1)
|
||||
{
|
||||
if ($accountName.Split("\")[0] -eq $env:COMPUTERNAME)
|
||||
{
|
||||
|
||||
}
|
||||
elseif ($accountName.Split("\")[0] -eq "IIS APPPOOL")
|
||||
{
|
||||
$SearchAppPools = $true
|
||||
$accountName = $accountName.split("\")[1]
|
||||
}
|
||||
else
|
||||
{
|
||||
$searchDomain = $true
|
||||
$accountName = $accountName.split("\")[1]
|
||||
}
|
||||
}
|
||||
Elseif ($accountName.contains("@"))
|
||||
{
|
||||
$searchDomain = $true
|
||||
$searchDomainUPN = $true
|
||||
}
|
||||
Else
|
||||
{
|
||||
#Default to local user account
|
||||
$accountName = $env:COMPUTERNAME + "\" + $accountName
|
||||
}
|
||||
|
||||
if (($searchDomain -eq $false) -and ($SearchAppPools -eq $false))
|
||||
{
|
||||
# do not use Win32_UserAccount, because e.g. SYSTEM (BUILTIN\SYSTEM or COMPUUTERNAME\SYSTEM) will not be listed. on Win32_Account groups will be listed too
|
||||
$localaccount = get-wmiobject -class "Win32_Account" -namespace "root\CIMV2" -filter "(LocalAccount = True)" | where {$_.Caption -eq $accountName}
|
||||
if ($localaccount)
|
||||
{
|
||||
return $localaccount.SID
|
||||
}
|
||||
}
|
||||
Elseif ($SearchAppPools -eq $true)
|
||||
{
|
||||
Import-Module WebAdministration
|
||||
$testiispath = Test-path "IIS:"
|
||||
if ($testiispath -eq $false)
|
||||
{
|
||||
return $null
|
||||
}
|
||||
else
|
||||
{
|
||||
$apppoolobj = Get-ItemProperty IIS:\AppPools\$accountName
|
||||
return $apppoolobj.applicationPoolSid
|
||||
}
|
||||
}
|
||||
{
|
||||
#Search by samaccountname
|
||||
$Searcher = [adsisearcher]""
|
||||
|
||||
If ($searchDomainUPN -eq $false) {
|
||||
$Searcher.Filter = "sAMAccountName=$($accountName)"
|
||||
}
|
||||
Else {
|
||||
$Searcher.Filter = "userPrincipalName=$($accountName)"
|
||||
}
|
||||
|
||||
$result = $Searcher.FindOne()
|
||||
if ($result)
|
||||
{
|
||||
$user = $result.GetDirectoryEntry()
|
||||
|
||||
# get binary SID from AD account
|
||||
$binarySID = $user.ObjectSid.Value
|
||||
|
||||
# convert to string SID
|
||||
return (New-Object System.Security.Principal.SecurityIdentifier($binarySID,0)).Value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$params = Parse-Args $args;
|
||||
|
||||
$result = New-Object PSObject;
|
||||
Set-Attr $result "changed" $false;
|
||||
|
||||
$path = Get-Attr $params "path" -failifempty $true
|
||||
$user = Get-Attr $params "user" -failifempty $true
|
||||
$rights = Get-Attr $params "rights" -failifempty $true
|
||||
|
||||
$type = Get-Attr $params "type" -failifempty $true -validateSet "allow","deny" -resultobj $result
|
||||
$state = Get-Attr $params "state" "present" -validateSet "present","absent" -resultobj $result
|
||||
|
||||
$inherit = Get-Attr $params "inherit" ""
|
||||
$propagation = Get-Attr $params "propagation" "None" -validateSet "None","NoPropagateInherit","InheritOnly" -resultobj $result
|
||||
|
||||
If (-Not (Test-Path -Path $path)) {
|
||||
Fail-Json $result "$path file or directory does not exist on the host"
|
||||
}
|
||||
|
||||
# Test that the user/group is resolvable on the local machine
|
||||
$sid = UserSearch -AccountName ($user)
|
||||
if (!$sid)
|
||||
{
|
||||
Fail-Json $result "$user is not a valid user or group on the host machine or domain"
|
||||
}
|
||||
|
||||
If (Test-Path -Path $path -PathType Leaf) {
|
||||
$inherit = "None"
|
||||
}
|
||||
ElseIf ($inherit -eq "") {
|
||||
$inherit = "ContainerInherit, ObjectInherit"
|
||||
}
|
||||
|
||||
Try {
|
||||
$colRights = [System.Security.AccessControl.FileSystemRights]$rights
|
||||
$InheritanceFlag = [System.Security.AccessControl.InheritanceFlags]$inherit
|
||||
$PropagationFlag = [System.Security.AccessControl.PropagationFlags]$propagation
|
||||
|
||||
If ($type -eq "allow") {
|
||||
$objType =[System.Security.AccessControl.AccessControlType]::Allow
|
||||
}
|
||||
Else {
|
||||
$objType =[System.Security.AccessControl.AccessControlType]::Deny
|
||||
}
|
||||
|
||||
$objUser = New-Object System.Security.Principal.SecurityIdentifier($sid)
|
||||
$objACE = New-Object System.Security.AccessControl.FileSystemAccessRule ($objUser, $colRights, $InheritanceFlag, $PropagationFlag, $objType)
|
||||
$objACL = Get-ACL $path
|
||||
|
||||
# Check if the ACE exists already in the objects ACL list
|
||||
$match = $false
|
||||
ForEach($rule in $objACL.Access){
|
||||
$ruleIdentity = $rule.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier])
|
||||
If (($rule.FileSystemRights -eq $objACE.FileSystemRights) -And ($rule.AccessControlType -eq $objACE.AccessControlType) -And ($ruleIdentity -eq $objACE.IdentityReference) -And ($rule.IsInherited -eq $objACE.IsInherited) -And ($rule.InheritanceFlags -eq $objACE.InheritanceFlags) -And ($rule.PropagationFlags -eq $objACE.PropagationFlags)) {
|
||||
$match = $true
|
||||
Break
|
||||
}
|
||||
}
|
||||
|
||||
If ($state -eq "present" -And $match -eq $false) {
|
||||
Try {
|
||||
$objACL.AddAccessRule($objACE)
|
||||
Set-ACL $path $objACL
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
Catch {
|
||||
Fail-Json $result "an exception occured when adding the specified rule"
|
||||
}
|
||||
}
|
||||
ElseIf ($state -eq "absent" -And $match -eq $true) {
|
||||
Try {
|
||||
$objACL.RemoveAccessRule($objACE)
|
||||
Set-ACL $path $objACL
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
Catch {
|
||||
Fail-Json $result "an exception occured when removing the specified rule"
|
||||
}
|
||||
}
|
||||
Else {
|
||||
# A rule was attempting to be added but already exists
|
||||
If ($match -eq $true) {
|
||||
Exit-Json $result "the specified rule already exists"
|
||||
}
|
||||
# A rule didn't exist that was trying to be removed
|
||||
Else {
|
||||
Exit-Json $result "the specified rule does not exist"
|
||||
}
|
||||
}
|
||||
}
|
||||
Catch {
|
||||
Fail-Json $result "an error occured when attempting to $state $rights permission(s) on $path for $user"
|
||||
}
|
||||
|
||||
Exit-Json $result
|
||||
146
lib/ansible/modules/windows/win_acl.py
Normal file
146
lib/ansible/modules/windows/win_acl.py
Normal file
@@ -0,0 +1,146 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2015, Phil Schwartz <schwartzmx@gmail.com>
|
||||
# Copyright 2015, Trond Hindenes
|
||||
# Copyright 2015, Hans-Joachim Kliemeck <git@kliemeck.de>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'core',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_acl
|
||||
version_added: "2.0"
|
||||
short_description: Set file/directory permissions for a system user or group.
|
||||
description:
|
||||
- Add or remove rights/permissions for a given user or group for the specified src file or folder.
|
||||
- If adding ACL's for AppPool identities (available since 2.3), the Windows "Feature Web-Scripting-Tools" must be enabled
|
||||
options:
|
||||
path:
|
||||
description:
|
||||
- File or Directory
|
||||
required: yes
|
||||
user:
|
||||
description:
|
||||
- User or Group to add specified rights to act on src file/folder
|
||||
required: yes
|
||||
default: none
|
||||
state:
|
||||
description:
|
||||
- Specify whether to add C(present) or remove C(absent) the specified access rule
|
||||
required: no
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
default: present
|
||||
type:
|
||||
description:
|
||||
- Specify whether to allow or deny the rights specified
|
||||
required: yes
|
||||
choices:
|
||||
- allow
|
||||
- deny
|
||||
default: none
|
||||
rights:
|
||||
description:
|
||||
- The rights/permissions that are to be allowed/denyed for the specified user or group for the given src file or directory. Can be entered as a comma separated list (Ex. "Modify, Delete, ExecuteFile"). For more information on the choices see MSDN FileSystemRights Enumeration.
|
||||
required: yes
|
||||
choices:
|
||||
- AppendData
|
||||
- ChangePermissions
|
||||
- Delete
|
||||
- DeleteSubdirectoriesAndFiles
|
||||
- ExecuteFile
|
||||
- FullControl
|
||||
- ListDirectory
|
||||
- Modify
|
||||
- Read
|
||||
- ReadAndExecute
|
||||
- ReadAttributes
|
||||
- ReadData
|
||||
- ReadExtendedAttributes
|
||||
- ReadPermissions
|
||||
- Synchronize
|
||||
- TakeOwnership
|
||||
- Traverse
|
||||
- Write
|
||||
- WriteAttributes
|
||||
- WriteData
|
||||
- WriteExtendedAttributes
|
||||
default: none
|
||||
inherit:
|
||||
description:
|
||||
- Inherit flags on the ACL rules. Can be specified as a comma separated list (Ex. "ContainerInherit, ObjectInherit"). For more information on the choices see MSDN InheritanceFlags Enumeration.
|
||||
required: no
|
||||
choices:
|
||||
- ContainerInherit
|
||||
- ObjectInherit
|
||||
- None
|
||||
default: For Leaf File, None; For Directory, ContainerInherit, ObjectInherit;
|
||||
propagation:
|
||||
description:
|
||||
- Propagation flag on the ACL rules. For more information on the choices see MSDN PropagationFlags Enumeration.
|
||||
required: no
|
||||
choices:
|
||||
- None
|
||||
- NoPropagateInherit
|
||||
- InheritOnly
|
||||
default: "None"
|
||||
author: Phil Schwartz (@schwartzmx), Trond Hindenes (@trondhindenes), Hans-Joachim Kliemeck (@h0nIg)
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Restrict write,execute access to User Fed-Phil
|
||||
$ ansible -i hosts -m win_acl -a "user=Fed-Phil path=C:\Important\Executable.exe type=deny rights='ExecuteFile,Write'" all
|
||||
|
||||
# Playbook example
|
||||
# Add access rule to allow IIS_IUSRS FullControl to MySite
|
||||
---
|
||||
- name: Add IIS_IUSRS allow rights
|
||||
win_acl:
|
||||
path: 'C:\inetpub\wwwroot\MySite'
|
||||
user: 'IIS_IUSRS'
|
||||
rights: 'FullControl'
|
||||
type: 'allow'
|
||||
state: 'present'
|
||||
inherit: 'ContainerInherit, ObjectInherit'
|
||||
propagation: 'None'
|
||||
|
||||
# Remove previously added rule for IIS_IUSRS
|
||||
- name: Remove FullControl AccessRule for IIS_IUSRS
|
||||
path: 'C:\inetpub\wwwroot\MySite'
|
||||
user: 'IIS_IUSRS'
|
||||
rights: 'FullControl'
|
||||
type: 'allow'
|
||||
state: 'absent'
|
||||
inherit: 'ContainerInherit, ObjectInherit'
|
||||
propagation: 'None'
|
||||
|
||||
# Deny Intern
|
||||
- name: Deny Deny
|
||||
path: 'C:\Administrator\Documents'
|
||||
user: 'Intern'
|
||||
rights: 'Read,Write,Modify,FullControl,Delete'
|
||||
type: 'deny'
|
||||
state: 'present'
|
||||
'''
|
||||
86
lib/ansible/modules/windows/win_acl_inheritance.ps1
Normal file
86
lib/ansible/modules/windows/win_acl_inheritance.ps1
Normal file
@@ -0,0 +1,86 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Copyright 2015, Hans-Joachim Kliemeck <git@kliemeck.de>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
|
||||
$params = Parse-Args $args;
|
||||
|
||||
$result = New-Object PSObject;
|
||||
Set-Attr $result "changed" $false;
|
||||
|
||||
$path = Get-Attr $params "path" -failifempty $true
|
||||
$state = Get-Attr $params "state" "absent" -validateSet "present","absent" -resultobj $result
|
||||
$reorganize = Get-Attr $params "reorganize" "no" -validateSet "no","yes" -resultobj $result
|
||||
$reorganize = $reorganize | ConvertTo-Bool
|
||||
|
||||
If (-Not (Test-Path -Path $path)) {
|
||||
Fail-Json $result "$path file or directory does not exist on the host"
|
||||
}
|
||||
|
||||
Try {
|
||||
$objACL = Get-ACL $path
|
||||
$inheritanceEnabled = !$objACL.AreAccessRulesProtected
|
||||
|
||||
If (($state -eq "present") -And !$inheritanceEnabled) {
|
||||
# second parameter is ignored if first=$False
|
||||
$objACL.SetAccessRuleProtection($False, $False)
|
||||
|
||||
If ($reorganize) {
|
||||
# it wont work without intermediate save, state would be the same
|
||||
Set-ACL $path $objACL
|
||||
$objACL = Get-ACL $path
|
||||
|
||||
# convert explicit ACE to inherited ACE
|
||||
ForEach($inheritedRule in $objACL.Access) {
|
||||
If (!$inheritedRule.IsInherited) {
|
||||
Continue
|
||||
}
|
||||
|
||||
ForEach($explicitRrule in $objACL.Access) {
|
||||
If ($explicitRrule.IsInherited) {
|
||||
Continue
|
||||
}
|
||||
|
||||
If (($inheritedRule.FileSystemRights -eq $explicitRrule.FileSystemRights) -And ($inheritedRule.AccessControlType -eq $explicitRrule.AccessControlType) -And ($inheritedRule.IdentityReference -eq $explicitRrule.IdentityReference) -And ($inheritedRule.InheritanceFlags -eq $explicitRrule.InheritanceFlags) -And ($inheritedRule.PropagationFlags -eq $explicitRrule.PropagationFlags)) {
|
||||
$objACL.RemoveAccessRule($explicitRrule)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set-ACL $path $objACL
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
Elseif (($state -eq "absent") -And $inheritanceEnabled) {
|
||||
If ($reorganize) {
|
||||
$objACL.SetAccessRuleProtection($True, $True)
|
||||
} Else {
|
||||
$objACL.SetAccessRuleProtection($True, $False)
|
||||
}
|
||||
|
||||
Set-ACL $path $objACL
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
}
|
||||
Catch {
|
||||
Fail-Json $result "an error occured when attempting to disable inheritance"
|
||||
}
|
||||
|
||||
Exit-Json $result
|
||||
83
lib/ansible/modules/windows/win_acl_inheritance.py
Normal file
83
lib/ansible/modules/windows/win_acl_inheritance.py
Normal file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2015, Hans-Joachim Kliemeck <git@kliemeck.de>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'core',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_acl_inheritance
|
||||
version_added: "2.1"
|
||||
short_description: Change ACL inheritance
|
||||
description:
|
||||
- Change ACL (Access Control List) inheritance and optionally copy inherited ACE's (Access Control Entry) to dedicated ACE's or vice versa.
|
||||
options:
|
||||
path:
|
||||
description:
|
||||
- Path to be used for changing inheritance
|
||||
required: true
|
||||
state:
|
||||
description:
|
||||
- Specify whether to enable I(present) or disable I(absent) ACL inheritance
|
||||
required: false
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
default: absent
|
||||
reorganize:
|
||||
description:
|
||||
- For P(state) = I(absent), indicates if the inherited ACE's should be copied from the parent directory. This is necessary (in combination with removal) for a simple ACL instead of using multiple ACE deny entries.
|
||||
- For P(state) = I(present), indicates if the inherited ACE's should be deduplicated compared to the parent directory. This removes complexity of the ACL structure.
|
||||
required: false
|
||||
choices:
|
||||
- no
|
||||
- yes
|
||||
default: no
|
||||
author: Hans-Joachim Kliemeck (@h0nIg)
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Playbook example
|
||||
---
|
||||
- name: Disable inherited ACE's
|
||||
win_acl_inheritance:
|
||||
path: 'C:\\apache\\'
|
||||
state: absent
|
||||
|
||||
- name: Disable and copy inherited ACE's
|
||||
win_acl_inheritance:
|
||||
path: 'C:\\apache\\'
|
||||
state: absent
|
||||
reorganize: yes
|
||||
|
||||
- name: Enable and remove dedicated ACE's
|
||||
win_acl_inheritance:
|
||||
path: 'C:\\apache\\'
|
||||
state: present
|
||||
reorganize: yes
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
|
||||
'''
|
||||
371
lib/ansible/modules/windows/win_chocolatey.ps1
Normal file
371
lib/ansible/modules/windows/win_chocolatey.ps1
Normal file
@@ -0,0 +1,371 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Copyright 2014, Trond Hindenes <trond@hindenes.com>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$params = Parse-Args $args;
|
||||
$result = New-Object PSObject;
|
||||
Set-Attr $result "changed" $false;
|
||||
|
||||
$package = Get-Attr -obj $params -name name -failifempty $true -emptyattributefailmessage "missing required argument: name"
|
||||
$force = Get-Attr -obj $params -name force -default "false" | ConvertTo-Bool
|
||||
$upgrade = Get-Attr -obj $params -name upgrade -default "false" | ConvertTo-Bool
|
||||
$version = Get-Attr -obj $params -name version -default $null
|
||||
|
||||
$source = Get-Attr -obj $params -name source -default $null
|
||||
if ($source) {$source = $source.Tolower()}
|
||||
|
||||
$showlog = Get-Attr -obj $params -name showlog -default "false" | ConvertTo-Bool
|
||||
$state = Get-Attr -obj $params -name state -default "present"
|
||||
|
||||
$installargs = Get-Attr -obj $params -name install_args -default $null
|
||||
$packageparams = Get-Attr -obj $params -name params -default $null
|
||||
$allowemptychecksums = Get-Attr -obj $params -name allow_empty_checksums -default "false" | ConvertTo-Bool
|
||||
$ignorechecksums = Get-Attr -obj $params -name ignore_checksums -default "false" | ConvertTo-Bool
|
||||
$ignoredependencies = Get-Attr -obj $params -name ignore_dependencies -default "false" | ConvertTo-Bool
|
||||
|
||||
# as of chocolatey 0.9.10, nonzero success exit codes can be returned
|
||||
# see https://github.com/chocolatey/choco/issues/512#issuecomment-214284461
|
||||
$successexitcodes = (0,1605,1614,1641,3010)
|
||||
|
||||
if ("present","absent" -notcontains $state)
|
||||
{
|
||||
Fail-Json $result "state is $state; must be present or absent"
|
||||
}
|
||||
|
||||
|
||||
Function Chocolatey-Install-Upgrade
|
||||
{
|
||||
[CmdletBinding()]
|
||||
|
||||
param()
|
||||
|
||||
$ChocoAlreadyInstalled = get-command choco -ErrorAction 0
|
||||
if ($ChocoAlreadyInstalled -eq $null)
|
||||
{
|
||||
#We need to install chocolatey
|
||||
$install_output = (new-object net.webclient).DownloadString("https://chocolatey.org/install.ps1") | powershell -
|
||||
if ($LASTEXITCODE -ne 0)
|
||||
{
|
||||
Set-Attr $result "choco_bootstrap_output" $install_output
|
||||
Fail-Json $result "Chocolatey bootstrap installation failed."
|
||||
}
|
||||
$result.changed = $true
|
||||
$script:executable = "C:\ProgramData\chocolatey\bin\choco.exe"
|
||||
}
|
||||
else
|
||||
{
|
||||
$script:executable = "choco.exe"
|
||||
|
||||
if ([Version](choco --version) -lt [Version]'0.9.9')
|
||||
{
|
||||
Choco-Upgrade chocolatey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Function Choco-IsInstalled
|
||||
{
|
||||
[CmdletBinding()]
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true, Position=1)]
|
||||
[string]$package
|
||||
)
|
||||
|
||||
$cmd = "$executable list --local-only $package"
|
||||
$results = invoke-expression $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "choco_error_cmd" $cmd
|
||||
Set-Attr $result "choco_error_log" "$results"
|
||||
|
||||
Throw "Error checking installation status for $package"
|
||||
}
|
||||
|
||||
If ("$results" -match "$package .* (\d+) packages installed.")
|
||||
{
|
||||
return $matches[1] -gt 0
|
||||
}
|
||||
|
||||
$false
|
||||
}
|
||||
|
||||
Function Choco-Upgrade
|
||||
{
|
||||
[CmdletBinding()]
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true, Position=1)]
|
||||
[string]$package,
|
||||
[Parameter(Mandatory=$false, Position=2)]
|
||||
[string]$version,
|
||||
[Parameter(Mandatory=$false, Position=3)]
|
||||
[string]$source,
|
||||
[Parameter(Mandatory=$false, Position=4)]
|
||||
[bool]$force,
|
||||
[Parameter(Mandatory=$false, Position=5)]
|
||||
[string]$installargs,
|
||||
[Parameter(Mandatory=$false, Position=6)]
|
||||
[string]$packageparams,
|
||||
[Parameter(Mandatory=$false, Position=7)]
|
||||
[bool]$allowemptychecksums,
|
||||
[Parameter(Mandatory=$false, Position=8)]
|
||||
[bool]$ignorechecksums,
|
||||
[Parameter(Mandatory=$false, Position=9)]
|
||||
[bool]$ignoredependencies
|
||||
)
|
||||
|
||||
if (-not (Choco-IsInstalled $package))
|
||||
{
|
||||
throw "$package is not installed, you cannot upgrade"
|
||||
}
|
||||
|
||||
$cmd = "$executable upgrade -dv -y $package"
|
||||
|
||||
if ($version)
|
||||
{
|
||||
$cmd += " -version $version"
|
||||
}
|
||||
|
||||
if ($source)
|
||||
{
|
||||
$cmd += " -source $source"
|
||||
}
|
||||
|
||||
if ($force)
|
||||
{
|
||||
$cmd += " -force"
|
||||
}
|
||||
|
||||
if ($installargs)
|
||||
{
|
||||
$cmd += " -installargs '$installargs'"
|
||||
}
|
||||
|
||||
if ($packageparams)
|
||||
{
|
||||
$cmd += " -params '$packageparams'"
|
||||
}
|
||||
|
||||
if ($allowemptychecksums)
|
||||
{
|
||||
$cmd += " --allow-empty-checksums"
|
||||
}
|
||||
|
||||
if ($ignorechecksums)
|
||||
{
|
||||
$cmd += " --ignore-checksums"
|
||||
}
|
||||
|
||||
if ($ignoredependencies)
|
||||
{
|
||||
$cmd += " -ignoredependencies"
|
||||
}
|
||||
|
||||
$results = invoke-expression $cmd
|
||||
|
||||
if ($LastExitCode -notin $successexitcodes)
|
||||
{
|
||||
Set-Attr $result "choco_error_cmd" $cmd
|
||||
Set-Attr $result "choco_error_log" "$results"
|
||||
Throw "Error installing $package"
|
||||
}
|
||||
|
||||
if ("$results" -match ' upgraded (\d+)/\d+ package\(s\)\. ')
|
||||
{
|
||||
if ($matches[1] -gt 0)
|
||||
{
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Function Choco-Install
|
||||
{
|
||||
[CmdletBinding()]
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true, Position=1)]
|
||||
[string]$package,
|
||||
[Parameter(Mandatory=$false, Position=2)]
|
||||
[string]$version,
|
||||
[Parameter(Mandatory=$false, Position=3)]
|
||||
[string]$source,
|
||||
[Parameter(Mandatory=$false, Position=4)]
|
||||
[bool]$force,
|
||||
[Parameter(Mandatory=$false, Position=5)]
|
||||
[bool]$upgrade,
|
||||
[Parameter(Mandatory=$false, Position=6)]
|
||||
[string]$installargs,
|
||||
[Parameter(Mandatory=$false, Position=7)]
|
||||
[string]$packageparams,
|
||||
[Parameter(Mandatory=$false, Position=8)]
|
||||
[bool]$allowemptychecksums,
|
||||
[Parameter(Mandatory=$false, Position=9)]
|
||||
[bool]$ignorechecksums,
|
||||
[Parameter(Mandatory=$false, Position=10)]
|
||||
[bool]$ignoredependencies
|
||||
)
|
||||
|
||||
if (Choco-IsInstalled $package)
|
||||
{
|
||||
if ($upgrade)
|
||||
{
|
||||
Choco-Upgrade -package $package -version $version -source $source -force $force `
|
||||
-installargs $installargs -packageparams $packageparams `
|
||||
-allowemptychecksums $allowemptychecksums -ignorechecksums $ignorechecksums `
|
||||
-ignoredependencies $ignoredependencies
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (-not $force)
|
||||
{
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
$cmd = "$executable install -dv -y $package"
|
||||
|
||||
if ($version)
|
||||
{
|
||||
$cmd += " -version $version"
|
||||
}
|
||||
|
||||
if ($source)
|
||||
{
|
||||
$cmd += " -source $source"
|
||||
}
|
||||
|
||||
if ($force)
|
||||
{
|
||||
$cmd += " -force"
|
||||
}
|
||||
|
||||
if ($installargs)
|
||||
{
|
||||
$cmd += " -installargs '$installargs'"
|
||||
}
|
||||
|
||||
if ($packageparams)
|
||||
{
|
||||
$cmd += " -params '$packageparams'"
|
||||
}
|
||||
|
||||
if ($allowemptychecksums)
|
||||
{
|
||||
$cmd += " --allow-empty-checksums"
|
||||
}
|
||||
|
||||
if ($ignorechecksums)
|
||||
{
|
||||
$cmd += " --ignore-checksums"
|
||||
}
|
||||
|
||||
if ($ignoredependencies)
|
||||
{
|
||||
$cmd += " -ignoredependencies"
|
||||
}
|
||||
|
||||
$results = invoke-expression $cmd
|
||||
|
||||
if ($LastExitCode -notin $successexitcodes)
|
||||
{
|
||||
Set-Attr $result "choco_error_cmd" $cmd
|
||||
Set-Attr $result "choco_error_log" "$results"
|
||||
Throw "Error installing $package"
|
||||
}
|
||||
|
||||
$result.changed = $true
|
||||
}
|
||||
|
||||
Function Choco-Uninstall
|
||||
{
|
||||
[CmdletBinding()]
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true, Position=1)]
|
||||
[string]$package,
|
||||
[Parameter(Mandatory=$false, Position=2)]
|
||||
[string]$version,
|
||||
[Parameter(Mandatory=$false, Position=3)]
|
||||
[bool]$force
|
||||
)
|
||||
|
||||
if (-not (Choco-IsInstalled $package))
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
$cmd = "$executable uninstall -dv -y $package"
|
||||
|
||||
if ($version)
|
||||
{
|
||||
$cmd += " -version $version"
|
||||
}
|
||||
|
||||
if ($force)
|
||||
{
|
||||
$cmd += " -force"
|
||||
}
|
||||
|
||||
if ($packageparams)
|
||||
{
|
||||
$cmd += " -params '$packageparams'"
|
||||
}
|
||||
|
||||
$results = invoke-expression $cmd
|
||||
|
||||
if ($LastExitCode -notin $successexitcodes)
|
||||
{
|
||||
Set-Attr $result "choco_error_cmd" $cmd
|
||||
Set-Attr $result "choco_error_log" "$results"
|
||||
Throw "Error uninstalling $package"
|
||||
}
|
||||
|
||||
$result.changed = $true
|
||||
}
|
||||
Try
|
||||
{
|
||||
Chocolatey-Install-Upgrade
|
||||
|
||||
if ($state -eq "present")
|
||||
{
|
||||
Choco-Install -package $package -version $version -source $source `
|
||||
-force $force -upgrade $upgrade -installargs $installargs `
|
||||
-packageparams $packageparams -allowemptychecksums $allowemptychecksums `
|
||||
-ignorechecksums $ignorechecksums -ignoredependencies $ignoredependencies
|
||||
}
|
||||
else
|
||||
{
|
||||
Choco-Uninstall -package $package -version $version -force $force
|
||||
}
|
||||
|
||||
Exit-Json $result;
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Fail-Json $result $_.Exception.Message
|
||||
}
|
||||
|
||||
|
||||
120
lib/ansible/modules/windows/win_chocolatey.py
Normal file
120
lib/ansible/modules/windows/win_chocolatey.py
Normal file
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2014, Trond Hindenes <trond@hindenes.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'committer',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_chocolatey
|
||||
version_added: "1.9"
|
||||
short_description: Installs packages using chocolatey
|
||||
description:
|
||||
- Installs packages using Chocolatey (http://chocolatey.org/). If Chocolatey is missing from the system, the module will install it. List of packages can be found at http://chocolatey.org/packages
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Name of the package to be installed
|
||||
required: true
|
||||
state:
|
||||
description:
|
||||
- State of the package on the system
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
default: present
|
||||
force:
|
||||
description:
|
||||
- Forces install of the package (even if it already exists). Using Force will cause ansible to always report that a change was made
|
||||
choices:
|
||||
- yes
|
||||
- no
|
||||
default: no
|
||||
upgrade:
|
||||
description:
|
||||
- If package is already installed it, try to upgrade to the latest version or to the specified version
|
||||
choices:
|
||||
- yes
|
||||
- no
|
||||
default: no
|
||||
version:
|
||||
description:
|
||||
- Specific version of the package to be installed
|
||||
- Ignored when state == 'absent'
|
||||
source:
|
||||
description:
|
||||
- Specify source rather than using default chocolatey repository
|
||||
install_args:
|
||||
description:
|
||||
- Arguments to pass to the native installer
|
||||
version_added: '2.1'
|
||||
params:
|
||||
description:
|
||||
- Parameters to pass to the package
|
||||
version_added: '2.1'
|
||||
allow_empty_checksums:
|
||||
description:
|
||||
- Allow empty Checksums to be used
|
||||
require: false
|
||||
default: false
|
||||
version_added: '2.2'
|
||||
ignore_checksums:
|
||||
description:
|
||||
- Ignore Checksums
|
||||
require: false
|
||||
default: false
|
||||
version_added: '2.2'
|
||||
ignore_dependencies:
|
||||
description:
|
||||
- Ignore dependencies, only install/upgrade the package itself
|
||||
default: false
|
||||
version_added: '2.1'
|
||||
author: "Trond Hindenes (@trondhindenes), Peter Mounce (@petemounce), Pepe Barbe (@elventear), Adam Keech (@smadam813)"
|
||||
'''
|
||||
|
||||
# TODO:
|
||||
# * Better parsing when a package has dependencies - currently fails
|
||||
# * Time each item that is run
|
||||
# * Support 'changed' with gems - would require shelling out to `gem list` first and parsing, kinda defeating the point of using chocolatey.
|
||||
|
||||
EXAMPLES = '''
|
||||
# Install git
|
||||
win_chocolatey:
|
||||
name: git
|
||||
|
||||
# Install notepadplusplus version 6.6
|
||||
win_chocolatey:
|
||||
name: notepadplusplus.install
|
||||
version: '6.6'
|
||||
|
||||
# Uninstall git
|
||||
win_chocolatey:
|
||||
name: git
|
||||
state: absent
|
||||
|
||||
# Install git from specified repository
|
||||
win_chocolatey:
|
||||
name: git
|
||||
source: https://someserver/api/v2/
|
||||
'''
|
||||
69
lib/ansible/modules/windows/win_dotnet_ngen.ps1
Normal file
69
lib/ansible/modules/windows/win_dotnet_ngen.ps1
Normal file
@@ -0,0 +1,69 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Copyright 2015, Peter Mounce <public@neverrunwithscissors.com>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$params = Parse-Args $args;
|
||||
$result = New-Object PSObject;
|
||||
Set-Attr $result "changed" $false;
|
||||
|
||||
function Invoke-NGen
|
||||
{
|
||||
[CmdletBinding()]
|
||||
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory=$false, Position=0)] [string] $arity = ""
|
||||
)
|
||||
|
||||
if ($arity -eq $null)
|
||||
{
|
||||
$arity = ""
|
||||
}
|
||||
$cmd = "$($env:windir)\microsoft.net\framework$($arity)\v4.0.30319\ngen.exe"
|
||||
if (test-path $cmd)
|
||||
{
|
||||
$update = Invoke-Expression "$cmd update /force";
|
||||
Set-Attr $result "dotnet_ngen$($arity)_update_exit_code" $lastexitcode
|
||||
Set-Attr $result "dotnet_ngen$($arity)_update_output" $update
|
||||
$eqi = Invoke-Expression "$cmd executequeueditems";
|
||||
Set-Attr $result "dotnet_ngen$($arity)_eqi_exit_code" $lastexitcode
|
||||
Set-Attr $result "dotnet_ngen$($arity)_eqi_output" $eqi
|
||||
|
||||
$result.changed = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "Not found: $cmd"
|
||||
}
|
||||
}
|
||||
|
||||
Try
|
||||
{
|
||||
Invoke-NGen
|
||||
Invoke-NGen -arity "64"
|
||||
|
||||
Exit-Json $result;
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Fail-Json $result $_.Exception.Message
|
||||
}
|
||||
48
lib/ansible/modules/windows/win_dotnet_ngen.py
Normal file
48
lib/ansible/modules/windows/win_dotnet_ngen.py
Normal file
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Peter Mounce <public@neverrunwithscissors.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_dotnet_ngen
|
||||
version_added: "2.0"
|
||||
short_description: Runs ngen to recompile DLLs after .NET updates
|
||||
description:
|
||||
- After .NET framework is installed/updated, Windows will probably want to recompile things to optimise for the host.
|
||||
- This happens via scheduled task, usually at some inopportune time.
|
||||
- This module allows you to run this task on your own schedule, so you incur the CPU hit at some more convenient and controlled time.
|
||||
- "http://blogs.msdn.com/b/dotnet/archive/2013/08/06/wondering-why-mscorsvw-exe-has-high-cpu-usage-you-can-speed-it-up.aspx"
|
||||
notes:
|
||||
- there are in fact two scheduled tasks for ngen but they have no triggers so aren't a problem
|
||||
- there's no way to test if they've been completed (?)
|
||||
- the stdout is quite likely to be several megabytes
|
||||
author: Peter Mounce
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Run ngen tasks
|
||||
win_dotnet_ngen:
|
||||
'''
|
||||
53
lib/ansible/modules/windows/win_environment.ps1
Normal file
53
lib/ansible/modules/windows/win_environment.ps1
Normal file
@@ -0,0 +1,53 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Copyright 2015, Jon Hawkesworth (@jhawkesworth) <figs@unity.demon.co.uk>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$params = Parse-Args $args;
|
||||
$state = Get-AnsibleParam -obj $params -name "state" -default "present" -validateSet "present","absent"
|
||||
$name = Get-AnsibleParam -obj $params -name "name" -failifempty $true
|
||||
$level = Get-AnsibleParam -obj $params -name "level" -validateSet "machine","process","user" -failifempty $true
|
||||
$value = Get-AnsibleParam -obj $params -name "value"
|
||||
|
||||
If ($level) {
|
||||
$level = $level.ToString().ToLower()
|
||||
}
|
||||
|
||||
$before_value = [Environment]::GetEnvironmentVariable($name, $level)
|
||||
|
||||
$state = $state.ToString().ToLower()
|
||||
if ($state -eq "present" ) {
|
||||
[Environment]::SetEnvironmentVariable($name, $value, $level)
|
||||
} Elseif ($state -eq "absent") {
|
||||
[Environment]::SetEnvironmentVariable($name, $null, $level)
|
||||
}
|
||||
|
||||
$after_value = [Environment]::GetEnvironmentVariable($name, $level)
|
||||
|
||||
$result = New-Object PSObject;
|
||||
Set-Attr $result "changed" $false;
|
||||
Set-Attr $result "name" $name;
|
||||
Set-Attr $result "before_value" $before_value;
|
||||
Set-Attr $result "value" $after_value;
|
||||
Set-Attr $result "level" $level;
|
||||
if ($before_value -ne $after_value) {
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
|
||||
Exit-Json $result;
|
||||
90
lib/ansible/modules/windows/win_environment.py
Normal file
90
lib/ansible/modules/windows/win_environment.py
Normal file
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Jon Hawkesworth (@jhawkesworth) <figs@unity.demon.co.uk>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_environment
|
||||
version_added: "2.0"
|
||||
short_description: Modifies environment variables on windows hosts.
|
||||
description:
|
||||
- Uses .net Environment to set or remove environment variables and can set at User, Machine or Process level.
|
||||
- User level environment variables will be set, but not available until the user has logged off and on again.
|
||||
options:
|
||||
state:
|
||||
description:
|
||||
- present to ensure environment variable is set, or absent to ensure it is removed
|
||||
required: false
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
name:
|
||||
description:
|
||||
- The name of the environment variable
|
||||
required: true
|
||||
default: no default
|
||||
value:
|
||||
description:
|
||||
- The value to store in the environment variable. Can be omitted for state=absent
|
||||
required: false
|
||||
default: no default
|
||||
level:
|
||||
description:
|
||||
- The level at which to set the environment variable.
|
||||
- Use 'machine' to set for all users.
|
||||
- Use 'user' to set for the current user that ansible is connected as.
|
||||
- Use 'process' to set for the current process. Probably not that useful.
|
||||
required: true
|
||||
default: no default
|
||||
choices:
|
||||
- machine
|
||||
- process
|
||||
- user
|
||||
author: "Jon Hawkesworth (@jhawkesworth)"
|
||||
notes:
|
||||
- This module does not broadcast change events.
|
||||
This means that the minority of windows applications which can have
|
||||
their environment changed without restarting will not be notified and
|
||||
therefore will need restarting to pick up new environment settings.
|
||||
User level environment variables will require the user to log out
|
||||
and in again before they become available.
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Set an environment variable for all users
|
||||
win_environment:
|
||||
state: present
|
||||
name: TestVariable
|
||||
value: "Test value"
|
||||
level: machine
|
||||
# Remove an environment variable for the current users
|
||||
win_environment:
|
||||
state: absent
|
||||
name: TestVariable
|
||||
level: user
|
||||
'''
|
||||
|
||||
78
lib/ansible/modules/windows/win_file_version.ps1
Normal file
78
lib/ansible/modules/windows/win_file_version.ps1
Normal file
@@ -0,0 +1,78 @@
|
||||
#!powershell
|
||||
|
||||
#this file is part of Ansible
|
||||
#Copyright © 2015 Sam Liu <sam.liu@activenetwork.com>
|
||||
|
||||
#This program is free software: you can redistribute it and/or modify
|
||||
#it under the terms of the GNU General Public License as published by
|
||||
#the Free Software Foundation, either version 3 of the License, or
|
||||
#(at your option) any later version.
|
||||
|
||||
#This program is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU General Public License for more details.
|
||||
|
||||
#You should have received a copy of the GNU General Public License
|
||||
#along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$params = Parse-Args $args;
|
||||
|
||||
$result = New-Object psobject @{
|
||||
win_file_version = New-Object psobject
|
||||
changed = $false
|
||||
}
|
||||
|
||||
$path = Get-AnsibleParam $params "path" -failifempty $true -resultobj $result
|
||||
|
||||
If (-Not (Test-Path -Path $path -PathType Leaf)){
|
||||
Fail-Json $result "Specfied path $path does exist or is not a file."
|
||||
}
|
||||
$ext = [System.IO.Path]::GetExtension($path)
|
||||
If ( $ext -notin '.exe', '.dll'){
|
||||
Fail-Json $result "Specfied path $path is not a vaild file type; must be DLL or EXE."
|
||||
}
|
||||
|
||||
Try {
|
||||
$_version_fields = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($path)
|
||||
$file_version = $_version_fields.FileVersion
|
||||
If ($file_version -eq $null){
|
||||
$file_version = ''
|
||||
}
|
||||
$product_version = $_version_fields.ProductVersion
|
||||
If ($product_version -eq $null){
|
||||
$product_version= ''
|
||||
}
|
||||
$file_major_part = $_version_fields.FileMajorPart
|
||||
If ($file_major_part -eq $null){
|
||||
$file_major_part= ''
|
||||
}
|
||||
$file_minor_part = $_version_fields.FileMinorPart
|
||||
If ($file_minor_part -eq $null){
|
||||
$file_minor_part= ''
|
||||
}
|
||||
$file_build_part = $_version_fields.FileBuildPart
|
||||
If ($file_build_part -eq $null){
|
||||
$file_build_part = ''
|
||||
}
|
||||
$file_private_part = $_version_fields.FilePrivatePart
|
||||
If ($file_private_part -eq $null){
|
||||
$file_private_part = ''
|
||||
}
|
||||
}
|
||||
Catch{
|
||||
Fail-Json $result "Error: $_.Exception.Message"
|
||||
}
|
||||
|
||||
Set-Attr $result.win_file_version "path" $path.toString()
|
||||
Set-Attr $result.win_file_version "file_version" $file_version.toString()
|
||||
Set-Attr $result.win_file_version "product_version" $product_version.toString()
|
||||
Set-Attr $result.win_file_version "file_major_part" $file_major_part.toString()
|
||||
Set-Attr $result.win_file_version "file_minor_part" $file_minor_part.toString()
|
||||
Set-Attr $result.win_file_version "file_build_part" $file_build_part.toString()
|
||||
Set-Attr $result.win_file_version "file_private_part" $file_private_part.toString()
|
||||
Exit-Json $result;
|
||||
|
||||
90
lib/ansible/modules/windows/win_file_version.py
Normal file
90
lib/ansible/modules/windows/win_file_version.py
Normal file
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Get DLL or EXE build version
|
||||
# Copyright © 2015 Sam Liu <sam.liu@activenetwork.com>
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_file_version
|
||||
version_added: "2.1"
|
||||
short_description: Get DLL or EXE file build version
|
||||
description:
|
||||
- Get DLL or EXE file build version
|
||||
- change state alway be false
|
||||
options:
|
||||
path:
|
||||
description:
|
||||
- File to get version(provide absolute path)
|
||||
required: true
|
||||
aliases: []
|
||||
author: Sam Liu
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# get C:\Windows\System32\cmd.exe version in playbook
|
||||
---
|
||||
- name: Get acm instance version
|
||||
win_file_version:
|
||||
path: 'C:\Windows\System32\cmd.exe'
|
||||
register: exe_file_version
|
||||
|
||||
- debug:
|
||||
msg: '{{ exe_file_version }}'
|
||||
|
||||
'''
|
||||
|
||||
RETURN = """
|
||||
win_file_version.path:
|
||||
description: file path
|
||||
returned: always
|
||||
type: string
|
||||
|
||||
win_file_version.file_version:
|
||||
description: file version number.
|
||||
returned: no error
|
||||
type: string
|
||||
|
||||
win_file_version.product_version:
|
||||
description: the version of the product this file is distributed with.
|
||||
returned: no error
|
||||
type: string
|
||||
|
||||
win_file_version.file_major_part:
|
||||
description: the major part of the version number.
|
||||
returned: no error
|
||||
type: string
|
||||
|
||||
win_file_version.file_minor_part:
|
||||
description: the minor part of the version number of the file.
|
||||
returned: no error
|
||||
type: string
|
||||
|
||||
win_file_version.file_build_part:
|
||||
description: build number of the file.
|
||||
returned: no error
|
||||
type: string
|
||||
|
||||
win_file_version.file_private_part:
|
||||
description: file private part number.
|
||||
returned: no error
|
||||
type: string
|
||||
|
||||
"""
|
||||
362
lib/ansible/modules/windows/win_firewall_rule.ps1
Normal file
362
lib/ansible/modules/windows/win_firewall_rule.ps1
Normal file
@@ -0,0 +1,362 @@
|
||||
#!powershell
|
||||
#
|
||||
# (c) 2014, Timothy Vandenbrande <timothy.vandenbrande@gmail.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
function getFirewallRule ($fwsettings) {
|
||||
try {
|
||||
|
||||
#$output = Get-NetFirewallRule -name $($fwsettings.'Rule Name');
|
||||
$rawoutput=@(netsh advfirewall firewall show rule name="$($fwsettings.'Rule Name')" verbose)
|
||||
if (!($rawoutput -eq 'No rules match the specified criteria.')){
|
||||
$rawoutput | Where {$_ -match '^([^:]+):\s*(\S.*)$'} | Foreach -Begin {
|
||||
$FirstRun = $true;
|
||||
$HashProps = @{};
|
||||
} -Process {
|
||||
if (($Matches[1] -eq 'Rule Name') -and (!($FirstRun))) {
|
||||
#$output=New-Object -TypeName PSCustomObject -Property $HashProps;
|
||||
$output=$HashProps;
|
||||
$HashProps = @{};
|
||||
};
|
||||
$HashProps.$($Matches[1]) = $Matches[2];
|
||||
$FirstRun = $false;
|
||||
} -End {
|
||||
#$output=New-Object -TypeName PSCustomObject -Property $HashProps;
|
||||
$output=$HashProps;
|
||||
}
|
||||
}
|
||||
$exists=$false;
|
||||
$correct=$true;
|
||||
$diff=$false;
|
||||
$multi=$false;
|
||||
$correct=$false;
|
||||
$difference=@();
|
||||
$msg=@();
|
||||
if ($($output|measure).count -gt 0) {
|
||||
$exists=$true;
|
||||
$msg += @("The rule '" + $fwsettings.'Rule Name' + "' exists.");
|
||||
if ($($output|measure).count -gt 1) {
|
||||
$multi=$true
|
||||
$msg += @("The rule '" + $fwsettings.'Rule Name' + "' has multiple entries.");
|
||||
ForEach($rule in $output.GetEnumerator()) {
|
||||
ForEach($fwsetting in $fwsettings.GetEnumerator()) {
|
||||
if ( $rule.$fwsetting -ne $fwsettings.$fwsetting) {
|
||||
$diff=$true;
|
||||
#$difference+=@($fwsettings.$($fwsetting.Key));
|
||||
$difference+=@("output:$rule.$fwsetting,fwsetting:$fwsettings.$fwsetting");
|
||||
};
|
||||
};
|
||||
if ($diff -eq $false) {
|
||||
$correct=$true
|
||||
};
|
||||
};
|
||||
} else {
|
||||
ForEach($fwsetting in $fwsettings.GetEnumerator()) {
|
||||
if ( $output.$($fwsetting.Key) -ne $fwsettings.$($fwsetting.Key)) {
|
||||
|
||||
if (($fwsetting.Key -eq 'RemoteIP') -and ($output.$($fwsetting.Key) -eq ($fwsettings.$($fwsetting.Key)+'-'+$fwsettings.$($fwsetting.Key)))) {
|
||||
$donothing=$false
|
||||
} elseif (($fwsetting.Key -eq 'DisplayName') -and ($output."Rule Name" -eq $fwsettings.$($fwsetting.Key))) {
|
||||
$donothing=$false
|
||||
} else {
|
||||
$diff=$true;
|
||||
$difference+=@($fwsettings.$($fwsetting.Key));
|
||||
};
|
||||
};
|
||||
};
|
||||
if ($diff -eq $false) {
|
||||
$correct=$true
|
||||
};
|
||||
};
|
||||
if ($correct) {
|
||||
$msg += @("An identical rule exists");
|
||||
} else {
|
||||
$msg += @("The rule exists but has different values");
|
||||
}
|
||||
} else {
|
||||
$msg += @("No rule could be found");
|
||||
};
|
||||
$result = @{
|
||||
failed = $false
|
||||
exists = $exists
|
||||
identical = $correct
|
||||
multiple = $multi
|
||||
difference = $difference
|
||||
msg = $msg
|
||||
}
|
||||
} catch [Exception]{
|
||||
$result = @{
|
||||
failed = $true
|
||||
error = $_.Exception.Message
|
||||
msg = $msg
|
||||
}
|
||||
};
|
||||
return $result
|
||||
};
|
||||
|
||||
function createFireWallRule ($fwsettings) {
|
||||
$msg=@()
|
||||
$execString="netsh advfirewall firewall add rule"
|
||||
|
||||
ForEach ($fwsetting in $fwsettings.GetEnumerator()) {
|
||||
if ($fwsetting.key -eq 'Direction') {
|
||||
$key='dir'
|
||||
} elseif ($fwsetting.key -eq 'Rule Name') {
|
||||
$key='name'
|
||||
} elseif ($fwsetting.key -eq 'Enabled') {
|
||||
$key='enable'
|
||||
} elseif ($fwsetting.key -eq 'Profiles') {
|
||||
$key='profile'
|
||||
} else {
|
||||
$key=$($fwsetting.key).ToLower()
|
||||
};
|
||||
$execString+=" ";
|
||||
$execString+=$key;
|
||||
$execString+="=";
|
||||
$execString+='"';
|
||||
$execString+=$fwsetting.value;
|
||||
$execString+='"';
|
||||
};
|
||||
try {
|
||||
#$msg+=@($execString);
|
||||
$output=$(Invoke-Expression $execString| ? {$_});
|
||||
$msg+=@("Created firewall rule $name");
|
||||
|
||||
$result=@{
|
||||
failed = $false
|
||||
output=$output
|
||||
changed=$true
|
||||
msg=$msg
|
||||
};
|
||||
|
||||
} catch [Exception]{
|
||||
$msg=@("Failed to create the rule")
|
||||
$result=@{
|
||||
output=$output
|
||||
failed=$true
|
||||
error=$_.Exception.Message
|
||||
msg=$msg
|
||||
};
|
||||
};
|
||||
return $result
|
||||
};
|
||||
|
||||
function removeFireWallRule ($fwsettings) {
|
||||
$msg=@()
|
||||
try {
|
||||
$rawoutput=@(netsh advfirewall firewall delete rule name="$($fwsettings.'Rule Name')")
|
||||
$rawoutput | Where {$_ -match '^([^:]+):\s*(\S.*)$'} | Foreach -Begin {
|
||||
$FirstRun = $true;
|
||||
$HashProps = @{};
|
||||
} -Process {
|
||||
if (($Matches[1] -eq 'Rule Name') -and (!($FirstRun))) {
|
||||
$output=$HashProps;
|
||||
$HashProps = @{};
|
||||
};
|
||||
$HashProps.$($Matches[1]) = $Matches[2];
|
||||
$FirstRun = $false;
|
||||
} -End {
|
||||
$output=$HashProps;
|
||||
};
|
||||
$msg+=@("Removed the rule")
|
||||
$result=@{
|
||||
failed=$false
|
||||
changed=$true
|
||||
msg=$msg
|
||||
output=$output
|
||||
};
|
||||
} catch [Exception]{
|
||||
$msg+=@("Failed to remove the rule")
|
||||
$result=@{
|
||||
failed=$true
|
||||
error=$_.Exception.Message
|
||||
msg=$msg
|
||||
}
|
||||
};
|
||||
return $result
|
||||
}
|
||||
|
||||
# Mount Drives
|
||||
$change=$false;
|
||||
$fail=$false;
|
||||
$msg=@();
|
||||
$fwsettings=@{}
|
||||
|
||||
# Variabelise the arguments
|
||||
$params=Parse-Args $args;
|
||||
|
||||
$name = Get-AnsibleParam -obj $params -name "name" -failifempty $true
|
||||
$direction = Get-AnsibleParam -obj $params -name "direction" -failifempty $true -validateSet "in","out"
|
||||
$action = Get-AnsibleParam -obj $params -name "action" -failifempty $true -validateSet "allow","block","bypass"
|
||||
$program = Get-AnsibleParam -obj $params -name "program"
|
||||
$service = Get-AnsibleParam -obj $params -name "service" -default "any"
|
||||
$description = Get-AnsibleParam -obj $params -name "description"
|
||||
$enable = ConvertTo-Bool (Get-AnsibleParam -obj $params -name "enable" -default "true")
|
||||
$winprofile = Get-AnsibleParam -obj $params -name "profile" -default "any"
|
||||
$localip = Get-AnsibleParam -obj $params -name "localip" -default "any"
|
||||
$remoteip = Get-AnsibleParam -obj $params -name "remoteip" -default "any"
|
||||
$localport = Get-AnsibleParam -obj $params -name "localport" -default "any"
|
||||
$remoteport = Get-AnsibleParam -obj $params -name "remoteport" -default "any"
|
||||
$protocol = Get-AnsibleParam -obj $params -name "protocol" -default "any"
|
||||
|
||||
$state = Get-AnsibleParam -obj $params -name "state" -failifempty $true -validateSet "present","absent"
|
||||
$force = ConvertTo-Bool (Get-AnsibleParam -obj $params -name "force" -default "false")
|
||||
|
||||
# Check the arguments
|
||||
If ($enable -eq $true) {
|
||||
$fwsettings.Add("Enabled", "yes");
|
||||
} Else {
|
||||
$fwsettings.Add("Enabled", "no");
|
||||
};
|
||||
|
||||
$fwsettings.Add("Rule Name", $name)
|
||||
#$fwsettings.Add("displayname", $name)
|
||||
|
||||
$state = $state.ToString().ToLower()
|
||||
If ($state -eq "present"){
|
||||
$fwsettings.Add("Direction", $direction)
|
||||
$fwsettings.Add("Action", $action)
|
||||
};
|
||||
|
||||
If ($description) {
|
||||
$fwsettings.Add("Description", $description);
|
||||
}
|
||||
|
||||
If ($program) {
|
||||
$fwsettings.Add("Program", $program);
|
||||
}
|
||||
|
||||
$fwsettings.Add("LocalIP", $localip);
|
||||
$fwsettings.Add("RemoteIP", $remoteip);
|
||||
$fwsettings.Add("LocalPort", $localport);
|
||||
$fwsettings.Add("RemotePort", $remoteport);
|
||||
$fwsettings.Add("Service", $service);
|
||||
$fwsettings.Add("Protocol", $protocol);
|
||||
$fwsettings.Add("Profiles", $winprofile)
|
||||
|
||||
$output=@()
|
||||
$capture=getFirewallRule ($fwsettings);
|
||||
if ($capture.failed -eq $true) {
|
||||
$msg+=$capture.msg;
|
||||
$result=New-Object psobject @{
|
||||
changed=$false
|
||||
failed=$true
|
||||
error=$capture.error
|
||||
msg=$msg
|
||||
};
|
||||
Exit-Json $result;
|
||||
} else {
|
||||
$diff=$capture.difference
|
||||
$msg+=$capture.msg;
|
||||
$identical=$capture.identical;
|
||||
$multiple=$capture.multiple;
|
||||
}
|
||||
|
||||
|
||||
switch ($state){
|
||||
"present" {
|
||||
if ($capture.exists -eq $false) {
|
||||
$capture=createFireWallRule($fwsettings);
|
||||
$msg+=$capture.msg;
|
||||
$change=$true;
|
||||
if ($capture.failed -eq $true){
|
||||
$result=New-Object psobject @{
|
||||
failed=$capture.failed
|
||||
error=$capture.error
|
||||
output=$capture.output
|
||||
changed=$change
|
||||
msg=$msg
|
||||
difference=$diff
|
||||
fwsettings=$fwsettings
|
||||
};
|
||||
Exit-Json $result;
|
||||
}
|
||||
} elseif ($capture.identical -eq $false) {
|
||||
if ($force -eq $true) {
|
||||
$capture=removeFirewallRule($fwsettings);
|
||||
$msg+=$capture.msg;
|
||||
$change=$true;
|
||||
if ($capture.failed -eq $true){
|
||||
$result=New-Object psobject @{
|
||||
failed=$capture.failed
|
||||
error=$capture.error
|
||||
changed=$change
|
||||
msg=$msg
|
||||
output=$capture.output
|
||||
fwsettings=$fwsettings
|
||||
};
|
||||
Exit-Json $result;
|
||||
}
|
||||
$capture=createFireWallRule($fwsettings);
|
||||
$msg+=$capture.msg;
|
||||
$change=$true;
|
||||
if ($capture.failed -eq $true){
|
||||
$result=New-Object psobject @{
|
||||
failed=$capture.failed
|
||||
error=$capture.error
|
||||
changed=$change
|
||||
msg=$msg
|
||||
difference=$diff
|
||||
fwsettings=$fwsettings
|
||||
};
|
||||
Exit-Json $result;
|
||||
}
|
||||
|
||||
} else {
|
||||
$fail=$true
|
||||
$msg+=@("There was already a rule $name with different values, use force=True to overwrite it");
|
||||
}
|
||||
} elseif ($capture.identical -eq $true) {
|
||||
$msg+=@("Firewall rule $name was already created");
|
||||
};
|
||||
}
|
||||
"absent" {
|
||||
if ($capture.exists -eq $true) {
|
||||
$capture=removeFirewallRule($fwsettings);
|
||||
$msg+=$capture.msg;
|
||||
$change=$true;
|
||||
if ($capture.failed -eq $true){
|
||||
$result=New-Object psobject @{
|
||||
failed=$capture.failed
|
||||
error=$capture.error
|
||||
changed=$change
|
||||
msg=$msg
|
||||
output=$capture.output
|
||||
fwsettings=$fwsettings
|
||||
};
|
||||
Exit-Json $result;
|
||||
}
|
||||
} else {
|
||||
$msg+=@("Firewall rule $name did not exist");
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
$result=New-Object psobject @{
|
||||
failed=$fail
|
||||
changed=$change
|
||||
msg=$msg
|
||||
difference=$diff
|
||||
fwsettings=$fwsettings
|
||||
};
|
||||
|
||||
|
||||
Exit-Json $result;
|
||||
127
lib/ansible/modules/windows/win_firewall_rule.py
Normal file
127
lib/ansible/modules/windows/win_firewall_rule.py
Normal file
@@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# (c) 2014, Timothy Vandenbrande <timothy.vandenbrande@gmail.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_firewall_rule
|
||||
version_added: "2.0"
|
||||
author: Timothy Vandenbrande
|
||||
short_description: Windows firewall automation
|
||||
description:
|
||||
- allows you to create/remove/update firewall rules
|
||||
options:
|
||||
enable:
|
||||
description:
|
||||
- is this firewall rule enabled or disabled
|
||||
default: true
|
||||
required: false
|
||||
state:
|
||||
description:
|
||||
- should this rule be added or removed
|
||||
default: "present"
|
||||
required: true
|
||||
choices: ['present', 'absent']
|
||||
name:
|
||||
description:
|
||||
- the rules name
|
||||
default: null
|
||||
required: true
|
||||
direction:
|
||||
description:
|
||||
- is this rule for inbound or outbound trafic
|
||||
default: null
|
||||
required: true
|
||||
choices: ['in', 'out']
|
||||
action:
|
||||
description:
|
||||
- what to do with the items this rule is for
|
||||
default: null
|
||||
required: true
|
||||
choices: ['allow', 'block', 'bypass']
|
||||
description:
|
||||
description:
|
||||
- description for the firewall rule
|
||||
default: null
|
||||
required: false
|
||||
localip:
|
||||
description:
|
||||
- the local ip address this rule applies to
|
||||
default: 'any'
|
||||
required: false
|
||||
remoteip:
|
||||
description:
|
||||
- the remote ip address/range this rule applies to
|
||||
default: 'any'
|
||||
required: false
|
||||
localport:
|
||||
description:
|
||||
- the local port this rule applies to
|
||||
default: 'any'
|
||||
required: false
|
||||
remoteport:
|
||||
description:
|
||||
- the remote port this rule applies to
|
||||
default: 'any'
|
||||
required: false
|
||||
program:
|
||||
description:
|
||||
- the program this rule applies to
|
||||
default: null
|
||||
required: false
|
||||
service:
|
||||
description:
|
||||
- the service this rule applies to
|
||||
default: 'any'
|
||||
required: false
|
||||
protocol:
|
||||
description:
|
||||
- the protocol this rule applies to
|
||||
default: 'any'
|
||||
required: false
|
||||
profile:
|
||||
description:
|
||||
- the profile this rule applies to, e.g. Domain,Private,Public
|
||||
default: 'any'
|
||||
required: false
|
||||
force:
|
||||
description:
|
||||
- Enforces the change if a rule with different values exists
|
||||
default: false
|
||||
required: false
|
||||
|
||||
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Firewall rule to allow smtp on TCP port 25
|
||||
action: win_firewall_rule
|
||||
args:
|
||||
name: smtp
|
||||
enable: yes
|
||||
state: present
|
||||
localport: 25
|
||||
action: allow
|
||||
direction: In
|
||||
protocol: TCP
|
||||
|
||||
'''
|
||||
132
lib/ansible/modules/windows/win_iis_virtualdirectory.ps1
Normal file
132
lib/ansible/modules/windows/win_iis_virtualdirectory.ps1
Normal file
@@ -0,0 +1,132 @@
|
||||
#!powershell
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Henrik Wallström <henrik@wallstroms.nu>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$params = Parse-Args $args;
|
||||
|
||||
# Name parameter
|
||||
$name = Get-Attr $params "name" $FALSE;
|
||||
If ($name -eq $FALSE) {
|
||||
Fail-Json (New-Object psobject) "missing required argument: name";
|
||||
}
|
||||
|
||||
# Site
|
||||
$site = Get-Attr $params "site" $FALSE;
|
||||
If ($site -eq $FALSE) {
|
||||
Fail-Json (New-Object psobject) "missing required argument: site";
|
||||
}
|
||||
|
||||
# Application
|
||||
$application = Get-Attr $params "application" $FALSE;
|
||||
|
||||
# State parameter
|
||||
$state = Get-Attr $params "state" "present";
|
||||
If (($state -ne 'present') -and ($state -ne 'absent')) {
|
||||
Fail-Json $result "state is '$state'; must be 'present' or 'absent'"
|
||||
}
|
||||
|
||||
# Path parameter
|
||||
$physical_path = Get-Attr $params "physical_path" $FALSE;
|
||||
|
||||
# Ensure WebAdministration module is loaded
|
||||
if ((Get-Module "WebAdministration" -ErrorAction SilentlyContinue) -eq $null) {
|
||||
Import-Module WebAdministration
|
||||
}
|
||||
|
||||
# Result
|
||||
$result = New-Object psobject @{
|
||||
directory = New-Object psobject
|
||||
changed = $false
|
||||
};
|
||||
|
||||
# Construct path
|
||||
$directory_path = if($application) {
|
||||
"IIS:\Sites\$($site)\$($application)\$($name)"
|
||||
} else {
|
||||
"IIS:\Sites\$($site)\$($name)"
|
||||
}
|
||||
|
||||
# Directory info
|
||||
$directory = if($application) {
|
||||
Get-WebVirtualDirectory -Site $site -Name $name -Application $application
|
||||
} else {
|
||||
Get-WebVirtualDirectory -Site $site -Name $name
|
||||
}
|
||||
|
||||
try {
|
||||
# Add directory
|
||||
If(($state -eq 'present') -and (-not $directory)) {
|
||||
If ($physical_path -eq $FALSE) {
|
||||
Fail-Json (New-Object psobject) "missing required arguments: physical_path"
|
||||
}
|
||||
If (-not (Test-Path $physical_path)) {
|
||||
Fail-Json (New-Object psobject) "specified folder must already exist: physical_path"
|
||||
}
|
||||
|
||||
$directory_parameters = New-Object psobject @{
|
||||
Site = $site
|
||||
Name = $name
|
||||
PhysicalPath = $physical_path
|
||||
};
|
||||
|
||||
If ($application) {
|
||||
$directory_parameters.Application = $application
|
||||
}
|
||||
|
||||
$directory = New-WebVirtualDirectory @directory_parameters -Force
|
||||
$result.changed = $true
|
||||
}
|
||||
|
||||
# Remove directory
|
||||
If ($state -eq 'absent' -and $directory) {
|
||||
Remove-Item $directory_path
|
||||
$result.changed = $true
|
||||
}
|
||||
|
||||
$directory = Get-WebVirtualDirectory -Site $site -Name $name
|
||||
If($directory) {
|
||||
|
||||
# Change Physical Path if needed
|
||||
if($physical_path) {
|
||||
If (-not (Test-Path $physical_path)) {
|
||||
Fail-Json (New-Object psobject) "specified folder must already exist: physical_path"
|
||||
}
|
||||
|
||||
$vdir_folder = Get-Item $directory.PhysicalPath
|
||||
$folder = Get-Item $physical_path
|
||||
If($folder.FullName -ne $vdir_folder.FullName) {
|
||||
Set-ItemProperty $directory_path -name physicalPath -value $physical_path
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Fail-Json $result $_.Exception.Message
|
||||
}
|
||||
|
||||
# Result
|
||||
$directory = Get-WebVirtualDirectory -Site $site -Name $name
|
||||
$result.directory = New-Object psobject @{
|
||||
PhysicalPath = $directory.PhysicalPath
|
||||
}
|
||||
|
||||
Exit-Json $result
|
||||
71
lib/ansible/modules/windows/win_iis_virtualdirectory.py
Normal file
71
lib/ansible/modules/windows/win_iis_virtualdirectory.py
Normal file
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Henrik Wallström <henrik@wallstroms.nu>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_iis_virtualdirectory
|
||||
version_added: "2.0"
|
||||
short_description: Configures a virtual directory in IIS.
|
||||
description:
|
||||
- Creates, Removes and configures a virtual directory in IIS.
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- The name of the virtual directory to create or remove
|
||||
required: true
|
||||
state:
|
||||
description:
|
||||
- Whether to add or remove the specified virtual directory
|
||||
choices:
|
||||
- absent
|
||||
- present
|
||||
required: false
|
||||
default: present
|
||||
site:
|
||||
description:
|
||||
- The site name under which the virtual directory is created or exists.
|
||||
required: true
|
||||
application:
|
||||
description:
|
||||
- The application under which the virtual directory is created or exists.
|
||||
required: false
|
||||
default: null
|
||||
physical_path:
|
||||
description:
|
||||
- The physical path to the folder in which the new virtual directory is created. The specified folder must already exist.
|
||||
required: false
|
||||
default: null
|
||||
author: Henrik Wallström
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# This creates a virtual directory if it doesn't exist.
|
||||
$ ansible -i hosts -m win_iis_virtualdirectory -a "name='somedirectory' site=somesite state=present physical_path=c:\\virtualdirectory\\some" host
|
||||
|
||||
# This removes a virtual directory if it exists.
|
||||
$ ansible -i hosts -m win_iis_virtualdirectory -a "name='somedirectory' site=somesite state=absent" host
|
||||
|
||||
# This creates a virtual directory on an application if it doesn't exist.
|
||||
$ ansible -i hosts -m win_iis_virtualdirectory -a "name='somedirectory' site=somesite application=someapp state=present physical_path=c:\\virtualdirectory\\some" host
|
||||
'''
|
||||
132
lib/ansible/modules/windows/win_iis_webapplication.ps1
Normal file
132
lib/ansible/modules/windows/win_iis_webapplication.ps1
Normal file
@@ -0,0 +1,132 @@
|
||||
#!powershell
|
||||
|
||||
# (c) 2015, Henrik Wallström <henrik@wallstroms.nu>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$params = Parse-Args $args;
|
||||
|
||||
# Name parameter
|
||||
$name = Get-Attr $params "name" $FALSE;
|
||||
If ($name -eq $FALSE) {
|
||||
Fail-Json (New-Object psobject) "missing required argument: name";
|
||||
}
|
||||
|
||||
# Site
|
||||
$site = Get-Attr $params "site" $FALSE;
|
||||
If ($site -eq $FALSE) {
|
||||
Fail-Json (New-Object psobject) "missing required argument: site";
|
||||
}
|
||||
|
||||
# State parameter
|
||||
$state = Get-Attr $params "state" "present";
|
||||
$state.ToString().ToLower();
|
||||
If (($state -ne 'present') -and ($state -ne 'absent')) {
|
||||
Fail-Json $result "state is '$state'; must be 'present' or 'absent'"
|
||||
}
|
||||
|
||||
# Path parameter
|
||||
$physical_path = Get-Attr $params "physical_path" $FALSE;
|
||||
|
||||
# Application Pool Parameter
|
||||
$application_pool = Get-Attr $params "application_pool" $FALSE;
|
||||
|
||||
|
||||
# Ensure WebAdministration module is loaded
|
||||
if ((Get-Module "WebAdministration" -ErrorAction SilentlyContinue) -eq $null) {
|
||||
Import-Module WebAdministration
|
||||
}
|
||||
|
||||
# Result
|
||||
$result = New-Object psobject @{
|
||||
application = New-Object psobject
|
||||
changed = $false
|
||||
};
|
||||
|
||||
# Application info
|
||||
$application = Get-WebApplication -Site $site -Name $name
|
||||
|
||||
try {
|
||||
# Add application
|
||||
If(($state -eq 'present') -and (-not $application)) {
|
||||
If ($physical_path -eq $FALSE) {
|
||||
Fail-Json (New-Object psobject) "missing required arguments: physical_path"
|
||||
}
|
||||
If (-not (Test-Path $physical_path)) {
|
||||
Fail-Json (New-Object psobject) "specified folder must already exist: physical_path"
|
||||
}
|
||||
|
||||
$application_parameters = New-Object psobject @{
|
||||
Site = $site
|
||||
Name = $name
|
||||
PhysicalPath = $physical_path
|
||||
};
|
||||
|
||||
If ($application_pool) {
|
||||
$application_parameters.ApplicationPool = $application_pool
|
||||
}
|
||||
|
||||
$application = New-WebApplication @application_parameters -Force
|
||||
$result.changed = $true
|
||||
|
||||
}
|
||||
|
||||
# Remove application
|
||||
if ($state -eq 'absent' -and $application) {
|
||||
$application = Remove-WebApplication -Site $site -Name $name
|
||||
$result.changed = $true
|
||||
}
|
||||
|
||||
$application = Get-WebApplication -Site $site -Name $name
|
||||
If($application) {
|
||||
|
||||
# Change Physical Path if needed
|
||||
if($physical_path) {
|
||||
If (-not (Test-Path $physical_path)) {
|
||||
Fail-Json (New-Object psobject) "specified folder must already exist: physical_path"
|
||||
}
|
||||
|
||||
$app_folder = Get-Item $application.PhysicalPath
|
||||
$folder = Get-Item $physical_path
|
||||
If($folder.FullName -ne $app_folder.FullName) {
|
||||
Set-ItemProperty "IIS:\Sites\$($site)\$($name)" -name physicalPath -value $physical_path
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
|
||||
# Change Application Pool if needed
|
||||
if($application_pool) {
|
||||
If($application_pool -ne $application.applicationPool) {
|
||||
Set-ItemProperty "IIS:\Sites\$($site)\$($name)" -name applicationPool -value $application_pool
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Fail-Json $result $_.Exception.Message
|
||||
}
|
||||
|
||||
# Result
|
||||
$application = Get-WebApplication -Site $site -Name $name
|
||||
$result.application = New-Object psobject @{
|
||||
PhysicalPath = $application.PhysicalPath
|
||||
ApplicationPool = $application.applicationPool
|
||||
}
|
||||
|
||||
Exit-Json $result
|
||||
72
lib/ansible/modules/windows/win_iis_webapplication.py
Normal file
72
lib/ansible/modules/windows/win_iis_webapplication.py
Normal file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Henrik Wallström <henrik@wallstroms.nu>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_iis_webapplication
|
||||
version_added: "2.0"
|
||||
short_description: Configures a IIS Web application.
|
||||
description:
|
||||
- Creates, Removes and configures a IIS Web applications
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Name of the Web applicatio
|
||||
required: true
|
||||
default: null
|
||||
aliases: []
|
||||
site:
|
||||
description:
|
||||
- Name of the site on which the application is created.
|
||||
required: true
|
||||
default: null
|
||||
aliases: []
|
||||
state:
|
||||
description:
|
||||
- State of the web application
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
physical_path:
|
||||
description:
|
||||
- The physical path on the remote host to use for the new applicatiojn. The specified folder must already exist.
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
application_pool:
|
||||
description:
|
||||
- The application pool in which the new site executes.
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
author: Henrik Wallström
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
$ ansible -i hosts -m win_iis_webapplication -a "name=api site=acme physical_path=c:\\apps\\acme\\api" host
|
||||
|
||||
'''
|
||||
123
lib/ansible/modules/windows/win_iis_webapppool.ps1
Normal file
123
lib/ansible/modules/windows/win_iis_webapppool.ps1
Normal file
@@ -0,0 +1,123 @@
|
||||
#!powershell
|
||||
|
||||
# (c) 2015, Henrik Wallström <henrik@wallstroms.nu>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$params = Parse-Args $args;
|
||||
|
||||
# Name parameter
|
||||
$name = Get-Attr $params "name" $FALSE;
|
||||
If ($name -eq $FALSE) {
|
||||
Fail-Json (New-Object psobject) "missing required argument: name";
|
||||
}
|
||||
|
||||
# State parameter
|
||||
$state = Get-Attr $params "state" $FALSE;
|
||||
$valid_states = ('started', 'restarted', 'stopped', 'absent');
|
||||
If (($state -Ne $FALSE) -And ($state -NotIn $valid_states)) {
|
||||
Fail-Json $result "state is '$state'; must be $($valid_states)"
|
||||
}
|
||||
|
||||
# Attributes parameter - Pipe separated list of attributes where
|
||||
# keys and values are separated by comma (paramA:valyeA|paramB:valueB)
|
||||
$attributes = @{};
|
||||
If (Get-Member -InputObject $params -Name attributes) {
|
||||
$params.attributes -split '\|' | foreach {
|
||||
$key, $value = $_ -split "\:";
|
||||
$attributes.Add($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure WebAdministration module is loaded
|
||||
if ((Get-Module "WebAdministration" -ErrorAction SilentlyContinue) -eq $NULL){
|
||||
Import-Module WebAdministration
|
||||
}
|
||||
|
||||
# Result
|
||||
$result = New-Object psobject @{
|
||||
changed = $FALSE
|
||||
attributes = $attributes
|
||||
};
|
||||
|
||||
# Get pool
|
||||
$pool = Get-Item IIS:\AppPools\$name
|
||||
|
||||
try {
|
||||
# Add
|
||||
if (-not $pool -and $state -in ('started', 'stopped', 'restarted')) {
|
||||
New-WebAppPool $name
|
||||
$result.changed = $TRUE
|
||||
}
|
||||
|
||||
# Remove
|
||||
if ($pool -and $state -eq 'absent') {
|
||||
Remove-WebAppPool $name
|
||||
$result.changed = $TRUE
|
||||
}
|
||||
|
||||
$pool = Get-Item IIS:\AppPools\$name
|
||||
if($pool) {
|
||||
# Set properties
|
||||
$attributes.GetEnumerator() | foreach {
|
||||
$newParameter = $_;
|
||||
$currentParameter = Get-ItemProperty ("IIS:\AppPools\" + $name) $newParameter.Key
|
||||
if(-not $currentParameter -or ($currentParameter.Value -as [String]) -ne $newParameter.Value) {
|
||||
Set-ItemProperty ("IIS:\AppPools\" + $name) $newParameter.Key $newParameter.Value
|
||||
$result.changed = $TRUE
|
||||
}
|
||||
}
|
||||
|
||||
# Set run state
|
||||
if (($state -eq 'stopped') -and ($pool.State -eq 'Started')) {
|
||||
Stop-WebAppPool -Name $name -ErrorAction Stop
|
||||
$result.changed = $TRUE
|
||||
}
|
||||
if ((($state -eq 'started') -and ($pool.State -eq 'Stopped'))) {
|
||||
Start-WebAppPool -Name $name -ErrorAction Stop
|
||||
$result.changed = $TRUE
|
||||
}
|
||||
if ($state -eq 'restarted') {
|
||||
switch ($pool.State)
|
||||
{
|
||||
'Stopped' { Start-WebAppPool -Name $name -ErrorAction Stop }
|
||||
default { Restart-WebAppPool -Name $name -ErrorAction Stop }
|
||||
}
|
||||
$result.changed = $TRUE
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Fail-Json $result $_.Exception.Message
|
||||
}
|
||||
|
||||
# Result
|
||||
$pool = Get-Item IIS:\AppPools\$name
|
||||
if ($pool)
|
||||
{
|
||||
$result.info = @{
|
||||
name = $pool.Name
|
||||
state = $pool.State
|
||||
attributes = New-Object psobject @{}
|
||||
};
|
||||
|
||||
$pool.Attributes | ForEach { $result.info.attributes.Add($_.Name, $_.Value)};
|
||||
}
|
||||
|
||||
Exit-Json $result
|
||||
116
lib/ansible/modules/windows/win_iis_webapppool.py
Normal file
116
lib/ansible/modules/windows/win_iis_webapppool.py
Normal file
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Henrik Wallström <henrik@wallstroms.nu>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_iis_webapppool
|
||||
version_added: "2.0"
|
||||
short_description: Configures a IIS Web Application Pool.
|
||||
description:
|
||||
- Creates, Removes and configures a IIS Web Application Pool
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Names of application pool
|
||||
required: true
|
||||
default: null
|
||||
aliases: []
|
||||
state:
|
||||
description:
|
||||
- State of the binding
|
||||
choices:
|
||||
- absent
|
||||
- stopped
|
||||
- started
|
||||
- restarted
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
attributes:
|
||||
description:
|
||||
- Application Pool attributes from string where attributes are seperated by a pipe and attribute name/values by colon Ex. "foo:1|bar:2"
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
author: Henrik Wallström
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# This return information about an existing application pool
|
||||
$ansible -i inventory -m win_iis_webapppool -a "name='DefaultAppPool'" windows
|
||||
host | success >> {
|
||||
"attributes": {},
|
||||
"changed": false,
|
||||
"info": {
|
||||
"attributes": {
|
||||
"CLRConfigFile": "",
|
||||
"applicationPoolSid": "S-1-5-82-3006700770-424185619-1745488364-794895919-4004696415",
|
||||
"autoStart": true,
|
||||
"enable32BitAppOnWin64": false,
|
||||
"enableConfigurationOverride": true,
|
||||
"managedPipelineMode": 0,
|
||||
"managedRuntimeLoader": "webengine4.dll",
|
||||
"managedRuntimeVersion": "v4.0",
|
||||
"name": "DefaultAppPool",
|
||||
"passAnonymousToken": true,
|
||||
"queueLength": 1000,
|
||||
"startMode": 0,
|
||||
"state": 1
|
||||
},
|
||||
"name": "DefaultAppPool",
|
||||
"state": "Started"
|
||||
}
|
||||
}
|
||||
|
||||
# This creates a new application pool in 'Started' state
|
||||
$ ansible -i inventory -m win_iis_webapppool -a "name='AppPool' state=started" windows
|
||||
|
||||
# This stoppes an application pool
|
||||
$ ansible -i inventory -m win_iis_webapppool -a "name='AppPool' state=stopped" windows
|
||||
|
||||
# This restarts an application pool
|
||||
$ ansible -i inventory -m win_iis_webapppool -a "name='AppPool' state=restart" windows
|
||||
|
||||
# This restarts an application pool
|
||||
$ ansible -i inventory -m win_iis_webapppool -a "name='AppPool' state=restart" windows
|
||||
|
||||
# This change application pool attributes without touching state
|
||||
$ ansible -i inventory -m win_iis_webapppool -a "name='AppPool' attributes='managedRuntimeVersion:v4.0|autoStart:false'" windows
|
||||
|
||||
# This creates an application pool and sets attributes
|
||||
$ ansible -i inventory -m win_iis_webapppool -a "name='AnotherAppPool' state=started attributes='managedRuntimeVersion:v4.0|autoStart:false'" windows
|
||||
|
||||
|
||||
# Playbook example
|
||||
---
|
||||
|
||||
- name: App Pool with .NET 4.0
|
||||
win_iis_webapppool:
|
||||
name: 'AppPool'
|
||||
state: started
|
||||
attributes: managedRuntimeVersion:v4.0
|
||||
register: webapppool
|
||||
|
||||
'''
|
||||
131
lib/ansible/modules/windows/win_iis_webbinding.ps1
Normal file
131
lib/ansible/modules/windows/win_iis_webbinding.ps1
Normal file
@@ -0,0 +1,131 @@
|
||||
#!powershell
|
||||
|
||||
# (c) 2015, Henrik Wallström <henrik@wallstroms.nu>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$params = Parse-Args $args;
|
||||
|
||||
$name = Get-AnsibleParam $params -name "name" -failifempty $true
|
||||
$state = Get-AnsibleParam $params "state" -default "present" -validateSet "present","absent"
|
||||
$host_header = Get-AnsibleParam $params -name "host_header"
|
||||
$protocol = Get-AnsibleParam $params -name "protocol"
|
||||
$port = Get-AnsibleParam $params -name "port"
|
||||
$ip = Get-AnsibleParam $params -name "ip"
|
||||
$certificatehash = Get-AnsibleParam $params -name "certificate_hash" -default $false
|
||||
$certificateStoreName = Get-AnsibleParam $params -name "certificate_store_name" -default "MY"
|
||||
|
||||
$binding_parameters = New-Object psobject @{
|
||||
Name = $name
|
||||
};
|
||||
|
||||
If ($host_header) {
|
||||
$binding_parameters.HostHeader = $host_header
|
||||
}
|
||||
|
||||
If ($protocol) {
|
||||
$binding_parameters.Protocol = $protocol
|
||||
}
|
||||
|
||||
If ($port) {
|
||||
$binding_parameters.Port = $port
|
||||
}
|
||||
|
||||
If ($ip) {
|
||||
$binding_parameters.IPAddress = $ip
|
||||
}
|
||||
|
||||
# Ensure WebAdministration module is loaded
|
||||
if ((Get-Module "WebAdministration" -ErrorAction SilentlyContinue) -eq $null){
|
||||
Import-Module WebAdministration
|
||||
}
|
||||
|
||||
function Create-Binding-Info {
|
||||
return New-Object psobject @{
|
||||
"bindingInformation" = $args[0].bindingInformation
|
||||
"certificateHash" = $args[0].certificateHash
|
||||
"certificateStoreName" = $args[0].certificateStoreName
|
||||
"isDsMapperEnabled" = $args[0].isDsMapperEnabled
|
||||
"protocol" = $args[0].protocol
|
||||
"sslFlags" = $args[0].sslFlags
|
||||
}
|
||||
}
|
||||
|
||||
# Result
|
||||
$result = New-Object psobject @{
|
||||
changed = $false
|
||||
parameters = $binding_parameters
|
||||
matched = @()
|
||||
removed = @()
|
||||
added = @()
|
||||
};
|
||||
|
||||
# Get bindings matching parameters
|
||||
$curent_bindings = Get-WebBinding @binding_parameters
|
||||
$curent_bindings | Foreach {
|
||||
$result.matched += Create-Binding-Info $_
|
||||
}
|
||||
|
||||
try {
|
||||
# Add
|
||||
if (-not $curent_bindings -and $state -eq 'present') {
|
||||
New-WebBinding @binding_parameters -Force
|
||||
|
||||
# Select certificat
|
||||
if($certificateHash -ne $FALSE) {
|
||||
|
||||
$ip = $binding_parameters["IPAddress"]
|
||||
if((!$ip) -or ($ip -eq "*")) {
|
||||
$ip = "0.0.0.0"
|
||||
}
|
||||
|
||||
$port = $binding_parameters["Port"]
|
||||
if(!$port) {
|
||||
$port = 443
|
||||
}
|
||||
|
||||
$result.port = $port
|
||||
$result.ip = $ip
|
||||
|
||||
Push-Location IIS:\SslBindings\
|
||||
Get-Item Cert:\LocalMachine\$certificateStoreName\$certificateHash | New-Item "$($ip)!$($port)"
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
$result.added += Create-Binding-Info (Get-WebBinding @binding_parameters)
|
||||
$result.changed = $true
|
||||
}
|
||||
|
||||
# Remove
|
||||
if ($curent_bindings -and $state -eq 'absent') {
|
||||
$curent_bindings | foreach {
|
||||
Remove-WebBinding -InputObject $_
|
||||
$result.removed += Create-Binding-Info $_
|
||||
}
|
||||
$result.changed = $true
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch {
|
||||
Fail-Json $result $_.Exception.Message
|
||||
}
|
||||
|
||||
Exit-Json $result
|
||||
141
lib/ansible/modules/windows/win_iis_webbinding.py
Normal file
141
lib/ansible/modules/windows/win_iis_webbinding.py
Normal file
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Henrik Wallström <henrik@wallstroms.nu>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_iis_webbinding
|
||||
version_added: "2.0"
|
||||
short_description: Configures a IIS Web site.
|
||||
description:
|
||||
- Creates, Removes and configures a binding to an existing IIS Web site
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Names of web site
|
||||
required: true
|
||||
default: null
|
||||
aliases: []
|
||||
state:
|
||||
description:
|
||||
- State of the binding
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
port:
|
||||
description:
|
||||
- The port to bind to / use for the new site.
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
ip:
|
||||
description:
|
||||
- The IP address to bind to / use for the new site.
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
host_header:
|
||||
description:
|
||||
- The host header to bind to / use for the new site.
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
protocol:
|
||||
description:
|
||||
- The protocol to be used for the Web binding (usually HTTP, HTTPS, or FTP).
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
certificate_hash:
|
||||
description:
|
||||
- Certificate hash for the SSL binding. The certificate hash is the unique identifier for the certificate.
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
certificate_store_name:
|
||||
description:
|
||||
- Name of the certificate store where the certificate for the binding is located.
|
||||
required: false
|
||||
default: "My"
|
||||
aliases: []
|
||||
author: Henrik Wallström
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# This will return binding information for an existing host
|
||||
$ ansible -i vagrant-inventory -m win_iis_webbinding -a "name='Default Web Site'" windows
|
||||
host | success >> {
|
||||
"added": [],
|
||||
"changed": false,
|
||||
"matched": [
|
||||
{
|
||||
"bindingInformation": "*:80:",
|
||||
"certificateHash": "",
|
||||
"certificateStoreName": "",
|
||||
"isDsMapperEnabled": false,
|
||||
"protocol": "http",
|
||||
"sslFlags": 0
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Name": "Default Web Site"
|
||||
},
|
||||
"removed": []
|
||||
}
|
||||
|
||||
# This will return the HTTPS binding information for an existing host
|
||||
$ ansible -i vagrant-inventory -m win_iis_webbinding -a "name='Default Web Site' protocol=https" windows
|
||||
|
||||
# This will return the HTTPS binding information for an existing host
|
||||
$ ansible -i vagrant-inventory -m win_iis_webbinding -a "name='Default Web Site' port:9090 state=present" windows
|
||||
|
||||
# This will add a HTTP binding on port 9090
|
||||
$ ansible -i vagrant-inventory -m win_iis_webbinding -a "name='Default Web Site' port=9090 state=present" windows
|
||||
|
||||
# This will remove the HTTP binding on port 9090
|
||||
$ ansible -i vagrant-inventory -m win_iis_webbinding -a "name='Default Web Site' port=9090 state=present" windows
|
||||
|
||||
# This will add a HTTPS binding
|
||||
$ ansible -i vagrant-inventory -m win_iis_webbinding -a "name='Default Web Site' protocol=https state=present" windows
|
||||
|
||||
# This will add a HTTPS binding and select certificate to use
|
||||
# ansible -i vagrant-inventory -m win_iis_webbinding -a "name='Default Web Site' protocol=https certificate_hash= B0D0FA8408FC67B230338FCA584D03792DA73F4C" windows
|
||||
|
||||
|
||||
# Playbook example
|
||||
---
|
||||
|
||||
- name: Website http/https bidings
|
||||
win_iis_webbinding:
|
||||
name: "Default Web Site"
|
||||
protocol: https
|
||||
port: 443
|
||||
certificate_hash: "D1A3AF8988FD32D1A3AF8988FD323792DA73F4C"
|
||||
state: present
|
||||
when: monitor_use_https
|
||||
|
||||
'''
|
||||
196
lib/ansible/modules/windows/win_iis_website.ps1
Normal file
196
lib/ansible/modules/windows/win_iis_website.ps1
Normal file
@@ -0,0 +1,196 @@
|
||||
#!powershell
|
||||
|
||||
# (c) 2015, Henrik Wallström <henrik@wallstroms.nu>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$params = Parse-Args $args;
|
||||
|
||||
# Name parameter
|
||||
$name = Get-Attr $params "name" $FALSE;
|
||||
If ($name -eq $FALSE) {
|
||||
Fail-Json (New-Object psobject) "missing required argument: name";
|
||||
}
|
||||
|
||||
# State parameter
|
||||
$state = Get-Attr $params "state" $FALSE;
|
||||
$state.ToString().ToLower();
|
||||
If (($state -ne $FALSE) -and ($state -ne 'started') -and ($state -ne 'stopped') -and ($state -ne 'restarted') -and ($state -ne 'absent')) {
|
||||
Fail-Json (New-Object psobject) "state is '$state'; must be 'started', 'restarted', 'stopped' or 'absent'"
|
||||
}
|
||||
|
||||
# Path parameter
|
||||
$physical_path = Get-Attr $params "physical_path" $FALSE;
|
||||
$site_id = Get-Attr $params "site_id" $FALSE;
|
||||
|
||||
# Application Pool Parameter
|
||||
$application_pool = Get-Attr $params "application_pool" $FALSE;
|
||||
|
||||
# Binding Parameters
|
||||
$bind_port = Get-Attr $params "port" $FALSE;
|
||||
$bind_ip = Get-Attr $params "ip" $FALSE;
|
||||
$bind_hostname = Get-Attr $params "hostname" $FALSE;
|
||||
$bind_ssl = Get-Attr $params "ssl" $FALSE;
|
||||
|
||||
# Custom site Parameters from string where properties
|
||||
# are seperated by a pipe and property name/values by colon.
|
||||
# Ex. "foo:1|bar:2"
|
||||
$parameters = Get-Attr $params "parameters" $null;
|
||||
if($parameters -ne $null) {
|
||||
$parameters = @($parameters -split '\|' | ForEach {
|
||||
return ,($_ -split "\:", 2);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
# Ensure WebAdministration module is loaded
|
||||
if ((Get-Module "WebAdministration" -ErrorAction SilentlyContinue) -eq $null) {
|
||||
Import-Module WebAdministration
|
||||
}
|
||||
|
||||
# Result
|
||||
$result = New-Object psobject @{
|
||||
site = New-Object psobject
|
||||
changed = $false
|
||||
};
|
||||
|
||||
# Site info
|
||||
$site = Get-Website | Where { $_.Name -eq $name }
|
||||
|
||||
Try {
|
||||
# Add site
|
||||
If(($state -ne 'absent') -and (-not $site)) {
|
||||
If ($physical_path -eq $FALSE) {
|
||||
Fail-Json (New-Object psobject) "missing required arguments: physical_path"
|
||||
}
|
||||
ElseIf (-not (Test-Path $physical_path)) {
|
||||
Fail-Json (New-Object psobject) "specified folder must already exist: physical_path"
|
||||
}
|
||||
|
||||
$site_parameters = New-Object psobject @{
|
||||
Name = $name
|
||||
PhysicalPath = $physical_path
|
||||
};
|
||||
|
||||
If ($application_pool) {
|
||||
$site_parameters.ApplicationPool = $application_pool
|
||||
}
|
||||
|
||||
If ($site_id) {
|
||||
$site_parameters.ID = $site_id
|
||||
}
|
||||
|
||||
If ($bind_port) {
|
||||
$site_parameters.Port = $bind_port
|
||||
}
|
||||
|
||||
If ($bind_ip) {
|
||||
$site_parameters.IPAddress = $bind_ip
|
||||
}
|
||||
|
||||
If ($bind_hostname) {
|
||||
$site_parameters.HostHeader = $bind_hostname
|
||||
}
|
||||
|
||||
# Fix for error "New-Item : Index was outside the bounds of the array."
|
||||
# This is a bug in the New-WebSite commandlet. Apparently there must be at least one site configured in IIS otherwise New-WebSite crashes.
|
||||
# For more details, see http://stackoverflow.com/questions/3573889/ps-c-new-website-blah-throws-index-was-outside-the-bounds-of-the-array
|
||||
$sites_list = get-childitem -Path IIS:\sites
|
||||
if ($sites_list -eq $null) { $site_parameters.ID = 1 }
|
||||
|
||||
$site = New-Website @site_parameters -Force
|
||||
$result.changed = $true
|
||||
}
|
||||
|
||||
# Remove site
|
||||
If ($state -eq 'absent' -and $site) {
|
||||
$site = Remove-Website -Name $name
|
||||
$result.changed = $true
|
||||
}
|
||||
|
||||
$site = Get-Website | Where { $_.Name -eq $name }
|
||||
If($site) {
|
||||
# Change Physical Path if needed
|
||||
if($physical_path) {
|
||||
If (-not (Test-Path $physical_path)) {
|
||||
Fail-Json (New-Object psobject) "specified folder must already exist: physical_path"
|
||||
}
|
||||
|
||||
$folder = Get-Item $physical_path
|
||||
If($folder.FullName -ne $site.PhysicalPath) {
|
||||
Set-ItemProperty "IIS:\Sites\$($site.Name)" -name physicalPath -value $folder.FullName
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
|
||||
# Change Application Pool if needed
|
||||
if($application_pool) {
|
||||
If($application_pool -ne $site.applicationPool) {
|
||||
Set-ItemProperty "IIS:\Sites\$($site.Name)" -name applicationPool -value $application_pool
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
|
||||
# Set properties
|
||||
if($parameters) {
|
||||
$parameters | foreach {
|
||||
$parameter_value = Get-ItemProperty "IIS:\Sites\$($site.Name)" $_[0]
|
||||
if((-not $parameter_value) -or ($parameter_value.Value -as [String]) -ne $_[1]) {
|
||||
Set-ItemProperty "IIS:\Sites\$($site.Name)" $_[0] $_[1]
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Set run state
|
||||
if (($state -eq 'stopped') -and ($site.State -eq 'Started'))
|
||||
{
|
||||
Stop-Website -Name $name -ErrorAction Stop
|
||||
$result.changed = $true
|
||||
}
|
||||
if ((($state -eq 'started') -and ($site.State -eq 'Stopped')) -or ($state -eq 'restarted'))
|
||||
{
|
||||
Start-Website -Name $name -ErrorAction Stop
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Fail-Json (New-Object psobject) $_.Exception.Message
|
||||
}
|
||||
|
||||
if ($state -ne 'absent')
|
||||
{
|
||||
$site = Get-Website | Where { $_.Name -eq $name }
|
||||
}
|
||||
|
||||
if ($site)
|
||||
{
|
||||
$result.site = New-Object psobject @{
|
||||
Name = $site.Name
|
||||
ID = $site.ID
|
||||
State = $site.State
|
||||
PhysicalPath = $site.PhysicalPath
|
||||
ApplicationPool = $site.applicationPool
|
||||
Bindings = @($site.Bindings.Collection | ForEach-Object { $_.BindingInformation })
|
||||
}
|
||||
}
|
||||
|
||||
Exit-Json $result
|
||||
143
lib/ansible/modules/windows/win_iis_website.py
Normal file
143
lib/ansible/modules/windows/win_iis_website.py
Normal file
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Henrik Wallström <henrik@wallstroms.nu>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_iis_website
|
||||
version_added: "2.0"
|
||||
short_description: Configures a IIS Web site.
|
||||
description:
|
||||
- Creates, Removes and configures a IIS Web site
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Names of web site
|
||||
required: true
|
||||
default: null
|
||||
aliases: []
|
||||
site_id:
|
||||
description:
|
||||
- Explicitly set the IIS numeric ID for a site. Note that this value cannot be changed after the website has been created.
|
||||
required: false
|
||||
version_added: "2.1"
|
||||
default: null
|
||||
state:
|
||||
description:
|
||||
- State of the web site
|
||||
choices:
|
||||
- started
|
||||
- restarted
|
||||
- stopped
|
||||
- absent
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
physical_path:
|
||||
description:
|
||||
- The physical path on the remote host to use for the new site. The specified folder must already exist.
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
application_pool:
|
||||
description:
|
||||
- The application pool in which the new site executes.
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
port:
|
||||
description:
|
||||
- The port to bind to / use for the new site.
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
ip:
|
||||
description:
|
||||
- The IP address to bind to / use for the new site.
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
hostname:
|
||||
description:
|
||||
- The host header to bind to / use for the new site.
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
ssl:
|
||||
description:
|
||||
- Enables HTTPS binding on the site..
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
parameters:
|
||||
description:
|
||||
- Custom site Parameters from string where properties are seperated by a pipe and property name/values by colon Ex. "foo:1|bar:2"
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
author: Henrik Wallström
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# This return information about an existing host
|
||||
$ ansible -i vagrant-inventory -m win_iis_website -a "name='Default Web Site'" window
|
||||
host | success >> {
|
||||
"changed": false,
|
||||
"site": {
|
||||
"ApplicationPool": "DefaultAppPool",
|
||||
"Bindings": [
|
||||
"*:80:"
|
||||
],
|
||||
"ID": 1,
|
||||
"Name": "Default Web Site",
|
||||
"PhysicalPath": "%SystemDrive%\\inetpub\\wwwroot",
|
||||
"State": "Stopped"
|
||||
}
|
||||
}
|
||||
|
||||
# This stops an existing site.
|
||||
$ ansible -i hosts -m win_iis_website -a "name='Default Web Site' state=stopped" host
|
||||
|
||||
# This creates a new site.
|
||||
$ ansible -i hosts -m win_iis_website -a "name=acme physical_path=c:\\sites\\acme" host
|
||||
|
||||
# Change logfile .
|
||||
$ ansible -i hosts -m win_iis_website -a "name=acme physical_path=c:\\sites\\acme" host
|
||||
|
||||
|
||||
# Playbook example
|
||||
---
|
||||
|
||||
- name: Acme IIS site
|
||||
win_iis_website:
|
||||
name: "Acme"
|
||||
state: started
|
||||
port: 80
|
||||
ip: 127.0.0.1
|
||||
hostname: acme.local
|
||||
application_pool: "acme"
|
||||
physical_path: 'c:\\sites\\acme'
|
||||
parameters: 'logfile.directory:c:\\sites\\logs'
|
||||
register: website
|
||||
|
||||
'''
|
||||
685
lib/ansible/modules/windows/win_nssm.ps1
Normal file
685
lib/ansible/modules/windows/win_nssm.ps1
Normal file
@@ -0,0 +1,685 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Copyright 2015, George Frank <george@georgefrank.net>
|
||||
# Copyright 2015, Adam Keech <akeech@chathamfinancial.com>
|
||||
# Copyright 2015, Hans-Joachim Kliemeck <git@kliemeck.de>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$params = Parse-Args $args;
|
||||
|
||||
$result = New-Object PSObject;
|
||||
Set-Attr $result "changed" $false;
|
||||
|
||||
$name = Get-Attr $params "name" -failifempty $true
|
||||
$state = Get-Attr $params "state" -default "present" -validateSet "present", "absent", "started", "stopped", "restarted" -resultobj $result
|
||||
|
||||
$application = Get-Attr $params "application" -default $null
|
||||
$appParameters = Get-Attr $params "app_parameters" -default $null
|
||||
$startMode = Get-Attr $params "start_mode" -default "auto" -validateSet "auto", "manual", "disabled" -resultobj $result
|
||||
|
||||
$stdoutFile = Get-Attr $params "stdout_file" -default $null
|
||||
$stderrFile = Get-Attr $params "stderr_file" -default $null
|
||||
$dependencies = Get-Attr $params "dependencies" -default $null
|
||||
|
||||
$user = Get-Attr $params "user" -default $null
|
||||
$password = Get-Attr $params "password" -default $null
|
||||
|
||||
|
||||
#abstract the calling of nssm because some PowerShell environments
|
||||
#mishandle its stdout(which is Unicode) as UTF8
|
||||
Function Nssm-Invoke
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$cmd
|
||||
)
|
||||
Try {
|
||||
$encodingWas = [System.Console]::OutputEncoding
|
||||
[System.Console]::OutputEncoding = [System.Text.Encoding]::Unicode
|
||||
|
||||
$nssmOutput = invoke-expression "nssm $cmd"
|
||||
return $nssmOutput
|
||||
}
|
||||
Catch {
|
||||
$ErrorMessage = $_.Exception.Message
|
||||
Fail-Json $result "an exception occurred when invoking NSSM: $ErrorMessage"
|
||||
}
|
||||
Finally {
|
||||
# Set the console encoding back to what it was
|
||||
[System.Console]::OutputEncoding = $encodingWas
|
||||
}
|
||||
}
|
||||
|
||||
Function Service-Exists
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$name
|
||||
)
|
||||
|
||||
return [bool](Get-Service "$name" -ErrorAction SilentlyContinue)
|
||||
}
|
||||
|
||||
Function Nssm-Remove
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$name
|
||||
)
|
||||
|
||||
if (Service-Exists -name $name)
|
||||
{
|
||||
$cmd = "stop ""$name"""
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
$cmd = "remove ""$name"" confirm"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error removing service ""$name"""
|
||||
}
|
||||
|
||||
Set-Attr $result "changed_by" "remove_service"
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
|
||||
Function Nssm-Install
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$name,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[AllowEmptyString()]
|
||||
[string]$application
|
||||
)
|
||||
|
||||
if (!$application)
|
||||
{
|
||||
Throw "Error installing service ""$name"". No application was supplied."
|
||||
}
|
||||
If (-Not (Test-Path -Path $application -PathType Leaf)) {
|
||||
Throw "$application does not exist on the host"
|
||||
}
|
||||
|
||||
if (!(Service-Exists -name $name))
|
||||
{
|
||||
$results = Nssm-Invoke "install ""$name"" $application"
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error installing service ""$name"""
|
||||
}
|
||||
|
||||
Set-Attr $result "changed_by" "install_service"
|
||||
$result.changed = $true
|
||||
|
||||
} else {
|
||||
$results = Nssm-Invoke "get ""$name"" Application"
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error installing service ""$name"""
|
||||
}
|
||||
|
||||
if ($results -cnotlike $application)
|
||||
{
|
||||
$cmd = "set ""$name"" Application $application"
|
||||
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error installing service ""$name"""
|
||||
}
|
||||
Set-Attr $result "application" "$application"
|
||||
|
||||
Set-Attr $result "changed_by" "reinstall_service"
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
|
||||
if ($result.changed)
|
||||
{
|
||||
$applicationPath = (Get-Item $application).DirectoryName
|
||||
$cmd = "nssm set ""$name"" AppDirectory $applicationPath"
|
||||
|
||||
$results = invoke-expression $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error installing service ""$name"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Function ParseAppParameters()
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[AllowEmptyString()]
|
||||
[string]$appParameters
|
||||
)
|
||||
|
||||
$escapedAppParameters = $appParameters.TrimStart("@").TrimStart("{").TrimEnd("}").Replace("; ","`n").Replace("\","\\")
|
||||
|
||||
return ConvertFrom-StringData -StringData $escapedAppParameters
|
||||
}
|
||||
|
||||
|
||||
Function Nssm-Update-AppParameters
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$name,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[AllowEmptyString()]
|
||||
[string]$appParameters
|
||||
)
|
||||
|
||||
$cmd = "get ""$name"" AppParameters"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error updating AppParameters for service ""$name"""
|
||||
}
|
||||
|
||||
$appParamKeys = @()
|
||||
$appParamVals = @()
|
||||
$singleLineParams = ""
|
||||
|
||||
if ($appParameters)
|
||||
{
|
||||
$appParametersHash = ParseAppParameters -appParameters $appParameters
|
||||
$appParametersHash.GetEnumerator() |
|
||||
% {
|
||||
$key = $($_.Name)
|
||||
$val = $($_.Value)
|
||||
|
||||
$appParamKeys += $key
|
||||
$appParamVals += $val
|
||||
|
||||
if ($key -eq "_") {
|
||||
$singleLineParams = "$val " + $singleLineParams
|
||||
} else {
|
||||
$singleLineParams = $singleLineParams + "$key ""$val"""
|
||||
}
|
||||
}
|
||||
|
||||
Set-Attr $result "nssm_app_parameters_parsed" $appParametersHash
|
||||
Set-Attr $result "nssm_app_parameters_keys" $appParamKeys
|
||||
Set-Attr $result "nssm_app_parameters_vals" $appParamVals
|
||||
}
|
||||
|
||||
Set-Attr $result "nssm_app_parameters" $appParameters
|
||||
Set-Attr $result "nssm_single_line_app_parameters" $singleLineParams
|
||||
|
||||
if ($results -ne $singleLineParams)
|
||||
{
|
||||
if ($appParameters)
|
||||
{
|
||||
$cmd = "set ""$name"" AppParameters $singleLineParams"
|
||||
} else {
|
||||
$cmd = "set ""$name"" AppParameters '""""'"
|
||||
}
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error updating AppParameters for service ""$name"""
|
||||
}
|
||||
|
||||
Set-Attr $result "changed_by" "update_app_parameters"
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
|
||||
Function Nssm-Set-Output-Files
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$name,
|
||||
[string]$stdout,
|
||||
[string]$stderr
|
||||
)
|
||||
|
||||
$cmd = "get ""$name"" AppStdout"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error retrieving existing stdout file for service ""$name"""
|
||||
}
|
||||
|
||||
if ($results -cnotlike $stdout)
|
||||
{
|
||||
if (!$stdout)
|
||||
{
|
||||
$cmd = "reset ""$name"" AppStdout"
|
||||
} else {
|
||||
$cmd = "set ""$name"" AppStdout $stdout"
|
||||
}
|
||||
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error setting stdout file for service ""$name"""
|
||||
}
|
||||
|
||||
Set-Attr $result "changed_by" "set_stdout"
|
||||
$result.changed = $true
|
||||
}
|
||||
|
||||
$cmd = "get ""$name"" AppStderr"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error retrieving existing stderr file for service ""$name"""
|
||||
}
|
||||
|
||||
if ($results -cnotlike $stderr)
|
||||
{
|
||||
if (!$stderr)
|
||||
{
|
||||
$cmd = "reset ""$name"" AppStderr"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error clearing stderr file setting for service ""$name"""
|
||||
}
|
||||
} else {
|
||||
$cmd = "set ""$name"" AppStderr $stderr"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error setting stderr file for service ""$name"""
|
||||
}
|
||||
}
|
||||
|
||||
Set-Attr $result "changed_by" "set_stderr"
|
||||
$result.changed = $true
|
||||
}
|
||||
|
||||
###
|
||||
# Setup file rotation so we don't accidentally consume too much disk
|
||||
###
|
||||
|
||||
#set files to overwrite
|
||||
$cmd = "set ""$name"" AppStdoutCreationDisposition 2"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
$cmd = "set ""$name"" AppStderrCreationDisposition 2"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
#enable file rotation
|
||||
$cmd = "set ""$name"" AppRotateFiles 1"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
#don't rotate until the service restarts
|
||||
$cmd = "set ""$name"" AppRotateOnline 0"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
#both of the below conditions must be met before rotation will happen
|
||||
#minimum age before rotating
|
||||
$cmd = "set ""$name"" AppRotateSeconds 86400"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
#minimum size before rotating
|
||||
$cmd = "set ""$name"" AppRotateBytes 104858"
|
||||
$results = Nssm-Invoke $cmd
|
||||
}
|
||||
|
||||
Function Nssm-Update-Credentials
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$name,
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$user,
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$password
|
||||
)
|
||||
|
||||
$cmd = "get ""$name"" ObjectName"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error updating credentials for service ""$name"""
|
||||
}
|
||||
|
||||
if ($user) {
|
||||
if (!$password) {
|
||||
Throw "User without password is informed for service ""$name"""
|
||||
}
|
||||
else {
|
||||
$fullUser = $user
|
||||
If (-Not($user.contains("@")) -And ($user.Split("\").count -eq 1)) {
|
||||
$fullUser = ".\" + $user
|
||||
}
|
||||
|
||||
If ($results -ne $fullUser) {
|
||||
$cmd = "set ""$name"" ObjectName $fullUser $password"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error updating credentials for service ""$name"""
|
||||
}
|
||||
|
||||
Set-Attr $result "changed_by" "update_credentials"
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Function Nssm-Update-Dependencies
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$name,
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$dependencies
|
||||
)
|
||||
|
||||
$cmd = "get ""$name"" DependOnService"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error updating dependencies for service ""$name"""
|
||||
}
|
||||
|
||||
If (($dependencies) -and ($results.Tolower() -ne $dependencies.Tolower())) {
|
||||
$cmd = "set ""$name"" DependOnService $dependencies"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error updating dependencies for service ""$name"""
|
||||
}
|
||||
|
||||
Set-Attr $result "changed_by" "update-dependencies"
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
|
||||
Function Nssm-Update-StartMode
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$name,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$mode
|
||||
)
|
||||
|
||||
$cmd = "get ""$name"" Start"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error updating start mode for service ""$name"""
|
||||
}
|
||||
|
||||
$modes=@{"auto" = "SERVICE_AUTO_START"; "manual" = "SERVICE_DEMAND_START"; "disabled" = "SERVICE_DISABLED"}
|
||||
$mappedMode = $modes.$mode
|
||||
if ($results -cnotlike $mappedMode) {
|
||||
$cmd = "set ""$name"" Start $mappedMode"
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error updating start mode for service ""$name"""
|
||||
}
|
||||
|
||||
Set-Attr $result "changed_by" "start_mode"
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
|
||||
Function Nssm-Get-Status
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$name
|
||||
)
|
||||
|
||||
$cmd = "status ""$name"""
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
return ,$results
|
||||
}
|
||||
|
||||
Function Nssm-Start
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$name
|
||||
)
|
||||
|
||||
$currentStatus = Nssm-Get-Status -name $name
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error starting service ""$name"""
|
||||
}
|
||||
|
||||
switch ($currentStatus)
|
||||
{
|
||||
"SERVICE_RUNNING" { <# Nothing to do #> }
|
||||
"SERVICE_STOPPED" { Nssm-Start-Service-Command -name $name }
|
||||
|
||||
"SERVICE_CONTINUE_PENDING" { Nssm-Stop-Service-Command -name $name; Nssm-Start-Service-Command -name $name }
|
||||
"SERVICE_PAUSE_PENDING" { Nssm-Stop-Service-Command -name $name; Nssm-Start-Service-Command -name $name }
|
||||
"SERVICE_PAUSED" { Nssm-Stop-Service-Command -name $name; Nssm-Start-Service-Command -name $name }
|
||||
"SERVICE_START_PENDING" { Nssm-Stop-Service-Command -name $name; Nssm-Start-Service-Command -name $name }
|
||||
"SERVICE_STOP_PENDING" { Nssm-Stop-Service-Command -name $name; Nssm-Start-Service-Command -name $name }
|
||||
}
|
||||
}
|
||||
|
||||
Function Nssm-Start-Service-Command
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$name
|
||||
)
|
||||
|
||||
$cmd = "start ""$name"""
|
||||
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error starting service ""$name"""
|
||||
}
|
||||
|
||||
Set-Attr $result "changed_by" "start_service"
|
||||
$result.changed = $true
|
||||
}
|
||||
|
||||
Function Nssm-Stop-Service-Command
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$name
|
||||
)
|
||||
|
||||
$cmd = "stop ""$name"""
|
||||
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error stopping service ""$name"""
|
||||
}
|
||||
|
||||
Set-Attr $result "changed_by" "stop_service_command"
|
||||
$result.changed = $true
|
||||
}
|
||||
|
||||
Function Nssm-Stop
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$name
|
||||
)
|
||||
|
||||
$currentStatus = Nssm-Get-Status -name $name
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error stopping service ""$name"""
|
||||
}
|
||||
|
||||
if ($currentStatus -ne "SERVICE_STOPPED")
|
||||
{
|
||||
$cmd = "stop ""$name"""
|
||||
|
||||
$results = Nssm-Invoke $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "nssm_error_cmd" $cmd
|
||||
Set-Attr $result "nssm_error_log" "$results"
|
||||
Throw "Error stopping service ""$name"""
|
||||
}
|
||||
|
||||
Set-Attr $result "changed_by" "stop_service"
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
|
||||
Function Nssm-Restart
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$name
|
||||
)
|
||||
|
||||
Nssm-Stop-Service-Command -name $name
|
||||
Nssm-Start-Service-Command -name $name
|
||||
}
|
||||
|
||||
Function NssmProcedure
|
||||
{
|
||||
Nssm-Install -name $name -application $application
|
||||
Nssm-Update-AppParameters -name $name -appParameters $appParameters
|
||||
Nssm-Set-Output-Files -name $name -stdout $stdoutFile -stderr $stderrFile
|
||||
Nssm-Update-Dependencies -name $name -dependencies $dependencies
|
||||
Nssm-Update-Credentials -name $name -user $user -password $password
|
||||
Nssm-Update-StartMode -name $name -mode $startMode
|
||||
}
|
||||
|
||||
Try
|
||||
{
|
||||
switch ($state)
|
||||
{
|
||||
"absent" { Nssm-Remove -name $name }
|
||||
"present" {
|
||||
NssmProcedure
|
||||
}
|
||||
"started" {
|
||||
NssmProcedure
|
||||
Nssm-Start -name $name
|
||||
}
|
||||
"stopped" {
|
||||
NssmProcedure
|
||||
Nssm-Stop -name $name
|
||||
}
|
||||
"restarted" {
|
||||
NssmProcedure
|
||||
Nssm-Restart -name $name
|
||||
}
|
||||
}
|
||||
|
||||
Exit-Json $result;
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Fail-Json $result $_.Exception.Message
|
||||
}
|
||||
178
lib/ansible/modules/windows/win_nssm.py
Normal file
178
lib/ansible/modules/windows/win_nssm.py
Normal file
@@ -0,0 +1,178 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Heyo
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_nssm
|
||||
version_added: "2.0"
|
||||
short_description: NSSM - the Non-Sucking Service Manager
|
||||
description:
|
||||
- nssm is a service helper which doesn't suck. See https://nssm.cc/ for more information.
|
||||
requirements:
|
||||
- "nssm >= 2.24.0 # (install via win_chocolatey) win_chocolatey: name=nssm"
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Name of the service to operate on
|
||||
required: true
|
||||
state:
|
||||
description:
|
||||
- State of the service on the system
|
||||
- Note that NSSM actions like "pause", "continue", "rotate" do not fit the declarative style of ansible, so these should be implemented via the ansible command module
|
||||
required: false
|
||||
choices:
|
||||
- present
|
||||
- started
|
||||
- stopped
|
||||
- restarted
|
||||
- absent
|
||||
default: started
|
||||
application:
|
||||
description:
|
||||
- The application binary to run as a service
|
||||
- "Specify this whenever the service may need to be installed (state: present, started, stopped, restarted)"
|
||||
- "Note that the application name must look like the following, if the directory includes spaces:"
|
||||
- 'nssm install service "c:\\Program Files\\app.exe\\" "C:\\Path with spaces\\"'
|
||||
- "See commit 0b386fc1984ab74ee59b7bed14b7e8f57212c22b in the nssm.git project for more info (https://git.nssm.cc/?p=nssm.git;a=commit;h=0b386fc1984ab74ee59b7bed14b7e8f57212c22b)"
|
||||
required: false
|
||||
default: null
|
||||
stdout_file:
|
||||
description:
|
||||
- Path to receive output
|
||||
required: false
|
||||
default: null
|
||||
stderr_file:
|
||||
description:
|
||||
- Path to receive error output
|
||||
required: false
|
||||
default: null
|
||||
app_parameters:
|
||||
description:
|
||||
- Parameters to be passed to the application when it starts
|
||||
required: false
|
||||
default: null
|
||||
dependencies:
|
||||
description:
|
||||
- Service dependencies that has to be started to trigger startup, separated by comma.
|
||||
required: false
|
||||
default: null
|
||||
user:
|
||||
description:
|
||||
- User to be used for service startup
|
||||
required: false
|
||||
default: null
|
||||
password:
|
||||
description:
|
||||
- Password to be used for service startup
|
||||
required: false
|
||||
default: null
|
||||
start_mode:
|
||||
description:
|
||||
- If C(auto) is selected, the service will start at bootup. C(manual) means that the service will start only when another service needs it. C(disabled) means that the service will stay off, regardless if it is needed or not.
|
||||
required: true
|
||||
default: auto
|
||||
choices:
|
||||
- auto
|
||||
- manual
|
||||
- disabled
|
||||
author:
|
||||
- "Adam Keech (@smadam813)"
|
||||
- "George Frank (@georgefrank)"
|
||||
- "Hans-Joachim Kliemeck (@h0nIg)"
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Install and start the foo service
|
||||
- win_nssm:
|
||||
name: foo
|
||||
application: C:\windows\\foo.exe
|
||||
|
||||
# Install and start the foo service with a key-value pair argument
|
||||
# This will yield the following command: C:\windows\\foo.exe bar "true"
|
||||
- win_nssm:
|
||||
name: foo
|
||||
application: C:\windows\\foo.exe
|
||||
app_parameters:
|
||||
bar: true
|
||||
|
||||
# Install and start the foo service with a key-value pair argument, where the argument needs to start with a dash
|
||||
# This will yield the following command: C:\windows\\foo.exe -bar "true"
|
||||
- win_nssm:
|
||||
name: foo
|
||||
application: C:\windows\\foo.exe
|
||||
app_parameters:
|
||||
"-bar": true
|
||||
|
||||
# Install and start the foo service with a single parameter
|
||||
# This will yield the following command: C:\windows\\foo.exe bar
|
||||
- win_nssm:
|
||||
name: foo
|
||||
application: C:\windows\\foo.exe
|
||||
app_parameters:
|
||||
_: bar
|
||||
|
||||
# Install and start the foo service with a mix of single params, and key value pairs
|
||||
# This will yield the following command: C:\windows\\foo.exe bar -file output.bat
|
||||
- win_nssm:
|
||||
name: foo
|
||||
application: C:\windows\\foo.exe
|
||||
app_parameters:
|
||||
_: bar
|
||||
"-file": "output.bat"
|
||||
|
||||
# Install and start the foo service, redirecting stdout and stderr to the same file
|
||||
- win_nssm:
|
||||
name: foo
|
||||
application: C:\windows\\foo.exe
|
||||
stdout_file: C:\windows\\foo.log
|
||||
stderr_file: C:\windows\\foo.log
|
||||
|
||||
# Install and start the foo service, but wait for dependencies tcpip and adf
|
||||
- win_nssm:
|
||||
name: foo
|
||||
application: C:\windows\\foo.exe
|
||||
dependencies: 'adf,tcpip'
|
||||
|
||||
# Install and start the foo service with dedicated user
|
||||
- win_nssm:
|
||||
name: foo
|
||||
application: C:\windows\\foo.exe
|
||||
user: foouser
|
||||
password: secret
|
||||
|
||||
# Install the foo service but do not start it automatically
|
||||
- win_nssm:
|
||||
name: foo
|
||||
application: C:\windows\\foo.exe
|
||||
state: present
|
||||
start_mode: manual
|
||||
|
||||
# Remove the foo service
|
||||
- win_nssm:
|
||||
name: foo
|
||||
state: absent
|
||||
'''
|
||||
136
lib/ansible/modules/windows/win_owner.ps1
Normal file
136
lib/ansible/modules/windows/win_owner.ps1
Normal file
@@ -0,0 +1,136 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Copyright 2015, Hans-Joachim Kliemeck <git@kliemeck.de>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
#Functions
|
||||
Function UserSearch
|
||||
{
|
||||
Param ([string]$accountName)
|
||||
#Check if there's a realm specified
|
||||
|
||||
$searchDomain = $false
|
||||
$searchDomainUPN = $false
|
||||
if ($accountName.Split("\").count -gt 1)
|
||||
{
|
||||
if ($accountName.Split("\")[0] -ne $env:COMPUTERNAME)
|
||||
{
|
||||
$searchDomain = $true
|
||||
$accountName = $accountName.split("\")[1]
|
||||
}
|
||||
}
|
||||
Elseif ($accountName.contains("@"))
|
||||
{
|
||||
$searchDomain = $true
|
||||
$searchDomainUPN = $true
|
||||
}
|
||||
Else
|
||||
{
|
||||
#Default to local user account
|
||||
$accountName = $env:COMPUTERNAME + "\" + $accountName
|
||||
}
|
||||
|
||||
if ($searchDomain -eq $false)
|
||||
{
|
||||
# do not use Win32_UserAccount, because e.g. SYSTEM (BUILTIN\SYSTEM or COMPUUTERNAME\SYSTEM) will not be listed. on Win32_Account groups will be listed too
|
||||
$localaccount = get-wmiobject -class "Win32_Account" -namespace "root\CIMV2" -filter "(LocalAccount = True)" | where {$_.Caption -eq $accountName}
|
||||
if ($localaccount)
|
||||
{
|
||||
return $localaccount.SID
|
||||
}
|
||||
}
|
||||
Else
|
||||
{
|
||||
#Search by samaccountname
|
||||
$Searcher = [adsisearcher]""
|
||||
|
||||
If ($searchDomainUPN -eq $false) {
|
||||
$Searcher.Filter = "sAMAccountName=$($accountName)"
|
||||
}
|
||||
Else {
|
||||
$Searcher.Filter = "userPrincipalName=$($accountName)"
|
||||
}
|
||||
|
||||
$result = $Searcher.FindOne()
|
||||
if ($result)
|
||||
{
|
||||
$user = $result.GetDirectoryEntry()
|
||||
|
||||
# get binary SID from AD account
|
||||
$binarySID = $user.ObjectSid.Value
|
||||
|
||||
# convert to string SID
|
||||
return (New-Object System.Security.Principal.SecurityIdentifier($binarySID,0)).Value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$params = Parse-Args $args;
|
||||
|
||||
$result = New-Object PSObject;
|
||||
Set-Attr $result "changed" $false;
|
||||
|
||||
$path = Get-Attr $params "path" -failifempty $true
|
||||
$user = Get-Attr $params "user" -failifempty $true
|
||||
$recurse = Get-Attr $params "recurse" "no" -validateSet "no","yes" -resultobj $result
|
||||
$recurse = $recurse | ConvertTo-Bool
|
||||
|
||||
If (-Not (Test-Path -Path $path)) {
|
||||
Fail-Json $result "$path file or directory does not exist on the host"
|
||||
}
|
||||
|
||||
# Test that the user/group is resolvable on the local machine
|
||||
$sid = UserSearch -AccountName ($user)
|
||||
if (!$sid)
|
||||
{
|
||||
Fail-Json $result "$user is not a valid user or group on the host machine or domain"
|
||||
}
|
||||
|
||||
Try {
|
||||
$objUser = New-Object System.Security.Principal.SecurityIdentifier($sid)
|
||||
|
||||
$file = Get-Item -Path $path
|
||||
$acl = Get-Acl $file.FullName
|
||||
|
||||
If ($acl.getOwner([System.Security.Principal.SecurityIdentifier]) -ne $objUser) {
|
||||
$acl.setOwner($objUser)
|
||||
Set-Acl $file.FullName $acl
|
||||
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
|
||||
If ($recurse) {
|
||||
$files = Get-ChildItem -Path $path -Force -Recurse
|
||||
ForEach($file in $files){
|
||||
$acl = Get-Acl $file.FullName
|
||||
|
||||
If ($acl.getOwner([System.Security.Principal.SecurityIdentifier]) -ne $objUser) {
|
||||
$acl.setOwner($objUser)
|
||||
Set-Acl $file.FullName $acl
|
||||
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Catch {
|
||||
Fail-Json $result "an error occured when attempting to change owner on $path for $user"
|
||||
}
|
||||
|
||||
Exit-Json $result
|
||||
73
lib/ansible/modules/windows/win_owner.py
Normal file
73
lib/ansible/modules/windows/win_owner.py
Normal file
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2015, Hans-Joachim Kliemeck <git@kliemeck.de>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'core',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_owner
|
||||
version_added: "2.1"
|
||||
short_description: Set owner
|
||||
description:
|
||||
- Set owner of files or directories
|
||||
options:
|
||||
path:
|
||||
description:
|
||||
- Path to be used for changing owner
|
||||
required: true
|
||||
user:
|
||||
description:
|
||||
- Name to be used for changing owner
|
||||
required: true
|
||||
recurse:
|
||||
description:
|
||||
- Indicates if the owner should be changed recursively
|
||||
required: false
|
||||
choices:
|
||||
- no
|
||||
- yes
|
||||
default: no
|
||||
author: Hans-Joachim Kliemeck (@h0nIg)
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Playbook example
|
||||
---
|
||||
- name: Change owner of Path
|
||||
win_owner:
|
||||
path: 'C:\\apache\\'
|
||||
user: apache
|
||||
recurse: yes
|
||||
|
||||
- name: Set the owner of root directory
|
||||
win_owner:
|
||||
path: 'C:\\apache\\'
|
||||
user: SYSTEM
|
||||
recurse: no
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
|
||||
'''
|
||||
1326
lib/ansible/modules/windows/win_package.ps1
Normal file
1326
lib/ansible/modules/windows/win_package.ps1
Normal file
File diff suppressed because it is too large
Load Diff
99
lib/ansible/modules/windows/win_package.py
Normal file
99
lib/ansible/modules/windows/win_package.py
Normal file
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2014, Trond Hindenes <trond@hindenes.com>, and others
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'core',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_package
|
||||
version_added: "1.7"
|
||||
author: Trond Hindenes
|
||||
short_description: Installs/Uninstalls an installable package, either from local file system or url
|
||||
description:
|
||||
- Installs or uninstalls a package.
|
||||
- 'Optionally uses a product_id to check if the package needs installing. You can find product ids for installed programs in the windows registry either in C(HKLM:Software\\Microsoft\\Windows\CurrentVersion\\Uninstall) or for 32 bit programs C(HKLM:Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall)'
|
||||
options:
|
||||
path:
|
||||
description:
|
||||
- Location of the package to be installed (either on file system, network share or url)
|
||||
required: true
|
||||
name:
|
||||
description:
|
||||
- Name of the package, if name isn't specified the path will be used for log messages
|
||||
required: false
|
||||
default: null
|
||||
product_id:
|
||||
description:
|
||||
- product id of the installed package (used for checking if already installed)
|
||||
- You can find product ids for installed programs in the windows registry either in C(HKLM:Software\\Microsoft\\Windows\CurrentVersion\\Uninstall) or for 32 bit programs C(HKLM:Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall)'
|
||||
required: true
|
||||
aliases: [productid]
|
||||
arguments:
|
||||
description:
|
||||
- Any arguments the installer needs
|
||||
default: null
|
||||
required: false
|
||||
state:
|
||||
description:
|
||||
- Install or Uninstall
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
default: present
|
||||
required: false
|
||||
aliases: [ensure]
|
||||
user_name:
|
||||
description:
|
||||
- Username of an account with access to the package if its located on a file share. Only needed if the winrm user doesn't have access to the package. Also specify user_password for this to function properly.
|
||||
default: null
|
||||
required: false
|
||||
user_password:
|
||||
description:
|
||||
- Password of an account with access to the package if its located on a file share. Only needed if the winrm user doesn't have access to the package. Also specify user_name for this to function properly.
|
||||
default: null
|
||||
required: false
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Playbook example
|
||||
- name: Install the vc thingy
|
||||
win_package:
|
||||
name="Microsoft Visual C thingy"
|
||||
path="http://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x64.exe"
|
||||
Product_Id="{CF2BEA3C-26EA-32F8-AA9B-331F7E34BA97}"
|
||||
Arguments="/install /passive /norestart"
|
||||
|
||||
# Install/uninstall an msi-based package
|
||||
- name: Install msi-based package (Remote Desktop Connection Manager)
|
||||
win_package:
|
||||
path: "https://download.microsoft.com/download/A/F/0/AF0071F3-B198-4A35-AA90-C68D103BDCCF/rdcman.msi"
|
||||
product_id: "{0240359E-6A4C-4884-9E94-B397A02D893C}"
|
||||
- name: Uninstall msi-based package
|
||||
win_package:
|
||||
path: "https://download.microsoft.com/download/A/F/0/AF0071F3-B198-4A35-AA90-C68D103BDCCF/rdcman.msi"
|
||||
product_id: "{0240359E-6A4C-4884-9E94-B397A02D893C}"
|
||||
state: absent
|
||||
'''
|
||||
|
||||
237
lib/ansible/modules/windows/win_regedit.ps1
Normal file
237
lib/ansible/modules/windows/win_regedit.ps1
Normal file
@@ -0,0 +1,237 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# (c) 2015, Adam Keech <akeech@chathamfinancial.com>, Josh Ludwig <jludwig@chathamfinancial.com>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
New-PSDrive -PSProvider registry -Root HKEY_CLASSES_ROOT -Name HKCR -ErrorAction SilentlyContinue
|
||||
New-PSDrive -PSProvider registry -Root HKEY_USERS -Name HKU -ErrorAction SilentlyContinue
|
||||
New-PSDrive -PSProvider registry -Root HKEY_CURRENT_CONFIG -Name HCCC -ErrorAction SilentlyContinue
|
||||
|
||||
$params = Parse-Args $args;
|
||||
$result = New-Object PSObject;
|
||||
Set-Attr $result "changed" $false;
|
||||
Set-Attr $result "data_changed" $false;
|
||||
Set-Attr $result "data_type_changed" $false;
|
||||
|
||||
$registryKey = Get-Attr -obj $params -name "key" -failifempty $true
|
||||
$registryValue = Get-Attr -obj $params -name "value" -default $null
|
||||
$state = Get-Attr -obj $params -name "state" -validateSet "present","absent" -default "present"
|
||||
$registryData = Get-Attr -obj $params -name "data" -default $null
|
||||
$registryDataType = Get-Attr -obj $params -name "datatype" -validateSet "binary","dword","expandstring","multistring","string","qword" -default "string"
|
||||
|
||||
If ($state -eq "present" -and $registryData -eq $null -and $registryValue -ne $null)
|
||||
{
|
||||
Fail-Json $result "missing required argument: data"
|
||||
}
|
||||
|
||||
# check the registry key is in powershell ps-drive format: HKLM, HKCU, HKU, HKCR, HCCC
|
||||
If (-not ($registryKey -match "^H[KC][CLU][MURC]{0,1}:\\"))
|
||||
{
|
||||
Fail-Json $result "key: $registryKey is not a valid powershell path, see module documentation for examples."
|
||||
}
|
||||
|
||||
|
||||
Function Test-RegistryValueData {
|
||||
Param (
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]$Path,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]$Value
|
||||
)
|
||||
Try {
|
||||
Get-ItemProperty -Path $Path -Name $Value
|
||||
Return $true
|
||||
}
|
||||
Catch {
|
||||
Return $false
|
||||
}
|
||||
}
|
||||
|
||||
# Returns true if registry data matches.
|
||||
# Handles binary, integer(dword) and string registry data
|
||||
Function Compare-RegistryData {
|
||||
Param (
|
||||
[parameter(Mandatory=$true)]
|
||||
[AllowEmptyString()]$ReferenceData,
|
||||
[parameter(Mandatory=$true)]
|
||||
[AllowEmptyString()]$DifferenceData
|
||||
)
|
||||
|
||||
if ($ReferenceData -is [String] -or $ReferenceData -is [int]) {
|
||||
if ($ReferenceData -eq $DifferenceData) {
|
||||
return $true
|
||||
} else {
|
||||
return $false
|
||||
}
|
||||
} elseif ($ReferenceData -is [Object[]]) {
|
||||
if (@(Compare-Object $ReferenceData $DifferenceData -SyncWindow 0).Length -eq 0) {
|
||||
return $true
|
||||
} else {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Simplified version of Convert-HexStringToByteArray from
|
||||
# https://cyber-defense.sans.org/blog/2010/02/11/powershell-byte-array-hex-convert
|
||||
# Expects a hex in the format you get when you run reg.exe export,
|
||||
# and converts to a byte array so powershell can modify binary registry entries
|
||||
function Convert-RegExportHexStringToByteArray
|
||||
{
|
||||
Param (
|
||||
[parameter(Mandatory=$true)] [String] $String
|
||||
)
|
||||
|
||||
# remove 'hex:' from the front of the string if present
|
||||
$String = $String.ToLower() -replace '^hex\:', ''
|
||||
|
||||
#remove whitespace and any other non-hex crud.
|
||||
$String = $String.ToLower() -replace '[^a-f0-9\\,x\-\:]',''
|
||||
|
||||
# turn commas into colons
|
||||
$String = $String -replace ',',':'
|
||||
|
||||
#Maybe there's nothing left over to convert...
|
||||
if ($String.Length -eq 0) { ,@() ; return }
|
||||
|
||||
#Split string with or without colon delimiters.
|
||||
if ($String.Length -eq 1)
|
||||
{ ,@([System.Convert]::ToByte($String,16)) }
|
||||
elseif (($String.Length % 2 -eq 0) -and ($String.IndexOf(":") -eq -1))
|
||||
{ ,@($String -split '([a-f0-9]{2})' | foreach-object { if ($_) {[System.Convert]::ToByte($_,16)}}) }
|
||||
elseif ($String.IndexOf(":") -ne -1)
|
||||
{ ,@($String -split ':+' | foreach-object {[System.Convert]::ToByte($_,16)}) }
|
||||
else
|
||||
{ ,@() }
|
||||
|
||||
}
|
||||
|
||||
if($registryDataType -eq "binary" -and $registryData -ne $null -and $registryData -is [String]) {
|
||||
$registryData = Convert-RegExportHexStringToByteArray($registryData)
|
||||
}
|
||||
|
||||
if($state -eq "present") {
|
||||
if ((Test-Path $registryKey) -and $registryValue -ne $null)
|
||||
{
|
||||
if (Test-RegistryValueData -Path $registryKey -Value $registryValue)
|
||||
{
|
||||
# handle binary data
|
||||
$currentRegistryData =(Get-ItemProperty -Path $registryKey | Select-Object -ExpandProperty $registryValue)
|
||||
|
||||
if ($registryValue.ToLower() -eq "(default)") {
|
||||
# Special case handling for the key's default property. Because .GetValueKind() doesn't work for the (default) key property
|
||||
$oldRegistryDataType = "String"
|
||||
}
|
||||
else {
|
||||
$oldRegistryDataType = (Get-Item $registryKey).GetValueKind($registryValue)
|
||||
}
|
||||
|
||||
# Changes Data and DataType
|
||||
if ($registryDataType -ne $oldRegistryDataType)
|
||||
{
|
||||
Try
|
||||
{
|
||||
Remove-ItemProperty -Path $registryKey -Name $registryValue
|
||||
New-ItemProperty -Path $registryKey -Name $registryValue -Value $registryData -PropertyType $registryDataType
|
||||
$result.changed = $true
|
||||
$result.data_changed = $true
|
||||
$result.data_type_changed = $true
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Fail-Json $result $_.Exception.Message
|
||||
}
|
||||
}
|
||||
# Changes Only Data
|
||||
elseif (-Not (Compare-RegistryData -ReferenceData $currentRegistryData -DifferenceData $registryData))
|
||||
{
|
||||
Try {
|
||||
Set-ItemProperty -Path $registryKey -Name $registryValue -Value $registryData
|
||||
$result.changed = $true
|
||||
$result.data_changed = $true
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Fail-Json $result $_.Exception.Message
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Try
|
||||
{
|
||||
New-ItemProperty -Path $registryKey -Name $registryValue -Value $registryData -PropertyType $registryDataType
|
||||
$result.changed = $true
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Fail-Json $result $_.Exception.Message
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif(-not (Test-Path $registryKey))
|
||||
{
|
||||
Try
|
||||
{
|
||||
$newRegistryKey = New-Item $registryKey -Force
|
||||
$result.changed = $true
|
||||
|
||||
if($registryValue -ne $null) {
|
||||
$newRegistryKey | New-ItemProperty -Name $registryValue -Value $registryData -Force -PropertyType $registryDataType
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Fail-Json $result $_.Exception.Message
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Test-Path $registryKey)
|
||||
{
|
||||
if ($registryValue -eq $null) {
|
||||
Try
|
||||
{
|
||||
Remove-Item -Path $registryKey -Recurse
|
||||
$result.changed = $true
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Fail-Json $result $_.Exception.Message
|
||||
}
|
||||
}
|
||||
elseif (Test-RegistryValueData -Path $registryKey -Value $registryValue) {
|
||||
Try
|
||||
{
|
||||
Remove-ItemProperty -Path $registryKey -Name $registryValue
|
||||
$result.changed = $true
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Fail-Json $result $_.Exception.Message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Exit-Json $result
|
||||
151
lib/ansible/modules/windows/win_regedit.py
Normal file
151
lib/ansible/modules/windows/win_regedit.py
Normal file
@@ -0,0 +1,151 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Adam Keech <akeech@chathamfinancial.com>, Josh Ludwig <jludwig@chathamfinancial.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'core',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_regedit
|
||||
version_added: "2.0"
|
||||
short_description: Add, Edit, or Remove Registry Keys and Values
|
||||
description:
|
||||
- Add, Edit, or Remove Registry Keys and Values using ItemProperties Cmdlets
|
||||
options:
|
||||
key:
|
||||
description:
|
||||
- Name of Registry Key
|
||||
required: true
|
||||
default: null
|
||||
aliases: []
|
||||
value:
|
||||
description:
|
||||
- Name of Registry Value
|
||||
required: true
|
||||
default: null
|
||||
aliases: []
|
||||
data:
|
||||
description:
|
||||
- Registry Value Data. Binary data should be expressed a yaml byte array or as comma separated hex values. An easy way to generate this is to run C(regedit.exe) and use the I(Export) option to save the registry values to a file. In the exported file binary values will look like C(hex:be,ef,be,ef). The C(hex:) prefix is optional.
|
||||
required: false
|
||||
default: null
|
||||
aliases: []
|
||||
datatype:
|
||||
description:
|
||||
- Registry Value Data Type
|
||||
required: false
|
||||
choices:
|
||||
- binary
|
||||
- dword
|
||||
- expandstring
|
||||
- multistring
|
||||
- string
|
||||
- qword
|
||||
default: string
|
||||
aliases: []
|
||||
state:
|
||||
description:
|
||||
- State of Registry Value
|
||||
required: false
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
default: present
|
||||
aliases: []
|
||||
author: "Adam Keech (@smadam813), Josh Ludwig (@joshludwig)"
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Creates Registry Key called MyCompany.
|
||||
win_regedit:
|
||||
key: HKCU:\Software\MyCompany
|
||||
|
||||
# Creates Registry Key called MyCompany,
|
||||
# a value within MyCompany Key called "hello", and
|
||||
# data for the value "hello" containing "world".
|
||||
win_regedit:
|
||||
key: HKCU:\Software\MyCompany
|
||||
value: hello
|
||||
data: world
|
||||
|
||||
# Creates Registry Key called MyCompany,
|
||||
# a value within MyCompany Key called "hello", and
|
||||
# data for the value "hello" containing "1337" as type "dword".
|
||||
win_regedit:
|
||||
key: HKCU:\Software\MyCompany
|
||||
value: hello
|
||||
data: 1337
|
||||
datatype: dword
|
||||
|
||||
# Creates Registry Key called MyCompany,
|
||||
# a value within MyCompany Key called "hello", and
|
||||
# binary data for the value "hello" as type "binary"
|
||||
# data expressed as comma separated list
|
||||
win_regedit:
|
||||
key: HKCU:\Software\MyCompany
|
||||
value: hello
|
||||
data: hex:be,ef,be,ef,be,ef,be,ef,be,ef
|
||||
datatype: binary
|
||||
|
||||
# Creates Registry Key called MyCompany,
|
||||
# a value within MyCompany Key called "hello", and
|
||||
# binary data for the value "hello" as type "binary"
|
||||
# data expressed as yaml array of bytes
|
||||
win_regedit:
|
||||
key: HKCU:\Software\MyCompany
|
||||
value: hello
|
||||
data: [0xbe,0xef,0xbe,0xef,0xbe,0xef,0xbe,0xef,0xbe,0xef]
|
||||
datatype: binary
|
||||
|
||||
# Delete Registry Key MyCompany
|
||||
# NOTE: Not specifying a value will delete the root key which means
|
||||
# all values will be deleted
|
||||
win_regedit:
|
||||
key: HKCU:\Software\MyCompany
|
||||
state: absent
|
||||
|
||||
# Delete Registry Value "hello" from MyCompany Key
|
||||
win_regedit:
|
||||
key: HKCU:\Software\MyCompany
|
||||
value: hello
|
||||
state: absent
|
||||
|
||||
# Ensure registry paths containing spaces are quoted.
|
||||
# Creates Registry Key called 'My Company'.
|
||||
win_regedit:
|
||||
key: 'HKCU:\Software\My Company'
|
||||
|
||||
'''
|
||||
RETURN = '''
|
||||
data_changed:
|
||||
description: whether this invocation changed the data in the registry value
|
||||
returned: success
|
||||
type: boolean
|
||||
sample: False
|
||||
data_type_changed:
|
||||
description: whether this invocation changed the datatype of the registry value
|
||||
returned: success
|
||||
type: boolean
|
||||
sample: True
|
||||
'''
|
||||
100
lib/ansible/modules/windows/win_regmerge.ps1
Normal file
100
lib/ansible/modules/windows/win_regmerge.ps1
Normal file
@@ -0,0 +1,100 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Copyright 2015, Jon Hawkesworth (@jhawkesworth) <figs@unity.demon.co.uk>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
Function Convert-RegistryPath {
|
||||
Param (
|
||||
[parameter(Mandatory=$True)]
|
||||
[ValidateNotNullOrEmpty()]$Path
|
||||
)
|
||||
|
||||
$output = $Path -replace "HKLM:", "HKLM"
|
||||
$output = $output -replace "HKCU:", "HKCU"
|
||||
|
||||
Return $output
|
||||
}
|
||||
|
||||
$params = Parse-Args $args
|
||||
$result = New-Object PSObject
|
||||
Set-Attr $result "changed" $False
|
||||
|
||||
$path = Get-Attr -obj $params -name path -failifempty $True -resultobj $result
|
||||
$compare_to = Get-Attr -obj $params -name compare_to -failifempty $False -resultobj $result
|
||||
|
||||
# check it looks like a reg key, warn if key not present - will happen first time
|
||||
# only accepting PS-Drive style key names (starting with HKLM etc, not HKEY_LOCAL_MACHINE etc)
|
||||
|
||||
$do_comparison = $False
|
||||
|
||||
If ($compare_to) {
|
||||
$compare_to_key = $params.compare_to.ToString()
|
||||
If (Test-Path $compare_to_key -pathType container ) {
|
||||
$do_comparison = $True
|
||||
} Else {
|
||||
Set-Attr $result "compare_to_key_found" $False
|
||||
}
|
||||
}
|
||||
|
||||
If ( $do_comparison -eq $True ) {
|
||||
$guid = [guid]::NewGuid()
|
||||
$exported_path = $env:TEMP + "\" + $guid.ToString() + 'ansible_win_regmerge.reg'
|
||||
|
||||
$expanded_compare_key = Convert-RegistryPath ($compare_to_key)
|
||||
|
||||
# export from the reg key location to a file
|
||||
$reg_args = @("EXPORT", "$expanded_compare_key", $exported_path)
|
||||
& reg.exe $reg_args
|
||||
|
||||
# compare the two files
|
||||
$comparison_result = Compare-Object -ReferenceObject $(Get-Content $path) -DifferenceObject $(Get-Content $exported_path)
|
||||
|
||||
If (Get-Member -InputObject $comparison_result -Name "count" -MemberType Properties )
|
||||
{
|
||||
# Something is different, actually do reg merge
|
||||
$reg_import_args = @("IMPORT", "$path")
|
||||
$ret = & reg.exe $reg_import_args 2>&1
|
||||
If ($LASTEXITCODE -eq 0) {
|
||||
Set-Attr $result "changed" $True
|
||||
Set-Attr $result "difference_count" $comparison_result.count
|
||||
} Else {
|
||||
Set-Attr $result "rc" $LASTEXITCODE
|
||||
Fail-Json $result "$ret"
|
||||
}
|
||||
} Else {
|
||||
Set-Attr $result "difference_count" 0
|
||||
}
|
||||
|
||||
Remove-Item $exported_path
|
||||
Set-Attr $result "compared" $True
|
||||
|
||||
} Else {
|
||||
# not comparing, merge and report changed
|
||||
$reg_import_args = @("IMPORT", "$path")
|
||||
$ret = & reg.exe $reg_import_args 2>&1
|
||||
If ( $LASTEXITCODE -eq 0 ) {
|
||||
Set-Attr $result "changed" $True
|
||||
Set-Attr $result "compared" $False
|
||||
} Else {
|
||||
Set-Attr $result "rc" $LASTEXITCODE
|
||||
Fail-Json $result "$ret"
|
||||
}
|
||||
}
|
||||
|
||||
Exit-Json $result
|
||||
91
lib/ansible/modules/windows/win_regmerge.py
Normal file
91
lib/ansible/modules/windows/win_regmerge.py
Normal file
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Jon Hawkesworth (@jhawkesworth) <figs@unity.demon.co.uk>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_regmerge
|
||||
version_added: "2.1"
|
||||
short_description: Merges the contents of a registry file into the windows registry
|
||||
description:
|
||||
- Wraps the reg.exe command to import the contents of a registry file.
|
||||
- Suitable for use with registry files created using M(win_template).
|
||||
- Windows registry files have a specific format and must be constructed correctly with carriage return and line feed line endings otherwise they will not be merged.
|
||||
- Exported registry files often start with a Byte Order Mark which must be removed if the file is to templated using M(win_template).
|
||||
- Registry file format is described at U(https://support.microsoft.com/en-us/kb/310516)
|
||||
- See also M(win_template), M(win_regedit)
|
||||
options:
|
||||
path:
|
||||
description:
|
||||
- The full path including file name to the registry file on the remote machine to be merged
|
||||
required: true
|
||||
default: no default
|
||||
compare_key:
|
||||
description:
|
||||
- The parent key to use when comparing the contents of the registry to the contents of the file. Needs to be in HKLM or HKCU part of registry. Use a PS-Drive style path for example HKLM:\SOFTWARE not HKEY_LOCAL_MACHINE\SOFTWARE
|
||||
If not supplied, or the registry key is not found, no comparison will be made, and the module will report changed.
|
||||
required: false
|
||||
default: no default
|
||||
author: "Jon Hawkesworth (@jhawkesworth)"
|
||||
notes:
|
||||
- Organise your registry files so that they contain a single root registry
|
||||
key if you want to use the compare_to functionality.
|
||||
This module does not force registry settings to be in the state
|
||||
described in the file. If registry settings have been modified externally
|
||||
the module will merge the contents of the file but continue to report
|
||||
differences on subsequent runs.
|
||||
To force registry change, use M(win_regedit) with state=absent before
|
||||
using M(win_regmerge).
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Merge in a registry file without comparing to current registry
|
||||
# Note that paths using / to separate are preferred as they require less special handling than \
|
||||
win_regmerge:
|
||||
path: C:/autodeploy/myCompany-settings.reg
|
||||
# Compare and merge registry file
|
||||
win_regmerge:
|
||||
path: C:/autodeploy/myCompany-settings.reg
|
||||
compare_to: HKLM:\SOFTWARE\myCompany
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
compare_to_key_found:
|
||||
description: whether the parent registry key has been found for comparison
|
||||
returned: when comparison key not found in registry
|
||||
type: boolean
|
||||
sample: false
|
||||
difference_count:
|
||||
description: number of differences between the registry and the file
|
||||
returned: changed
|
||||
type: integer
|
||||
sample: 1
|
||||
compared:
|
||||
description: whether a comparison has taken place between the registry and the file
|
||||
returned: when a comparison key has been supplied and comparison has been attempted
|
||||
type: boolean
|
||||
sample: true
|
||||
'''
|
||||
147
lib/ansible/modules/windows/win_robocopy.ps1
Normal file
147
lib/ansible/modules/windows/win_robocopy.ps1
Normal file
@@ -0,0 +1,147 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Copyright 2015, Corwin Brown <corwin.brown@maxpoint.com>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$params = Parse-Args $args;
|
||||
|
||||
$result = New-Object psobject @{
|
||||
win_robocopy = New-Object psobject @{
|
||||
recurse = $false
|
||||
purge = $false
|
||||
}
|
||||
changed = $false
|
||||
}
|
||||
|
||||
$src = Get-AnsibleParam -obj $params -name "src" -failifempty $true
|
||||
$dest = Get-AnsibleParam -obj $params -name "dest" -failifempty $true
|
||||
$purge = ConvertTo-Bool (Get-AnsibleParam -obj $params -name "purge" -default $false)
|
||||
$recurse = ConvertTo-Bool (Get-AnsibleParam -obj $params -name "recurse" -default $false)
|
||||
$flags = Get-AnsibleParam -obj $params -name "flags" -default $null
|
||||
$_ansible_check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -default $false
|
||||
|
||||
# Search for an Error Message
|
||||
# Robocopy seems to display an error after 3 '-----' separator lines
|
||||
Function SearchForError($cmd_output, $default_msg) {
|
||||
$separator_count = 0
|
||||
$error_msg = $default_msg
|
||||
ForEach ($line in $cmd_output) {
|
||||
if (-Not $line) {
|
||||
continue
|
||||
}
|
||||
|
||||
if ($separator_count -ne 3) {
|
||||
if (Select-String -InputObject $line -pattern "^(\s+)?(\-+)(\s+)?$") {
|
||||
$separator_count += 1
|
||||
}
|
||||
}
|
||||
Else {
|
||||
If (Select-String -InputObject $line -pattern "error") {
|
||||
$error_msg = $line
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $error_msg
|
||||
}
|
||||
|
||||
# Build Arguments
|
||||
$robocopy_opts = @()
|
||||
|
||||
if (-Not (Test-Path $src)) {
|
||||
Fail-Json $result "$src does not exist!"
|
||||
}
|
||||
|
||||
$robocopy_opts += $src
|
||||
Set-Attr $result.win_robocopy "src" $src
|
||||
|
||||
$robocopy_opts += $dest
|
||||
Set-Attr $result.win_robocopy "dest" $dest
|
||||
|
||||
if ($flags -eq $null) {
|
||||
if ($purge) {
|
||||
$robocopy_opts += "/purge"
|
||||
}
|
||||
|
||||
if ($recurse) {
|
||||
$robocopy_opts += "/e"
|
||||
}
|
||||
}
|
||||
Else {
|
||||
$robocopy_opts += $flags
|
||||
}
|
||||
|
||||
Set-Attr $result.win_robocopy "purge" $purge
|
||||
Set-Attr $result.win_robocopy "recurse" $recurse
|
||||
Set-Attr $result.win_robocopy "flags" $flags
|
||||
|
||||
$robocopy_output = ""
|
||||
$rc = 0
|
||||
If ($_ansible_check_mode -eq $true) {
|
||||
$robocopy_output = "Would have copied the contents of $src to $dest"
|
||||
$rc = 0
|
||||
}
|
||||
Else {
|
||||
Try {
|
||||
&robocopy $robocopy_opts | Tee-Object -Variable robocopy_output | Out-Null
|
||||
$rc = $LASTEXITCODE
|
||||
}
|
||||
Catch {
|
||||
$ErrorMessage = $_.Exception.Message
|
||||
Fail-Json $result "Error synchronizing $src to $dest! Msg: $ErrorMessage"
|
||||
}
|
||||
}
|
||||
|
||||
Set-Attr $result.win_robocopy "return_code" $rc
|
||||
Set-Attr $result.win_robocopy "output" $robocopy_output
|
||||
|
||||
$cmd_msg = "Success"
|
||||
If ($rc -eq 0) {
|
||||
$cmd_msg = "No files copied."
|
||||
}
|
||||
ElseIf ($rc -eq 1) {
|
||||
$cmd_msg = "Files copied successfully!"
|
||||
$changed = $true
|
||||
}
|
||||
ElseIf ($rc -eq 2) {
|
||||
$cmd_msg = "Extra files or directories were detected!"
|
||||
$changed = $true
|
||||
}
|
||||
ElseIf ($rc -eq 4) {
|
||||
$cmd_msg = "Some mismatched files or directories were detected!"
|
||||
$changed = $true
|
||||
}
|
||||
ElseIf ($rc -eq 8) {
|
||||
$error_msg = SearchForError $robocopy_output "Some files or directories could not be copied!"
|
||||
Fail-Json $result $error_msg
|
||||
}
|
||||
ElseIf ($rc -eq 10) {
|
||||
$error_msg = SearchForError $robocopy_output "Serious Error! No files were copied! Do you have permissions to access $src and $dest?"
|
||||
Fail-Json $result $error_msg
|
||||
}
|
||||
ElseIf ($rc -eq 16) {
|
||||
$error_msg = SearchForError $robocopy_output "Fatal Error!"
|
||||
Fail-Json $result $error_msg
|
||||
}
|
||||
|
||||
Set-Attr $result.win_robocopy "msg" $cmd_msg
|
||||
Set-Attr $result.win_robocopy "changed" $changed
|
||||
|
||||
Exit-Json $result
|
||||
147
lib/ansible/modules/windows/win_robocopy.py
Normal file
147
lib/ansible/modules/windows/win_robocopy.py
Normal file
@@ -0,0 +1,147 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Corwin Brown <blakfeld@gmail.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: win_robocopy
|
||||
version_added: "2.2"
|
||||
short_description: Synchronizes the contents of two directories using Robocopy.
|
||||
description:
|
||||
- Synchronizes the contents of two directories on the remote machine. Under the hood this just calls out to RoboCopy, since that should be available on most modern Windows Systems.
|
||||
options:
|
||||
src:
|
||||
description:
|
||||
- Source file/directory to sync.
|
||||
required: true
|
||||
dest:
|
||||
description:
|
||||
- Destination file/directory to sync (Will receive contents of src).
|
||||
required: true
|
||||
recurse:
|
||||
description:
|
||||
- Includes all subdirectories (Toggles the `/e` flag to RoboCopy). If "flags" is set, this will be ignored.
|
||||
choices:
|
||||
- true
|
||||
- false
|
||||
defaults: false
|
||||
required: false
|
||||
purge:
|
||||
description:
|
||||
- Deletes any files/directories found in the destination that do not exist in the source (Toggles the `/purge` flag to RoboCopy). If "flags" is set, this will be ignored.
|
||||
choices:
|
||||
- true
|
||||
- false
|
||||
defaults: false
|
||||
required: false
|
||||
flags:
|
||||
description:
|
||||
- Directly supply Robocopy flags. If set, purge and recurse will be ignored.
|
||||
default: None
|
||||
required: false
|
||||
author: Corwin Brown (@blakfeld)
|
||||
notes:
|
||||
- This is not a complete port of the "synchronize" module. Unlike the "synchronize" module this only performs the sync/copy on the remote machine, not from the master to the remote machine.
|
||||
- This module does not currently support all Robocopy flags.
|
||||
- Works on Windows 7, Windows 8, Windows Server 2k8, and Windows Server 2k12
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
# Syncs the contents of one diretory to another.
|
||||
$ ansible -i hosts all -m win_robocopy -a "src=C:\\DirectoryOne dest=C:\\DirectoryTwo"
|
||||
|
||||
# Sync the contents of one directory to another, including subdirectories.
|
||||
$ ansible -i hosts all -m win_robocopy -a "src=C:\\DirectoryOne dest=C:\\DirectoryTwo recurse=true"
|
||||
|
||||
# Sync the contents of one directory to another, and remove any files/directories found in destination that do not exist in the source.
|
||||
$ ansible -i hosts all -m win_robocopy -a "src=C:\\DirectoryOne dest=C:\\DirectoryTwo purge=true"
|
||||
|
||||
# Sample sync
|
||||
---
|
||||
- name: Sync Two Directories
|
||||
win_robocopy:
|
||||
src: "C:\\DirectoryOne
|
||||
dest: "C:\\DirectoryTwo"
|
||||
recurse: true
|
||||
purge: true
|
||||
|
||||
---
|
||||
- name: Sync Two Directories
|
||||
win_robocopy:
|
||||
src: "C:\\DirectoryOne
|
||||
dest: "C:\\DirectoryTwo"
|
||||
recurse: true
|
||||
purge: true
|
||||
flags: '/XD SOME_DIR /XF SOME_FILE /MT:32'
|
||||
"""
|
||||
|
||||
RETURN = '''
|
||||
src:
|
||||
description: The Source file/directory of the sync.
|
||||
returned: always
|
||||
type: string
|
||||
sample: "c:/Some/Path"
|
||||
dest:
|
||||
description: The Destination file/directory of the sync.
|
||||
returned: always
|
||||
type: string
|
||||
sample: "c:/Some/Path"
|
||||
recurse:
|
||||
description: Whether or not the recurse flag was toggled.
|
||||
returned: always
|
||||
type: bool
|
||||
sample: False
|
||||
purge:
|
||||
description: Whether or not the purge flag was toggled.
|
||||
returned: always
|
||||
type: bool
|
||||
sample: False
|
||||
flags:
|
||||
description: Any flags passed in by the user.
|
||||
returned: always
|
||||
type: string
|
||||
sample: "/e /purge"
|
||||
return_code:
|
||||
description: The return code retuned by robocopy.
|
||||
returned: success
|
||||
type: int
|
||||
sample: 1
|
||||
output:
|
||||
description: The output of running the robocopy command.
|
||||
returned: success
|
||||
type: string
|
||||
sample: "-------------------------------------------------------------------------------\n ROBOCOPY :: Robust File Copy for Windows \n-------------------------------------------------------------------------------\n"
|
||||
msg:
|
||||
description: Output intrepreted into a concise message.
|
||||
returned: always
|
||||
type: string
|
||||
sample: No files copied!
|
||||
changed:
|
||||
description: Whether or not any changes were made.
|
||||
returned: always
|
||||
type: bool
|
||||
sample: False
|
||||
'''
|
||||
106
lib/ansible/modules/windows/win_say.ps1
Normal file
106
lib/ansible/modules/windows/win_say.ps1
Normal file
@@ -0,0 +1,106 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Copyright 2016, Jon Hawkesworth (@jhawkesworth) <figs@unity.demon.co.uk>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$params = Parse-Args $args;
|
||||
$result = New-Object PSObject;
|
||||
$msg = Get-AnsibleParam -obj $params -name "msg"
|
||||
$msg_file = Get-AnsibleParam -obj $params -name "msg_file"
|
||||
$start_sound_path = Get-AnsibleParam -obj $params -name "start_sound_path"
|
||||
$end_sound_path = Get-AnsibleParam -obj $params -name "end_sound_path"
|
||||
$voice = Get-AnsibleParam -obj $params -name "voice"
|
||||
$speech_speed = Get-AnsibleParam -obj $params -name "speech_speed"
|
||||
$speed = 0
|
||||
$words = $null
|
||||
|
||||
if ($speech_speed -ne $null) {
|
||||
try {
|
||||
$speed = [convert]::ToInt32($speech_speed, 10)
|
||||
} catch {
|
||||
Fail-Json $result "speech_speed needs to a integer in the range -10 to 10. The value $speech_speed could not be converted to an integer."
|
||||
|
||||
}
|
||||
if ($speed -lt -10 -or $speed -gt 10) {
|
||||
Fail-Json $result "speech_speed needs to a integer in the range -10 to 10. The value $speech_speed is outside this range."
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($msg_file -ne $null -and $msg -ne $null ) {
|
||||
Fail-Json $result "Please specify either msg_file or msg parameters, not both"
|
||||
}
|
||||
|
||||
if ($msg_file -eq $null -and $msg -eq $null -and $start_sound_path -eq $null -and $end_sound_path -eq $null) {
|
||||
Fail-Json $result "No msg_file, msg, start_sound_path, or end_sound_path parameters have been specified. Please specify at least one so the module has something to do"
|
||||
|
||||
}
|
||||
|
||||
|
||||
if ($msg_file -ne $null) {
|
||||
if (Test-Path $msg_file) {
|
||||
$words = Get-Content $msg_file | Out-String
|
||||
} else {
|
||||
Fail-Json $result "Message file $msg_file could not be found or opened. Ensure you have specified the full path to the file, and the ansible windows user has permission to read the file."
|
||||
}
|
||||
}
|
||||
|
||||
if ($start_sound_path -ne $null) {
|
||||
if (Test-Path $start_sound_path) {
|
||||
(new-object Media.SoundPlayer $start_sound_path).playSync();
|
||||
} else {
|
||||
Fail-Json $result "Start sound file $start_sound_path could not be found or opened. Ensure you have specified the full path to the file, and the ansible windows user has permission to read the file."
|
||||
}
|
||||
}
|
||||
|
||||
if ($msg -ne $null) {
|
||||
$words = $msg
|
||||
}
|
||||
|
||||
if ($words -ne $null) {
|
||||
Add-Type -AssemblyName System.speech
|
||||
$tts = New-Object System.Speech.Synthesis.SpeechSynthesizer
|
||||
if ($voice -ne $null) {
|
||||
try {
|
||||
$tts.SelectVoice($voice)
|
||||
} catch [System.Management.Automation.MethodInvocationException] {
|
||||
Set-Attr $result "voice_info" "Could not load voice $voice, using system default voice."
|
||||
}
|
||||
}
|
||||
|
||||
Set-Attr $result "voice" $tts.Voice.Name
|
||||
if ($speed -ne 0) {
|
||||
$tts.Rate = $speed
|
||||
}
|
||||
$tts.Speak($words)
|
||||
$tts.Dispose()
|
||||
}
|
||||
|
||||
if ($end_sound_path -ne $null) {
|
||||
if (Test-Path $end_sound_path) {
|
||||
(new-object Media.SoundPlayer $end_sound_path).playSync();
|
||||
} else {
|
||||
Fail-Json $result "End sound file $start_sound_path could not be found or opened. Ensure you have specified the full path to the file, and the ansible windows user has permission to read the file."
|
||||
}
|
||||
}
|
||||
|
||||
Set-Attr $result "changed" $false;
|
||||
Set-Attr $result "message_text" $words;
|
||||
|
||||
Exit-Json $result;
|
||||
114
lib/ansible/modules/windows/win_say.py
Normal file
114
lib/ansible/modules/windows/win_say.py
Normal file
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2016, Jon Hawkesworth (@jhawkesworth) <figs@unity.demon.co.uk>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_say
|
||||
version_added: "2.3"
|
||||
short_description: Text to speech module for Windows to speak messages and optionally play sounds
|
||||
description:
|
||||
- Uses .NET libraries to convert text to speech and optionally play .wav sounds. Audio Service needs to be running and some kind of speakers or headphones need to be attached to the windows target(s) for the speech to be audible.
|
||||
options:
|
||||
msg:
|
||||
description:
|
||||
- The text to be spoken. Use either msg or msg_file. Optional so that you can use this module just to play sounds.
|
||||
required: false
|
||||
default: none
|
||||
msg_file:
|
||||
description:
|
||||
- Full path to a windows format text file containing the text to be spokend. Use either msg or msg_file. Optional so that you can use this module just to play sounds.
|
||||
required: false
|
||||
default: none
|
||||
voice:
|
||||
description:
|
||||
- Which voice to use. See notes for how to discover installed voices. If the requested voice is not available the default voice will be used. Example voice names from Windows 10 are 'Microsoft Zira Desktop' and 'Microsoft Hazel Desktop'.
|
||||
required: false
|
||||
default: system default voice
|
||||
speech_speed:
|
||||
description:
|
||||
- How fast or slow to speak the text. Must be an integer value in the range -10 to 10. -10 is slowest, 10 is fastest.
|
||||
required: false
|
||||
default: 0
|
||||
start_sound_path:
|
||||
description:
|
||||
- Full path to a C(.wav) file containing a sound to play before the text is spoken. Useful on conference calls to alert other speakers that ansible has something to say.
|
||||
required: false
|
||||
default: null
|
||||
end_sound_path:
|
||||
description:
|
||||
- Full path to a C(.wav) file containing a sound to play after the text has been spoken. Useful on conference calls to alert other speakers that ansible has finished speaking.
|
||||
required: false
|
||||
default: null
|
||||
author: "Jon Hawkesworth (@jhawkesworth)"
|
||||
notes:
|
||||
- Needs speakers or headphones to do anything useful.
|
||||
- To find which voices are installed, run the following powershell
|
||||
Add-Type -AssemblyName System.Speech
|
||||
$speech = New-Object -TypeName System.Speech.Synthesis.SpeechSynthesizer
|
||||
$speech.GetInstalledVoices() | ForEach-Object { $_.VoiceInfo }
|
||||
$speech.Dispose()
|
||||
- Speech can be surprisingly slow, so its best to keep message text short.
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Warn of impending deployment
|
||||
- win_say:
|
||||
msg: Warning, deployment commencing in 5 minutes, please log out.
|
||||
# Using a different voice and a start sound
|
||||
- win_say:
|
||||
start_sound_path: 'C:\Windows\Media\ding.wav'
|
||||
msg: Warning, deployment commencing in 5 minutes, please log out.
|
||||
voice: Microsoft Hazel Desktop
|
||||
# example with start and end sound
|
||||
- win_say:
|
||||
start_sound_path: 'C:\Windows\Media\Windows Balloon.wav'
|
||||
msg: "New software installed"
|
||||
end_sound_path: 'C:\Windows\Media\chimes.wav'
|
||||
# text from file example
|
||||
- win_say:
|
||||
start_sound_path: 'C:\Windows\Media\Windows Balloon.wav'
|
||||
msg_file: AppData\Local\Temp\morning_report.txt
|
||||
end_sound_path: 'C:\Windows\Media\chimes.wav'
|
||||
'''
|
||||
RETURN = '''
|
||||
message_text:
|
||||
description: the text that the module attempted to speak
|
||||
returned: success
|
||||
type: string
|
||||
sample: "Warning, deployment commencing in 5 minutes."
|
||||
voice:
|
||||
description: the voice used to speak the text.
|
||||
returned: success
|
||||
type: string
|
||||
sample: Microsoft Hazel Desktop
|
||||
voice_info:
|
||||
description: the voice used to speak the text.
|
||||
returned: when requested voice could not be loaded
|
||||
type: string
|
||||
sample: Could not load voice TestVoice, using system default voice
|
||||
'''
|
||||
|
||||
164
lib/ansible/modules/windows/win_scheduled_task.ps1
Normal file
164
lib/ansible/modules/windows/win_scheduled_task.ps1
Normal file
@@ -0,0 +1,164 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Copyright 2015, Peter Mounce <public@neverrunwithscissors.com>
|
||||
# Michael Perzel <michaelperzel@gmail.com>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$params = Parse-Args $args;
|
||||
|
||||
$days_of_week = Get-AnsibleParam $params -name "days_of_week"
|
||||
$enabled = Get-AnsibleParam $params -name "enabled" -default $true
|
||||
$enabled = $enabled | ConvertTo-Bool
|
||||
$description = Get-AnsibleParam $params -name "description" -default " "
|
||||
$path = Get-AnsibleParam $params -name "path"
|
||||
$argument = Get-AnsibleParam $params -name "argument"
|
||||
|
||||
$result = New-Object PSObject;
|
||||
Set-Attr $result "changed" $false;
|
||||
|
||||
#Required vars
|
||||
$name = Get-AnsibleParam -obj $params -name name -failifempty $true -resultobj $result
|
||||
$state = Get-AnsibleParam -obj $params -name state -failifempty $true -resultobj $result -validateSet "present","absent"
|
||||
|
||||
#Vars conditionally required
|
||||
$present_args_required = $state -eq "present"
|
||||
$execute = Get-AnsibleParam -obj $params -name execute -failifempty $present_args_required -resultobj $result
|
||||
$frequency = Get-AnsibleParam -obj $params -name frequency -failifempty $present_args_required -resultobj $result
|
||||
$time = Get-AnsibleParam -obj $params -name time -failifempty $present_args_required -resultobj $result
|
||||
$user = Get-AnsibleParam -obj $params -name user -failifempty $present_args_required -resultobj $result
|
||||
|
||||
|
||||
# Mandatory Vars
|
||||
if ($frequency -eq "weekly")
|
||||
{
|
||||
if (!($days_of_week))
|
||||
{
|
||||
Fail-Json $result "missing required argument: days_of_week"
|
||||
}
|
||||
}
|
||||
|
||||
if ($path)
|
||||
{
|
||||
$path = "\{0}\" -f $path
|
||||
}
|
||||
else
|
||||
{
|
||||
$path = "\" #default
|
||||
}
|
||||
|
||||
try {
|
||||
$task = Get-ScheduledTask -TaskPath "$path" | Where-Object {$_.TaskName -eq "$name"}
|
||||
|
||||
# Correlate task state to enable variable, used to calculate if state needs to be changed
|
||||
$taskState = if ($task) { $task.State } else { $null }
|
||||
if ($taskState -eq "Ready"){
|
||||
$taskState = $true
|
||||
}
|
||||
elseif($taskState -eq "Disabled"){
|
||||
$taskState = $false
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskState = $null
|
||||
}
|
||||
|
||||
$measure = $task | measure
|
||||
if ($measure.count -eq 1 ) {
|
||||
$exists = $true
|
||||
}
|
||||
elseif ( ($measure.count -eq 0) -and ($state -eq "absent") ){
|
||||
Set-Attr $result "msg" "Task does not exist"
|
||||
Exit-Json $result
|
||||
}
|
||||
elseif ($measure.count -eq 0){
|
||||
$exists = $false
|
||||
}
|
||||
else {
|
||||
# This should never occur
|
||||
Fail-Json $result "$($measure.count) scheduled tasks found"
|
||||
}
|
||||
|
||||
Set-Attr $result "exists" "$exists"
|
||||
|
||||
if ($frequency){
|
||||
if ($frequency -eq "daily") {
|
||||
$trigger = New-ScheduledTaskTrigger -Daily -At $time
|
||||
}
|
||||
elseif ($frequency -eq "weekly"){
|
||||
$trigger = New-ScheduledTaskTrigger -Weekly -At $time -DaysOfWeek $days_of_week
|
||||
}
|
||||
else {
|
||||
Fail-Json $result "frequency must be daily or weekly"
|
||||
}
|
||||
}
|
||||
|
||||
if ( ($state -eq "absent") -and ($exists -eq $true) ) {
|
||||
Unregister-ScheduledTask -TaskName $name -Confirm:$false
|
||||
$result.changed = $true
|
||||
Set-Attr $result "msg" "Deleted task $name"
|
||||
Exit-Json $result
|
||||
}
|
||||
elseif ( ($state -eq "absent") -and ($exists -eq $false) ) {
|
||||
Set-Attr $result "msg" "Task $name does not exist"
|
||||
Exit-Json $result
|
||||
}
|
||||
|
||||
$principal = New-ScheduledTaskPrincipal -UserId "$user" -LogonType ServiceAccount
|
||||
|
||||
if ($enabled -eq $false){
|
||||
$settings = New-ScheduledTaskSettingsSet -Disable
|
||||
}
|
||||
else {
|
||||
$settings = New-ScheduledTaskSettingsSet
|
||||
}
|
||||
|
||||
if ($argument) {
|
||||
$action = New-ScheduledTaskAction -Execute $execute -Argument $argument
|
||||
}
|
||||
else {
|
||||
$action = New-ScheduledTaskAction -Execute $execute
|
||||
}
|
||||
|
||||
if ( ($state -eq "present") -and ($exists -eq $false) ){
|
||||
Register-ScheduledTask -Action $action -Trigger $trigger -TaskName $name -Description $description -TaskPath $path -Settings $settings -Principal $principal
|
||||
$task = Get-ScheduledTask -TaskName $name
|
||||
Set-Attr $result "msg" "Added new task $name"
|
||||
$result.changed = $true
|
||||
}
|
||||
elseif( ($state -eq "present") -and ($exists -eq $true) ) {
|
||||
if ($task.Description -eq $description -and $task.TaskName -eq $name -and $task.TaskPath -eq $path -and $task.Actions.Execute -eq $execute -and $taskState -eq $enabled -and $task.Principal.UserId -eq $user) {
|
||||
#No change in the task
|
||||
Set-Attr $result "msg" "No change in task $name"
|
||||
}
|
||||
else {
|
||||
Unregister-ScheduledTask -TaskName $name -Confirm:$false
|
||||
Register-ScheduledTask -Action $action -Trigger $trigger -TaskName $name -Description $description -TaskPath $path -Settings $settings -Principal $principal
|
||||
Set-Attr $result "msg" "Updated task $name"
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
|
||||
Exit-Json $result;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Fail-Json $result $_.Exception.Message
|
||||
}
|
||||
102
lib/ansible/modules/windows/win_scheduled_task.py
Normal file
102
lib/ansible/modules/windows/win_scheduled_task.py
Normal file
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_scheduled_task
|
||||
version_added: "2.0"
|
||||
short_description: Manage scheduled tasks
|
||||
description:
|
||||
- Manage scheduled tasks
|
||||
notes:
|
||||
- This module requires Windows Server 2012 or later.
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Name of the scheduled task
|
||||
required: true
|
||||
description:
|
||||
description:
|
||||
- The description for the scheduled task
|
||||
required: false
|
||||
enabled:
|
||||
description:
|
||||
- Enable/disable the task
|
||||
choices:
|
||||
- yes
|
||||
- no
|
||||
default: yes
|
||||
state:
|
||||
description:
|
||||
- State that the task should become
|
||||
required: true
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
user:
|
||||
description:
|
||||
- User to run scheduled task as
|
||||
required: false
|
||||
execute:
|
||||
description:
|
||||
- Command the scheduled task should execute
|
||||
required: false
|
||||
argument:
|
||||
description:
|
||||
- Arguments to provide scheduled task action
|
||||
required: false
|
||||
frequency:
|
||||
description:
|
||||
- The frequency of the command, not idempotent
|
||||
required: false
|
||||
choices:
|
||||
- daily
|
||||
- weekly
|
||||
time:
|
||||
description:
|
||||
- Time to execute scheduled task, not idempotent
|
||||
required: false
|
||||
days_of_week:
|
||||
description:
|
||||
- Days of the week to run a weekly task, not idempotent
|
||||
required: false
|
||||
path:
|
||||
description:
|
||||
- Task folder in which this task will be stored
|
||||
default: '\'
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Create a scheduled task to open a command prompt
|
||||
- win_scheduled_task:
|
||||
name: TaskName
|
||||
execute: cmd
|
||||
frequency: daily
|
||||
time: 9am
|
||||
description: open command prompt
|
||||
path: example
|
||||
enable: yes
|
||||
state: present
|
||||
user: SYSTEM
|
||||
'''
|
||||
251
lib/ansible/modules/windows/win_share.ps1
Normal file
251
lib/ansible/modules/windows/win_share.ps1
Normal file
@@ -0,0 +1,251 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
|
||||
# Copyright 2015, Hans-Joachim Kliemeck <git@kliemeck.de>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
#Functions
|
||||
Function UserSearch
|
||||
{
|
||||
Param ([string]$accountName)
|
||||
#Check if there's a realm specified
|
||||
|
||||
$searchDomain = $false
|
||||
$searchDomainUPN = $false
|
||||
if ($accountName.Split("\").count -gt 1)
|
||||
{
|
||||
if ($accountName.Split("\")[0] -ne $env:COMPUTERNAME)
|
||||
{
|
||||
$searchDomain = $true
|
||||
$accountName = $accountName.split("\")[1]
|
||||
}
|
||||
}
|
||||
Elseif ($accountName.contains("@"))
|
||||
{
|
||||
$searchDomain = $true
|
||||
$searchDomainUPN = $true
|
||||
}
|
||||
Else
|
||||
{
|
||||
#Default to local user account
|
||||
$accountName = $env:COMPUTERNAME + "\" + $accountName
|
||||
}
|
||||
|
||||
if ($searchDomain -eq $false)
|
||||
{
|
||||
# do not use Win32_UserAccount, because e.g. SYSTEM (BUILTIN\SYSTEM or COMPUUTERNAME\SYSTEM) will not be listed. on Win32_Account groups will be listed too
|
||||
$localaccount = get-wmiobject -class "Win32_Account" -namespace "root\CIMV2" -filter "(LocalAccount = True)" | where {$_.Caption -eq $accountName}
|
||||
if ($localaccount)
|
||||
{
|
||||
return $localaccount.SID
|
||||
}
|
||||
}
|
||||
Else
|
||||
{
|
||||
#Search by samaccountname
|
||||
$Searcher = [adsisearcher]""
|
||||
|
||||
If ($searchDomainUPN -eq $false) {
|
||||
$Searcher.Filter = "sAMAccountName=$($accountName)"
|
||||
}
|
||||
Else {
|
||||
$Searcher.Filter = "userPrincipalName=$($accountName)"
|
||||
}
|
||||
|
||||
$result = $Searcher.FindOne()
|
||||
if ($result)
|
||||
{
|
||||
$user = $result.GetDirectoryEntry()
|
||||
|
||||
# get binary SID from AD account
|
||||
$binarySID = $user.ObjectSid.Value
|
||||
|
||||
# convert to string SID
|
||||
return (New-Object System.Security.Principal.SecurityIdentifier($binarySID,0)).Value
|
||||
}
|
||||
}
|
||||
}
|
||||
Function NormalizeAccounts
|
||||
{
|
||||
param(
|
||||
[parameter(valuefrompipeline=$true)]
|
||||
$users
|
||||
)
|
||||
|
||||
$users = $users.Trim()
|
||||
If ($users -eq "") {
|
||||
$splittedUsers = [Collections.Generic.List[String]] @()
|
||||
}
|
||||
Else {
|
||||
$splittedUsers = [Collections.Generic.List[String]] $users.Split(",")
|
||||
}
|
||||
|
||||
$normalizedUsers = [Collections.Generic.List[String]] @()
|
||||
ForEach($splittedUser in $splittedUsers) {
|
||||
$sid = UserSearch $splittedUser
|
||||
If (!$sid) {
|
||||
Fail-Json $result "$splittedUser is not a valid user or group on the host machine or domain"
|
||||
}
|
||||
|
||||
$normalizedUser = (New-Object System.Security.Principal.SecurityIdentifier($sid)).Translate([System.Security.Principal.NTAccount])
|
||||
$normalizedUsers.Add($normalizedUser)
|
||||
}
|
||||
|
||||
return ,$normalizedUsers
|
||||
}
|
||||
|
||||
$params = Parse-Args $args;
|
||||
|
||||
$result = New-Object PSObject;
|
||||
Set-Attr $result "changed" $false;
|
||||
|
||||
$name = Get-Attr $params "name" -failifempty $true
|
||||
$state = Get-Attr $params "state" "present" -validateSet "present","absent" -resultobj $result
|
||||
|
||||
Try {
|
||||
$share = Get-SmbShare $name -ErrorAction SilentlyContinue
|
||||
If ($state -eq "absent") {
|
||||
If ($share) {
|
||||
Remove-SmbShare -Force -Name $name
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
}
|
||||
Else {
|
||||
$path = Get-Attr $params "path" -failifempty $true
|
||||
$description = Get-Attr $params "description" ""
|
||||
|
||||
$permissionList = Get-Attr $params "list" "no" -validateSet "no","yes" -resultobj $result | ConvertTo-Bool
|
||||
$folderEnum = if ($permissionList) { "Unrestricted" } else { "AccessBased" }
|
||||
|
||||
$permissionRead = Get-Attr $params "read" "" | NormalizeAccounts
|
||||
$permissionChange = Get-Attr $params "change" "" | NormalizeAccounts
|
||||
$permissionFull = Get-Attr $params "full" "" | NormalizeAccounts
|
||||
$permissionDeny = Get-Attr $params "deny" "" | NormalizeAccounts
|
||||
|
||||
If (-Not (Test-Path -Path $path)) {
|
||||
Fail-Json $result "$path directory does not exist on the host"
|
||||
}
|
||||
|
||||
# normalize path and remove slash at the end
|
||||
$path = (Get-Item $path).FullName -replace "\\$"
|
||||
|
||||
# need to (re-)create share
|
||||
If (!$share) {
|
||||
New-SmbShare -Name $name -Path $path
|
||||
$share = Get-SmbShare $name -ErrorAction SilentlyContinue
|
||||
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
If ($share.Path -ne $path) {
|
||||
Remove-SmbShare -Force -Name $name
|
||||
|
||||
New-SmbShare -Name $name -Path $path
|
||||
$share = Get-SmbShare $name -ErrorAction SilentlyContinue
|
||||
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
|
||||
# updates
|
||||
If ($share.Description -ne $description) {
|
||||
Set-SmbShare -Force -Name $name -Description $description
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
If ($share.FolderEnumerationMode -ne $folderEnum) {
|
||||
Set-SmbShare -Force -Name $name -FolderEnumerationMode $folderEnum
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
|
||||
# clean permissions that imply others
|
||||
ForEach ($user in $permissionFull) {
|
||||
$permissionChange.remove($user)
|
||||
$permissionRead.remove($user)
|
||||
}
|
||||
ForEach ($user in $permissionChange) {
|
||||
$permissionRead.remove($user)
|
||||
}
|
||||
|
||||
# remove permissions
|
||||
$permissions = Get-SmbShareAccess -Name $name
|
||||
ForEach ($permission in $permissions) {
|
||||
If ($permission.AccessControlType -eq "Deny") {
|
||||
If (!$permissionDeny.Contains($permission.AccountName)) {
|
||||
Unblock-SmbShareAccess -Force -Name $name -AccountName $permission.AccountName
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
}
|
||||
ElseIf ($permission.AccessControlType -eq "Allow") {
|
||||
If ($permission.AccessRight -eq "Full") {
|
||||
If (!$permissionFull.Contains($permission.AccountName)) {
|
||||
Revoke-SmbShareAccess -Force -Name $name -AccountName $permission.AccountName
|
||||
Set-Attr $result "changed" $true;
|
||||
|
||||
Continue
|
||||
}
|
||||
|
||||
# user got requested permissions
|
||||
$permissionFull.remove($permission.AccountName)
|
||||
}
|
||||
ElseIf ($permission.AccessRight -eq "Change") {
|
||||
If (!$permissionChange.Contains($permission.AccountName)) {
|
||||
Revoke-SmbShareAccess -Force -Name $name -AccountName $permission.AccountName
|
||||
Set-Attr $result "changed" $true;
|
||||
|
||||
Continue
|
||||
}
|
||||
|
||||
# user got requested permissions
|
||||
$permissionChange.remove($permission.AccountName)
|
||||
}
|
||||
ElseIf ($permission.AccessRight -eq "Read") {
|
||||
If (!$permissionRead.Contains($permission.AccountName)) {
|
||||
Revoke-SmbShareAccess -Force -Name $name -AccountName $permission.AccountName
|
||||
Set-Attr $result "changed" $true;
|
||||
|
||||
Continue
|
||||
}
|
||||
|
||||
# user got requested permissions
|
||||
$permissionRead.Remove($permission.AccountName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# add missing permissions
|
||||
ForEach ($user in $permissionRead) {
|
||||
Grant-SmbShareAccess -Force -Name $name -AccountName $user -AccessRight "Read"
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
ForEach ($user in $permissionChange) {
|
||||
Grant-SmbShareAccess -Force -Name $name -AccountName $user -AccessRight "Change"
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
ForEach ($user in $permissionFull) {
|
||||
Grant-SmbShareAccess -Force -Name $name -AccountName $user -AccessRight "Full"
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
ForEach ($user in $permissionDeny) {
|
||||
Block-SmbShareAccess -Force -Name $name -AccountName $user
|
||||
Set-Attr $result "changed" $true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Catch {
|
||||
Fail-Json $result "an error occured when attempting to create share $name"
|
||||
}
|
||||
|
||||
Exit-Json $result
|
||||
121
lib/ansible/modules/windows/win_share.py
Normal file
121
lib/ansible/modules/windows/win_share.py
Normal file
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2015, Hans-Joachim Kliemeck <git@kliemeck.de>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'core',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_share
|
||||
version_added: "2.1"
|
||||
short_description: Manage Windows shares
|
||||
description:
|
||||
- Add, modify or remove Windows share and set share permissions.
|
||||
requirements:
|
||||
- Windows 8.1 / Windows 2012 or newer
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Share name
|
||||
required: yes
|
||||
path:
|
||||
description:
|
||||
- Share directory
|
||||
required: yes
|
||||
state:
|
||||
description:
|
||||
- Specify whether to add C(present) or remove C(absent) the specified share
|
||||
required: no
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
default: present
|
||||
description:
|
||||
description:
|
||||
- Share description
|
||||
required: no
|
||||
default: none
|
||||
list:
|
||||
description:
|
||||
- Specify whether to allow or deny file listing, in case user got no permission on share
|
||||
required: no
|
||||
choices:
|
||||
- yes
|
||||
- no
|
||||
default: none
|
||||
read:
|
||||
description:
|
||||
- Specify user list that should get read access on share, separated by comma.
|
||||
required: no
|
||||
default: none
|
||||
change:
|
||||
description:
|
||||
- Specify user list that should get read and write access on share, separated by comma.
|
||||
required: no
|
||||
default: none
|
||||
full:
|
||||
description:
|
||||
- Specify user list that should get full access on share, separated by comma.
|
||||
required: no
|
||||
default: none
|
||||
deny:
|
||||
description:
|
||||
- Specify user list that should get no access, regardless of implied access on share, separated by comma.
|
||||
required: no
|
||||
default: none
|
||||
author: Hans-Joachim Kliemeck (@h0nIg)
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Playbook example
|
||||
# Add share and set permissions
|
||||
---
|
||||
- name: Add secret share
|
||||
win_share:
|
||||
name: internal
|
||||
description: top secret share
|
||||
path: C:/shares/internal
|
||||
list: 'no'
|
||||
full: Administrators,CEO
|
||||
read: HR-Global
|
||||
deny: HR-External
|
||||
|
||||
- name: Add public company share
|
||||
win_share:
|
||||
name: company
|
||||
description: top secret share
|
||||
path: C:/shares/company
|
||||
list: 'yes'
|
||||
full: Administrators,CEO
|
||||
read: Global
|
||||
|
||||
# Remove previously added share
|
||||
win_share:
|
||||
name: internal
|
||||
state: absent
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
|
||||
'''
|
||||
71
lib/ansible/modules/windows/win_timezone.ps1
Normal file
71
lib/ansible/modules/windows/win_timezone.ps1
Normal file
@@ -0,0 +1,71 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Copyright 2015, Phil Schwartz <schwartzmx@gmail.com>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$params = Parse-Args $args;
|
||||
|
||||
$result = New-Object psobject @{
|
||||
win_timezone = New-Object psobject
|
||||
changed = $false
|
||||
}
|
||||
|
||||
$timezone = Get-Attr -obj $params -name timezone -failifempty $true -resultobj $result
|
||||
|
||||
Try {
|
||||
# Get the current timezone set
|
||||
$currentTZ = $(tzutil.exe /g)
|
||||
If ($LASTEXITCODE -ne 0) { Throw "An error occured when getting the current machine's timezone setting." }
|
||||
|
||||
If ( $currentTZ -eq $timezone ) {
|
||||
Exit-Json $result "$timezone is already set on this machine"
|
||||
}
|
||||
Else {
|
||||
$tzExists = $false
|
||||
#Check that timezone can even be set (if it is listed from tzutil as an available timezone to the machine)
|
||||
$tzList = $(tzutil.exe /l)
|
||||
If ($LASTEXITCODE -ne 0) { Throw "An error occured when listing the available timezones." }
|
||||
ForEach ($tz in $tzList) {
|
||||
If ( $tz -eq $timezone ) {
|
||||
$tzExists = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
If ( $tzExists ) {
|
||||
tzutil.exe /s "$timezone"
|
||||
If ($LASTEXITCODE -ne 0) { Throw "An error occured when setting the specified timezone with tzutil." }
|
||||
$newTZ = $(tzutil.exe /g)
|
||||
If ($LASTEXITCODE -ne 0) { Throw "An error occured when getting the current machine's timezone setting." }
|
||||
|
||||
If ( $timezone -eq $newTZ ) {
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
Else {
|
||||
Fail-Json $result "The specified timezone: $timezone isn't supported on the machine."
|
||||
}
|
||||
}
|
||||
}
|
||||
Catch {
|
||||
Fail-Json $result "Error setting timezone to: $timezone."
|
||||
}
|
||||
|
||||
|
||||
Exit-Json $result;
|
||||
53
lib/ansible/modules/windows/win_timezone.py
Normal file
53
lib/ansible/modules/windows/win_timezone.py
Normal file
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Phil Schwartz <schwartzmx@gmail.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_timezone
|
||||
version_added: "2.1"
|
||||
short_description: Sets Windows machine timezone
|
||||
description:
|
||||
- Sets machine time to the specified timezone, the module will check if the provided timezone is supported on the machine.
|
||||
options:
|
||||
timezone:
|
||||
description:
|
||||
- Timezone to set to. Example Central Standard Time
|
||||
required: true
|
||||
default: null
|
||||
aliases: []
|
||||
|
||||
author: Phil Schwartz
|
||||
'''
|
||||
|
||||
|
||||
EXAMPLES = '''
|
||||
# Set machine's timezone to Central Standard Time
|
||||
win_timezone:
|
||||
timezone: "Central Standard Time"
|
||||
'''
|
||||
|
||||
RETURN = '''# '''
|
||||
142
lib/ansible/modules/windows/win_unzip.ps1
Normal file
142
lib/ansible/modules/windows/win_unzip.ps1
Normal file
@@ -0,0 +1,142 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Copyright 2015, Phil Schwartz <schwartzmx@gmail.com>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
|
||||
$params = Parse-Args $args;
|
||||
|
||||
$result = New-Object psobject @{
|
||||
win_unzip = New-Object psobject
|
||||
changed = $false
|
||||
}
|
||||
|
||||
$creates = Get-AnsibleParam -obj $params -name "creates"
|
||||
If ($creates -ne $null) {
|
||||
If (Test-Path $params.creates) {
|
||||
Exit-Json $result "The 'creates' file or directory already exists."
|
||||
}
|
||||
}
|
||||
|
||||
$src = Get-AnsibleParam -obj $params -name "src" -failifempty $true
|
||||
If (-Not (Test-Path -path $src)){
|
||||
Fail-Json $result "src file: $src does not exist."
|
||||
}
|
||||
|
||||
$ext = [System.IO.Path]::GetExtension($src)
|
||||
|
||||
|
||||
$dest = Get-AnsibleParam -obj $params -name "dest" -failifempty $true
|
||||
If (-Not (Test-Path $dest -PathType Container)){
|
||||
Try{
|
||||
New-Item -itemtype directory -path $dest
|
||||
}
|
||||
Catch {
|
||||
$err_msg = $_.Exception.Message
|
||||
Fail-Json $result "Error creating $dest directory! Msg: $err_msg"
|
||||
}
|
||||
}
|
||||
|
||||
$recurse = ConvertTo-Bool (Get-AnsibleParam -obj $params -name "recurse" -default "false")
|
||||
$rm = ConvertTo-Bool (Get-AnsibleParam -obj $params -name "rm" -default "false")
|
||||
|
||||
If ($ext -eq ".zip" -And $recurse -eq $false) {
|
||||
Try {
|
||||
$shell = New-Object -ComObject Shell.Application
|
||||
$zipPkg = $shell.NameSpace([IO.Path]::GetFullPath($src))
|
||||
$destPath = $shell.NameSpace([IO.Path]::GetFullPath($dest))
|
||||
# 20 means do not display any dialog (4) and overwrite any file (16)
|
||||
$destPath.CopyHere($zipPkg.Items(), 20)
|
||||
$result.changed = $true
|
||||
}
|
||||
Catch {
|
||||
$err_msg = $_.Exception.Message
|
||||
Fail-Json $result "Error unzipping $src to $dest! Msg: $err_msg"
|
||||
}
|
||||
}
|
||||
# Requires PSCX
|
||||
Else {
|
||||
# Check if PSCX is installed
|
||||
$list = Get-Module -ListAvailable
|
||||
|
||||
If (-Not ($list -match "PSCX")) {
|
||||
Fail-Json $result "PowerShellCommunityExtensions PowerShell Module (PSCX) is required for non-'.zip' compressed archive types."
|
||||
}
|
||||
Else {
|
||||
Set-Attr $result.win_unzip "pscx_status" "present"
|
||||
}
|
||||
|
||||
# Import
|
||||
Try {
|
||||
Import-Module PSCX
|
||||
}
|
||||
Catch {
|
||||
Fail-Json $result "Error importing module PSCX"
|
||||
}
|
||||
|
||||
Try {
|
||||
If ($recurse) {
|
||||
Expand-Archive -Path $src -OutputPath $dest -Force
|
||||
|
||||
If ($rm -eq $true) {
|
||||
Get-ChildItem $dest -recurse | Where {$_.extension -eq ".gz" -Or $_.extension -eq ".zip" -Or $_.extension -eq ".bz2" -Or $_.extension -eq ".tar" -Or $_.extension -eq ".msu"} | % {
|
||||
Expand-Archive $_.FullName -OutputPath $dest -Force
|
||||
Remove-Item $_.FullName -Force
|
||||
}
|
||||
}
|
||||
Else {
|
||||
Get-ChildItem $dest -recurse | Where {$_.extension -eq ".gz" -Or $_.extension -eq ".zip" -Or $_.extension -eq ".bz2" -Or $_.extension -eq ".tar" -Or $_.extension -eq ".msu"} | % {
|
||||
Expand-Archive $_.FullName -OutputPath $dest -Force
|
||||
}
|
||||
}
|
||||
}
|
||||
Else {
|
||||
Expand-Archive -Path $src -OutputPath $dest -Force
|
||||
}
|
||||
}
|
||||
Catch {
|
||||
$err_msg = $_.Exception.Message
|
||||
If ($recurse) {
|
||||
Fail-Json $result "Error recursively expanding $src to $dest! Msg: $err_msg"
|
||||
}
|
||||
Else {
|
||||
Fail-Json $result "Error expanding $src to $dest! Msg: $err_msg"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
If ($rm -eq $true){
|
||||
Remove-Item $src -Recurse -Force
|
||||
Set-Attr $result.win_unzip "rm" "true"
|
||||
}
|
||||
|
||||
# Fixes a fail error message (when the task actually succeeds) for a "Convert-ToJson: The converted JSON string is in bad format"
|
||||
# This happens when JSON is parsing a string that ends with a "\", which is possible when specifying a directory to download to.
|
||||
# This catches that possible error, before assigning the JSON $result
|
||||
If ($src[$src.length-1] -eq "\") {
|
||||
$src = $src.Substring(0, $src.length-1)
|
||||
}
|
||||
If ($dest[$dest.length-1] -eq "\") {
|
||||
$dest = $dest.Substring(0, $dest.length-1)
|
||||
}
|
||||
Set-Attr $result.win_unzip "src" $src.toString()
|
||||
Set-Attr $result.win_unzip "dest" $dest.toString()
|
||||
Set-Attr $result.win_unzip "recurse" $recurse.toString()
|
||||
|
||||
Exit-Json $result;
|
||||
110
lib/ansible/modules/windows/win_unzip.py
Normal file
110
lib/ansible/modules/windows/win_unzip.py
Normal file
@@ -0,0 +1,110 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Phil Schwartz <schwartzmx@gmail.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_unzip
|
||||
version_added: "2.0"
|
||||
short_description: Unzips compressed files and archives on the Windows node
|
||||
description:
|
||||
- Unzips compressed files and archives. For extracting any compression types other than .zip, the PowerShellCommunityExtensions (PSCX) Module is required. This module (in conjunction with PSCX) has the ability to recursively unzip files within the src zip file provided and also functionality for many other compression types. If the destination directory does not exist, it will be created before unzipping the file. Specifying rm parameter will force removal of the src file after extraction.
|
||||
options:
|
||||
src:
|
||||
description:
|
||||
- File to be unzipped (provide absolute path)
|
||||
required: true
|
||||
dest:
|
||||
description:
|
||||
- Destination of zip file (provide absolute path of directory). If it does not exist, the directory will be created.
|
||||
required: true
|
||||
rm:
|
||||
description:
|
||||
- Remove the zip file, after unzipping
|
||||
required: no
|
||||
choices:
|
||||
- true
|
||||
- false
|
||||
- yes
|
||||
- no
|
||||
default: false
|
||||
recurse:
|
||||
description:
|
||||
- Recursively expand zipped files within the src file.
|
||||
required: no
|
||||
default: false
|
||||
choices:
|
||||
- true
|
||||
- false
|
||||
- yes
|
||||
- no
|
||||
creates:
|
||||
description:
|
||||
- If this file or directory exists the specified src will not be extracted.
|
||||
required: no
|
||||
default: null
|
||||
author: Phil Schwartz
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
# This unzips a library that was downloaded with win_get_url, and removes the file after extraction
|
||||
$ ansible -i hosts -m win_unzip -a "src=C:\LibraryToUnzip.zip dest=C:\Lib rm=true" all
|
||||
# Playbook example
|
||||
|
||||
# Simple unzip
|
||||
---
|
||||
- name: Unzip a bz2 (BZip) file
|
||||
win_unzip:
|
||||
src: "C:\Users\Phil\Logs.bz2"
|
||||
dest: "C:\Users\Phil\OldLogs"
|
||||
creates: "C:\Users\Phil\OldLogs"
|
||||
|
||||
# This playbook example unzips a .zip file and recursively decompresses the contained .gz files and removes all unneeded compressed files after completion.
|
||||
---
|
||||
- name: Unzip ApplicationLogs.zip and decompress all GZipped log files
|
||||
hosts: all
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Recursively decompress GZ files in ApplicationLogs.zip
|
||||
win_unzip:
|
||||
src: C:\Downloads\ApplicationLogs.zip
|
||||
dest: C:\Application\Logs
|
||||
recurse: yes
|
||||
rm: true
|
||||
|
||||
# Install PSCX to use for extracting a gz file
|
||||
- name: Grab PSCX msi
|
||||
win_get_url:
|
||||
url: 'http://download-codeplex.sec.s-msft.com/Download/Release?ProjectName=pscx&DownloadId=923562&FileTime=130585918034470000&Build=20959'
|
||||
dest: 'C:\pscx.msi'
|
||||
- name: Install PSCX
|
||||
win_msi:
|
||||
path: 'C:\pscx.msi'
|
||||
- name: Unzip gz log
|
||||
win_unzip:
|
||||
src: "C:\Logs\application-error-logs.gz"
|
||||
dest: "C:\ExtractedLogs\application-error-logs"
|
||||
'''
|
||||
424
lib/ansible/modules/windows/win_updates.ps1
Normal file
424
lib/ansible/modules/windows/win_updates.ps1
Normal file
@@ -0,0 +1,424 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Copyright 2015, Matt Davis <mdavis@rolpdog.com>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$FormatEnumerationLimit = -1 # prevent out-string et al from truncating collection dumps
|
||||
|
||||
<# Most of the Windows Update Agent API will not run under a remote token,
|
||||
which a remote WinRM session always has. win_updates uses the Task Scheduler
|
||||
to run the bulk of the update functionality under a local token. Powershell's
|
||||
Scheduled-Job capability provides a decent abstraction over the Task Scheduler
|
||||
and handles marshaling Powershell args in and output/errors/etc back. The
|
||||
module schedules a single job that executes all interactions with the Update
|
||||
Agent API, then waits for completion. A significant amount of hassle is
|
||||
involved to ensure that only one of these jobs is running at a time, and to
|
||||
clean up the various error conditions that can occur. #>
|
||||
|
||||
# define the ScriptBlock that will be passed to Register-ScheduledJob
|
||||
$job_body = {
|
||||
Param(
|
||||
[hashtable]$boundparms=@{},
|
||||
[Object[]]$unboundargs=$()
|
||||
)
|
||||
|
||||
Set-StrictMode -Version 2
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$DebugPreference = "Continue"
|
||||
$FormatEnumerationLimit = -1 # prevent out-string et al from truncating collection dumps
|
||||
|
||||
# set this as a global for the Write-DebugLog function
|
||||
$log_path = $boundparms['log_path']
|
||||
|
||||
Write-DebugLog "Scheduled job started with boundparms $($boundparms | out-string) and unboundargs $($unboundargs | out-string)"
|
||||
|
||||
# FUTURE: elevate this to module arg validation once we have it
|
||||
Function MapCategoryNameToGuid {
|
||||
Param([string] $category_name)
|
||||
|
||||
$category_guid = switch -exact ($category_name) {
|
||||
# as documented by TechNet @ https://technet.microsoft.com/en-us/library/ff730937.aspx
|
||||
"Application" {"5C9376AB-8CE6-464A-B136-22113DD69801"}
|
||||
"Connectors" {"434DE588-ED14-48F5-8EED-A15E09A991F6"}
|
||||
"CriticalUpdates" {"E6CF1350-C01B-414D-A61F-263D14D133B4"}
|
||||
"DefinitionUpdates" {"E0789628-CE08-4437-BE74-2495B842F43B"}
|
||||
"DeveloperKits" {"E140075D-8433-45C3-AD87-E72345B36078"}
|
||||
"FeaturePacks" {"B54E7D24-7ADD-428F-8B75-90A396FA584F"}
|
||||
"Guidance" {"9511D615-35B2-47BB-927F-F73D8E9260BB"}
|
||||
"SecurityUpdates" {"0FA1201D-4330-4FA8-8AE9-B877473B6441"}
|
||||
"ServicePacks" {"68C5B0A3-D1A6-4553-AE49-01D3A7827828"}
|
||||
"Tools" {"B4832BD8-E735-4761-8DAF-37F882276DAB"}
|
||||
"UpdateRollups" {"28BC880E-0592-4CBF-8F95-C79B17911D5F"}
|
||||
"Updates" {"CD5FFD1E-E932-4E3A-BF74-18BF0B1BBD83"}
|
||||
default { throw "Unknown category_name $category_name, must be one of (Application,Connectors,CriticalUpdates,DefinitionUpdates,DeveloperKits,FeaturePacks,Guidance,SecurityUpdates,ServicePacks,Tools,UpdateRollups,Updates)" }
|
||||
}
|
||||
|
||||
return $category_guid
|
||||
}
|
||||
|
||||
Function DoWindowsUpdate {
|
||||
Param(
|
||||
[string[]]$category_names=@("CriticalUpdates","SecurityUpdates","UpdateRollups"),
|
||||
[ValidateSet("installed", "searched")]
|
||||
[string]$state="installed",
|
||||
[bool]$_ansible_check_mode=$false
|
||||
)
|
||||
|
||||
$is_check_mode = $($state -eq "searched") -or $_ansible_check_mode
|
||||
|
||||
$category_guids = $category_names | % { MapCategoryNameToGUID $_ }
|
||||
|
||||
$update_status = @{ changed = $false }
|
||||
|
||||
Write-DebugLog "Creating Windows Update session..."
|
||||
$session = New-Object -ComObject Microsoft.Update.Session
|
||||
|
||||
Write-DebugLog "Create Windows Update searcher..."
|
||||
$searcher = $session.CreateUpdateSearcher()
|
||||
|
||||
# OR is only allowed at the top-level, so we have to repeat base criteria inside
|
||||
# FUTURE: change this to client-side filtered?
|
||||
$criteriabase = "IsInstalled = 0"
|
||||
$criteria_list = $category_guids | % { "($criteriabase AND CategoryIDs contains '$_')" }
|
||||
|
||||
$criteria = [string]::Join(" OR ", $criteria_list)
|
||||
|
||||
Write-DebugLog "Search criteria: $criteria"
|
||||
|
||||
Write-DebugLog "Searching for updates to install in category IDs $category_guids..."
|
||||
$searchresult = $searcher.Search($criteria)
|
||||
|
||||
Write-DebugLog "Creating update collection..."
|
||||
|
||||
$updates_to_install = New-Object -ComObject Microsoft.Update.UpdateColl
|
||||
|
||||
Write-DebugLog "Found $($searchresult.Updates.Count) updates"
|
||||
|
||||
$update_status.updates = @{ }
|
||||
|
||||
# FUTURE: add further filtering options
|
||||
foreach($update in $searchresult.Updates) {
|
||||
if(-Not $update.EulaAccepted) {
|
||||
Write-DebugLog "Accepting EULA for $($update.Identity.UpdateID)"
|
||||
$update.AcceptEula()
|
||||
}
|
||||
|
||||
if($update.IsHidden) {
|
||||
Write-DebugLog "Skipping hidden update $($update.Title)"
|
||||
continue
|
||||
}
|
||||
|
||||
Write-DebugLog "Adding update $($update.Identity.UpdateID) - $($update.Title)"
|
||||
$res = $updates_to_install.Add($update)
|
||||
|
||||
$update_status.updates[$update.Identity.UpdateID] = @{
|
||||
title = $update.Title
|
||||
# TODO: pluck the first KB out (since most have just one)?
|
||||
kb = $update.KBArticleIDs
|
||||
id = $update.Identity.UpdateID
|
||||
installed = $false
|
||||
}
|
||||
}
|
||||
|
||||
Write-DebugLog "Calculating pre-install reboot requirement..."
|
||||
|
||||
# calculate this early for check mode, and to see if we should allow updates to continue
|
||||
$sysinfo = New-Object -ComObject Microsoft.Update.SystemInfo
|
||||
$update_status.reboot_required = $sysinfo.RebootRequired
|
||||
$update_status.found_update_count = $updates_to_install.Count
|
||||
$update_status.installed_update_count = 0
|
||||
|
||||
# bail out here for check mode
|
||||
if($is_check_mode -eq $true) {
|
||||
Write-DebugLog "Check mode; exiting..."
|
||||
Write-DebugLog "Return value: $($update_status | out-string)"
|
||||
|
||||
if($updates_to_install.Count -gt 0) { $update_status.changed = $true }
|
||||
return $update_status
|
||||
}
|
||||
|
||||
if($updates_to_install.Count -gt 0) {
|
||||
if($update_status.reboot_required) {
|
||||
throw "A reboot is required before more updates can be installed."
|
||||
}
|
||||
else {
|
||||
Write-DebugLog "No reboot is pending..."
|
||||
}
|
||||
Write-DebugLog "Downloading updates..."
|
||||
}
|
||||
|
||||
foreach($update in $updates_to_install) {
|
||||
if($update.IsDownloaded) {
|
||||
Write-DebugLog "Update $($update.Identity.UpdateID) already downloaded, skipping..."
|
||||
continue
|
||||
}
|
||||
Write-DebugLog "Creating downloader object..."
|
||||
$dl = $session.CreateUpdateDownloader()
|
||||
Write-DebugLog "Creating download collection..."
|
||||
$dl.Updates = New-Object -ComObject Microsoft.Update.UpdateColl
|
||||
Write-DebugLog "Adding update $($update.Identity.UpdateID)"
|
||||
$res = $dl.Updates.Add($update)
|
||||
Write-DebugLog "Downloading update $($update.Identity.UpdateID)..."
|
||||
$download_result = $dl.Download()
|
||||
# FUTURE: configurable download retry
|
||||
if($download_result.ResultCode -ne 2) { # OperationResultCode orcSucceeded
|
||||
throw "Failed to download update $($update.Identity.UpdateID)"
|
||||
}
|
||||
}
|
||||
|
||||
if($updates_to_install.Count -lt 1 ) { return $update_status }
|
||||
|
||||
Write-DebugLog "Installing updates..."
|
||||
|
||||
# install as a batch so the reboot manager will suppress intermediate reboots
|
||||
Write-DebugLog "Creating installer object..."
|
||||
$inst = $session.CreateUpdateInstaller()
|
||||
Write-DebugLog "Creating install collection..."
|
||||
$inst.Updates = New-Object -ComObject Microsoft.Update.UpdateColl
|
||||
|
||||
foreach($update in $updates_to_install) {
|
||||
Write-DebugLog "Adding update $($update.Identity.UpdateID)"
|
||||
$res = $inst.Updates.Add($update)
|
||||
}
|
||||
|
||||
# FUTURE: use BeginInstall w/ progress reporting so we can at least log intermediate install results
|
||||
Write-DebugLog "Installing updates..."
|
||||
$install_result = $inst.Install()
|
||||
|
||||
$update_success_count = 0
|
||||
$update_fail_count = 0
|
||||
|
||||
# WU result API requires us to index in to get the install results
|
||||
$update_index = 0
|
||||
|
||||
foreach($update in $updates_to_install) {
|
||||
$update_result = $install_result.GetUpdateResult($update_index)
|
||||
$update_resultcode = $update_result.ResultCode
|
||||
$update_hresult = $update_result.HResult
|
||||
|
||||
$update_index++
|
||||
|
||||
$update_dict = $update_status.updates[$update.Identity.UpdateID]
|
||||
|
||||
if($update_resultcode -eq 2) { # OperationResultCode orcSucceeded
|
||||
$update_success_count++
|
||||
$update_dict.installed = $true
|
||||
Write-DebugLog "Update $($update.Identity.UpdateID) succeeded"
|
||||
}
|
||||
else {
|
||||
$update_fail_count++
|
||||
$update_dict.installed = $false
|
||||
$update_dict.failed = $true
|
||||
$update_dict.failure_hresult_code = $update_hresult
|
||||
Write-DebugLog "Update $($update.Identity.UpdateID) failed resultcode $update_hresult hresult $update_hresult"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if($update_fail_count -gt 0) {
|
||||
$update_status.failed = $true
|
||||
$update_status.msg="Failed to install one or more updates"
|
||||
}
|
||||
else { $update_status.changed = $true }
|
||||
|
||||
Write-DebugLog "Performing post-install reboot requirement check..."
|
||||
|
||||
# recalculate reboot status after installs
|
||||
$sysinfo = New-Object -ComObject Microsoft.Update.SystemInfo
|
||||
$update_status.reboot_required = $sysinfo.RebootRequired
|
||||
$update_status.installed_update_count = $update_success_count
|
||||
$update_status.failed_update_count = $update_fail_count
|
||||
|
||||
Write-DebugLog "Return value: $($update_status | out-string)"
|
||||
|
||||
return $update_status
|
||||
}
|
||||
|
||||
Try {
|
||||
# job system adds a bunch of cruft to top-level dict, so we have to send a sub-dict
|
||||
return @{ job_output = DoWindowsUpdate @boundparms }
|
||||
}
|
||||
Catch {
|
||||
$excep = $_
|
||||
Write-DebugLog "Fatal exception: $($excep.Exception.Message) at $($excep.ScriptStackTrace)"
|
||||
return @{ job_output = @{ failed=$true;error=$excep.Exception.Message;location=$excep.ScriptStackTrace } }
|
||||
}
|
||||
}
|
||||
|
||||
Function DestroyScheduledJob {
|
||||
Param([string] $job_name)
|
||||
|
||||
# find a scheduled job with the same name (should normally fail)
|
||||
$schedjob = Get-ScheduledJob -Name $job_name -ErrorAction SilentlyContinue
|
||||
|
||||
# nuke it if it's there
|
||||
If($schedjob -ne $null) {
|
||||
Write-DebugLog "ScheduledJob $job_name exists, ensuring it's not running..."
|
||||
# can't manage jobs across sessions, so we have to resort to the Task Scheduler script object to kill running jobs
|
||||
$schedserv = New-Object -ComObject Schedule.Service
|
||||
Write-DebugLog "Connecting to scheduler service..."
|
||||
$schedserv.Connect()
|
||||
Write-DebugLog "Getting running tasks named $job_name"
|
||||
$running_tasks = @($schedserv.GetRunningTasks(0) | Where-Object { $_.Name -eq $job_name })
|
||||
|
||||
Foreach($task_to_stop in $running_tasks) {
|
||||
Write-DebugLog "Stopping running task $($task_to_stop.InstanceGuid)..."
|
||||
$task_to_stop.Stop()
|
||||
}
|
||||
|
||||
<# FUTURE: add a global waithandle for this to release any other waiters. Wait-Job
|
||||
and/or polling will block forever, since the killed job object in the parent
|
||||
session doesn't know it's been killed :( #>
|
||||
|
||||
Unregister-ScheduledJob -Name $job_name
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Function RunAsScheduledJob {
|
||||
Param([scriptblock] $job_body, [string] $job_name, [scriptblock] $job_init, [Object[]] $job_arg_list=@())
|
||||
|
||||
DestroyScheduledJob -job_name $job_name
|
||||
|
||||
$rsj_args = @{
|
||||
ScriptBlock = $job_body
|
||||
Name = $job_name
|
||||
ArgumentList = $job_arg_list
|
||||
ErrorAction = "Stop"
|
||||
ScheduledJobOption = @{ RunElevated=$True }
|
||||
}
|
||||
|
||||
if($job_init) { $rsj_args.InitializationScript = $job_init }
|
||||
|
||||
Write-DebugLog "Registering scheduled job with args $($rsj_args | Out-String -Width 300)"
|
||||
$schedjob = Register-ScheduledJob @rsj_args
|
||||
|
||||
# RunAsTask isn't available in PS3- fall back to a 2s future trigger
|
||||
if($schedjob | Get-Member -Name RunAsTask) {
|
||||
Write-DebugLog "Starting scheduled job (PS4 method)"
|
||||
$schedjob.RunAsTask()
|
||||
}
|
||||
else {
|
||||
Write-DebugLog "Starting scheduled job (PS3 method)"
|
||||
Add-JobTrigger -inputobject $schedjob -trigger $(New-JobTrigger -once -at $(Get-Date).AddSeconds(2))
|
||||
}
|
||||
|
||||
$sw = [System.Diagnostics.Stopwatch]::StartNew()
|
||||
|
||||
$job = $null
|
||||
|
||||
Write-DebugLog "Waiting for job completion..."
|
||||
|
||||
# Wait-Job can fail for a few seconds until the scheduled task starts- poll for it...
|
||||
while ($job -eq $null) {
|
||||
start-sleep -Milliseconds 100
|
||||
if($sw.ElapsedMilliseconds -ge 30000) { # tasks scheduled right after boot on 2008R2 can take awhile to start...
|
||||
Throw "Timed out waiting for scheduled task to start"
|
||||
}
|
||||
|
||||
# FUTURE: configurable timeout so we don't block forever?
|
||||
# FUTURE: add a global WaitHandle in case another instance kills our job, so we don't block forever
|
||||
$job = Wait-Job -Name $schedjob.Name -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
$sw = [System.Diagnostics.Stopwatch]::StartNew()
|
||||
|
||||
# NB: output from scheduled jobs is delayed after completion (including the sub-objects after the primary Output object is available)
|
||||
While (($job.Output -eq $null -or -not ($job.Output | Get-Member -Name Keys -ErrorAction Ignore) -or -not $job.Output.Keys.Contains('job_output')) -and $sw.ElapsedMilliseconds -lt 15000) {
|
||||
Write-DebugLog "Waiting for job output to populate..."
|
||||
Start-Sleep -Milliseconds 500
|
||||
}
|
||||
|
||||
# NB: fallthru on both timeout and success
|
||||
|
||||
$ret = @{
|
||||
ErrorOutput = $job.Error
|
||||
WarningOutput = $job.Warning
|
||||
VerboseOutput = $job.Verbose
|
||||
DebugOutput = $job.Debug
|
||||
}
|
||||
|
||||
If ($job.Output -eq $null -or -not $job.Output.Keys.Contains('job_output')) {
|
||||
$ret.Output = @{failed = $true; msg = "job output was lost"}
|
||||
}
|
||||
Else {
|
||||
$ret.Output = $job.Output.job_output # sub-object returned, can only be accessed as a property for some reason
|
||||
}
|
||||
|
||||
Try { # this shouldn't be fatal, but can fail with both Powershell errors and COM Exceptions, hence the dual error-handling...
|
||||
Unregister-ScheduledJob -Name $job_name -Force -ErrorAction Continue
|
||||
}
|
||||
Catch {
|
||||
Write-DebugLog "Error unregistering job after execution: $($_.Exception.ToString()) $($_.ScriptStackTrace)"
|
||||
}
|
||||
|
||||
return $ret
|
||||
}
|
||||
|
||||
Function Log-Forensics {
|
||||
Write-DebugLog "Arguments: $job_args | out-string"
|
||||
Write-DebugLog "OS Version: $([environment]::OSVersion.Version | out-string)"
|
||||
Write-DebugLog "Running as user: $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)"
|
||||
Write-DebugLog "Powershell version: $($PSVersionTable | out-string)"
|
||||
# FUTURE: log auth method (kerb, password, etc)
|
||||
}
|
||||
|
||||
# code shared between the scheduled job and the host script
|
||||
$common_inject = {
|
||||
# FUTURE: capture all to a list, dump on error
|
||||
Function Write-DebugLog {
|
||||
Param(
|
||||
[string]$msg
|
||||
)
|
||||
|
||||
$DebugPreference = "Continue"
|
||||
$ErrorActionPreference = "Continue"
|
||||
$date_str = Get-Date -Format u
|
||||
$msg = "$date_str $msg"
|
||||
|
||||
Write-Debug $msg
|
||||
|
||||
if($log_path -ne $null) {
|
||||
Add-Content $log_path $msg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# source the common code into the current scope so we can call it
|
||||
. $common_inject
|
||||
|
||||
$parsed_args = Parse-Args $args $true
|
||||
# grr, why use PSCustomObject for args instead of just native hashtable?
|
||||
$parsed_args.psobject.properties | foreach -begin {$job_args=@{}} -process {$job_args."$($_.Name)" = $_.Value} -end {$job_args}
|
||||
|
||||
# set the log_path for the global log function we injected earlier
|
||||
$log_path = $job_args['log_path']
|
||||
|
||||
Log-Forensics
|
||||
|
||||
Write-DebugLog "Starting scheduled job with args: $($job_args | Out-String -Width 300)"
|
||||
|
||||
# pass the common code as job_init so it'll be injected into the scheduled job script
|
||||
$sjo = RunAsScheduledJob -job_init $common_inject -job_body $job_body -job_name ansible-win-updates -job_arg_list $job_args
|
||||
|
||||
Write-DebugLog "Scheduled job completed with output: $($sjo.Output | Out-String -Width 300)"
|
||||
|
||||
Exit-Json $sjo.Output
|
||||
148
lib/ansible/modules/windows/win_updates.py
Normal file
148
lib/ansible/modules/windows/win_updates.py
Normal file
@@ -0,0 +1,148 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Matt Davis <mdavis_ansible@rolpdog.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'core',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_updates
|
||||
version_added: "2.0"
|
||||
short_description: Download and install Windows updates
|
||||
description:
|
||||
- Searches, downloads, and installs Windows updates synchronously by automating the Windows Update client
|
||||
options:
|
||||
category_names:
|
||||
description:
|
||||
- A scalar or list of categories to install updates from
|
||||
required: false
|
||||
default: ["CriticalUpdates","SecurityUpdates","UpdateRollups"]
|
||||
choices:
|
||||
- Application
|
||||
- Connectors
|
||||
- CriticalUpdates
|
||||
- DefinitionUpdates
|
||||
- DeveloperKits
|
||||
- FeaturePacks
|
||||
- Guidance
|
||||
- SecurityUpdates
|
||||
- ServicePacks
|
||||
- Tools
|
||||
- UpdateRollups
|
||||
- Updates
|
||||
state:
|
||||
description:
|
||||
- Controls whether found updates are returned as a list or actually installed.
|
||||
- This module also supports Ansible check mode, which has the same effect as setting state=searched
|
||||
required: false
|
||||
default: installed
|
||||
choices:
|
||||
- installed
|
||||
- searched
|
||||
log_path:
|
||||
description:
|
||||
- If set, win_updates will append update progress to the specified file. The directory must already exist.
|
||||
required: false
|
||||
author: "Matt Davis (@mattdavispdx)"
|
||||
notes:
|
||||
- win_updates must be run by a user with membership in the local Administrators group
|
||||
- win_updates will use the default update service configured for the machine (Windows Update, Microsoft Update, WSUS, etc)
|
||||
- win_updates does not manage reboots, but will signal when a reboot is required with the reboot_required return value.
|
||||
- win_updates can take a significant amount of time to complete (hours, in some cases). Performance depends on many factors, including OS version, number of updates, system load, and update server load.
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Install all security, critical, and rollup updates
|
||||
- win_updates:
|
||||
category_names:
|
||||
- SecurityUpdates
|
||||
- CriticalUpdates
|
||||
- UpdateRollups
|
||||
|
||||
# Install only security updates
|
||||
- win_updates:
|
||||
category_names: SecurityUpdates
|
||||
|
||||
# Search-only, return list of found updates (if any), log to c:\ansible_wu.txt
|
||||
- win_updates:
|
||||
category_names: SecurityUpdates
|
||||
state: searched
|
||||
log_path: c:\ansible_wu.txt
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
reboot_required:
|
||||
description: True when the target server requires a reboot to complete updates (no further updates can be installed until after a reboot)
|
||||
returned: success
|
||||
type: boolean
|
||||
sample: True
|
||||
|
||||
updates:
|
||||
description: List of updates that were found/installed
|
||||
returned: success
|
||||
type: dictionary
|
||||
sample:
|
||||
contains:
|
||||
title:
|
||||
description: Display name
|
||||
returned: always
|
||||
type: string
|
||||
sample: "Security Update for Windows Server 2012 R2 (KB3004365)"
|
||||
kb:
|
||||
description: A list of KB article IDs that apply to the update
|
||||
returned: always
|
||||
type: list of strings
|
||||
sample: [ '3004365' ]
|
||||
id:
|
||||
description: Internal Windows Update GUID
|
||||
returned: always
|
||||
type: string (guid)
|
||||
sample: "fb95c1c8-de23-4089-ae29-fd3351d55421"
|
||||
installed:
|
||||
description: Was the update successfully installed
|
||||
returned: always
|
||||
type: boolean
|
||||
sample: True
|
||||
failure_hresult_code:
|
||||
description: The HRESULT code from a failed update
|
||||
returned: on install failure
|
||||
type: boolean
|
||||
sample: 2147942402
|
||||
|
||||
found_update_count:
|
||||
description: The number of updates found needing to be applied
|
||||
returned: success
|
||||
type: int
|
||||
sample: 3
|
||||
installed_update_count:
|
||||
description: The number of updates successfully installed
|
||||
returned: success
|
||||
type: int
|
||||
sample: 2
|
||||
failed_update_count:
|
||||
description: The number of updates that failed to install
|
||||
returned: always
|
||||
type: int
|
||||
sample: 0
|
||||
'''
|
||||
86
lib/ansible/modules/windows/win_uri.ps1
Normal file
86
lib/ansible/modules/windows/win_uri.ps1
Normal file
@@ -0,0 +1,86 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Copyright 2015, Corwin Brown <corwin@corwinbrown.com>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$params = Parse-Args $args;
|
||||
|
||||
$result = New-Object psobject @{
|
||||
win_uri = New-Object psobject
|
||||
}
|
||||
|
||||
# Functions ###############################################
|
||||
|
||||
Function ConvertTo-SnakeCase($input_string) {
|
||||
$snake_case = $input_string -csplit "(?<!^)(?=[A-Z])" -join "_"
|
||||
$snake_case = $snake_case.ToLower()
|
||||
|
||||
return $snake_case
|
||||
}
|
||||
|
||||
# Build Arguments
|
||||
$webrequest_opts = @{}
|
||||
|
||||
$url = Get-AnsibleParam -obj $params -name "url" -failifempty $true
|
||||
$method = Get-AnsibleParam -obj $params "method" -default "GET"
|
||||
$content_type = Get-AnsibleParam -obj $params -name "content_type"
|
||||
$headers = Get-AnsibleParam -obj $params -name "headers"
|
||||
$body = Get-AnsibleParam -obj $params -name "body"
|
||||
$use_basic_parsing = ConvertTo-Bool (Get-AnsibleParam -obj $params -name "use_basic_parsing" -default $true)
|
||||
|
||||
$webrequest_opts.Uri = $url
|
||||
Set-Attr $result.win_uri "url" $url
|
||||
|
||||
$webrequest_opts.Method = $method
|
||||
Set-Attr $result.win_uri "method" $method
|
||||
|
||||
$webrequest_opts.ContentType = $content_type
|
||||
Set-Attr $result.win_uri "content_type" $content_type
|
||||
|
||||
$webrequest_opts.UseBasicParsing = $use_basic_parsing
|
||||
Set-Attr $result.win_uri "use_basic_parsing" $use_basic_parsing
|
||||
|
||||
if ($headers -ne $null) {
|
||||
$req_headers = @{}
|
||||
ForEach ($header in $headers.psobject.properties) {
|
||||
$req_headers.Add($header.Name, $header.Value)
|
||||
}
|
||||
|
||||
$webrequest_opts.Headers = $req_headers
|
||||
}
|
||||
|
||||
if ($body -ne $null) {
|
||||
$webrequest_opts.Body = $body
|
||||
Set-Attr $result.win_uri "body" $body
|
||||
}
|
||||
|
||||
try {
|
||||
$response = Invoke-WebRequest @webrequest_opts
|
||||
} catch {
|
||||
$ErrorMessage = $_.Exception.Message
|
||||
Fail-Json $result $ErrorMessage
|
||||
}
|
||||
|
||||
ForEach ($prop in $response.psobject.properties) {
|
||||
$result_key = ConvertTo-SnakeCase $prop.Name
|
||||
$result_value = $prop.Value
|
||||
Set-Attr $result $result_key $result_value
|
||||
}
|
||||
|
||||
Exit-Json $result
|
||||
158
lib/ansible/modules/windows/win_uri.py
Normal file
158
lib/ansible/modules/windows/win_uri.py
Normal file
@@ -0,0 +1,158 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Corwin Brown <corwin@corwinbrown.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: win_uri
|
||||
version_added: "2.1"
|
||||
short_description: Interacts with webservices.
|
||||
description:
|
||||
- Interacts with HTTP and HTTPS web services and supports Digest, Basic and WSSE HTTP authentication mechanisms.
|
||||
options:
|
||||
url:
|
||||
description:
|
||||
- HTTP or HTTPS URL in the form of (http|https)://host.domain:port/path
|
||||
method:
|
||||
description:
|
||||
- The HTTP Method of the request or response.
|
||||
default: GET
|
||||
choices:
|
||||
- GET
|
||||
- POST
|
||||
- PUT
|
||||
- HEAD
|
||||
- DELETE
|
||||
- OPTIONS
|
||||
- PATCH
|
||||
- TRACE
|
||||
- CONNECT
|
||||
- REFRESH
|
||||
content_type:
|
||||
description:
|
||||
- Sets the "Content-Type" header.
|
||||
body:
|
||||
description:
|
||||
- The body of the HTTP request/response to the web service.
|
||||
headers:
|
||||
description:
|
||||
- 'Key Value pairs for headers. Example "Host: www.somesite.com"'
|
||||
use_basic_parsing:
|
||||
description:
|
||||
- This module relies upon 'Invoke-WebRequest', which by default uses the Internet Explorer Engine to parse a webpage. There's an edge-case where if a user hasn't run IE before, this will fail. The only advantage to using the Internet Explorer praser is that you can traverse the DOM in a powershell script. That isn't useful for Ansible, so by default we toggle 'UseBasicParsing'. However, you can toggle that off here.
|
||||
choices:
|
||||
- True
|
||||
- False
|
||||
default: True
|
||||
author: Corwin Brown (@blakfeld)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
# Send a GET request and store the output:
|
||||
---
|
||||
- name: Perform a GET and Store Output
|
||||
win_uri:
|
||||
url: http://www.somesite.com/myendpoint
|
||||
register: http_output
|
||||
|
||||
# Set a HOST header to hit an internal webserver:
|
||||
---
|
||||
- name: Hit a Specific Host on the Server
|
||||
win_uri:
|
||||
url: http://my.internal.server.com
|
||||
method: GET
|
||||
headers:
|
||||
host: "www.somesite.com"
|
||||
|
||||
# Do a HEAD request on an endpoint
|
||||
---
|
||||
- name: Perform a HEAD on an Endpoint
|
||||
win_uri:
|
||||
url: http://www.somesite.com
|
||||
method: HEAD
|
||||
|
||||
# Post a body to an endpoint
|
||||
---
|
||||
- name: POST a Body to an Endpoint
|
||||
win_uri:
|
||||
url: http://www.somesite.com
|
||||
method: POST
|
||||
body: "{ 'some': 'json' }"
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
url:
|
||||
description: The Target URL
|
||||
returned: always
|
||||
type: string
|
||||
sample: "https://www.ansible.com"
|
||||
method:
|
||||
description: The HTTP method used.
|
||||
returned: always
|
||||
type: string
|
||||
sample: "GET"
|
||||
content_type:
|
||||
description: The "content-type" header used.
|
||||
returned: always
|
||||
type: string
|
||||
sample: "application/json"
|
||||
use_basic_parsing:
|
||||
description: The state of the "use_basic_parsing" flag.
|
||||
returned: always
|
||||
type: bool
|
||||
sample: True
|
||||
body:
|
||||
description: The content of the body used
|
||||
returned: when body is specified
|
||||
type: string
|
||||
sample: '{"id":1}'
|
||||
version_added: "2.3"
|
||||
status_code:
|
||||
description: The HTTP Status Code of the response.
|
||||
returned: success
|
||||
type: int
|
||||
sample: 200
|
||||
status_description:
|
||||
description: A summery of the status.
|
||||
returned: success
|
||||
type: string
|
||||
stample: "OK"
|
||||
raw_content:
|
||||
description: The raw content of the HTTP response.
|
||||
returned: success
|
||||
type: string
|
||||
sample: 'HTTP/1.1 200 OK\nX-XSS-Protection: 1; mode=block\nX-Frame-Options: SAMEORIGIN\nAlternate-Protocol: 443:quic,p=1\nAlt-Svc: quic="www.google.com:443"; ma=2592000; v="30,29,28,27,26,25",quic=":443"; ma=2...'
|
||||
headers:
|
||||
description: The Headers of the response.
|
||||
returned: success
|
||||
type: dict
|
||||
sample: {"Content-Type": "application/json"}
|
||||
raw_content_length:
|
||||
description: The byte size of the response.
|
||||
returned: success
|
||||
type: int
|
||||
sample: 54447
|
||||
"""
|
||||
132
lib/ansible/modules/windows/win_webpicmd.ps1
Normal file
132
lib/ansible/modules/windows/win_webpicmd.ps1
Normal file
@@ -0,0 +1,132 @@
|
||||
#!powershell
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Copyright 2015, Peter Mounce <public@neverrunwithscissors.com>
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
|
||||
$params = Parse-Args $args;
|
||||
$result = New-Object PSObject;
|
||||
Set-Attr $result "changed" $false;
|
||||
|
||||
$package = Get-AnsibleParam $params -name "name" -failifempty $true
|
||||
|
||||
Function Find-Command
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true, Position=0)] [string] $command
|
||||
)
|
||||
$installed = get-command $command -erroraction Ignore
|
||||
write-verbose "$installed"
|
||||
if ($installed)
|
||||
{
|
||||
return $installed
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
Function Find-WebPiCmd
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param()
|
||||
$p = Find-Command "webpicmd.exe"
|
||||
if ($p -ne $null)
|
||||
{
|
||||
return $p
|
||||
}
|
||||
$a = Find-Command "c:\programdata\chocolatey\bin\webpicmd.exe"
|
||||
if ($a -ne $null)
|
||||
{
|
||||
return $a
|
||||
}
|
||||
Throw "webpicmd.exe is not installed. It must be installed (use chocolatey)"
|
||||
}
|
||||
|
||||
Function Test-IsInstalledFromWebPI
|
||||
{
|
||||
[CmdletBinding()]
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true, Position=0)]
|
||||
[string]$package
|
||||
)
|
||||
|
||||
$cmd = "$executable /list /listoption:installed"
|
||||
$results = invoke-expression $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "webpicmd_error_cmd" $cmd
|
||||
Set-Attr $result "webpicmd_error_log" "$results"
|
||||
|
||||
Throw "Error checking installation status for $package"
|
||||
}
|
||||
Write-Verbose "$results"
|
||||
|
||||
if ($results -match "^$package\s+")
|
||||
{
|
||||
return $true
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
|
||||
Function Install-WithWebPICmd
|
||||
{
|
||||
[CmdletBinding()]
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true, Position=0)]
|
||||
[string]$package
|
||||
)
|
||||
|
||||
$cmd = "$executable /install /products:$package /accepteula /suppressreboot"
|
||||
|
||||
$results = invoke-expression $cmd
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Set-Attr $result "webpicmd_error_cmd" $cmd
|
||||
Set-Attr $result "webpicmd_error_log" "$results"
|
||||
Throw "Error installing $package"
|
||||
}
|
||||
|
||||
write-verbose "$results"
|
||||
|
||||
if ($results -match "Install of Products: SUCCESS")
|
||||
{
|
||||
$result.changed = $true
|
||||
}
|
||||
}
|
||||
|
||||
Try
|
||||
{
|
||||
$script:executable = Find-WebPiCmd
|
||||
if ((Test-IsInstalledFromWebPI -package $package) -eq $false)
|
||||
{
|
||||
Install-WithWebPICmd -package $package
|
||||
}
|
||||
|
||||
Exit-Json $result;
|
||||
}
|
||||
Catch
|
||||
{
|
||||
Fail-Json $result $_.Exception.Message
|
||||
}
|
||||
51
lib/ansible/modules/windows/win_webpicmd.py
Normal file
51
lib/ansible/modules/windows/win_webpicmd.py
Normal file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Peter Mounce <public@neverrunwithscissors.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: win_webpicmd
|
||||
version_added: "2.0"
|
||||
short_description: Installs packages using Web Platform Installer command-line
|
||||
description:
|
||||
- Installs packages using Web Platform Installer command-line (http://www.iis.net/learn/install/web-platform-installer/web-platform-installer-v4-command-line-webpicmdexe-rtw-release).
|
||||
- Must be installed and present in PATH (see win_chocolatey module; 'webpicmd' is the package name, and you must install 'lessmsi' first too)
|
||||
- Install IIS first (see win_feature module)
|
||||
notes:
|
||||
- accepts EULAs and suppresses reboot - you will need to check manage reboots yourself (see win_reboot module)
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Name of the package to be installed
|
||||
required: true
|
||||
author: Peter Mounce
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Install URLRewrite2.
|
||||
win_webpicmd:
|
||||
name: URLRewrite2
|
||||
'''
|
||||
Reference in New Issue
Block a user