none
More fun with OU names from distinguishedname - inconsistent number of children RRS feed

  • Question

  • Hi - this is a followup question to something I asked earlier. I want to extract OU names for a bunch of  distinguishednames I've obtained using get-adcomputer....

    The only consistent thing is that they're all under a parent OU, OU=NOTWANTED. E.g., 

    CN=COMPUTERNAME,OU=OU3,OU=OU2,OU=OU1,OU=NOTWANTED,DC=FOO,DC=BAR,DC=COM
    
    CN=COMPUTERNAME,OU=OU2,OU=OU1,OU=NOTWANTED,DC=FOO,DC=BAR,DC=COM
    
    CN=COMPUTERNAME,OU=OU1,OU=NOTWANTED,DC=FOO,DC=BAR,DC=COM
    
    CN=COMPUTERNAME,OU=NOTWANTED,DC=FOO,DC=BAR,DC=COM
    


    What I have right now (thank you, jrv...) is: 

    $fullDN=[adsi]"LDAP://$($computername.DistinguishedName)"
    	
    $container1=[adsi]$FullDN.Parent
    $container2=[adsi]$container1.Parent
    $container3=[adsi]$container2.Parent
    
    $ou1=$container1.Name 
    $ou2=$container2.Name
    $ou3=$container3.Name
    	
    $OU="$OU3/$OU2/$OU1"   
    

    This is a good start, but:

    1. I want to see *only* the OUs that are children of OU=NOTWANTED, and not the parent OU NOTWANTED,
      except ...
    2. If there is no child OU under OU=NOTWANTED, I just want to see NOTWANTED, and nothing else.

    Thanks for any help you can provide; if I'm not phrasing this question well, please let me know how I can improve it.  

    Tx

    LW


               

    Lanwench ** Do not fold, spindle or mutilate. Use only a #2 pencil. Fill in the box completely and erase any stray marks.

    Tuesday, April 22, 2014 7:17 PM

Answers

  • Here's an example that uses Get-ADPathname.ps1 and array indexing:


    function Get-ElementIndex {
      param(
        [Object[]] $array,
        $element
      )
      for ( $i = 0; $i -lt $array.Count; $i++ ) {
        if ( $element -eq $array[$i] ) {
          return $i
        }
      }
      return -1
    }
    
    $path = 'CN=COMPUTERNAME,OU=OU3,OU=OU2,OU=OU1,OU=NOTWANTED,DC=FOO,DC=BAR,DC=COM'
    $pathSplit = Get-ADPathname $path -Split
    $notWantedIndex = Get-ElementIndex $pathSplit 'OU=NOTWANTED'
    if ( $notWantedIndex -gt -1 ) {
      $result = & {
        for ( $i = 1; $i -lt $notWantedIndex; $i++ ) {
          $pathSplit[$i]
        }
      }
      $result -join '/'  # outputs 'OU=3/OU=2/OU=1'
    }


    -- Bill Stewart [Bill_Stewart]

    Wednesday, April 23, 2014 3:18 PM
    Moderator

All replies

  • What do you mean by "see"?  Are you saying you want to retrieve all of the OUs under that OU?

    ¯\_(ツ)_/¯

    Tuesday, April 22, 2014 7:29 PM
  • Yep, retrieve.

    I want to ignore the CN=whatever, and get all the OUs up to NOTWANTED individually  (unless there is no child OU under NOTWANTED ..in which case I want only NOTWANTED .

    I don't want to include the text "OU=" either. Just the name of the OU.

    Does that help clarify?


    Lanwench ** Do not fold, spindle or mutilate. Use only a #2 pencil. Fill in the box completely and erase any stray marks.


    • Edited by Lanwench Tuesday, April 22, 2014 7:33 PM clarification of verb
    Tuesday, April 22, 2014 7:32 PM
  • It sounds like the Get-ADPathname.ps1 script might be useful to you.

    Windows IT Pro: Use PowerShell to Handle Active Directory Paths


    PS C:\> Get-ADPathname 'CN=COMPUTERNAME,OU=OU3,OU=OU2,OU=OU1,OU=NOTWANTED,DC=FOO,DC=BAR,DC=COM' -RemoveLeafElement
    OU=OU3,OU=OU2,OU=OU1,OU=NOTWANTED,DC=FOO,DC=BAR,DC=COM
    


    -- Bill Stewart [Bill_Stewart]

    Tuesday, April 22, 2014 7:54 PM
    Moderator
  • Thanks, Bill - it does look interesting. Am checking it out. I'm still quite new to powershell & am self-educating, so a lot of this is still confusing me :)

    Lanwench ** Do not fold, spindle or mutilate. Use only a #2 pencil. Fill in the box completely and erase any stray marks.

    Tuesday, April 22, 2014 8:07 PM
  • Yep, retrieve.

    I want to ignore the CN=whatever, and get all the OUs up to NOTWANTED individually  (unless there is no child OU under NOTWANTED ..in which case I want only NOTWANTED .

    I don't want to include the text "OU=" either. Just the name of the OU.

    Does that help clarify?


    Lanwench ** Do not fold, spindle or mutilate. Use only a #2 pencil. Fill in the box completely and erase any stray marks.


    Please answer the question exactly.  Are you trying to retrieve all objects that are children of "OU=NOTWANTED,DC=FOO,DC=BAR,DC=COM"?

    If that is it then ther eis a much easier way to do this. It is the way you are asking the question that is confusing you.  That is what I meant about not using technology to ask because when you do not know the definition of terms thay only confuse the question.

    FYI: The CN= and OU= are the "Name" value of the object.  First we locate the objects then we return what you need.
    To figure this out we need to know "why".  The "why" will tell us how.



    ¯\_(ツ)_/¯

    Tuesday, April 22, 2014 8:42 PM
  • >>Please answer the question exactly.  Are you trying to retrieve all objects that are children of "OU=NOTWANTED,DC=FOO,DC=BAR,DC=COM"?

    Yes, except for the CN. Just the OUs. :-)


    Lanwench ** Do not fold, spindle or mutilate. Use only a #2 pencil. Fill in the box completely and erase any stray marks.

    Tuesday, April 22, 2014 8:44 PM
  • >>Please answer the question exactly.  Are you trying to retrieve all objects that are children of "OU=NOTWANTED,DC=FOO,DC=BAR,DC=COM"?

    Yes, except for the CN. Just the OUs. :-)


    Lanwench ** Do not fold, spindle or mutilate. Use only a #2 pencil. Fill in the box completely and erase any stray marks.

    What does that mean.  Do you want the names of child objects under that OU? Why? 


    ¯\_(ツ)_/¯

    Tuesday, April 22, 2014 8:51 PM
  • Get the OU and then get all servers recursively then get the names.  It is simple.  It is accurate.  I showed you above how to get the objects parent and grandparent.

    You are not saying why?  It is the why that tells us how to best get this. 

    The 'Name' property of each object is what you say you want.  Get the objects and get the names.


    ¯\_(ツ)_/¯

    Wednesday, April 23, 2014 12:18 AM
  • Hmm...we seem to be on different pages here. Perhaps 

    >>Get the OU and then get all servers recursively then get the names.

    But I don't need to get at the computer objects - I have those, and I know how to get them. Anyway, the list of servers in question here, is generated elsewhere, and that list is what I need to start with as my base. 

    You indeed showed me how to get the names of the parent/grandparent, yes - but in order for that to meet my requirements as I've outlined them, I would have to have a consistent/fixed hierarchy/level, which I don't.  

    For each of these servers, I want to get the parent OUs names only up to a certain level. . 

    I can't simply ask for parent/grandparent/great-grandparent - there may not be that many. I want to exclude everything above & including DONOTWANT unless it itself is the parent of the server object. 

    I was originally thinking that a regex was the way to go but those are even further beyond my current skillset.

    As to the why - eh, I want to know how to do this. I'm doing some auditing/reporting.  I'm not planning to use this knowledge to make IEDs - I simply want to be able to break out each of these names into individual pieces.

     



    Lanwench ** Do not fold, spindle or mutilate. Use only a #2 pencil. Fill in the box completely and erase any stray marks.

    Wednesday, April 23, 2014 12:33 AM
  • Yes you can.  I have done this many, many times.  It is the easiest way to do it.

    If you don't understand how AD works and just want to play with strings then use the split method I showed you in the beginning. Just test each element of the returned array and stop when there is a match.


    ¯\_(ツ)_/¯


    • Edited by jrv Wednesday, April 23, 2014 12:36 AM
    Wednesday, April 23, 2014 12:35 AM
  • I suspect you are trying to get the cononical name of the object.  That can be done in two lines.  That is why I asked you "why".


    ¯\_(ツ)_/¯

    Wednesday, April 23, 2014 12:39 AM
  • The Get-ADPathname.ps1 script is designed to do exactly what you are asking. No regex or string-splitting is necessary. Let it do the work for you.


    -- Bill Stewart [Bill_Stewart]

    Wednesday, April 23, 2014 2:41 PM
    Moderator
  • The following is a copy of the question:

    I want to see *only* the OUs that are children of OU=NOTWANTED, and not the parent OU NOTWANTED,
    except ...
    • If there is no child OU under OU=NOTWANTED, I just want to see NOTWANTED, and nothing else.

    Thanks for any help you can provide; if I'm not phrasing this question well, please let me know how I can improve it.  

    This gets all OUs that are children of "NOTWANTED"

    Get-ADobject -filter {objectclass -eq 'organizationalunit'} -SearchBase 'OU=NOTWANTED,dc=foo,dc=bar,dc=com'

    The output can be formatted in any way needed.

    This returns all direct children that are contained in the target container and that are organizationalunits.

    Of course the question and the discussion do not agree so it is very difficult to determine exactly what is being asked.

    The above query can be very easily written in AD classes.


    ¯\_(ツ)_/¯

    Wednesday, April 23, 2014 3:01 PM
  • Here's an example that uses Get-ADPathname.ps1 and array indexing:


    function Get-ElementIndex {
      param(
        [Object[]] $array,
        $element
      )
      for ( $i = 0; $i -lt $array.Count; $i++ ) {
        if ( $element -eq $array[$i] ) {
          return $i
        }
      }
      return -1
    }
    
    $path = 'CN=COMPUTERNAME,OU=OU3,OU=OU2,OU=OU1,OU=NOTWANTED,DC=FOO,DC=BAR,DC=COM'
    $pathSplit = Get-ADPathname $path -Split
    $notWantedIndex = Get-ElementIndex $pathSplit 'OU=NOTWANTED'
    if ( $notWantedIndex -gt -1 ) {
      $result = & {
        for ( $i = 1; $i -lt $notWantedIndex; $i++ ) {
          $pathSplit[$i]
        }
      }
      $result -join '/'  # outputs 'OU=3/OU=2/OU=1'
    }


    -- Bill Stewart [Bill_Stewart]

    Wednesday, April 23, 2014 3:18 PM
    Moderator
  • Yes. I know very well how to get the OUs out of AD. I need to do it for each server in a list. I'll try again, since I'm clearly not explaining myself very well...

    I have a list of server names.

    server1
    server2
    server3
    etc

    For each of these servers, I want to get its parent OUs..but only up to a certain point.

    I can go get the cn or the dn easily using get-adcomputer. 


    foo.bar.com/galaxy/earth/bedrock/fred/barney/wilma/server1
    or
    DN=server1,OU=wilma,OU=barney,OU=fred,OU=bedrock,OU=earth,OU=galaxy,DC=foo,DC=bar=DC=com

    I don't care what's in galaxy or earth or anything....bedrock & under.

    If the server is in OU wilma, I want: 
    servername = server1, OU3=fred, OU2=barney, OU1=wilma

    If the server is in OU barney, I want: 
    servername = server1, OU path = OU2=fred, OU1=barney

    If the server is in OU fred, I want: 
    servername = server1, OU1=fred

    But, if the server is just floating around loose in bedrock, I want: 
    servername = server1, OU1=bedrock


    Does that make sense to you?

    What I got from you in the other thread is extremely helpful, and gives me three levels of names:

    $blah=[adsi]"LDAP://$($server.DistinguishedName)"
    $container1=[adsi]$blah.Parent
    $container2=[adsi]$blah.Parent
    $container3=[adsi]$blah.Parent
    $ou1=$container1.Name 
    $ou2=$container2.Name
    $ou3=$container3.Name

    $OU="$OU3/$OU2/$OU1"  

    ...but if I were to apply this to a server in OU fred, I would get 

    $OU1="fred"
    $OU2="bedrock"
    $OU3="earth"

    Correct?

    because I don't know how to tell it, ignore everything above bedrock, including bedrock, unless that's the only parent.

    I was originally using split, which I suspect would work fine for me if I understood how to tell it how to ignore/discard what I don't want to get.



    Lanwench ** Do not fold, spindle or mutilate. Use only a #2 pencil. Fill in the box completely and erase any stray marks.

    Wednesday, April 23, 2014 4:43 PM
  • Thanks, Bill - this looks very promising. I will try this and see :)

    Lanwench ** Do not fold, spindle or mutilate. Use only a #2 pencil. Fill in the box completely and erase any stray marks.

    Wednesday, April 23, 2014 4:45 PM
  • That is the purpose of using SearchBase.  Set SearchBase to thelevel you want.  Thati s how AD works.

    You are thinking in strings and not in AD objects.

    Query at the level you want.

    You are also transposing the terms parent and child.  You are saying you want the children below a point and NOT the parenst above a point. They are opposites.


    ¯\_(ツ)_/¯

    Wednesday, April 23, 2014 5:02 PM
  • Sounds like you want something along these lines:

    $distinguishedNames = @(
        'CN=server1,OU=wilma,OU=barney,OU=fred,OU=bedrock,OU=earth,OU=galaxy,DC=foo,DC=bar,DC=com'
        'CN=server2,OU=bedrock,OU=earth,OU=galaxy,DC=foo,DC=bar,DC=com'
    )
    
    foreach ($distinguishedName in $distinguishedNames)
    {
        $tokens = $distinguishedName -split ',?(?:CN|OU|DC)=' -match '\S'
    
        $serverName = $tokens[0]
    
        $firstToken = $true
        $pathTokens = @(
            for ($i = 1; $i -lt $tokens.Count; $i++)
            {
                if ($tokens[$i] -eq 'bedrock')
                {
                    if ($firstToken)
                    {
                        $tokens[$i]
                    }
                    break
                }
    
                $firstToken = $false
                $tokens[$i]
            }
        )
    
        Write-Verbose -Verbose "ServerName: $serverName, Path: $($pathTokens -join '/')"
    }

    The Write-Verbose line is just for demonstration purposes. The $serverName variable will be a string, and $pathTokens will be an array of strings.
    Wednesday, April 23, 2014 5:21 PM
  • There's no need for regular expressions if you use the Pathname object. The Pathname object also accounts for special characters.


    -- Bill Stewart [Bill_Stewart]

    Wednesday, April 23, 2014 5:30 PM
    Moderator
  • If the computer accounts behind the Distinguished Names still exist, you could use 

    Get-ADComputer <DN> -prop CanonicalName

    to get the canonical names.
    Benefit: The elements within the canonical name are in reverse order compared to the DN. And you dont have to deal with "OU=" and "CN=".

    So what about this:

    $CanName1 = "FOO.BAR.COM/NOTWANTED/OU1/OU2/OU3/COMPUTERNAME"
    $CanName2 = $CanName1.Substring( $CanName1.IndexOf("/")+1 )
    $CanName3 = $CanName2.Substring( 0, $CanName2.LastIndexOf("/") )
    if ( $CanName3 -match "/" ) { 
        $CanName4 = $CanName3.Substring( $CanName3.IndexOf("/")+1 ) 
    } else { 
        $CanName4 = $CanName3 
    }
    

    The variables have these values:

    PS C:\> $CanName1
    FOO.BAR.COM/NOTWANTED/OU1/OU2/OU3/COMPUTERNAME

    PS C:\> $CanName2
    NOTWANTED/OU1/OU2/OU3/COMPUTERNAME

    PS C:\> $CanName3
    NOTWANTED/OU1/OU2/OU3

    PS C:\> $CanName4
    OU1/OU2/OU3

    I know it can be done with less variables but I like it easier to understand as long as it is no performance issue.

    Wednesday, April 23, 2014 6:29 PM
  • Thanks, Walter. This is getting me much closer to where I was trying to go. However, it seems like it's still expecting a fixed number of levels in the hierarchy.

    Here's the actual  (foobled, duh) CN:

    $CanName1 = "foo.bar.com/Universe/Galaxy/Earth/Pangaea/Bedrock/fred/barney/wilma/computername"
    

    So when I run this:

    $CanName2 = $CanName1.Substring( $CanName1.IndexOf("/")+1 )
    $CanName3 = $CanName2.Substring( 0, $CanName2.LastIndexOf("/") )
    if ( $CanName3 -match "/" ) { 
        $CanName4 = $CanName3.Substring( $CanName3.IndexOf("/")+1 ) 
    } else { 
        $CanName4 = $CanName3 
    }

    ...I get this:

    $canname2 = Universe/Galaxy/Earth/Pangaea/Bedrock/fred/barney/wilma/computername
    
    $Canname3 = 
    Universe/Galaxy/Earth/Pangaea/Bedrock/fred/barney/wilma
    
    $Canname4 = 
    Galaxy/Earth/Pangaea/Bedrock/fred/barney/wilma

    I'm sure all of this is very fixable if I can get the syntax/rules right.  It's a valuable learning opportunity :)


    Lanwench ** Do not fold, spindle or mutilate. Use only a #2 pencil. Fill in the box completely and erase any stray marks.

    Thursday, April 24, 2014 10:06 PM
  • Well, get-adcomputer & searchbase are how this list of servers was originally generated, so I'm all good there. My list contains 0 server objects in OU levels higher than BEDROCK. That isn't an issue. 

    You're right, I guess I *am* seeing this as a string. I've got access to either 
    foo.bar.com/Universe/Galaxy/Earth/Pangaea/Bedrock/fred/barney/wilma/computername 
    -or-
    DN=computername,OU=WILMA,OU=BARNEY,OU=FRED,OU=BEDROCK,OU=PANGAEA,OU=EARTH,OU=GALAXY,OU=UNIVERSE,DC=FOO,DC=BAR,DC=COM

    I was assuming it would be easier than it is to just take that as a line of text and lop off the endpieces I don't want to include. 

    As to your comment that I'm reversing the order of my terms: 

    1) John is the child of Mary who is the child of Sam who is the child of Christopher
    2) Christopher is the parent of Sam who is the parent of Mary who is the parent of John

    I think you'd agree that one can scan this hierarchy 'upstream' from baby John, or 'downstream' from great-grandfather Christopher, and you can get the same information (Sam is John's grandfather). 

    I suspect you comprehend my meaning perfectly and are merely enjoying quibbling over semantics. ;)



    Lanwench ** Do not fold, spindle or mutilate. Use only a #2 pencil. Fill in the box completely and erase any stray marks.

    Thursday, April 24, 2014 10:18 PM
  • Woohoo!

    Here's how I doctored up what you provided (just added additional servers to the $distinguishedname array: 

    $distinguishedNames = @(
        'CN=server1,OU=wilma,OU=barney,OU=fred,OU=bedrock,OU=pangaea,OU=earth,OU=galaxy,OU=universe,DC=foo,DC=bar,DC=com'
        'CN=server2,OU=barney,OU=bedrock,OU=pangaea,OU=earth,OU=galaxy,OU=universe,DC=foo,DC=bar,DC=com'
        'CN=server3,OU=fred,OU=bedrock,OU=pangaea,OU=earth,OU=galaxy,OU=universe,DC=foo,DC=bar,DC=com'
        'CN=server4,OU=bedrock,OU=pangaea,OU=earth,OU=galaxy,OU=universe,DC=foo,DC=bar,DC=com'
        'CN=server5,OU=bambam,OU=wilma,OU=bedrock,OU=pangaea,OU=earth,OU=galaxy,OU=universe,DC=foo,DC=bar,DC=com'
    )

    foreach ($distinguishedName in $distinguishedNames){ $tokens = $distinguishedName -split ',?(?:CN|OU|DC)=' -match '\S' $serverName = $tokens[0] $firstToken = $true $pathTokens = @( for ($i = 1; $i -lt $tokens.Count; $i++) { if ($tokens[$i] -eq 'Bedrock') { if ($firstToken) { $tokens[$i] } break } $firstToken = $false $tokens[$i] } ) Write-Verbose -Verbose "ServerName: $serverName, Path: $($pathTokens -join '/')" }

    ...and here's what it gives me:

    VERBOSE: ServerName: server1, Path: wilma/barney/fred
    VERBOSE: ServerName: server2, Path: barney
    VERBOSE: ServerName: server3, Path: fred
    VERBOSE: ServerName: server4, Path: bedrock
    VERBOSE: ServerName: server5, Path: bambam/wilma

    I then figured out how to reverse the order in the array, so that it's big to little instead of little to big - I added

    [Array]::Reverse($Pathtokens)

    So that gave me fred/barney/wilma, instead of  wilma/barney/fred - just as I wanted. 

    Now, let's say I also wanted to grab each of the array members from $Pathtokens and assign each to a variable? 

    E.g.,  out of $Pathtokens,
    $OU3 = wilma
    $OU2 = barney
    $OU1 = fred

    I feel like this must be easy, but I'm missing something.

    If I were to use $pathtoken[1], $pathtoken[2], $pathtoken[3] etc., I would be in trouble if this server was at the root of the bedrock OU, and hence had only one parent OU visible, right? I don't want anything that requires I know how many items are in the array. 

    This is fun. At least, for me.


    Lanwench ** Do not fold, spindle or mutilate. Use only a #2 pencil. Fill in the box completely and erase any stray marks.


    • Edited by Lanwench Thursday, April 24, 2014 10:46 PM correction
    Thursday, April 24, 2014 10:44 PM
  • You are not seeing as a string you are thinking in strings and not in objects or in AD structures.  Your question is clearly related to a recursive search from a specific root.

    Each object returned ahas a cononoical path which is what you are after.  I still don't understand why you want to truncate the path.

    Tis I s a canonical path.  YOu want everything after bedrock so just split It at bedrock.

    foo.bar.com/Universe/Galaxy/Earth/Pangaea/Bedrock/fred/barney/wilma/computername 

    PS > $cpath='foo.bar.com/Universe/Galaxy/Earth/Pangaea/Bedrock/fred/barney/wilma/computername'
    PS > $cpath -match 'bedrock/(.*)'
    True
    PS > $matches[1]
    fred/barney/wilma/computername

    That is it.  Just grab the path and split it with a regex.


    ¯\_(ツ)_/¯

    Thursday, April 24, 2014 11:25 PM
  • Ah - now we're getting closer. You may recall that what I was asking for in the first place, is how to tell Powershell *what* I want it to ignore in this line of text I already have, and get each of the wanted items out into individual variables. It got confusing when you were telling me that I needed to go ask AD anything at all - that was a blind alley. As I'd already said, I have a list of servernames (and canonical names and distinguishednames for each) retrieved from AD in the first place. For simplicity's sake, let's say that list looks like this:

    servername, distinguishedname
    or
    servername, canonicalname

    It doesn't matter whether the list contains the canonicalname or distinguishedname properties or lines from "Alice In Wonderland," really. It's just text from which I want to extract certain words based on where they are.

    Based on what you provided, I just ran this: 

    $canonicalnames = @(
        'foo.bar.com/Universe/Galaxy/Earth/Pangaea/Bedrock/fred/barney/wilma/server1'
        'foo.bar.com/Universe/Galaxy/Earth/Pangaea/Bedrock/fred/barney/server2'
        'foo.bar.com/Universe/Galaxy/Earth/Pangaea/Bedrock/fred/server3'
        'foo.bar.com/Universe/Galaxy/Earth/Pangaea/Bedrock/server4'
    )
    
    $canonicalnames | foreach-object {
    	    $s = $_
    	    $y = $s -match 'Bedrock/(.*)'
    	    $matches[1]
    	}

    That yields:

    fred/barney/wilma/server1
    fred/barney/server2
    fred/server3
    server4

    But, what I'd want it to yield is:

    fred/barney/wilma
    fred/barney
    fred
    bedrock

    ...I don't want to see the server name here at all, and I only want to see 'bedrock' if it's the only, uh, surviving parent(!) within this searchbase (that being bedrock & its child OUs). 

    And, I also want to know how to break that out path into separate variables.

    Progress, progress. ;)



    Lanwench ** Do not fold, spindle or mutilate. Use only a #2 pencil. Fill in the box completely and erase any stray marks.


    • Edited by Lanwench Friday, April 25, 2014 12:37 AM
    Friday, April 25, 2014 12:36 AM
  • That is why I said in the beginning you needed to use my first method of getting the objects and  selecting the parents and names.

    Now I am tired of this because you keep changing what you are asking for.

    You will eventually figure this out I suppose.  I have other things to do that are less aggravating.

    Sorry - I guess you've run everyone out of steam.


    ¯\_(ツ)_/¯

    Friday, April 25, 2014 12:41 AM
  • E.g.,  out of $Pathtokens,
    $OU3 = wilma
    $OU2 = barney
    $OU1 = fred

    I feel like this must be easy, but I'm missing something.

    If I were to use $pathtoken[1], $pathtoken[2], $pathtoken[3] etc., I would be in trouble if this server was at the root of the bedrock OU, and hence had only one parent OU visible, right? I don't want anything that requires I know how many items are in the array. 

    This is fun. At least, for me.


    Lanwench ** Do not fold, spindle or mutilate. Use only a #2 pencil. Fill in the box completely and erase any stray marks.


    Personally, I think that anytime you're creating variables named $OU1, $OU2, and $OU3, you should really just be dealing with a collection named $OU, where the numbers become indexes.  But if you really want that behavior, you have to decide what should be in $OU2 and $OU3 if the array only contains one or two elements.  Should they be $null?  Empty strings?

    In any case, so long as you don't have strict mode enabled, you don't have to worry about how many elements are in the array.  If you access an index that's outside the array's bounds, that expression just evaluates to $null.  If you do have strict mode enabled, then you need to be more careful about that.  Here are a couple of ways to do it:

    # without strict mode enabled (default behavior)
    
    # Convenient shortcut syntax for assigning multiple
    # variables from an array
    $OU1, $OU2, $OU3 = $pathTokens[0..2]
    
    # with strict mode enabled; have to be careful not to
    # access an array index that's out of bounds.
    
    $OU1, $OU2, $OU3 =
    for($i = 0; $i -lt 3; $i++) {
        if ($i -lt $pathTokens.Count) {
            $pathTokens[$i]
        } else {
            $null
        }
    }

    Friday, April 25, 2014 1:56 AM