Relocating extras into lib/ansible/modules/ after merge

This commit is contained in:
James Cammarata
2016-12-08 00:36:57 -05:00
committed by Matt Clay
parent c65ba07d2c
commit 011ea55a8f
596 changed files with 0 additions and 266 deletions

View 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

View 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'
'''

View 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

View 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 = '''
'''

View 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
}

View 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/
'''

View 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
}

View 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:
'''

View 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;

View 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
'''

View 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;

View 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
"""

View 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;

View 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
'''

View 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

View 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
'''

View 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

View 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
'''

View 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

View 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
'''

View 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

View 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
'''

View 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

View 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
'''

View 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
}

View 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
'''

View 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

View 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 = '''
'''

File diff suppressed because it is too large Load Diff

View 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
'''

View 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

View 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
'''

View 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

View 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
'''

View 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

View 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
'''

View 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;

View 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
'''

View 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
}

View 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
'''

View 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

View 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 = '''
'''

View 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;

View 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 = '''# '''

View 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;

View 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"
'''

View 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

View 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
'''

View 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

View 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
"""

View 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
}

View 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
'''