1

I wrote PowerShell script to automate some of the AD commands. Here is the script.

 $usergroup="TACACS Admins"
 $computerrole="1626-APPCONF"
 $zone="AWS"
 $username="<>"
 $password="<>";
 [String[]] $HostServers ='smp001-01','sl1ps01-13-9';

 $ValidatedHostServers = @()
 $NotValidatedHostServers = @()

 Import-Module ActiveDirectory
 Import-Module Centrify.DirectControl.PowerShell

 $Password = ConvertTo-SecureString $password -AsPlainText -Force
 $Cred = New-Object     System.Management.Automation.PSCredential($username,$Password)
Set-CdmCredential -Domain <> -Credential $Cred



function Add-HostComputer{
Param($cred,$zone,$computerrole,$ValidatedHostServers)

# Get Computer Role
$GroupName = Get-ADGroup -Identity $computerrole 
Write-Output $GroupName

foreach($Host in $ValidatedHostServers)
{
  #Get -Member 
  $DistinguishedName = Get-ADComputer -Identity $Host
  Write-Output $ValidatedHostServers

  #Add $Hostserver to $comprole computer Role
  $Output = Add-ADGroupMember -Identity $GroupName -Members $DistinguishedName -Credential $Cred
}
}



function ValidateHost{
  Param($HostServers)
  foreach($HostName in $HostServers)
 {
 try{
      $HostOutput = Get-ADComputer -Identity $HostName -ErrorAction SilentlyContinue
     $ValidatedHostServers += $HostName
 }
catch
{
    $NotValidatedHostServers += $HostName
}
}

 Write-Host $ValidatedHostServers
 $Result = @{"Valid_hosts"=$ValidatedHostServers;"Invalid_hosts"=$NotValidatedHostServers} | ConvertTo-Json -Compress
 Write-Host $Result
 Write-Host $ValidatedHostServers.Count
 If($ValidatedHostServers.Count -ne 0) 
  { 
  Write-Host $ValidatedHostServers
  Add-HostComputer -Cred $Cred -zone $zone -computerrole $computerrole - 
  ValidatedHostServers $ValidatedHostServers

  }

}
 $Final = ValidateHost -HostServers $HostServers
 Write-Host $Final

I have tried to write-host the inputs and found $ValidatedHostServers array does not coming as array. May I be I am missing something in syntax.

There are two values in array but

       Write-Host $ValidatedHostServers.Count display as 1.

Thanks in advance for helping here.

This is Error displayed in powerShell

  smp001-01sl1ps01-13-9
  {"Invalid_hosts":[],"Valid_hosts":"smp001-01sl1ps01-13-9"}
  1
  smp001-01sl1ps01-13-9
   Cannot overwrite variable Host because it is read-only or constant.
   At line:27 char:9 + foreach($Host in $ValidatedHostServers) + CategoryInfo : WriteError: (Host:String) [],      SessionStateUnauthorizedAccessException + FullyQualifiedErrorId : VariableNotWritable

 CN=1626-APPCONF,OU=Role Groups- 
 Computer,OU=Centrify,OU=Operations,DC=qateradatacloud,DC=com
2
  • 3
    $host is an automatic variable in PowerShell. You should not assign anything to it. Replace that at a minimum Commented Jun 5, 2019 at 1:28
  • 1
    It would be far easier to iterate over your list of validated hosts rather than try to import them all as a parameter. And it's not a good idea to use the same name for a variable and a function. Your $ValidatedHostServers.Count is 1 becuase it only has one object - you're concatenating the server names instead of adding as objects. Commented Jun 5, 2019 at 7:30

2 Answers 2

2

If you reduce your code to a minimum script that reproduces the behaviour you'll get something like this:

$ValidatedHostServers = @( "xxx" );

function ValidateHost
{
    write-host "inside before = '$($ValidatedHostServers | ConvertTo-Json)'";
    $ValidatedHostServers += "smp001-01";
    $ValidatedHostServers += "sl1ps01-13-9";
    write-host "inside after = '$($ValidatedHostServers | ConvertTo-Json)'";
    write-host ($ValidatedHostServers | ConvertTo-Json)
}

write-host "value before = '$($ValidatedHostServers | ConvertTo-Json)'";
ValidateHost;
write-host "value after = '$($ValidatedHostServers | ConvertTo-Json)'";

which outputs the following:

value before = '"xxx"'
inside before = '"xxx"'
inside after = '"smp001-01sl1ps01-13-9"'
value after = '"xxx"'

I think there's two things happening here:

  • Your function is executing in a child scope so the changes made inside your function to variables defined in the parent scope (i.e. $ValidatedHostServer) don't survive when the function exits - see quote from child scope link:

items that you create and change in the child scope do not affect the parent scope, unless you explicitly specify the scope when you create the items.

  • There's possibly a bug in PowerShell in the assignment by addition operator (i.e. '+=') when it first assigns a value to a parent variable in a child scope - it's basically treating the $ValidatedHostServers as if it were undefined and converting it into a string, which then causes the second += to do string concatenation instead of array appending.

You can work around both of these issues like this:

#$ValidatedHostServers = @( "xxx" ); <- replace this with the next line

Set-Variable -Name "ValidatedHostServers" -Option AllScope -Value @( "xxx" );

The "AllScope" option allows the child scope (i.e. the function) to modify variables in the parent scope so your changes will persist after the function exists. It also side-steps the potential bug in the "assignment by addition operator".

Set-Variable -Name "ValidatedHostServers" -Option AllScope -Value @( "xxx" );

function ValidateHost
{
    write-host "inside before = '$($ValidatedHostServers | ConvertTo-Json)'";
    $ValidatedHostServers += "smp001-01";
    $ValidatedHostServers += "sl1ps01-13-9";
    write-host "inside after = '$($ValidatedHostServers | ConvertTo-Json)'";
    write-host ($ValidatedHostServers | ConvertTo-Json)
}

write-host "value before = '$($ValidatedHostServers | ConvertTo-Json)'";
ValidateHost;
write-host "value after = '$($ValidatedHostServers | ConvertTo-Json)'";

and then we get this output

value before = '"xxx"'
inside before = '"xxx"'
inside after = '[
    "xxx",
    "smp001-01",
    "sl1ps01-13-9"
]'
[
    "xxx",
    "smp001-01",
    "sl1ps01-13-9"
]
value after = '[
    "xxx",
    "smp001-01",
    "sl1ps01-13-9"
]'

UPDATE

Related issues in PowerShell github repo:

Sign up to request clarification or add additional context in comments.

Comments

0

Try it this way, get the list then iterate over it:

function ValidateHost{
    Param($HostServers)
#
    $GroupName = Get-ADGroup -Identity $computerrole
#
# Get server validation list
    $CheckedServers = $HostServers | ForEach-Object {
        Try {
            $HostOutput = Get-ADComputer -Identity $_ -ErrorAction Stop
            $Validated = $true
        }
        Catch {
            $Validated = $false
        }
        [pscustomobject]@{HostName = $_;Validated = $Validated}
    }

    # Add-HostComputer
# Iterate over list of validated servers
    $CheckedServers | Where-Object { $_.Validated -eq $true } | ForEach-Object { 
        Try {
            $DistinguishedName = Get-ADComputer -Identity $_.HostName -ErrorAction Stop
            $Output = Add-ADGroupMember -Identity $GroupName -Members $DistinguishedName -Credential $Cred -ErrorAction Stop
        }
        Catch {
            $Output = $_
        }
        [pscustomobject]@{HostName = $_.HostName;DN = $DistinguishedName;Result = $output}
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.