-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #30 from d-strobel/feat/local-groupmember-functions
Feat/local-groupmember-functions
- Loading branch information
Showing
6 changed files
with
559 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
package local | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strings" | ||
) | ||
|
||
// GroupMember represents a member of a local Windows group. | ||
type GroupMember struct { | ||
Name string `json:"Name"` | ||
SID SID `json:"SID"` | ||
ObjectClass string `json:"ObjectClass"` | ||
} | ||
|
||
// GroupMemberParams contains the parameters required for working with local Windows group members. | ||
type GroupMemberParams struct { | ||
Name string | ||
SID string | ||
Member string | ||
} | ||
|
||
// GroupMemberRead retrieves information about a specific member in a local Windows group. | ||
// | ||
// Accepted GroupMemberParams: | ||
// - Name | ||
// - SID | ||
// - Member | ||
func (c *LocalClient) GroupMemberRead(ctx context.Context, params GroupMemberParams) (GroupMember, error) { | ||
// Declare GroupMember | ||
var gm GroupMember | ||
|
||
// Assert needed parameters | ||
if params.Name == "" && params.SID == "" { | ||
return gm, fmt.Errorf("windows.local.GroupMemberRead: group member parameter 'Name' or 'SID' must be set") | ||
} | ||
|
||
if params.Member == "" { | ||
return gm, fmt.Errorf("windows.local.GroupMemberRead: group member parameter 'Member' must be set") | ||
} | ||
|
||
// Base command | ||
cmds := []string{"Get-LocalGroupMember"} | ||
|
||
// Add parameters | ||
// Prefer SID over Name | ||
if params.SID != "" { | ||
cmds = append(cmds, fmt.Sprintf("-SID %s", params.SID)) | ||
} else if params.Name != "" { | ||
cmds = append(cmds, fmt.Sprintf("-Name '%s'", params.Name)) | ||
} | ||
|
||
cmds = append(cmds, fmt.Sprintf("-Member '%s'", params.Member)) | ||
cmds = append(cmds, "| ConvertTo-Json -Compress") | ||
cmd := strings.Join(cmds, " ") | ||
|
||
// Run command | ||
if err := localRun[GroupMember](ctx, c, cmd, &gm); err != nil { | ||
return gm, fmt.Errorf("windows.local.GroupMemberRead: %s", err) | ||
} | ||
|
||
return gm, nil | ||
} | ||
|
||
// GroupMemberList returns a list of members for a specific local Windows group. | ||
// | ||
// Accepted GroupMemberParams: | ||
// - Name | ||
// - SID | ||
func (c *LocalClient) GroupMemberList(ctx context.Context, params GroupMemberParams) ([]GroupMember, error) { | ||
// Declare slice of GroupMember | ||
var gm []GroupMember | ||
|
||
// Assert needed parameters | ||
if params.Name == "" && params.SID == "" { | ||
return gm, fmt.Errorf("windows.local.GroupMemberList: group member parameter 'Name' or 'SID' must be set") | ||
} | ||
|
||
// Base command | ||
cmds := []string{"$gm=Get-LocalGroupMember"} | ||
|
||
// Add parameters | ||
// Prefer SID over Name | ||
if params.SID != "" { | ||
cmds = append(cmds, fmt.Sprintf("-SID %s", params.SID)) | ||
} else if params.Name != "" { | ||
cmds = append(cmds, fmt.Sprintf("-Name '%s'", params.Name)) | ||
} | ||
|
||
// Ensure that groups with a single group member is also printed as an array | ||
cmds = append(cmds, ";if($gm.Count -eq 1){ConvertTo-Json @($gm) -Compress}else{ConvertTo-Json $gm -Compress}") | ||
cmd := strings.Join(cmds, " ") | ||
|
||
// Run command | ||
if err := localRun[[]GroupMember](ctx, c, cmd, &gm); err != nil { | ||
return gm, fmt.Errorf("windows.local.GroupMemberList: %s", err) | ||
} | ||
|
||
return gm, nil | ||
} | ||
|
||
// GroupMemberCreate adds a new member to a local Windows group. | ||
// | ||
// Accepted GroupMemberParams: | ||
// - Name | ||
// - SID | ||
// - Member | ||
func (c *LocalClient) GroupMemberCreate(ctx context.Context, params GroupMemberParams) error { | ||
// Satisfy the localType interface | ||
var gm GroupMember | ||
|
||
// Assert needed parameters | ||
if params.Name == "" && params.SID == "" { | ||
return fmt.Errorf("windows.local.GroupMemberCreate: group member parameter 'Name' or 'SID' must be set") | ||
} | ||
|
||
if params.Member == "" { | ||
return fmt.Errorf("windows.local.GroupMemberCreate: group member parameter 'Member' must be set") | ||
} | ||
|
||
// Base command | ||
cmds := []string{"Add-LocalGroupMember"} | ||
|
||
// Add parameters | ||
// Prefer SID over Name | ||
if params.SID != "" { | ||
cmds = append(cmds, fmt.Sprintf("-SID %s", params.SID)) | ||
} else if params.Name != "" { | ||
cmds = append(cmds, fmt.Sprintf("-Name '%s'", params.Name)) | ||
} | ||
|
||
cmds = append(cmds, fmt.Sprintf("-Member '%s'", params.Member)) | ||
cmd := strings.Join(cmds, " ") | ||
|
||
// Run command | ||
if err := localRun[GroupMember](ctx, c, cmd, &gm); err != nil { | ||
return fmt.Errorf("windows.local.GroupMemberCreate: %s", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// GroupMemberDelete removes a member from a local Windows group. | ||
// | ||
// Accepted GroupMemberParams: | ||
// - Name | ||
// - SID | ||
// - Member | ||
func (c *LocalClient) GroupMemberDelete(ctx context.Context, params GroupMemberParams) error { | ||
// Satisfy the localType interface | ||
var gm GroupMember | ||
|
||
// Assert needed parameters | ||
if params.Name == "" && params.SID == "" { | ||
return fmt.Errorf("windows.local.GroupMemberDelete: group member parameter 'Name' or 'SID' must be set") | ||
} | ||
|
||
if params.Member == "" { | ||
return fmt.Errorf("windows.local.GroupMemberDelete: group member parameter 'Member' must be set") | ||
} | ||
|
||
// Base command | ||
cmds := []string{"Remove-LocalGroupMember"} | ||
|
||
// Add parameters | ||
// Prefer SID over Name | ||
if params.SID != "" { | ||
cmds = append(cmds, fmt.Sprintf("-SID %s", params.SID)) | ||
} else if params.Name != "" { | ||
cmds = append(cmds, fmt.Sprintf("-Name '%s'", params.Name)) | ||
} | ||
|
||
cmds = append(cmds, fmt.Sprintf("-Member '%s'", params.Member)) | ||
cmd := strings.Join(cmds, " ") | ||
|
||
// Run command | ||
if err := localRun[GroupMember](ctx, c, cmd, &gm); err != nil { | ||
return fmt.Errorf("windows.local.GroupMemberDelete: %s", err) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package local_test | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/d-strobel/gowindows/windows/local" | ||
) | ||
|
||
var groupMemberTestCases = []string{ | ||
"Guest", | ||
"DefaultAccount", | ||
} | ||
|
||
// We insert numbers into the function names to ensure that | ||
// the test functions for each local_* file run in a specific order. | ||
func (suite *LocalAccTestSuite) TestGroupMember1Read() { | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
|
||
for _, c := range suite.clients { | ||
params := local.GroupMemberParams{ | ||
Name: "Administrators", | ||
Member: "Administrator", | ||
} | ||
u, err := c.GroupMemberRead(ctx, params) | ||
suite.Require().NoError(err) | ||
suite.Equal(local.GroupMember{ | ||
Name: "WIN2022SC\\Administrator", | ||
SID: local.SID{ | ||
Value: "S-1-5-21-153895498-367353507-3704405138-500", | ||
}, | ||
ObjectClass: "User", | ||
}, u) | ||
} | ||
} | ||
|
||
func (suite *LocalAccTestSuite) TestGroupMember2List() { | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
|
||
for _, c := range suite.clients { | ||
u, err := c.GroupMemberList(ctx, local.GroupMemberParams{ | ||
Name: "Administrators", | ||
}) | ||
suite.Require().NoError(err) | ||
suite.Contains(u, local.GroupMember{ | ||
Name: "WIN2022SC\\Administrator", | ||
SID: local.SID{ | ||
Value: "S-1-5-21-153895498-367353507-3704405138-500", | ||
}, | ||
ObjectClass: "User", | ||
}) | ||
suite.Contains(u, local.GroupMember{ | ||
Name: "WIN2022SC\\vagrant", | ||
SID: local.SID{ | ||
Value: "S-1-5-21-153895498-367353507-3704405138-1000", | ||
}, | ||
ObjectClass: "User", | ||
}) | ||
} | ||
} | ||
|
||
func (suite *LocalAccTestSuite) TestGroupMember3Create() { | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
|
||
for i, c := range suite.clients { | ||
params := local.GroupMemberParams{ | ||
Name: "Administrators", | ||
Member: groupMemberTestCases[i], | ||
} | ||
err := c.GroupMemberCreate(ctx, params) | ||
suite.NoError(err) | ||
} | ||
} | ||
|
||
func (suite *LocalAccTestSuite) TestGroupMember4Remove() { | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
|
||
for i, c := range suite.clients { | ||
params := local.GroupMemberParams{ | ||
Name: "Administrators", | ||
Member: groupMemberTestCases[i], | ||
} | ||
err := c.GroupMemberDelete(ctx, params) | ||
suite.NoError(err) | ||
} | ||
} |
Oops, something went wrong.