Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

try catch and for loop

Posted on 2016-08-11
14
Medium Priority
?
82 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 59

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 41

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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
LVL 14

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 14

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 41

Assisted Solution

by:footech
footech earned 1000 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
 
LVL 14

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 41

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 71

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 14

Accepted Solution

by:
Dustin Saunders earned 1000 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

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

In previous parts of this Nano Server deployment series, we learned how to create, deploy and configure Nano Server as a Hyper-V host. In this part, we will look for a clustering option. We will create a Hyper-V cluster of 3 Nano Server host nodes w…
A walk-through example of how to obtain and apply new DID phone numbers to your cloud PBX enabled users that are configured in Office 365. Whether you have 1, 10 or 100+ users in your tenant, it's quite easy to get them phone-enabled and making/rece…
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an antispam), the admini…
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an anti-spam), the admin…

772 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