Solved

try catch and for loop

Posted on 2016-08-11
14
42 Views
Last Modified: 2016-08-15
I have a forEach loop. In the loop I have a try catch statement.  In the catch statement I would like to leave the current iteration of the loop and move to the next object. How do I do that?

Import-Csv "c:\scripts\sample.csv" | ForEach-Object {

try{
some code here
}
Catch{
some code here that will move on to the next object in the for loop.
$success = "false"
}

$success = "true"
}

Open in new window

0
Comment
Question by:Roccat
  • 5
  • 4
  • 3
  • +2
14 Comments
 
LVL 52

Expert Comment

by:Bill Prew
ID: 41752451
Try adding a continue statement at the end of the catch block, that's normally the way to jump to the next iteration of a loop.

~bp
0
 
LVL 39

Expert Comment

by:footech
ID: 41752527
Unless I'm misunderstanding your question, the above post isn't correct.
Using continue in a ForEach-Object loop will exit out of the loop, not go to the next object.
1
 

Author Comment

by:Roccat
ID: 41752529
You are correct footech. I accepted the answer before testing. I had to use "return"
0
 
LVL 12

Expert Comment

by:Dustin Saunders
ID: 41752562
Also, not sure how much code you're putting in Try but in your sample you can add your $success call to the try.

Import-Csv "c:\scripts\sample.csv" | ForEach-Object {

try{
some code here
$success = "true"
}
Catch{
some code here that will move on to the next object in the for loop.
$success = "false"
}
}

Open in new window


Depending on what you need to do for each item when true, you can call extended code in functions from the try loop to keep it all contained like that.
1
 
LVL 12

Expert Comment

by:Dustin Saunders
ID: 41752570
ex 2:
function DoThing1($object)
{
    try{
        some code here
        $success = "true"
    }
    Catch{
        some code here that will move on to the next object in the for loop.
        $success = "false"
    }
}

function DoThing2($object)
{
    try{
        some code here
        $success = "true"
    }
    Catch{
        some code here that will move on to the next object in the for loop.
        $success = "false"
    }
}

$objects = Import-Csv "c:\scripts\sample.csv"

foreach ($object in $objects)
{
    DoThing1 $object
    DoThing2 $object
}

Open in new window

0
 
LVL 39

Assisted Solution

by:footech
footech earned 250 total points
ID: 41752592
Unless you want to skip some code in the catch block, there's no need to use return.
In other scenarios if you want to skip some code in a loop, if you were using the foreach statement instead of the ForEach-Object cmdlet, there's more options for using keywords like break and continue.
0
 

Author Comment

by:Roccat
ID: 41752598
When I added the return to the catch block it returns to the foreach-object loop. It skips the rest of the code after the catch block. This is what I was aiming for.  Does this sound like the behavior you would expect?
0
Optimizing Cloud Backup for Low Bandwidth

With cloud storage prices going down a growing number of SMBs start to use it for backup storage. Unfortunately, business data volume rarely fits the average Internet speed. This article provides an overview of main Internet speed challenges and reveals backup best practices.

 
LVL 12

Expert Comment

by:Dustin Saunders
ID: 41752686
Yes, the return terminates the current loop object run through, not the overall loop behavior in that context.  But depending on what you're looking to do there may be more efficient ways to handle the code.
0
 
LVL 39

Expert Comment

by:footech
ID: 41752690
Yes.  It would have been more accurate for me to state, "Unless you want to skip some code in the catch block or anything else in the loop after the return keyword..."

There's a variety of ways to do the equivalent.   Some pseudo code...
Import-Csv "c:\scripts\sample.csv" | ForEach-Object {
    try{
        some code here that might generate a terminating error
        some code which will not run if the previous line encountered an error
    }
    Catch{
        some code to run only if there was an error
    }
}

Open in new window

0
 
LVL 68

Expert Comment

by:Qlemo
ID: 41752799
From a programmer's viewpoint you should always try to have anything in the try block, not use anything like return or such. This applies even more for pipelines like with foreach-object.
0
 

Author Comment

by:Roccat
ID: 41752834
I use the return because if the aduser cant be created there is no use in executing the rest of the code.
0
 

Author Comment

by:Roccat
ID: 41752928
This is the script I am working on. If you notice the $ADUser block I use the try catch statement with the return in the catch.  

Import-Module ActiveDirectory
$ErrorCount = 0
$TotalCount = 0
$ErrorArray = @{}
$HomefolderErrorArray = @{}
$HomeFolderError = 0

#Modify Log file
$d = Get-Date
$log = "C:\log\userCreate.log"

function WriteLog($message)
{
 $d = Get-Date
    $out = "`n" , $d , $message
    Add-Content -Path $log -Value $out
}


<#
This is where the error count and log is cleared. The count is increased from the default
256 to 10,000. You should be able to call the error from the log like this $error[0]
#>

$error.clear()
$MaximumErrorCount = 10000


<#
This is where the CSV is imported then each row gets passed through the foreach-object loop. 
#> 
Import-Csv "C:\Scripts\accounts\first16.csv" | ForEach-Object {

$TotalCount++

#These are some sample write host statement to help troubleshoot.
#    Write-Host $_.Login
#     Write-Host $_.LastName
#      Write-Host $_.FirstName
#       Write-Host $_.'Job Title'
#        Write-Host $_.EID



<# 
OU Switch Case statement checks the Location field in the csv imported. the "$_." characters before each column name variable are needed to get the data from the csv.
 It checks to see if the location is the name of the school and then assigns the OU to the $OU variable which is referenced in the $aduser below in the script.
  The description variable is assigned also and this is used in the ad user creation $aduser below in the scrip;t. 
#>



        switch ($_.Location)
	{
		As {
			$OU = "OU=Staff,OU=As,dc=homelab,dc=com"
			$Description = "Staff - AS"
		}
		Bn {
			$OU = "OU=Staff,OU=Bn,dc=homelab,dc=com"
			$Description = "Staff - BN"
		}
		
		default
		{
			$OU = "OU=Staff,dc=homelab,dc=com"
			$Description = "Staff - "
		}
	}

<#
This if statement checks to see if the Logon name is taken and if it is 
it will change the logon variable value to the value of the login2 column
#>

if (dsquery user -samid $_.Login)
		{
			$LogonName = $_.Login2
         # Write-Host $OU
		}
		else
        {
            $LogonName = $_.Login
          #  Write-Host $LogonName
       }


<#
This is a splatted hash table that takes all the variables and assigns them to the $ADUser array 
and sends that array to the new-aduser command. 
#> 

try{

$fullname = $_.FirstName + " " + $_.LastName
    $NamePlace = "hello"
    $ADUser = [ordered]@{ }
	$ADUser['Name'] = $_.FirstName + " " + $_.LastName
	$ADUser['SamAccountName'] = $LogonName
	$ADUser['GivenName'] = $_.FirstName
	$ADUser['Surname'] = $_.LastName
    $ADUser['Description'] = $Description
	$ADUser['DisplayName'] = $_.FirstName + " " + $_.LastName
	$ADUser['UserPrincipalName'] = $LogonName + "@homelab.com"
	$ADUser['AccountPassword'] = ConvertTo-SecureString -AsPlainText 'P@ssw0rd' -Force
	$ADUser['Title'] = $_."Job Title"
	$ADUser['EmailAddress'] = $LogonName + "@homelab.com"
	$ADUser['Office'] = $_.EID
    $ADUser['Path'] = $OU
	$ADUser['Enabled'] = $True
	$ADUser['HomeDirectory'] = "\\homelab\staff\$LogonName"
	$ADUser['HomeDrive'] = 'H:'
	New-ADUser @ADUser 
}
catch{
$ErrorCount++
$ErrorArray[$TotalCount] = $fullname
return
}
  
<#
This adds the user just created to the 
googleapps group and yard-staff ou groups.
#>

	Add-ADGroupMember "googleapps" –Members $LogonName
	Add-ADGroupMember "yard-staff" –Members $LogonName


<#
This creates the homefolder on the shae in the set-acl statement below.
#>
    try{
	New-Item -type directory -path "\\dc-pc\share\$LogonName"
	$Acl = Get-Acl "\\dc-pc\share\$LogonName"
	$Ar = New-Object system.security.accesscontrol.filesystemaccessrule ("$LogonName", "Modify", "ContainerInherit, ObjectInherit", "None", "Allow")
	$Acl.SetAccessRule($Ar)
	Set-Acl "\\dc-pc\share\$LogonName" $Acl
    }
    catch {
    $HomeFolderError++
    $HomeFolderErrorArray[$TotalCount] = $fullname
    }
  
}
Write-Host ($ErrorArray | out-string)
    $SuccessfulCount = ($TotalCount - $ErrorCount)
 WriteLog("Accounts Attempted:  " + $TotalCount , "  Failures:  "+ $ErrorCount , "      Successful:  " + $SuccessfulCount ,"      Home Folder Errors:  " + $HomeFolderError , "`r`n`r`n", "Account Creation Error names",($ErrorArray  | out-string) , "Home Folder Creation Error names",($HomeFolderErrorArray  | out-string))

Open in new window

0
 
LVL 12

Accepted Solution

by:
Dustin Saunders earned 250 total points
ID: 41753036
I'd probably organize it like so, so it's easy to edit and work on.  Putting each step into a separate function makes it easier to change the catch in the event there's a problem, or if you need to add other items later on too.  I personally have an easier time reading and modifying code when it's laid out like this, but just one opinion.

Import-Module ActiveDirectory
$errorCount = 0
$totalCount = 0

$d = Get-Date
$log = "C:\log\userCreate.log"

function WriteLog($message)
{
    $d = Get-Date
    $out = "`n" , $d , $message
    Add-Content -Path $log -Value $out
}

function ProcessLocation($location)
{
    switch ($location)
	{
		As {
			$OU = "OU=Staff,OU=As,dc=homelab,dc=com"
			$Description = "Staff - AS"
		}
		Bn {
			$OU = "OU=Staff,OU=Bn,dc=homelab,dc=com"
			$Description = "Staff - BN"
		}
		default
		{
			$OU = "OU=Staff,dc=homelab,dc=com"
			$Description = "Staff - "
		}
	}
}

function GetLogin($user)
{
    if (dsquery user -samid $user.Login)
    {
	    $ln = $user.Login2
    }
    else
    {
        $ln = $user.Login
    }
    return $ln
}

function CreateUser($user)
{
    try {
    $fullname = $_.FirstName + " " + $_.LastName
    $NamePlace = "hello"
    $ADUser = [ordered]@{ }
	$ADUser['Name'] = $_.FirstName + " " + $_.LastName
	$ADUser['SamAccountName'] = $logonName
	$ADUser['GivenName'] = $_.FirstName
	$ADUser['Surname'] = $_.LastName
    $ADUser['Description'] = $Description
	$ADUser['DisplayName'] = $_.FirstName + " " + $_.LastName
	$ADUser['UserPrincipalName'] = $addr
	$ADUser['AccountPassword'] = ConvertTo-SecureString -AsPlainText 'P@ssw0rd' -Force
	$ADUser['Title'] = $_."Job Title"
	$ADUser['EmailAddress'] = $addr
	$ADUser['Office'] = $_.EID
    $ADUser['Path'] = $OU
	$ADUser['Enabled'] = $True
	$ADUser['HomeDirectory'] = "\\homelab\staff\$LogonName"
	$ADUser['HomeDrive'] = 'H:'
	New-ADUser @ADUser
    WriteLog("Created user $logonName.")
    } catch {
    WriteLog("Failed to create user $logonName.")
    }
}

function AddToGroups($logonName)
{
    try {
    Add-ADGroupMember "googleapps" –Members $logonName
    Add-ADGroupMember "yard-staff" –Members $logonName
    WriteLog("Added $logonName to googleapps and yard-staff.")
    } catch {
    WriteLog("Failed adding $logonName to googleapps and yard-staff.")
    $errorCount++
    }
}

function CreateDirectory($logonName)
{
    try {
    New-Item -type directory -path "\\dc-pc\share\$logonName"
    $acl = Get-Acl "\\dc-pc\share\$logonName"
    $ar = New-Object system.security.accesscontrol.filesystemaccessrule ("$logonName", "Modify", "ContainerInherit, ObjectInherit", "None", "Allow")
    $acl.SetAccessRule($ar)
    Set-Acl "\\dc-pc\share\$logonName" $acl
    WriteLog("Created and set permissions for \\dc-pc\share\$logonName .")
    } catch {
    WriteLog("Failed to create and set permissions for \\dc-pc\share\$logonName .")
    $errorCount++
    }
}

$users = Import-CSV "C:\Scripts\accounts\first16.csv"

foreach ($user in $users)
{
    $totalCount++
    ProcessLocation $user.Location
    $logonName = GetLogin $user
    $addr = $logonName + "@homelab.com"
    CreateUser $user
    AddToGroups $logonName
    CreateDirectory $logonName
}

Open in new window

0
 

Author Comment

by:Roccat
ID: 41753200
That is nicely laid out.  For some reason the users permissions are not applying to the homefolder when I try this dustin. trying to figure out why not.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This script can help you clean up your user profile database by comparing profiles to Active Directory users in a particular OU, and removing the profiles that don't match.
A brief introduction to what I consider to be the best editor for PowerShell.
Hi friends,  in this video  I'll show you how new windows 10 user can learn the using of windows 10. Thank you.
Many functions in Excel can make decisions. The most simple of these is the IF function: it returns a value depending on whether a condition you describe is true or false. Once you get the hang of using the IF function, you will find it easier to us…

895 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now