diff --git a/ad/internal/winrmhelper/winrm_computer.go b/ad/internal/winrmhelper/winrm_computer.go index d3ac6a84..84ec7d87 100644 --- a/ad/internal/winrmhelper/winrm_computer.go +++ b/ad/internal/winrmhelper/winrm_computer.go @@ -15,6 +15,7 @@ type Computer struct { Name string GUID string `json:"ObjectGuid"` DN string `json:"DistinguishedName"` + Description string SAMAccountName string `json:"SamAccountName"` Path string SID SID `json:"SID"` @@ -25,6 +26,7 @@ func NewComputerFromResource(d *schema.ResourceData) *Computer { return &Computer{ Name: SanitiseTFInput(d, "name"), DN: SanitiseTFInput(d, "dn"), + Description: SanitiseTFInput(d, "description"), GUID: SanitiseTFInput(d, "guid"), SAMAccountName: SanitiseTFInput(d, "pre2kname"), Path: SanitiseTFInput(d, "container"), @@ -67,6 +69,10 @@ func (m *Computer) Create(conn *winrm.Client, execLocally bool) (string, error) cmd = fmt.Sprintf("%s -Path %q", cmd, m.Path) } + if m.Description != "" { + cmd = fmt.Sprintf("%s -Description %q", cmd, m.Description) + } + result, err := RunWinRMCommand(conn, []string{cmd}, true, false, execLocally) if err != nil { return "", fmt.Errorf("winrm execution failure while creating computer object: %s", err) @@ -100,6 +106,22 @@ func (m *Computer) Update(conn *winrm.Client, changes map[string]interface{}, ex } } + if description, ok := changes["description"]; ok { + if description == "" { + description = "$null" + } else { + description = fmt.Sprintf("%q", description) + } + cmd := fmt.Sprintf("Set-ADComputer -Identity %q -Description %s", m.GUID, description) + result, err := RunWinRMCommand(conn, []string{cmd}, true, false, execLocally) + if err != nil { + return fmt.Errorf("winrm execution failure while modifying computer description: %s", err) + } + if result.ExitCode != 0 { + return fmt.Errorf("Set-ADComputer exited with a non zero exit code (%d), stderr: %s", result.ExitCode, result.StdErr) + } + } + return nil } diff --git a/ad/resource_ad_computer.go b/ad/resource_ad_computer.go index 3301a67b..fae8c99d 100644 --- a/ad/resource_ad_computer.go +++ b/ad/resource_ad_computer.go @@ -43,6 +43,11 @@ func resourceADComputer() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Specifies a description of the object. This parameter sets the value of the Description property for the computer object.", + }, "guid": { Type: schema.TypeString, Computed: true, @@ -80,6 +85,7 @@ func resourceADComputerRead(d *schema.ResourceData, meta interface{}) error { } _ = d.Set("name", computer.Name) _ = d.Set("dn", computer.DN) + _ = d.Set("description", computer.Description) _ = d.Set("guid", computer.GUID) _ = d.Set("pre2kname", computer.SAMAccountName) _ = d.Set("container", computer.Path) @@ -115,7 +121,7 @@ func resourceADComputerUpdate(d *schema.ResourceData, meta interface{}) error { defer meta.(ProviderConf).ReleaseWinRMClient(client) computer := winrmhelper.NewComputerFromResource(d) - keys := []string{"container"} + keys := []string{"container", "description"} changes := make(map[string]interface{}) for _, key := range keys { if d.HasChange(key) { diff --git a/ad/resource_ad_computer_test.go b/ad/resource_ad_computer_test.go index 5332cffb..2a4c16f2 100644 --- a/ad/resource_ad_computer_test.go +++ b/ad/resource_ad_computer_test.go @@ -33,6 +33,36 @@ func TestAccResourceADComputer_basic(t *testing.T) { }) } +func TestAccResourceADComputer_description(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: resource.ComposeTestCheckFunc( + testAccResourceADComputerDescriptionExists("ad_computer.c", "testdescription", false), + ), + Steps: []resource.TestStep{ + { + Config: testAccResourceADComputerConfigBasic("testcomputer", "TESTCOMPUTER$"), + Check: resource.ComposeTestCheckFunc( + testAccResourceADComputerExists("ad_computer.c", "testcomputer", true), + ), + }, + { + Config: testAccResourceADComputerConfigDescription("testcomputer", "TESTCOMPUTER$", "testdescription"), + Check: resource.ComposeTestCheckFunc( + testAccResourceADComputerDescriptionExists("ad_computer.c", "testdescription", true), + ), + }, + { + Config: testAccResourceADComputerConfigBasic("testcomputer", "TESTCOMPUTER$"), + Check: resource.ComposeTestCheckFunc( + testAccResourceADComputerDescriptionExists("ad_computer.c", "", true), + ), + }, + }, + }) +} + func TestAccResourceADComputer_move(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -69,6 +99,20 @@ resource "ad_computer" "c" { `, name, prewin2kname) } +func testAccResourceADComputerConfigDescription(name, prewin2kname, description string) string { + return fmt.Sprintf(` +variable "name" { default = %q } +variable "pre2kname" { default = %q } +variable "description" { default = %q } + +resource "ad_computer" "c" { + name = var.name + pre2kname = var.pre2kname + description = var.description +} +`, name, prewin2kname, description) +} + func testAccResourceADComputerConfigMove(name, prewin2kname string) string { return fmt.Sprintf(` variable "name" { default = %q } @@ -114,3 +158,32 @@ func testAccResourceADComputerExists(resource, name string, expected bool) resou return nil } } + +func testAccResourceADComputerDescriptionExists(resource, description string, expected bool) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resource] + if !ok { + return fmt.Errorf("%s key not found in state", resource) + } + + client, err := testAccProvider.Meta().(ProviderConf).AcquireWinRMClient() + if err != nil { + return err + } + defer testAccProvider.Meta().(ProviderConf).ReleaseWinRMClient(client) + + guid := rs.Primary.ID + computer, err := winrmhelper.NewComputerFromHost(client, guid, false) + if err != nil { + if strings.Contains(err.Error(), "ObjectNotFound") && !expected { + return nil + } + return err + } + + if computer.Description != description { + return fmt.Errorf("Computer description %q does not match expected description %q", computer.Description, description) + } + return nil + } +} diff --git a/docs/resources/computer.md b/docs/resources/computer.md index e25bd8c5..1a33203c 100644 --- a/docs/resources/computer.md +++ b/docs/resources/computer.md @@ -30,6 +30,7 @@ resource "ad_computer" "c" { ### Optional - **container** (String, Optional) The DN of the container used to hold the computer account. +- **description** (String, Optional) Specifies a description of the object. This parameter sets the value of the Description property for the computer object. - **id** (String, Optional) The ID of this resource. - **pre2kname** (String, Optional) The pre-win2k name for the computer account.