locked
Why -ErrorAction is not respected? RRS feed

  • General discussion

  • Hi,

    Does anybody have an idea why -errorAction SilentlyContinue does not work? Some CMDLets respects that, but e.g. "get-aduser -identity doesnotExists -errorAction SilentlyContinue" returns the error just like the parameter was not set.

    Do I do something wrong or is the quality really so bad? And this is not the first place where this doesn't work.


    Petri

    • Changed type jrv Saturday, October 21, 2017 3:17 PM Not a question - a discussion
    Thursday, October 5, 2017 4:38 PM

All replies

  • It's the behavior of the cmdlet

    If you find that my post has answered your question, please mark it as the answer. If you find my post to be helpful in anyway, please click vote as helpful. (99,108,97,121,109,97,110,50,64,110,121,99,97,112,46,114,114,46,99,111,109|%{[char]$_})-join''

    Thursday, October 5, 2017 5:48 PM
  • research terminating and non-terminating exceptions for a full explanation.


    \_(ツ)_/

    Thursday, October 5, 2017 8:05 PM
  • jrv,

    Would you like to enlighten what do you mean? :)

    From "enduser" point of view this is error during CMDLet process. But you say, only certain kind of errors are handled? Sounds...not so logical :D


    Petri

    Monday, October 9, 2017 11:22 AM
  • Follow my suggestion.  It will answer your question.

    \_(ツ)_/

    Monday, October 9, 2017 11:25 AM
  • Terminating errors are errors that cause the application to halt execution. Non-terminating errors are general errors but the application keeps on going.

    ErrorAction SilentlyContinue will suppress Non-terminating errors

    ErrorAction Stop mimics terminating errors and stops the application.

    Since Get-ADUser is looking for a single user, if it fails to do so the cmdlet stops processing as there is nothing more to do and sends the error.

    Terminating errors can be caught using try catch block, whereas, non-terminating errors cannot.

    try
    {
      Get-ADUser NoSuchUser
    }
    catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] # Catch specific Exception type
    {
      Write-Host "User Not Found"
    }
    catch # Catch all exception types
    {
      Write-Host "Other errors"
    }


    If you find that my post has answered your question, please mark it as the answer. If you find my post to be helpful in anyway, please click vote as helpful. (99,108,97,121,109,97,110,50,64,110,121,99,97,112,46,114,114,46,99,111,109|%{[char]$_})-join''


    • Edited by clayman2 Tuesday, October 10, 2017 12:34 PM added script
    Tuesday, October 10, 2017 12:29 PM
  • Hi,
    Just checking in to see if the information provided was helpful. Please let us know if you would like further assistance.

    Best Regards,

    Frank

    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com.

    Wednesday, October 11, 2017 3:37 PM
  • There are 2 types of error a cmdlet can encounter: terminating and non terminating. The Erroraction (and the $ErrorActionPreference variable) operate on just non-terminating errors. if you want to handle terminating errors, use Try/Catch to try the 'risky' operation then catch any errors. You can use the ErrorAction parameter to turn a non-terminating error into a terminating error.

    Fuller details are, as noted, in the help text.


    Thomas Lee <DoctorDNS@Gmail.Com>

    Wednesday, October 11, 2017 7:58 PM
  • One simple question: is this the quality you are expecting to see on PowersHell?

    I understand there could be two different types of errors, but from the quality point of view: what is the differences for user? I was pretty sure, that this was not documented :) But it looks like the newer documents speaks about this.

    But I still feel, if PowersHell team of Microsoft like to get people to get used to use PowersHell, then issues like this should be handled by either having one kind of error or having possibility to handle both errors. As, at the end, both error are written by red color without describing which one of them is "non-terminated error" and which one is "terminating error". You just need to know?

    And as you can see, there are still plenty of other CMDLets which behaves as - IMHO - they should:

    Get-Service -Name SomeThingWhichDoesNotExists -ErrorAction SilentlyContinue

    Get-ChildItem -Name SomeThingWhichDoesNotExists -ErrorAction SilentlyContinue

    Try and Catch sections, yes they are working, but for me they sounds like: you have perfect system, but to make it real, you need to build it up by your own, like you do when buy something from Ikea.


    Petri

    Friday, October 20, 2017 8:38 PM
  • If you were  developer of applications software and/or operating systems and components then you would realize that your issue is not an issue.  All OSs  and software systems behave in almost the exact same way that PowerShell does.  Exceptions are pretty much standardized across all industries although there are "flavors" of handling.

    PowerShell is not a compiled language and because of this it must handle some kinds of errors outside of any trapping mechanism.  Certain serious errors that cannot be trapped in a scripting environment must be passed to the user.  These errors then need to be addressed immediately if we are to have predictable and safe scripting.

    I will agree that some CmdLets may need to be improved.  This is not PowerShell's responsibility but is the responsibility of the CmdLet/Module provider.  If you pick a specific CmdLet and a specific error condition that causes you grief perhaps we can determine if it is you and your usage or if it is truly an issue with the CmdLet.

    If you believe that you have specific issues then there is a place where you can post the issue for review.  Many user issues and suggestions make their way into both PowerShell and the documentation.

    The site is called PowerShell UserVoice. Post issues, ideas and errors/bugs there.

    I have noticed that many new to PowerShell with no or little experience in programming in a modern system tend to blame PowerShell for errors that are most often caused by poor programming and lack of understanding of how errors (exceptions) are processed in a modern system.  PowerShell is not an end user program.  It is a tool box that is wide open and capable of doing almost anything we need in the way of computer and program maintenance.  It is based on all available industry standards and is built and designed using the most modern design techniques.  PowerShell has a formal definition of its grammar which is published for all to review.  As of PS V2 the sources have been posted to the public and PS ha been ported to most current Unix and Apple systems. It will even run on smartphones.

    The biggest drawback for new user is the need to gain both basic knowledge of PowerShell and to learn basic programming.  Once these mountain have been climbed the sky is the limit. 

    PowerShell has also been designed to be a simple command line command processor just like the old CMD.EXE shell.  It can execute any program in the system and has much better error management at the prompt than Unix , IBM or Apple.

    Take some time to gain expertise in PowerShell and you will see why it has become so popular and important.

    You can type all of these standard commands and they work just like they always have:

    dir, ipconfig, tasklist, ipconfig, query.... the list is infinite.  Whatever you have installed in Windows.  TO see the available commands type the following:

    get-command -CommandType Application

    Type the following to see how many commands you have available:

    (get-command -CommandType All).Count

    This will be in the thousands and, on a big system it can be in the tens of thousands.

    Good luck.


    \_(ツ)_/

    Friday, October 20, 2017 9:09 PM
  • From the quality point of view, yes these two types of error really are different and can usefully be handled using separate means.

    A non-terminating error can be one you may be able to ignore, whereas a terminating error isn't. 

    Suppose I do this

    Get-ChildItem c:\*.ps1 -Recurse

    This cmdlet gets all the PS1 files in my system, but for a few folders (eg c:\perflogs) it gets a non-terminating error. This is fine - if I am looking for files then ignoring the non-terminating errors is a good thing.

    Another common pattern is this:

    If (-Not (Test-Path -Path $folderpath -ea 0) 
    { 
        "Folder being created"
        New-Item -Path $folderpah -ItemType Directory 
    }
    Else
    {
       "folder exists"
    }
    


    To be able to differentiate these terminatingerrors is very useful in cases like this. On the other hand, a real terminating error is one you probably can't get around. For example

    $srvs = Get-Service -ComputerName nonexistant.nonexistant.com

    There is no point continuing on after this since that system does not exist. 

    So - the PowerShell team is full of very smart people who recognise the richness of the environment. Just because YOU do not understand the difference does not mean the difference does not exist or can be important.

    As you learn PowerShell, you'll find the distinction very useful.


    Thomas Lee <DoctorDNS@Gmail.Com>


    • Edited by Thomas Lee Monday, October 23, 2017 8:54 AM
    Saturday, October 21, 2017 2:06 PM
  • For this discussion here is how a terminating error is thrown.

    function Test-ThrowTerminatingError {
    	Param (
    		[PArameter()]
    		[switch]$Terminating
    	)
    	$exception = [System.Exception]::new('A bad thing happened')
    	$errorId = 'Too much of a good thing'
    	$errorCategory = [System.Management.Automation.ErrorCategory]::LimitsExceeded
    	$targetObject = 'Me'
    	$errorRecord = [System.Management.Automation.ErrorRecord]::New($exception, $errorId, $errorCategory, $targetObject)
    	
    	if($Terminating){$PsCmdLet.ThrowTerminatingError($errorRecord)}
    	$PsCmdLet.WriteError($errorRecord)
    }
    Test-ThrowTerminatingError -ErrorAction SilentlyContinue
    # now make it a terminating error
    Test-ThrowTerminatingError -ErrorAction SilentlyContinue -Terminating

    First time the error is thrown as a normal error.  With the "Terminating" switch the error is thrown as a terminating error.

    As you can see this is not a decision made by PowerShell but is made by the CmdLet programmer.  As I noted above, PowerShell is extremely well designed form a rigorous design and mathematical perspective.  I have seen no deficiencies in the language or engine design or implementation.  All issues I have had are with CmdLet design. (Exchange, ActiveDirectory, SharePoint).  These were designed before WMF 3 and will likely be redesigned as PS moves forward. They fail to closely follow the PS model much of the time.

    Systems are evolutionary.  Criticism is almost always good as it makes all of us think.  PowerShell and Net have been inheritors of the evolutionary design of computer systems.  They are also moving forwards as if on steroids due to the large technical public interest in the model and the accessibility of such a powerful set of tools.


    \_(ツ)_/


    • Edited by jrv Saturday, October 21, 2017 3:18 PM
    Saturday, October 21, 2017 3:16 PM
  • Jrv,

    It looks like my notes are from years like this describes: Blog: -ErrorAction and -ErrorVariable. At that time there was only the Error. But it looks like documents gets better and better :D

    Still, it looks like this is a pretty wild world. The newer documentation on: About CommonParameters says: "The ErrorAction parameter has no effect on terminating errors (such as missing data, parameters that are not valid, or insufficient permissions) that prevent a command from completing successfully." But if I e.g. run

    - Get-ChildItem -Path C:\AccessDeniedFolder -errorAction SilentlyContinue

    - Get-Process -Name DoesNotExists -ErrorAction silentlyContinue

    thouse should cause a terminated error (?) and they should not be affected by -errorAction parameter, but they do.

    The original problem behind of this story was: I do have O365 users in AzureAD and then our internal on-premises AD. To see, which users are correctly replicated between those, I run get-ADuser using the data what I get from get-msoluser. For this and other similar stuff I like to use one simple oneliner. I know, when you have massive amount of users the prompt is not the correct place and outputs should go to output file etc.. But the power of PowerShell is to run simple commands and pipe objects to next CMDLet. If you want to compare one attribute in 100 objects you do not want (IMHO) to write script for that. The problem was, that there were those "not found" users on the screen and I was not able to avoid them,

    While reading your reponse I get a feeling, that it is just because of CMDLet's writer's kindness for us, the -errorAction is working in some cases.

    But one thing I have troubles to agree :) "PowerShell is not an end user program." When we speak about oneliners and simple commands, I feel those could be friendly for end-users as well. Of course the main focus has been happy system administrators =)


    Petri

    Sunday, October 22, 2017 8:25 PM
  • The issue and mechanism is exactly as documented.  Get-AdUser behaves exactly as it always ahs and as it is designed.

    if($aduser = Get-AdUser -Filter "SamAccountName -eq 'someuser'"){
        # found user.
    }else{
        # user not found
    }

    This has been the method for doing what you are trying to do.  If you had actually posted you real problem instead of picking on a technical issue that you fail to understand we would have given you the solution a long time ago.

    The code terminates because that CmdLet results in an "object not found" and the author designed this to  be a terminating error.  Using the filter the command does not error it just returns nothing which is how we determine if something "exists" or not.  THe same is tru of most other CmdLets.


    \_(ツ)_/

    Sunday, October 22, 2017 8:57 PM
  • Thomas,

    "So - the PowerShell team is full of very smart people who recognise the richness of the environment. Just because YOU do not understand the difference does not mean the difference does not exist or can be important.

    As you learn PowerShell, you'll find the distinction very useful."

    No doubts of that ! They are guys/girls with great skills and PS has been really find the place :D And what comes to my knowledge, at least I have had possibilities to learnt from one of the best. You had PowerShell MasterClass education in here around year.......2011 perhaps. Thank you for that ! :D

    About the last example, it is a bit funny:

    $srvs = Get-Service -ComputerName doesnotexists -errorAction SilentlyContinue

    Above returns the exception as normally, but:

    $srv = Get-Service -Name DoesNotExists -ComputerName doesnotexists -errorAction SilentlyContinue
    $srv = Get-Service -Name DoesExists -ComputerName doesnotexists -errorAction SilentlyContinue

    Those does not return any error.

    But that just mean that I still have not leart the differences between the errors and my journey still continue. Still, somehow it sounds a logically for me, if CMDLet runner like to skip the errors it should be possible and it is her/his responsible to take care of the errors. Like the documentation says in year 2006 speaks :D


    Petri

    Sunday, October 22, 2017 9:05 PM
  • Again.   It depends on what the designer of the CmdLet chose to do when throwing an exception and has nothing to do with any design flaws in PowerShell.

    If you still think this is wrong then please post your issue in "UserVoice".


    \_(ツ)_/

    Sunday, October 22, 2017 9:20 PM
  • So let me re-summarise. With PowerShell, there are two types of error: non-terminating (the cmdlet can complain by continue) and terminating where the error is fatal and execution stops. I hope you can differentiate between these two types of error.

    Having said that, the distinction between what constitutes each type of error is up to the cmdlet writer.  And ultimately, that means having to know how the individual cmdlets work.

    I spent 9 months working on a PowerShell book - and I can tell you that different modules (and cmdlets included in them) do vary. With enough experience, you discover these behaviours.

    And finally - the code Get-Service -name Foo vs Get-Service -Computer XXX -Name Foo - I see what you mean. The logic in the first case is that you can get to the computer to find services just not this one, vs the second case where you can't get o the computer. Not finding a service on a system the cmdlet can get to is non-terminating, not being able to get to the server IS terminating.


    Thomas Lee <DoctorDNS@Gmail.Com>

    Monday, October 23, 2017 9:02 AM
  • Uuf, one word: blushing...

    Petri

    Monday, October 23, 2017 5:23 PM
  • Hi,

    I have just come across this exact issue and your comment that there is no point continuing is incorrect.  I am querying 300 hosts from a list of available servers. 

    $a=get-service -computer $myhosts *mySVC* -ErrorAction Ignore -ErrorVariable myError |where status -ne 'Running'

    A couple of the servers in that list are not available, but I still want the get-service cmdlet to return the services from the remainder, not to terminate just because 1 or 2 servers out of 300+ are not online at this point in time.

    For a cmdlet that is designed to query multiple hosts to terminate, if one  host is not available, seems to me to be a fundamental design flaw.

    Regards


    Tuesday, February 25, 2020 1:12 PM
  • I just checked Get-Service full help and Microsoft website, I did not see anything saying it is meant to run on MULTIPLE hosts.

    Source: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-service?view=powershell-7

    I checked also Get-Process -Name DoesNotExists -ErrorAction silentlyContinue. It returns an Error: ErrorRecord. When I looked, it is stated that it's an Non-terminating errors, therefore the expectations are met.

    Source: https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.errorrecord?view=pscore-6.2.0

    Tuesday, February 25, 2020 2:34 PM
  • There's actually 3 types of exceptions:


    command terminating

    script terminating

    non-terminating


    https://github.com/MicrosoftDocs/PowerShell-Docs/issues/1583

    • Edited by JS2010 Tuesday, February 25, 2020 3:36 PM
    Tuesday, February 25, 2020 3:28 PM
  • Here is how to use arrays with some CmdLets that are designed to use them

    2 computers, 2 service - one service is bogus

    Get-Service -Name spooler,xxxxx  -ComputerName sbs01,ws701 -ErrorAction 0 -ErrorVariable +e| 
         select machinename,servicename

    Results:

    PS C:\scripts> Get-Service -Name spooler,xxxxx  -ComputerName sbs01,ws701 -ErrorAction 0 -ErrorVariable +e|
               select machinename,servicename
    
    MachineName ServiceName
    ----------- -----------
    ws701       spooler
    sbs01       spooler
    
    
    PS C:\scripts> $e
    Get-Service : Cannot find any service with service name 'xxxxx'.
    At line:1 char:1
    + Get-Service -Name spooler,xxxxx  -ComputerName sbs01,ws701 -ErrorActi ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : ObjectNotFound: (xxxxx:String) [Get-Service], ServiceCommandException
        + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand
    
    Get-Service : Cannot find any service with service name 'xxxxx'.
    At line:1 char:1
    + Get-Service -Name spooler,xxxxx  -ComputerName sbs01,ws701 -ErrorActi ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : ObjectNotFound: (xxxxx:String) [Get-Service], ServiceCommandException
        + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand
    
    PS C:\scripts>

    We can extract exact info from the err5os but the command continues are expected.

    Learning the basics of PowerShell will help you to understand why this is and teach how PowerShell is designed to work and be used. It is not just a replacement for Kiddie Basic or a simple batch language.  YOU cannot learn or understand it by guessing or copying from the INternet.  YOu cannot learn it from forums.


    \_(ツ)_/

    Tuesday, February 25, 2020 3:51 PM
  • I just checked Get-Service full help and Microsoft website, I did not see anything saying it is meant to run on MULTIPLE hosts.

    Source: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-service?view=powershell-7

    I checked also Get-Process -Name DoesNotExists -ErrorAction silentlyContinue. It returns an Error: ErrorRecord. When I looked, it is stated that it's an Non-terminating errors, therefore the expectations are met.

    Source: https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.errorrecord?view=pscore-6.2.0

    That is because you don't know how to read or use the help.  It is explicitly documented in the help for the CmdLet. It is not part of teh error variable of preference variable.  It is per-command.

    Take some time to learn how to use PowerShell help.

    help help

    Read it ALL very carefully. It will always be extremely useful.


    \_(ツ)_/

    Tuesday, February 25, 2020 4:15 PM
  • That is because you don't know how to read or use the help.  It is explicitly documented in the help for the CmdLet.

    Take some time to learn how to use PowerShell help.

    This comment right here provide NO help whatsoever. Instead of saying stuff like that, point out my mistake, therefore it helps me and maybe others that are reading this thread.

    I am actually doing that, however the process isn't helped by comments like you.

    It seems like "I did not see anything saying it is meant to run on MULTIPLE hosts." meant is it totally true and there is no other answer.

    I am actually reading this part here to understand - https://docs.microsoft.com/en-ca/powershell/module/microsoft.powershell.core/about/about_commonparameters?view=powershell-7.

    Tuesday, February 25, 2020 6:43 PM
  • For what it's worth, if you pipe the identity in, you can silence the exception message.  It's strange.  You can catch the exception with try, but it doesn't seem to stop itself or the script it's in.


    'doesnotexist' | get-aduser -ErrorAction SilentlyContinue

    • Edited by JS2010 Tuesday, February 25, 2020 6:58 PM
    Tuesday, February 25, 2020 6:54 PM
  • Your mistake is that you didn't read teh help.  If you read the documentation for the CmdLet you will understand what I am saying.  To understand how to use help type the following:

    help help

    Read it.  If you knew how to use help and what it is and does in PowerShell there would be no issue.

    YOU are looking at the wrong things and in the wrong places.  This is because you do not have basic PowerShell training and are grabbing at what you have seen on the Internet as the source.  It is not.  What you have linked has nothing to do with the issue.

    You are looking at error variables and common parameters which have nothing at all to do with this issue other than to inform as to how to use these things in general.  Toi understand the capabilities of any CmdLet you must read the CmdLet help.

    Using a good book on basic PowerShell will give you the parts you are missing and that will help you to understand how these pieces actually work within PowerShell.  They do not answer your questions but are elements ne3eded along with the basics.

    PowerShell is a "scripting system" it is not just a language.  To use it you must understand the whole system and not just pieces.  

    You are trying to learn how fly a jet plane by learning how to fill the tires and how to open the cargo door.  By approaching any advanced technology in pieces like this you will never get to flying the plane.  You must start by learning basic aeronautic engineering.  This is a requirement for getting a license. It is similar to learning the laws of your state before getting drivers license.  You must satisfy the base requirements to move into the actual use of any technology.

    See: Windows PowerShell™ 4: TFM

    It's very good and it is free.  I also recommend the newer PowerShell books by PowerShell team members on Amazon.


    \_(ツ)_/

    Tuesday, February 25, 2020 6:58 PM
  • For what it's worth, if you pipe the identity in, you can silence the exception message.  It's strange.  You can catch the exception with try, but it doesn't seem to stop itself or the script it's in.


    'doesnotexist' | get-aduser -ErrorAction SilentlyContinue

    Unfortunately this just confuses the issue.  My point is that the use and behavior is dependent on the CmdLet.  Looking in teh global help files for errorvariable and common parameters will not solve the issue.  What this example does show is that this CmdLet does behave tis way.  Other CmdLets do not.  Only reading the help carefully and analyzing the exact error can tell us what is happening.  There is no one-size-fits-all solution. Thisis the nature of programming with any A{PI.  To understand these behaviors requires two things: a deeper understanding of PowerShell and a technical understanding or programmed (software enabled) systems.

    Some issue are generic to the OS, some generic to computing and some generic to the process and requirements of programmed systems.  Without a clear understanding of these elements of basic computing much of the rest becomes confusing.  Learning by asking questions is not possible until the questioner has a certain minimal amount of knowledge.

    Think that you need to learn to count before you can work as a cashier.

    All of life has prerequisites.   Working with computers outside of the GUI has a huge number of prerequisites that most GUI users don't have or know about.


    \_(ツ)_/

    Tuesday, February 25, 2020 7:08 PM
  • I was also going to suggest redirecting standard error to null, similar to unix.  But weirdly that doesn't work either.  Powershell has many nooks and crannies, like an English muffin.


    get-aduser doesntexist 2> $null

    get-aduser : Cannot find an object with identity: 'doesntexist' under: 'DC=microsoft,DC=com'.
    At line:1 char:1
    + get-aduser doesntexist 2> $null
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : ObjectNotFound: (doesntexist:ADUser) [Get-ADUser], ADIdentityNotFoundException
        + FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException,M
       icrosoft.ActiveDirectory.Management.Commands.GetADUser

    • Edited by JS2010 Tuesday, February 25, 2020 8:28 PM
    Tuesday, February 25, 2020 8:27 PM
  • The only way to avoid a terminating exception with Get-AdUser is the folowing:

    Get-AdUser -Filter "SamaccountNAme -eq 'userid'"

    Now there will be no errors.


    \_(ツ)_/

    Tuesday, February 25, 2020 8:40 PM
  • Here is the other way to handle this which I use in some cases:

    Try{get-aduser 'doesnotexist' -ErrorAction Stop}Catch{}


    \_(ツ)_/

    Tuesday, February 25, 2020 8:44 PM