Merge pull request #1213 from h0nIg/devel_win_share

win_share: add module to manage smb shares
This commit is contained in:
Matt Davis 2016-03-10 23:05:07 +00:00
commit 802432c21c
2 changed files with 368 additions and 0 deletions

251
windows/win_share.ps1 Normal file
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

117
windows/win_share.py Normal file
View file

@ -0,0 +1,117 @@
#!/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
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 = '''
'''