Hash Table with validation / IF / Else

Hello Everyone,

I am writting some PowerShell Modules for importing AD accounts from a CSV. Below is the code:

Function Import-ADUsers {


[CmdletBinding()]
Param(
    [Parameter(Mandatory=$true,HelpMessage='Supply the CSV file name and path')]
    [String]$CSVFile)
    
$users = import-csv $CSVFile

foreach ($user in $users) {

$pass = ConvertTo-SecureString -AsPlainText $user.AccountPassword -force
 
#define a hashtable to splat to New-ADUser
 $hash = [ordered]@{

  Description = $($user.description);
  Employeeid = $($user.employeeID);
  Path = $($user.distinguishedName);
  givenname = $($user.givenname);
  surname = $($user.sn);
  name = $($user.name);
  emailaddress = $($user.mail);
  title = $($user.title);
  department = $($user.department);
  streetaddress = $($user.streetaddress);
  city = $($user.l);
  postalcode = $($user.postalcode);
  officephone = $($user.telephonenumber);
  mobilephone = $($user.mobile);
  sAMAccountName = $($user.samaccountname);
  office = $($user.physicalDeliveryOfficeName);
  accountpassword = $pass;
  otherattributes = @{extensionattribute1=($user.extensionattribute1);proxyaddresses=($user.proxyaddresses -split ';')}; #this splits the proxyaddress string from the CSV, using ; as a delimiter
  #otherAttributes = @{proxyAddresses = ("SMTP:" + $user.mail)};
  userprincipalname = $($user.mail);
  } #close hash & child hash

  Write-Debug "Preparing to query $computer"
  
  New-ADUser @hash -Enabled $true -ChangePasswordAtLogon $true -PassThru -Server hhs-ln1-pdc01

 
  } #close foreach
  } #close function

Function Enable-MEU {




    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$True,
        HelpMessage='Supply the CSV file name and path')]
        [string]$CSVfile,
        
        [Parameter(Mandatory=$True,
        HelpMessage='Supply the target address starting with @')]
        [string]$TargetAddressSuffix
        )

# Connects to Exchange Server Remotely
#Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File C:\scripts\EXpassword.txt
$password=get-content C:\scripts\EXpassword.txt | ConvertTo-SecureString
$userid='a01.stuart.hendry'
$UserCredential=New-Object System.Management.Automation.PSCredential $userid,$password

$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://hhs-ln1-pexc01/PowerShell/ -Authentication Kerberos -Credential $UserCredential
Import-PSSession $Session
    
$users = import-csv $csvfile
$targetaddresssuffix = $targetaddresssuffix

foreach ($user in $users) {
   
   Enable-MailUser $user.SamAccountName -ExternalEmailAddress ($user.samaccountname + $targetaddresssuffix)
  #New-MailUser $user.SamAccountName -ExternalEmailAddress $users.emailaddress 
  #Set-MailUser $user.SamAccountName -EmailAddresses @{Add="$user.samaccountname",$targetaddresssuffix}
  } #close foreach
  } #close function

I want a way to check each hash table value, and if its $null (blank) then take it out of the hash table. The reason is, New-ADuser errors when some values in the HASH table are blank. For example, the ‘description’ field in the CSV import is blank. So the HASH table imports from the CSV it then passes a blank value to New-ADUser. This then causes an error. So I want a way to run an IF statement within the HASH table to check if the attribute has an assigned value. SO if = $null then dont pass the parameter to New-ADUser.

Is it ok to do IF / ELSE statements from within the hash table? Or is there a better way?

Many Thanks

The best approach will be to wrap New-ADUser in a Try Catch block and handle the errors. When you catch an error you could write it to a log file so you know which ones failed.

You can remove the keys with null values, but you have to take care. You can’t remove items while iterating through them. Create a list of the items to remove, then remove them.

Untested

$rem = New-Object System.Collections.ArrayList

foreach ($h in $hash.Keys) {
    if ([string]::IsNullOrEmpty($($hash.Item($h)))) {
        [void]$rem.Add($h)
    }
}

foreach ($h in $rem)
{
    $hash.Remove($h)
}

Another option is to add items to the hashtable if it’s not null:

Function Import-ADUsers {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true,HelpMessage='Supply the CSV file name and path')]
        [String]$CSVFile
    )
    $users = import-csv $CSVFile

    foreach ($user in $users) {

        $pass = ConvertTo-SecureString -AsPlainText $user.AccountPassword -force
 
        #define a hashtable to splat to New-ADUser
         $hash = [ordered]@{
              Description            = $($user.description);
              Employeeid             = $($user.employeeID);
              Path                   = $($user.distinguishedName);
              givenname              = $($user.givenname);
              surname                = $($user.sn);
              name                   = $($user.name);
              emailaddress           = $($user.mail);
              title                  = $($user.title);
              department             = $($user.department);
              streetaddress          = $($user.streetaddress);
              city                   = $($user.l);
              postalcode             = $($user.postalcode);
              officephone            = $($user.telephonenumber);
              sAMAccountName         = $($user.samaccountname);
              office                 = $($user.physicalDeliveryOfficeName);
              accountpassword        = $pass;
              otherattributes        = @{extensionattribute1=($user.extensionattribute1);proxyaddresses=($user.proxyaddresses -split ';')}; #this splits the proxyaddress string from the CSV, using ; as a delimiter
              #otherAttributes       = @{proxyAddresses = ("SMTP:" + $user.mail)};
              userprincipalname      = $($user.mail);
              Enabled                = $true
              ChangePasswordAtLogon  = $true
              Server                 = "pdc01"
              PassThru               = $true
          } #close hash & child hash

          #if the mobile is not null, add it to the hash
          if ( $user.mobile ) {$hash.Add( "mobilephone", $($user.mobile)) }

          Write-Debug "Preparing to query $computer"
  
          New-ADUser @hash  
 
    } #close foreach
 } #close function

Hi, thanks, yes I want to add in error reporting too at a later point, and was going to use the TRY CATCH method. However in many cases, its ok if these fields are blank. Could be that some fields like description are not desirable so would be left out on purpose, but this shouldnt be parsed otherwise it will error, rather it should be removed if blank. Then if critial attributes are missed (perhaps SamAccountName) then at that point it should be logged as a fail error and carry on with the rest.

Not quite there let with the error reporting bit, but its on the list of things. Takes me ages, as I am still learning. Thanks for your suggestion

Thank you

Awesome, looks good, I’ll try this now, thank you

Hi Rob,

I am just testing this out in a more simplied form. Cant see to get it to work:

$users = import-csv c:\import1.csv

foreach ($user in $users) {

#if the mobile is not null, add it to the hash
          if ( $user.Description ) {$hash.Add("Description", $($user.description)) }

          }

Just says “You cannot call a method on a null-valued expression.” I have turned on Debug mode in ISE, and its getting stuck on the IF statement. I have checked all the variables using Debug, $user is popupated with a ‘description’ within it.

I expect its a very simple fix. I went on an advanced course recently, but the devil is in the detail. As a beginner its always catching me out.

Thanks

Tried this too:

$users = import-csv c:\import1.csv
foreach ($user in $users) {
$hash = [ordered]@{
  Description = if ( $user.Description ) {$hash.Add("Description", $($user.description)) };
  }
  }

This almost works, but the output of $hash is:

Name Value


Description

So the value is blank

oh ive figured it out now thanks

  if ( $user.description ) {$hash.Add( "description", $($user.description)) };
  if ( $user.sn ) {$hash.Add( "surname", $($user.sn)) };

I thought you needed the ‘@’ to start a hash table. So your solution is to do away with the hash table, and create an array with $hash

Seems to work, is my understanding correct?

Thanks

Stuck at this point now:

if ($_.Description) {$hash.Add("Description", ($_.description)) };

Seems pipeline variables are not compatible in the syntax above. How to I use $_.var within the $hash.add ?

Many Thanks

Try this:

$hash.Add(“Description”, ($_).description)

perfect, may I ask, why is it necessary to put the ‘$_’ into brackers just because its a pipeline var?

I don’t know the exact technical reason, it has something to do with the order of evaluation inside of the function call.

This specific error is because you’ve not defined $hash in your code. After your import-csv and before the foreach, just add $hash=@{} and this code should work.

With the least modification of your original code in mind, you can simply remove empty values by doing this:

Foreach($val in $hash.keys){
  If([string]::IsNullOrEmpty($hash[$val])){
    $hash.remove($val)
  }
}

Place that before you call new-aduser.