Search code examples
powershellexchange-serverexchange-server-2010

Same array content, giving me different results


Summary of issue

I have two variables with the same content, the only difference is how the variable was populated, when i try to use it in exchange management shell i get for one variable an error while the other one works as it should be.

Long explanation - With examples

I created a transport rule to block emails from specific senders, I'm trying to use one line in powershell to add users the the block list.

  1. I tried first the regular way to manipulate an array using set-transportrule -identity "whatever" -from @{add="whoever"} But this doesn't work, i researched it and saw that it's by design, so i gave up on this.
  2. So I tried something else set-transportrule -identity "whatever" -from (get-transportrule -identity "whatever").from,"whoever2" But i again hit a road block.
  3. So tried set-transportrule -identity "whatever" -from "whoever1","whoever2" and it worked beautifully. But this is not what i want I'm trying to add to the existing values.

This got me thinking, so i started testing to find the differences between the two arrays

  1. First I created a variable variable1 = "whoever1","whoever2" and used it like this set-transportrule -identity "whatever" -from $variable1 and it worked as it should be.
  2. So I went ahead and created another variable variable2 = (get-transportrule -identity "whatever").from,"whoever2" and tried using it set-transportrule -identity "whatever" -from $variable2, but this didn't work.

I compared the variable types and they are identical. Whats going on here? What am i missing

Thanks in advance for any help!


Solution

  • In order to concatenate two arrays flatly, you must use +:

    set-transportrule -identity "whatever" `
                      -from ((get-transportrule -identity "whatever").from + "whoever2")
    

    Note: Since operator + can only be used in an expression, the entire -from argument must be enclosed in (...).

    By contrast, <array>, <scalar> creates a 2-element array whose 1st element is <array>, and whose 2nd element is <scalar>, which is not your intent.

    ,, which is PowerShell's array-construction operator, creates an array with each operand becoming an array element as-is, whether a given operand is a scalar or an array.

    By contrast, with an array-valued LHS, + concatenates the LHS and RHS, by appending the RHS element(s) as additional elements to the LHS (which implicitly creates a new array, given that arrays are fixed-size).


    A simplified example:

    $arr = 1, 2   # input array
    $scalar = 3   # scalar to append
    
    # INCORRECT: Creates *nested* array.
    ($arr, $scalar).Count # -> 2(!); [0] of the new array contains $arr, [1] $scalar
    # Same as: (1, 2), 3
    
    # CORRECT: Creates *flat* array.
    ($arr + $scalar).Count # -> 3
    # Same as: (1, 2) + 3 == 1, 2, 3
    

    Note that you can't tell the difference between $arr, $scalar and $arr + $scalar by how they print to the screen, because the implicit output formatting implicitly enumerates an array received as a single input object.

    You can make the difference visible by piping to Format-Table with -Expand CoreOnly, which suppresses the implicit enumeration and instead prints the properties of any array element itself:

    # Flat array: prints as expected.
    PS> $arr + $scalar | Format-Table -Expand CoreOnly
    1
    2
    3
    
    # Array with sub-arrays: output reveals the presence of subarrays
    PS> $arr, $scalar | Format-Table -Expand CoreOnly
    
    Length LongLength Rank SyncRoot IsReadOnly IsFixedSize IsSynchronized Count
    ------ ---------- ---- -------- ---------- ----------- -------------- -----
         2          2    1 {1, 2}        False        True          False     2
    3
    

    For additional information, see the bottom section of this answer.