Below is the script I want to execute. The issue here is once an exception occurs it stops executing, I used continue in the catch block but that did not work. How do I get it working even after an exception occurs it should loop in foreach.
I also used a while($true) loop but that went into infinite loop. How to go about it?
$ErrorActionPreference = "Stop";
try
{
# Loop through each of the users in the site
foreach($user in $users)
{
# Create an array that will be used to split the user name from the domain/membership provider
$a=#()
$displayname = $user.DisplayName
$userlogin = $user.UserLogin
# Separate the user name from the domain/membership provider
if($userlogin.Contains('\'))
{
$a = $userlogin.split("\")
$username = $a[1]
}
elseif($userlogin.Contains(':'))
{
$a = $userlogin.split(":")
$username = $a[1]
}
# Create the new username based on the given input
$newalias = $newprovider + "\" + $username
if (-not $convert)
{
$answer = Read-Host "Your first user will be changed from $userlogin to $newalias. Would you like to continue processing all users? [Y]es, [N]o"
switch ($answer)
{
"Y" {$convert = $true}
"y" {$convert = $true}
default {exit}
}
}
if(($userlogin -like "$oldprovider*") -and $convert)
{
LogWrite ("Migrating User old : " + $user + " New user : " + $newalias + " ")
move-spuser -identity $user -newalias $newalias -ignoresid -Confirm:$false
LogWrite ("Done")
}
}
}
catch {
LogWrite ("Caught the exception")
LogWrite ($Error[0].Exception)
}
You use try {...} catch {...} when you want to handle errors. If you want to ignore them, you should set $ErrorActionPreference = "Continue" (or "SilentlyContinue") as #C.B. suggested, or use -ErrorAction "SilentlyContinue" for the particular operation raising the error. If you want to handle errors from a certain instruction, you'd put that instruction in the try {...} catch {...} block, not the entire loop, e.g.:
foreach($user in $users) {
...
try {
if(($userlogin -like "$oldprovider*") -and $convert) {
LogWrite ("Migrating User old : " + $user + " New user : " + $newalias + " ")
move-spuser -identity $user -newalias $newalias -ignoresid -Confirm:$false
LogWrite ("Done")
}
} catch {
LogWrite ("Caught the exception")
LogWrite ($Error[0].Exception)
}
}
You seem to have placed the "catch" outside the loop body, so that aborts the loop. Put the catch inside the loop
Modified the code as below. Used the following piece of code after move-spuser -identity $user -newalias $newalias -ignoresid -Confirm:$false
if($?)
{
LogWrite ("Done!")
LogWrite (" ")
}
else
{
LogWrite ($Error[0].ToString())
LogWrite (" ")
}
Something that worked for me is to set the $ErrorActionPreference variable to stop, and then reset it back to continue in the catch block:
$e = $ErrorActionPreference
$ErrorActionPreference="stop"
try
{
#Do Something that throws the exception
}
catch
{
$ErrorActionPreference=$e
}
$ErrorActionPreference=$e;
Related
I'm trying to write output when get-addomain succeded.
Try/catch writes output only if command fails
try {
get-addomain -Identity d.contoso.com
}
catch {
Write-Output "failed"
}
I tried following:
if (-not (get-addomain -Identity d.contoso.com))
{
return "failed"
}
else
{
write-output "ok"
}
and
If (get-addomain -Identity d.contoso.com )
{
Write-Output "ok"
}
Else
{
write-output "failed"
}
but in both cases got
get-addomain : Cannot find an object with identity: 'd.contoso.com' under: 'DC=ad,DC=contoso,DC=com'.
The tryblock runs until a error is getting thrown. If get-addomain doesn't end with an error, the try-case will run the following commands written inside the {}.
So one way would be to just say the output is ok if no error gets thrown:
try {
get-addomain -Identity d.contoso.com
Write-Output "ok"
}
catch {
Write-Output "failed"
}
But if you want to double check, you can still do the if check in the try-catch:
try {
If (get-addomain -Identity d.contoso.com )
{
Write-Output "ok"
}
Else
{
write-output "failed"
}
}
catch {
Write-Output "failed"
}
try{
$domain = Get-ADDomain -Identity d.contoso.com
Write-Output $domain
}catch{
Write-Output "Failed with message '$($_.Exception.Message)'"
}
When you use the AD CmdLets, it fails when a non-existing identity is specified. Therefore if the object you search for does not exist, you will end up in the catch. The first piece of code you wrote is actually correct if you wish to output the AD domain information.
I understand Stackoverflow isn't a write your code for you forum, absolutely, but I'm finding it very difficult to find a good example of try/catch proper usage in Powershell. I have read up on fundamentals, and understand the theoretical concept, but execution I'm struggling with.
Here is a simple script that queries Active Directory:
do {
clear
Import-Module active*
"============ WhoIs Lookup ============="
Write-Host ""
$who = Read-Host "WhoIs";
$req = Get-ADUser -Identity $who
Write-Host ''
Write-Host "$who is " -NoNewline
Write-Host $req.Name -ForegroundColor Cyan
pause
} while ($run =1)
An example error is:
Get-ADUser : Cannot find an object with
identity: '5621521' under: 'DC=dcsg,DC=com'.
At C:\Tools\CSOCTools\Who_Is\whoIs.ps1:10
char:12
+ $req = Get-ADUser -Identity $who
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFoun
d: (5621521:ADUser) [Get-ADUser], ADIde
ntityNotFoundException
+ FullyQualifiedErrorId : ActiveDirecto
ryCmdlet:Microsoft.ActiveDirectory.Mana
gement.ADIdentityNotFoundException,Micr
osoft.ActiveDirectory.Management.Comman
ds.GetADUser
How would I catch this User Not Found error?
Simple example:
try {
Get-ADUser -Identity “bleh”
}
catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
{
Write-Warning “AD computer object not found”
}
For your case:
do {
clear
Import-Module active*
"============ WhoIs Lookup ============="
Write-Host ""
$who = Read-Host "WhoIs";
try {
$req = Get-ADUser -Identity $who
}
catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
{
Write-Warning “AD user object not found”
Write-Host ''
Write-Host "$who is " -NoNewline
Write-Host $req.Name -ForegroundColor Cyan
}
pause
} while ($run =1)
Edit: I put the Write-Host into the catch as you're eventually trying to reference to NULL when there's no object.
I got a very good example from here. For the exception types after the Catch (where I have two of them) I just grabbed them straight from the error message you provided. I haven't tried this out many times in my experience, let me know if it works for ya!
Try
{
do {
clear
Import-Module active*
"============ WhoIs Lookup ============="
Write-Host ""
$who = Read-Host "WhoIs";
$req = Get-ADUser -Identity $who
Write-Host ''
Write-Host "$who is " -NoNewline
Write-Host $req.Name -ForegroundColor Cyan
pause
} while ($run =1)
}
Catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException],[Microsoft.ActiveDirectory.Management.Commands.GetADUser]
{
# Error message here
}
Not having much luck with my Powershell script, so any help would be great! What I'm trying to do is to reference from a test file that contains lines of usernames, and compare it to the Excel spreadsheet on column A1. If exists, it should blank out the username.
$users = Get-Content "E:\temp\test.txt"
foreach ($user in $users) {
set-aduser $user -fax " "
$answer1 = read-host "Please Make a Selection"
if ($answer1 -eq 1){
$location="Melbourne"
}
if ($answer1 -eq 2){
$location="Sydney"
}
if ($answer1 -eq 3){
$location="Adelaide"
}
if ($answer1 -eq 4){
$location="Brisbane"
}
if ($answer1 -eq 5){
$location="Perth"
}
$ExcelPath = 'E:\temp\FX MFD UserPIN.xlsx'
$Excel = New-Object -ComObject Excel.Application
$Excel.Visible = $true
$ExcelWorkBook = $Excel.Workbooks.Open($ExcelPath)
$ExcelWorkSheet = $Excel.WorkSheets.item("$location")
$Range = $ExcelWorkSheet.Range("A1").EntireColumn
$Search = $Range.find($user)
If($Search.value() -contains $user)
{
Write-Host "User FOUND, removing now"
$Search.value() = ""
}
else {
Write-Host "User NOT FOUND"
}
}
Error code is this:
You cannot call a method on a null-valued expression.
At E:\temp\testsest.ps1:35 char:12
+ If($Search.value() -contains $SearchString)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
How do I replace the $Search to get $user?
Range.Find() returns Nothing if no match is found.
Therefore, before you check if there is a match, you have to check if there's a null value in $Search.
if ($Search -ne $null) {
if ($Search.value -contains $user)
{
Write-Host "User FOUND, removing now"
$Search.value = ""
}
else {
Write-Host $Search.value," what did we find?!"
}
}
else {
Write-Host "User NOT FOUND"
}
Also, value is not a method, it's a property, so don't use round brackets.
Thanks Vesper. I've made a couple more changes and can confirm it works now.
if ($Search -ne $null) {
if ($Search.text -contains $user)
{
Write-Host "User FOUND, removing now"
$Range.replace($Search,"")
}
else {
Write-Host $Search.text," what did we find?!"
}
}
else {
Write-Host "User NOT FOUND"
}
In my PowerShell script I try to do some error handling. However, I'm depending on an advanced function that uses the Try/Catch clauses. So once in a while the code block in the function fails and goes to the Catch clause after generating an error. At this point the variable $Error is filled with one error.
If I then consult within my script the variable $Error it tells me there's one record, which is correct. But I would like to know if it's possible to only delete the last error within the function in the Catch clause? So I can keep my $Error variable clear for the script errors.
The problem is within Get-ADTSProfileHC. I tried to delete the last error with $Error[0] | Remove-Item but it failed.
The function:
Function Get-ADusersHC {
[CmdletBinding(SupportsShouldProcess=$True)]
Param(
[Parameter(ValueFromPipelineByPropertyName=$true,ValueFromPipeline=$true,Position=0)]
[String[]] $OU
)
Begin {
Function Get-ADOUNameHC {
$CanonicalName = $_.CanonicalName
[System.Collections.ArrayList]$Pieces = $CanonicalName.split(“/”)
$Pieces.Remove($Pieces[-1])
$OU = $Pieces -join '\'
$OU -replace ($Pieces[0],$Pieces[0].ToUpper())
}
Function Get-ADManagerDisplayNameHC {
$m = Get-ADObject -Identity $_.manager -Properties displayName,cn
if($m.ObjectClass -eq "user") { $m.displayName } Else{ $m.cn }
}
Function Get-ADTSProfileHC {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true,Position=0)]
[String] $DistinguishedName,
[parameter(Mandatory=$true,Position=1)]
[ValidateNotNullOrEmpty()]
[ValidateSet('UserProfile','AllowLogon','HomeDirectory','HomeDrive')]
[String]$Property
)
Begin {
$User = [ADSI]"LDAP://$DistinguishedName"
}
Process {
Try {
Switch ($Property) {
'AllowLogon' {if ($($User.psbase.InvokeGet('allowLogon')) -eq '1'){$True}else{$False}}
'HomeDirectory' {$User.psbase.InvokeGet('TerminalServicesHomeDirectory')}
'HomeDrive' {$User.psbase.InvokeGet('TerminalServicesHomeDrive')}
'UserProfile' {$User.psbase.InvokeGet('TerminalServicesProfilePath')}
}
}
Catch {
# When we receive an error, it means the field has never been used before and is blank
# this is due to an error in the AD (same problem with the Quest CmdLet), AllowLogon is
# always 'TRUE' but we don't set it because we can't read it sometimes so we write 'blanks'
Write-Output $null
}
}
}
}
Process {
Foreach ($_ in $OU) {
Write-Verbose "Function Get-HCADusersNoManager > OU: $_"
Write-Verbose "Function Get-HCADusersNoManager > Manager field empty"
Get-ADUser -SearchBase $_ -Filter 'SAMAccountName -eq "shenn"' -Properties * |
#Get-ADUser -SearchBase $_ -Filter * -Properties * |
Foreach {
$Properties = ([Ordered] #{
"Creation date" = $_.whenCreated;
"Display name" = $_.displayName;
"CN name" = $_.name;
"Last name" = $_.sn;
"First name" = $_.givenName;
"Logon name" = $_.sAMAccountName;
"Manager" = if($_.manager){Get-ADManagerDisplayNameHC};
"Employee ID" = $_.EmployeeID;
"HeidelbergcCement Billing ID" = $_.extensionAttribute8
"Type of account" = $_.employeeType;
"OU" = Get-ADOUNameHC;
"Notes" = $_.info -replace "`n"," ";
"E-mail" = $_.EmailAddress;
"Logon script" = $_.scriptPath;
"TS User Profile" = Get-ADTSProfileHC $_.DistinguishedName 'UserProfile';
"TS Home directory" = Get-ADTSProfileHC $_.DistinguishedName 'HomeDirectory';
"TS Home drive" = Get-ADTSProfileHC $_.DistinguishedName 'HomeDrive';
"TS Allow logon" = Get-ADTSProfileHC $_.DistinguishedName 'AllowLogon'
})
$Object = New-Object -TypeName PSObject -Property $Properties
Write-Output $Object
}
}
}
}
Two easy ways to do this:
$error.Remove($error[0])
$Error.RemoveAt(0)
Don't forget to check there is an error first.
$Error.Remove($error[$Error.Count-1])
If errors variable is empty, you will not get any exception
I hope it helps
I have script:
$servers = "server01", "s02", "s03"
foreach ($server in $servers) {
$server = (New-Object System.Net.NetworkInformation.Ping).send($servers)
if ($server.Status -eq "Success") {
Write-Host "$server is OK"
}
}
Error message:
An exception occured during a Ping request.
I need to ping each server in $servers array and display status. I think, that Foreach statement is not properly used, but I'm unable to find out where is the problem. Thank you for your advice
You should not be modifying the value of $server within the foreach loop. Declare a new variable (e.g. $result). Also, Ping.Send takes the individual server name, not an array of server names as an argument. The following code should work.
Finally, you will need to trap the PingException that will be thrown if the host is unreachable, or your script will print out a big red error along with the expected results.
$servers = "server1", "server2"
foreach ($server in $servers) {
& {
trap [System.Net.NetworkInformation.PingException] { continue; }
$result = (New-Object System.Net.NetworkInformation.Ping).send($server)
if ($result.Status -eq "Success") {
Write-Host "$server is OK"
}
else {
Write-Host "$server is NOT OK"
}
}
}