Exception Handling Question

Welcome Forums General PowerShell Q&A Exception Handling Question

Viewing 11 reply threads
  • Author
    Posts
    • #174865
      Participant
      Topics: 1
      Replies: 7
      Points: 54
      Rank: Member

      Hi everyone.

      I've been learning PowerShell off the side of my desk for awhile now, and I'm learning lots but just scratching the surface.  I've been working on my first 'real world' project and I've run into a snag.

      Our school just upgraded our ERP system and had to remove a lot of customization to allow us to complete the upgrade.  Some of that customization affected a large account export that we use to populate Active Directory with student accounts.  The idea is to add the groups the new version is creating into toe groups the old ERP had previously created in order to maintain student access.  Unfortunately, some time in the past, the school wanted to denote certain programs, so they added extra characters into the name.  So the naming convention isn't the same for all groups.  Here's a basic synopsis.

      Start by getting a list of the groups that have access associated with them.  For each group in the list, do the following.

      • Add our standard Active Directory prefix for data access groups
      • Find the group.
      • If the group can't be found, add the special identifier and retry
      • Remove existing group members (as the import script no longer touches these groups, we don't want 1st year students seeing 2nd year exams)
      • Add the new group as a member of the old group
      • Find the new groups that associate with them and add them as members of the original group

      I can catch the notfound exception using a Try/Catch, but not sure how to get the change managed and still trap other exceptions.

      Here's a sample of what I'm trying to do.

      Import-Module ActiveDirectory
      
      # Load the OUs we need into a variable.  The real script gets them from AD.
      $OUs = 'OU1','OU2','OU3'
      
      # Variable will hold groups that don't follow standard naming conventions
      $NoGroup = @()
      
      # Process the groups
      $OUs | foreach {
          
          # Build the old group name
          $OldGroup = 'DtaG_Student_' + $_ + '_1Fa'
      
          # Build the new group name
          $NewGroup = 'DtaG_Student_' + $_ + '_190901Fa-'
          
          try
          {
              # Get-ADGroup $OldGroup
      
              # Get group members
              $Members = Get-ADGroupMember $OldGroup
      
              # Make sure last year's students aren't still in the old group
              Remove-ADGroupMember $Oldgroup -Members $Members -whatif
      
              # Add the new group to the old group
              Add-ADGroupMember $OldGroup -Members $NewGroup -whatif
          }
          catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
          {
              $NoGroup += $OldGroup
              Write-Host $OldGroup NOT FOUND
              # if the old group was one of the TEP groups, change the Old Group format to DtaG_Student_TEP_$OU_1Fa, 
              # then remove existing members, add the new group before looping to the next OU
      
          }
      }

      I hope this is clear enough to give everyone an idea of what I'm trying to accomplish.

      Thanks in advance for any help you can offer!

      Derek

    • #174910
      Participant
      Topics: 2
      Replies: 511
      Points: 1,306
      Helping Hand
      Rank: Community Hero

      If I understand you correctly, you're just looking to capture / log / handle additional exceptions, and just have special handling for the one exception type you're expecting to have fairly commonly?

      If so, you can cascade catch blocks one after another, adding extra ones for more exception types, and if you want a catch-all catch block for any exceptions that you're not expecting / handling in a specific way, you just add a typeless catch block:

    • #174964
      Participant
      Topics: 1
      Replies: 7
      Points: 54
      Rank: Member

      Thanks for your reply, Joel.

      Sorry I wasn't very clear.  That's what I get for posting a question on the way out the door :).

      Basically, the intent is to add a string into the old group name before the variable part, then rerun the commands that empty the old group and add the new ones to it, but only once.

      Is there a way to do this kind of thing with PowerShell?

      Thanks.

      Derek

      • #174988
        Participant
        Topics: 6
        Replies: 108
        Points: 302
        Helping Hand
        Rank: Contributor

        Sounds like you're just wanting to do recursion, which is definitely doable in Powershell, but you have to make a few changes.

        • Separate the repeatable part of the code into a function
        • If you hit the ADIdentityNotFoundException code, verify this is the first time you've executed the function for this group, modify the name, and call the function again.
        • Modify your loop to use the function instead of the code that is in the function
        • I've also added Joel's suggestions to put a generic catch block in your try..catch logic. That's always good practice, and it can alert you to other problems.

        *** Note that I haven't tested this code, so there are probably some things that need to be tweaked

        Import-Module ActiveDirectory
        # Load the OUs we need into a variable.  The real script gets them from AD.
        $OUs = 'OU1','OU2','OU3'
        # Variable will hold groups that don't follow standard naming conventions
        $NoGroup = @()
        # Process the groups
        $OUs | foreach {
            # Build the old group name
            $OldGroup = 'DtaG_Student_' + $_ + '_1Fa'
            # Build the new group name
            $NewGroup = 'DtaG_Student_' + $_ + '_190901Fa-'
            
            CleanOldGroup -OldGroup $OldGroup -NewGroup $NewGroup
        }
        
        
        function CleanOldGroup
        {
            param (
                [string]
                $OldGroup,
        
                [string]
                $NewGroup
            )
                
            try
            {
                # Get-ADGroup $OldGroup
                # Get group members
                $Members = Get-ADGroupMember $OldGroup
                # Make sure last year's students aren't still in the old group
                Remove-ADGroupMember $Oldgroup -Members $Members -whatif
                # Add the new group to the old group
                Add-ADGroupMember $OldGroup -Members $NewGroup -whatif
            }
            catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
            {
                $NoGroup += $OldGroup
                Write-Host $OldGroup NOT FOUND
                # if the old group was one of the TEP groups, change the Old Group format to DtaG_Student_TEP_$OU_1Fa, 
                # then remove existing members, add the new group before looping to the next OU
        
                # This is assuming that if the value of $OldGroup doesn't already contain the extra string before the variable, 
                # then this is the first time you've executed the function for that group.
                if ($OldGroup -notlike "")
                {
                    $newGroupName = ""
        
                    CleanOldGroup -OldGroup $newGroupName -NewGroup $NewGroup
                }
            }
            catch {
                # Log additional errors, and either rethrow the error or pass it to Write-Error
                # depending on whether you want execution to terminate or keep going through the
                # rest of your OUs.
                
                # Rethrow (terminate execution) options:
                # 1. $PSCmdlet.ThrowTerminatingError($_)
                # 2. throw $_
                # 3. $_ | Write-Error -ErrorAction Stop
                
                # Otherwise just write-error:
                # $_ | Write-Error
            }
        }
        
    • #174997
      Participant
      Topics: 1
      Replies: 7
      Points: 54
      Rank: Member

      Thanks Charles!  This looks like it'll do what I need!  I need to spend some more time on functions :).

      I'm going to try this anyway, but can I use a wildcard pattern with -notlike?  What I would need is something like -notlike '*_TEP_*'

      Thanks again for your help!

    • #175009
      Participant
      Topics: 2
      Replies: 511
      Points: 1,306
      Helping Hand
      Rank: Community Hero

      Yep, -like and -notlike are wildcard operators and should work as expected there. 🙂

      • #175054
        Participant
        Topics: 6
        Replies: 108
        Points: 302
        Helping Hand
        Rank: Contributor

        That's what I get for not verifying my code when I pasted it in... I intended for that to be:

         if ($OldGroup -notlike "whatever the group name would be with the extra string")
                {
                    $newGroupName = "whatever the group name would be with the extra string"
                    CleanOldGroup -OldGroup $newGroupName -NewGroup $NewGroup
                }
        

        You could also just wildcards in the conditional like "*string to add to the old group name*" so you wouldn't have to build the group name before the conditional.

        Hope it works out for you!

    • #175126
      Participant
      Topics: 1
      Replies: 7
      Points: 54
      Rank: Member

      Thanks Charles.

      That's no problem.  I knew what you meant the way you had it, so I filled I know I'm close, but it's getting a little weird.  It's hitting the If statement, but after I insert the characters, it's still hitting the Else as well.  Since there are a few OUs whos names got completely changed in the conversion, I'm trying to write those somewhere so I can do them manually.  I see the whatif saying it will update the group, but then I see the write-host I used to show me if it's being hit.

      Here's the updated code.

      Import-Module ActiveDirectory
      # Load the OUs we need into a variable.  The real script gets them from AD.
      $OUs = 'OU1','OU2','OU3','ETC'
      # Variable will hold groups that don't follow standard naming conventions
      $NoGroup = @()
      # Process the groups
      $OUs | foreach {
          # Build the old group name
          $OldGroup = 'DtaG_Student_' + $_ + '_1Fa'
          # Build the new group name
          $NewGroup = 'DtaG_Student_' + $_ + '_190901Fa-'
          
          NestGroup -OldGroup $OldGroup -NewGroup $NewGroup -OUName $_
      }
      
      
      function NestGroup
      {
          param (
              [string]
              $OldGroup,
      
              [string]
              $NewGroup,
      
              [string]
              $OUName
          )
              
          try
          {
              # Get-ADGroup $OldGroup
              # Get group members
              $Members = Get-ADGroupMember $OldGroup
              # Make sure last year's students aren't still in the old group
              Remove-ADGroupMember $Oldgroup -Members $Members -whatif
              # Add the new group to the old group
              Add-ADGroupMember $OldGroup -Members $NewGroup -whatif
          }
          catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
          {
              #$NoGroup += $OldGroup
              # Write-Host $OldGroup NOT FOUND
              # if the old group was one of the TEP groups, change the Old Group format to DtaG_Student_TEP_$OU_1Fa, 
              # then remove existing members, add the new group before looping to the next OU
      
              # This is assuming that if the value of $OldGroup doesn't already contain the extra string before the variable, 
              # then this is the first time you've executed the function for that group.
              $NewGroupName = ''
              
              if ($OldGroup -notlike "DtaG_Student_TEP_*")
              {
                  $newGroupName = "DtaG_Student_TEP_" + $OUName + "_1Fa"
      
                  NestGroup -OldGroup $newGroupName -NewGroup $NewGroup -OUName $OUName
              }
              else
              {
                  write-host $OldGroup + "doesn't exist!"
                  $NoGroup += $OldGroup
              }
          }
          catch {
              # Log additional errors, and either rethrow the error or pass it to Write-Error
              # depending on whether you want execution to terminate or keep going through the
              # rest of your OUs.
              
              # Rethrow (terminate execution) options:
              # 1. $PSCmdlet.ThrowTerminatingError($_)
              # 2. throw $_
              # 3. $_ | Write-Error -ErrorAction Stop
              
              # Otherwise just write-error:
              # $_ | Write-Error
          }
      }
      
      
    • #175210
      Participant
      Topics: 6
      Replies: 108
      Points: 302
      Helping Hand
      Rank: Contributor

      That's pretty screwy, Derek... The code looks good, I think. Are you sure that the Write-Host isn't for another execution of the function, (i.e. the next OU that you're trying to modify)?

      It may also be something with the -whatif on the other statements. If the Remove and Add statements don't end with a real return code, the code may fall into that catch block... doesn't really make sense to me, either, but I've seen some strange stuff with it.

      A couple of things I would try in troubleshooting:

      • Add some more Write-Host/Write-Debug statements. You could put one in the Try block that executes every time you enter it or after the Add-ADGroupMember statement or both. And then put one in the Catch block before the If and one inside the If. That way you would know exactly which blocks are being executed and it's easier to follow the logic through the output. (FWIW, I've gotten to where I really like the Write-Debug option. I can add lots of output to help with troubleshooting, but I don't have to see them one every execution if I don't want to! It's just a matter of modifying the $DebugPreference session variable.)
      • Add a break statement in the Try block after the Add-ADGroupMember. That would force the code to jump out of the function if the Add-ADGroupMember statement executed successfully. If your problems are because of the -whatif, this may force the code to recognize everything is good and that it isn't supposed to execute the Catch block.

      CMD

    • #175240
      Participant
      Topics: 1
      Replies: 7
      Points: 54
      Rank: Member

      Thanks for your response, Charles!  This is very helpful!

       

      That's pretty screwy, Derek... The code looks good, I think. Are you sure that the Write-Host isn't for another execution of the function, (i.e. the next OU that you're trying to modify)?

      I'm sure this is not the case, because I see the whatif for the Add, then I see the Write-Host with the same name.

      A couple of things I would try in troubleshooting:

      • Add some more Write-Host/Write-Debug statements. You could put one in the Try block that executes every time you enter it or after the Add-ADGroupMember statement or both. And then put one in the Catch block before the If and one inside the If. That way you would know exactly which blocks are being executed and it's easier to follow the logic through the output. (FWIW, I've gotten to where I really like the Write-Debug option. I can add lots of output to help with troubleshooting, but I don't have to see them one every execution if I don't want to! It's just a matter of modifying the $DebugPreference session variable.)
      • Add a break statement in the Try block after the Add-ADGroupMember. That would force the code to jump out of the function if the Add-ADGroupMember statement executed successfully. If your problems are because of the -whatif, this may force the code to recognize everything is good and that it isn't supposed to execute the Catch block.

      I'll play around with Write-debug.  I haven't used it much, as I'm just getting into PS, but it's there for a reason :).

      I'm going to try the break statement.  That sounds like it'll do the trick.  I'll let you know how it goes!

    • #175246
      Participant
      Topics: 1
      Replies: 7
      Points: 54
      Rank: Member

      I figured out what's going on!

      Since the function is passing the TEP_ group in as $OldGroup, $OldGroup now contains the search text used in the If statement.  Now to figure out how to fix it!

    • #175249
      Participant
      Topics: 1
      Replies: 7
      Points: 54
      Rank: Member

      Thanks to both Charles and Joel for their help on this.  Charles was right.  Sopme of the errors were actually coming from the new group, because there were no first-years in those programs yet.  For reference of anyone interested, here's the final code.

      Import-Module ActiveDirectory
      # Load the OUs we need into a variable. The real script gets them from AD.
      $OUs = 'OU1','OU2','OU3','ETC"OOSD','ISA','DAAN','IT','BSN','JAPO','ITTS','JAF','IRM','CS'
      # Variable will hold groups that don't follow standard naming conventions
      $NoGroup = @()
      # Process the groups
      del $env:TEMP\FixBanner.txt
      $OUs | foreach {
      # Build the old group name
      $OldGroup = 'DtaG_Student_' + $_ + '_1Fa'
      # Build the new group name
      $NewGroup = 'DtaG_Student_' + $_ + '_190901Fa-'

      NestGroup -OldGroup $OldGroup -NewGroup $NewGroup -OUName $_
      $NoGroup
      }

      function NestGroup
      {
      param (
      [string]
      $OldGroup,

      [string]
      $NewGroup,

      [string]
      $OUName
      )

      try
      {
      # Get-ADGroup $OldGroup
      # Get group members
      $Members = Get-ADGroupMember $OldGroup
      # Make sure last year's students aren't still in the old group
      Remove-ADGroupMember $Oldgroup -Members $Members -whatif
      # Add the new group to the old group
      Add-ADGroupMember $OldGroup -Members $NewGroup -whatif
      }
      catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
      {
      # if the old group was one of the TEP groups, change the Old Group format to DtaG_Student_TEP_$OU_1Fa,
      # then remove existing members, add the new group before looping to the next OU

      # This is assuming that if the value of $OldGroup doesn't already contain the extra string before the variable,
      # then this is the first time you've executed the function for that group.
      $NewGroupName = "

      if ($Error[0].CategoryInfo.TargetName -contains $OldGroup-and $OldGroup -notlike "DtaG_Student_TEP_*")
      {
      $newGroupName = "DtaG_Student_TEP_" + $OUName + "_1Fa"

      NestGroup -OldGroup $newGroupName -NewGroup $NewGroup -OUName $OUName
      }
      elseif ($Error[0].CategoryInfo.TargetName -contains $NewGroup)
      {
      Write-Host $NewGroup "doesn't exist" -ForegroundColor Yellow
      # Out-File -FilePath $env:TEMP\FixBanner.txt -Append -InputObject $NewGroup
      }
      else
      {
      # write-host $Error[0].CategoryInfo.TargetName -ForegroundColor Yellow
      Out-File -FilePath $env:TEMP\FixBanner.txt -Append -InputObject ('DtaG_Student_' + $OUName + '_1Fa')
      }

      }
      catch {
      Write-Host "Something's not right!" -ForegroundColor Yellow
      # Log additional errors, and either rethrow the error or pass it to Write-Error
      # depending on whether you want execution to terminate or keep going through the
      # rest of your OUs.

      # Rethrow (terminate execution) options:
      # 1. $PSCmdlet.ThrowTerminatingError($_)
      # 2. throw $_
      # 3. $_ | Write-Error -ErrorAction Stop

      # Otherwise just write-error:
      # $_ | Write-Error
      }
      }

       

    • #175252
      Participant
      Topics: 6
      Replies: 108
      Points: 302
      Helping Hand
      Rank: Contributor

      w00t!

    • #175255
      Participant
      Topics: 1
      Replies: 7
      Points: 54
      Rank: Member

      Well it turns out that both Charles and I are right.  I did some more testing and found that sometimes the error was indeed coming from the new group.  Apparently, we have some courses that don't start September 1 :).  So a little more work, and we have a working script!

      Import-Module ActiveDirectory
      # Load the OUs we need into a variable. The real script gets them from AD.
      $OUs = 'OU1','OU3','OU2','ETC',
      # Variable will hold groups that don't follow standard naming conventions
      $NoGroup = @()
      # Process the groups
      del $env:TEMP\FixBanner.txt
      $OUs | foreach {
      # Build the old group name
      $OldGroup = 'DtaG_Student_' + $_ + '_1Fa'
      # Build the new group name
      $NewGroup = 'DtaG_Student_' + $_ + '_190901Fa-'
      
      NestGroup -OldGroup $OldGroup -NewGroup $NewGroup -OUName $_
      $NoGroup
      }
      
      function NestGroup
      {
      param (
      [string]
      $OldGroup,
      
      [string]
      $NewGroup,
      
      [string]
      $OUName
      )
      
      try
      {
      # Get-ADGroup $OldGroup
      # Get group members
      $Members = Get-ADGroupMember $OldGroup
      # Make sure last year's students aren't still in the old group
      Remove-ADGroupMember $Oldgroup -Members $Members -whatif
      # Add the new group to the old group
      Add-ADGroupMember $OldGroup -Members $NewGroup -whatif
      }
      catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
      {
      # if the old group was one of the TEP groups, change the Old Group format to DtaG_Student_TEP_$OU_1Fa, 
      # then remove existing members, add the new group before looping to the next OU
      
      # This is assuming that if the value of $OldGroup doesn't already contain the extra string before the variable, 
      # then this is the first time you've executed the function for that group.
      $NewGroupName = ''
      
      if ($Error[0].CategoryInfo.TargetName -contains $OldGroup-and $OldGroup -notlike "DtaG_Student_TEP_*")
      {
      $newGroupName = "DtaG_Student_TEP_" + $OUName + "_1Fa"
      
      NestGroup -OldGroup $newGroupName -NewGroup $NewGroup -OUName $OUName
      }
      elseif ($Error[0].CategoryInfo.TargetName -contains $NewGroup)
      {
      Write-Host $NewGroup "doesn't exist" -ForegroundColor Yellow
      # Out-File -FilePath $env:TEMP\FixBanner.txt -Append -InputObject $NewGroup
      }
      else
      {
      # write-host $Error[0].CategoryInfo.TargetName -ForegroundColor Yellow
      Out-File -FilePath $env:TEMP\FixBanner.txt -Append -InputObject ('DtaG_Student_' + $OUName + '_1Fa')
      }
      
      }
      catch {
      Write-Host "Something's not right!" -ForegroundColor Yellow
      # Log additional errors, and either rethrow the error or pass it to Write-Error
      # depending on whether you want execution to terminate or keep going through the
      # rest of your OUs.
      
      # Rethrow (terminate execution) options:
      # 1. $PSCmdlet.ThrowTerminatingError($_)
      # 2. throw $_
      # 3. $_ | Write-Error -ErrorAction Stop
      
      # Otherwise just write-error:
      # $_ | Write-Error
      }
      }

       

Viewing 11 reply threads
  • The topic ‘Exception Handling Question’ is closed to new replies.