Suppress error message

How can I suppress error messages for a shell command? For example, if there are only jpg files in a directory, running ls *.zip gives an error message: $ ls *.zip ls: cannot access '*.zip': No

How can I suppress error messages for a shell command?

For example, if there are only jpg files in a directory, running ls *.zip gives an error message:

   $ ls *.zip
   ls: cannot access '*.zip': No such file or directory

Is there an option to suppress such error messages? I want to use this command in a Bash script, but I want to hide all errors.

Peter Mortensen's user avatar

asked Sep 3, 2015 at 15:31

Peter's user avatar

6

Most Unix commands, including ls, will write regular output to standard output and error messages to standard error, so you can use Bash redirection to throw away the error messages while leaving the regular output in place:

ls *.zip 2> /dev/null

Peter Mortensen's user avatar

answered Sep 3, 2015 at 15:33

AJefferiss's user avatar

AJefferissAJefferiss

1,5731 gold badge12 silver badges17 bronze badges

1

$ ls *.zip 2>/dev/null

will redirect any error messages on stderr to /dev/null (i.e. you won’t see them)

Note the return value (given by $?) will still reflect that an error occurred.

answered Sep 3, 2015 at 15:34

Brian Agnew's user avatar

Brian AgnewBrian Agnew

266k36 gold badges331 silver badges439 bronze badges

To suppress error messages and also return the exit status zero, append || true. For example:

$ ls *.zip && echo hello
ls: cannot access *.zip: No such file or directory
$ ls *.zip 2>/dev/null && echo hello
$ ls *.zip 2>/dev/null || true && echo hello
hello

$ touch x.zip
$ ls *.zip 2>/dev/null || true && echo hello
x.zip
hello

Peter Mortensen's user avatar

answered Nov 11, 2017 at 6:45

A-C's user avatar

A-CA-C

1211 silver badge4 bronze badges

2

I attempted ls -R [existing file] and got an immediate error.
ls: cannot access ‘existing file’: No such file or directory

So, I used the following:

ls -R 2>dev/null | grep -i [existing file]*

ls -R 2>dev/null | grep -i text*

Or, in your case:

ls -R 2>dev/null | grep -i *.zip

answered Jan 4, 2022 at 19:36

Richard's user avatar

1

My solution with a raspberry pi3 with buster.

ls -R 2>/dev/null | grep -i [existing file]*

2>/dev/null is very usefull with Bash script to avoid useless warnings or errors.

Do not forget slash caracter

answered Feb 6 at 13:32

fr3d mobile's user avatar

New contributor

fr3d mobile is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

1

I am currently looking ways to suppress error command in Linux, in particular, the command cp.

I do:

root@ubuntu:~$ cp /srv/ftp/201*/wha*/*.jj ~/.
cp: cannot stat `/srv/ftp/201*/wha*/*.jj': No such file or directory

How do I suppress the error message that gets printed on the screen? I.e., I don’t want to see this error message in my monitor.

Anthon's user avatar

Anthon

77k42 gold badges159 silver badges217 bronze badges

asked Mar 23, 2015 at 17:58

andy_ttse's user avatar

2

To suppress error output in bash, append 2>/dev/null to the end of your command. This redirects filehandle 2 (STDERR) to /dev/null. There are similar constructs in other shells, though the specific construct may vary slightly.

answered Mar 23, 2015 at 18:03

John's user avatar

JohnJohn

16.1k1 gold badge32 silver badges40 bronze badges

2

Redirect the error message (STDERR) to /dev/null:

root@ubuntu:~$ cp /srv/ftp/201*/wha*/*.jj ~/. 2>/dev/null

Example:

$ cp /srv/ftp/201*/wha*/*.jj ~/.  ##Error message gets printed
cp: cannot stat ‘/srv/ftp/201*/wha*/*.jj’: No such file or directory

$ cp /srv/ftp/201*/wha*/*.jj ~/. 2>/dev/null  ##No error message gets printed

answered Mar 23, 2015 at 18:02

heemayl's user avatar

heemaylheemayl

53.2k7 gold badges120 silver badges139 bronze badges

Your question is not clear. The most sensible thing to do would be to not run cp at all when the wildcard doesn’t match any file, rather than run cp and hide the error message.

To do that, if the shell is bash, set the nullglob option so that the wildcard pattern expands to nothing if it doesn’t match any files. Then check whether the pattern expanded to anything, and don’t call cp in that case.

#!/bin/bash
shopt -s nullglob
files=(/srv/ftp/201*/wha*/*.jj)
if [[ ${#files[@]} -ne 0 ]]; then
  cp "${files[@]}" ~
fi

In plain sh, test whether the glob was left unchanged, pointing to a non-existent file.

set -- /srv/ftp/201*/wha*/*.jj
if ! [ -e "$1" ] && ! [ -L "$1" ]; then
  cp "$@" ~
fi

answered Mar 23, 2015 at 23:26

Gilles 'SO- stop being evil''s user avatar

1

you can use either:
1 option: 2>/dev/null.
2 option: 2>&1
Besides you can use this at the end of your command it will suppress the error messages:

Example here-

$cp nofile.txt b.txt > log.txt 2>/dev/null

here u can’t retrieve any info about the error message.
Ex2:

$cp nofile.txt b.txt > log.txt 2>&1

here you can retrieve some info from the below log file:

$ cat log.txt
cp: cannot stat `nofile.txt': No such file or directory

sam's user avatar

sam

21.5k4 gold badges21 silver badges30 bronze badges

answered Dec 29, 2016 at 15:48

jeevan kishore's user avatar

Add this in ~/.bashrc:

alias cp='cp 2> /dev/null'

then:

source ~/.bashrc

answered Mar 24, 2015 at 1:13

M122's user avatar

3

When you try to run rm *.bar and there is no file that matches *.bar, basically two things can happen:

  • The POSIX behavior is the shell runs rm with literal *.bar as an argument. The tool tries to remove a file literally named *.bar (as if you run rm '*.bar'), it fails and prints something like rm: *.bar: No such file or directory. This is how the POSIX shell (sh) and compatible shells behave.

  • Non-POSIX behavior is the shell detects there is no match, prints something like no matches found: *.bar and doesn’t run rm at all. This is how Zsh behaves by default. (For comparison: in Bash you can switch to this behavior by shopt -s failglob.)

An error from rm (the former case) is printed to the stderr of rm. An error from the shell (the latter case) is printed to the stderr of the shell.

The redirection in rm *.bar 2>/dev/null affects the stderr of rm only+. In your example rm doesn’t even run.

To redirect the stderr of the main shell you need exec. By «the main shell» I mean the interactive shell where you type; or, in case of running a script, the shell interpreting the script. Example:

exec 2>/dev/null

In Zsh you can even close it:

exec 2>&-

A reasonable approach is to duplicate the original stderr beforehand, just in case you need to use (or restore) it later. Example (note if you want to paste this code into an interactive Zsh then you should invoke setopt interactive_comments first):

exec 7>&2           # "save" stderr
exec 2>/dev/null    # redirect
rm *.bar
whatever
exec 2>&7           # restore
exec 7>&-           # close descriptor which is no longer needed

Here 7 is an arbitrary single-digit number, otherwise unused as a file descriptor. The first two lines can be written as one: exec 7>&2 2>/dev/null; similarly the last two lines can.

Note rm or any command (like whatever) invoked without stderr redirection inherits stderr from the shell. This means in the above example rm (if it ever runs) and whatever will print their error messages (if any) to /dev/null. After exec 2>/dev/null you can invoke any number or commands and they all will have /dev/null as their stderr. If you really want to suppress all kinds of error messages then this is the way.

The solution works in many shells, not only in Zsh. If you want to redirect stderr of an interactive shell then keep in mind some less sophisticated shells use stderr to print their prompt.

Note a process may redirect its own stderr (like our shell does with exec 2>…); or it can print error messages to stdout or to /dev/tty (it shouldn’t, but it technically can). Therefore exec 2>/dev/null does not guarantee you will see no messages that look like error messages.

After exec 2>/dev/null you still can redirect stderr of any command on demand. E.g. if instead whatever we had:

whatever 2>&7

then its error messages would go to the original stderr we deliberately saved as file descriptor 7.


exec is not the only way to redirect stderr (or another file descriptor) of a shell. You can treat a shell (not the whole main shell though) like you treat rm in rm … 2>/dev/null. You can treat a subshell like this:

( rm *.bar ) 2>/dev/null

or just some code interpreted by the main shell:

{ rm *.bar; } 2>/dev/null

(; here is optional in Zsh, mandatory in some other shells; I just wanted the code to work outside of Zsh as well).

Any of these lines can solve your problem. In the context of suppressing error messages coming from a shell, the two lines are equivalent++.

Note the redirection starts at (/{ and ends at )/}, its scope is limited. Still you can place many commands inside the parentheses, so the «limited» scope may actually be the whole script. Or it may be just a part of the script (including whatever introduced earlier in this answer, whatever you want). The fact the redirection stops working after )/} makes this approach a neat alternative to saving and restoring stderr with exec.


+ Strictly: it affects «rm» before and after it becomes (or tries to become) rm. Bear with me. The redirection in rm … 2>/dev/null starts as a redirection performed by a forked shell that is about to replace itself with rm executable. This shell redirects its own stderr before it tries to replace itself with rm. Any error it reports after performing the redirection will go to /dev/null. E.g. if rm is not to be found then the already performed redirection will suppress the command not found error.

++ Technically ( … ) creates a subshell, { … } does not. A subshell behaves like a separate shell process that inherits variables and current working directory, but cannot change anything (like variables or current working directory) in its parent shell. It may or may not be realized as a truly separate process, it’s the behavior that matters. OTOH { … } only groups commands for some purpose (in our case the purpose is redirection). This doesn’t mean there’s never a subshell when you use { … }; e.g. in a pipeline all parts but the last one are subshells anyway (in some shells: all parts including the last one). These technical details are irrelevant in the context of our problem alone, but in general they can make a difference.

When you design a PowerShell script, there may be situations where you cannot eliminate all possible runtime errors. If your script maps network drives, there could be a situation where no more drive letters are available, and when your script performs a remote WMI query, the remote machine may not be available.

In this chapter, you learn how to discover and handle runtime errors gracefully.

Topics Covered:

  • Suppressing Errors
  • Handling Errors
    • Try/Catch
    • Using Traps
  • Handling Native Commands
    • Understanding Exceptions
    • Handling Particular Exceptions
    • Throwing Your Own Exceptions
    • Stepping And Tracing
  • Summary

Suppressing Errors

Every cmdlet has built-in error handling which is controlled by the -ErrorAction parameter. The default ErrorAction is «Continue»: the cmdlet outputs errors but continues to run.

This default is controlled by the variable $ErrorActionPreference. When you assign a different setting to this variable, it becomes the new default ErrorAction. The default ErrorAction applies to all cmdlets that do not specify an individual ErrorAction by using the parameter -ErrorAction.

To suppress error messages, set the ErrorAction to SilentlyContinue. For example, when you search the windows folder recursively for some files or folder, your code may eventually touch system folders where you have no sufficient access privileges. By default, PowerShell would then throw an exception but would continue to search through the subfolders. If you just want the files you can get your hands on and suppress ugly error messages, try this:

PS> Get-Childitem $env:windir -ErrorAction SilentlyContinue -recurse -filter *.log

Likewise, if you do not have full local administrator privileges, you cannot access processes you did not start yourself. Listing process files would produce a lot of error messages. Again, you can suppress these errors to get at least those files that you are able to access:

Get-Process -FileVersion -ErrorAction SilentlyContinue

Suppress errors with care because errors have a purpose, and suppressing errors will not solve the underlying problem. In many situations, it is invaluable to receive errors, get alarmed and act accordingly. So only suppress errors you know are benign.

NOTE: Sometimes, errors will not get suppressed despite using SilentlyContinue. If a cmdlet encounters a serious error (which is called «Terminating Error»), the error will still appear, and the cmdlet will stop and not continue regardless of your ErrorAction setting.

Whether or not an error is considered «serious» or «terminating» is solely at the cmdlet authors discretion. For example, Get-WMIObject will throw a (non-maskable) terminating error when you use -ComputerName to access a remote computer and receive an «Access Denied» error. If Get-WMIObject encounters an «RPC system not available» error because the machine you wanted to access is not online, that is considered not a terminating error, so this type of error would be successfully suppressed.

Handling Errors

To handle an error, your code needs to become aware that there was an error. It then can take steps to respond to that error. To handle errors, the most important step is setting the ErrorAction default to Stop:

$ErrorActionPreference = 'Stop'

As an alternative, you could add the parameter -ErrorAction Stop to individual cmdlet calls but chances are you would not want to do this for every single call except if you wanted to handle only selected cmdlets errors. Changing the default ErrorAction is much easier in most situations.

The ErrorAction setting not only affects cmdlets (which have a parameter -ErrorAction) but also native commands (which do not have such a parameter and thus can only be controlled via the default setting).

Once you changed the ErrorAction to Stop, your code needs to set up an error handler to become aware of errors. There is a local error handler (try/catch) and also a global error handler (trap). You can mix both if you want.

Try/Catch

To handle errors in selected areas of your code, use the try/catch statements. They always come as pair and need to follow each other immediately. The try-block marks the area of your code where you want to handle errors. The catch-block defines the code that is executed when an error in the try-block occurs.

Take a look at this simple example:

'localhost', '127.0.0.1', 'storage1', 'nonexistent', 'offline' |
  ForEach-Object {
    try {
      Get-WmiObject -class Win32_BIOS -computername $_ -ErrorAction Stop | 
        Select-Object __Server, Version
    }
    catch {
      Write-Warning "Error occured: $_"
    }
  }

It takes a list of computer names (or IP addresses) which could also come from a text file (use Get-Content to read a text file instead of listing hard-coded computer names). It then uses Foreach-Object to feed the computer names into Get-WMIObject which remotely tries to get BIOS information from these machines.

Get-WMIObject is encapsulated in a try-block and also uses the ErrorAction setting Stop, so any error this cmdlet throws will execute the catch-block. Inside the catch-block, in this example a warning is outputted. The reason for the error is available in $_ inside the catch-block.

Try and play with this example. When you remove the -ErrorAction parameter from Get-WMIObject, you will notice that errors will no longer be handled. Also note that whenever an error occurs in the try-block, PowerShell jumps to the corresponding catch-block and will not return and resume the try-block. This is why only Get-WMIObject is placed inside the try-block, not the Foreach-Object statement. So when an error does occur, the loop continues to run and continues to process the remaining computers in your list.

The error message created by the catch-block is not yet detailed enough:

WARNING: Error occured: The RPC server is unavailable. (Exception from HRESULT:0x800706BA)

You may want to report the name of the script where the error occured, and of course you’d want to output the computer name that failed. Here is a slight variant which accomplishes these tasks. Note also that in this example, the general ErrorActionPreference was set to Stop so it no longer is necessary to submit the -ErrorAction parameter to individual cmdlets:

'localhost', '127.0.0.1', 'storage1', 'nonexistent', 'offline' |
  ForEach-Object {
    try {
      $ErrorActionPreference = 'Stop'
      $currentcomputer = $_
      Get-WmiObject -class Win32_BIOS -computername $currentcomputer  | 
        Select-Object __Server, Version
    }
    catch {
      Write-Warning ('Failed to access "{0}" : {1} in "{2}"' -f $currentcomputer, `
$_.Exception.Message, $_.InvocationInfo.ScriptName) } }

This time, the warning is a lot more explicit:

WARNING: Failed to access "nonexistent" : The RPC server is unavailable. 
(
Exception from HRESULT: 0x800706BA) in "C:Usersw7-pc9AppDataLocalTempUntitled3.ps1"

Here, two procedures were needed: first of all, the current computer name processed by Foreach-Object needed to be stored in a new variable because the standard $_ variable is reused inside the catch-block and refers to the current error. So it can no longer be used to read the current computer name. That’s why the example stored the content of $_ in $currentcomputer before an error could occur. This way, the script code became more legible as well.

Second, inside the catch-block, $_ resembles the current error. This variable contains a complex object which contains all details about the error. Information about the cause can be found in the property Exception whereas information about the place the error occured are found in InvocationInfo.

To examine the object stored in $_, you can save it in a global variable. This way, the object remains accessible (else it would be discarded once the catch-block is processed). So when an error was handled, you can examine your test variable using Get-Member. This is how you would adjust the catch-block:

    catch {
      $global:test = $_
      Write-Warning ('Failed to access "{0}" : {1} in "{2}"' -f $currentcomputer, `
$_.Exception.Message, $_.InvocationInfo.ScriptName) } }

Then, once the script ran (and encountered an error), check the content of $test:

PS> Get-Member -InputObject $test


   TypeName: System.Management.Automation.ErrorRecord

Name                  MemberType     Definition
----                  ----------     ----------
Equals                Method         bool Equals(System.Object obj)
GetHashCode           Method         int GetHashCode()
GetObjectData         Method         System.Void GetObjectData(System.Runtime.Seriali...
GetType               Method         type GetType()
ToString              Method         string ToString()
CategoryInfo          Property       System.Management.Automation.ErrorCategoryInfo C...
ErrorDetails          Property       System.Management.Automation.ErrorDetails ErrorD...
Exception             Property       System.Exception Exception {get;}
FullyQualifiedErrorId Property       System.String FullyQualifiedErrorId {get;}
InvocationInfo        Property       System.Management.Automation.InvocationInfo Invo...
PipelineIterationInfo Property       System.Collections.ObjectModel.ReadOnlyCollectio...
TargetObject          Property       System.Object TargetObject {get;}
PSMessageDetails      ScriptProperty System.Object PSMessageDetails {get=& { Set-Stri...

As you see, the error information has a number of subproperties like the one used in the example. One of the more useful properties is InvocationInfo which you can examine like this:

PS> Get-Member -InputObject $test.InvocationInfo


   TypeName: System.Management.Automation.InvocationInfo

Name             MemberType Definition
----             ---------- ----------
Equals           Method     bool Equals(System.Object obj)
GetHashCode      Method     int GetHashCode()
GetType          Method     type GetType()
ToString         Method     string ToString()
BoundParameters  Property   System.Collections.Generic.Dictionary`2[[System.String, m...
CommandOrigin    Property   System.Management.Automation.CommandOrigin CommandOrigin ...
ExpectingInput   Property   System.Boolean ExpectingInput {get;}
HistoryId        Property   System.Int64 HistoryId {get;}
InvocationName   Property   System.String InvocationName {get;}
Line             Property   System.String Line {get;}
MyCommand        Property   System.Management.Automation.CommandInfo MyCommand {get;}
OffsetInLine     Property   System.Int32 OffsetInLine {get;}
PipelineLength   Property   System.Int32 PipelineLength {get;}
PipelinePosition Property   System.Int32 PipelinePosition {get;}
PositionMessage  Property   System.String PositionMessage {get;}
ScriptLineNumber Property   System.Int32 ScriptLineNumber {get;}
ScriptName       Property   System.String ScriptName {get;}
UnboundArguments Property   System.Collections.Generic.List`1[[System.Object, mscorli...

It tells you all details about the place the error occured.

Using Traps

If you do not want to focus your error handler on a specific part of your code, you can also use a global error handler which is called «Trap». Actually, a trap really is almost like a catch-block without a try-block. Check out this example:

trap {
      Write-Warning ('Failed to access "{0}" : {1} in "{2}"' -f $currentcomputer, `
$_.Exception.Message, $_.InvocationInfo.ScriptName) continue } 'localhost', '127.0.0.1', 'storage1', 'nonexistent', 'offline' | ForEach-Object { $currentcomputer = $_ Get-WmiObject -class Win32_BIOS -computername $currentcomputer -ErrorAction Stop | Select-Object __Server, Version }

This time, the script uses a trap at its top which looks almost like the catch-block used before. It does contain one more statement to make it act like a catch-block: Continue. Without using Continue, the trap would handle the error but then forward it on to other handlers including PowerShell. So without Continue, you would get your own error message and then also the official PowerShell error message.

When you run this script, you will notice differences, though. When the first error occurs, the trap handles the error just fine, but then the script stops. It does not execute the remaining computers in your list. Why?

Whenever an error occurs and your handler gets executed, it continues execution with the next statement following the erroneous statement – in the scope of the handler. So when you look at the example code, you’ll notice that the error occurred inside the Foreach-Object loop. Whenever your code uses braces, the code inside the braces resembles a new «territory» or «scope». So the trap did process the first error correctly and then continued with the next statement in its own scope. Since there was no code following your loop, nothing else was executed.

This example illustrates that it always is a good idea to plan what you want your error handler to do. You can choose between try/catch and trap, and also you can change the position of your trap.

If you placed your trap inside the «territory» or «scope» where the error occurs, you could make sure all computers in your list are processed:

'localhost', '127.0.0.1', 'storage1', 'nonexistent', 'offline' |
  ForEach-Object {
      trap {
        Write-Warning ('Failed to access "{0}" : {1} in "{2}"' -f $currentcomputer, `
$_.Exception.Message, $_.InvocationInfo.ScriptName) continue } $currentcomputer = $_ Get-WmiObject -class Win32_BIOS -computername $currentcomputer -ErrorAction Stop | Select-Object __Server, Version }

Handling Native Commands

Most errors in your PowerShell code can be handled in the way described above. The only command type that does not fit into this error handling scheme are native commands. Since these commands were not developed specifically for PowerShell, and since they do not necessarily use the .NET framework, they cannot directly participate in PowerShells error handling.

Console-based applications return their error messages through another mechanism: they emit error messages using the console ErrOut channel. PowerShell can monitor this channel and treat outputs that come from this channel as regular exceptions. To make this work, you need to do two things: first of all, you need to set $ErrorActionPreference to Stop, and second, you need to redirect the ErrOut channel to the StdOut channel because only this channel is processed by PowerShell. Here is an example:

When you run the following native command, you will receive an error, but the error is not red nor does it look like the usual PowerShell error messages because it comes as plain text directly from the application you ran:

PS> net user willibald
The user name could not be found.

More help is available by typing NET HELPMSG 2221.

When you redirect the error channel to the output channel, the error suddenly becomes red and is turned into a «real» PowerShell error:

PS> net user willibald 2>&1
net.exe : The user name could not be found.
At line:1 char:4
+ net <<<<  user willibald 2>&1
    + CategoryInfo          : NotSpecified: (The user name could not be found.:String)
   [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

More help is available by typing NET HELPMSG 2221.

You can still not handle the error. When you place the code in a try/catch-block, the catch-block never executes:

try {
  net user willibald 2>&1
  }
  
catch {
  Write-Warning "Oops: $_"
}

As you know from cmdlets, to handle errors you need to set the ErrorAction to Stop. With cmdlets, this was easy because each cmdlet has a -ErrorAction preference. Native commands do not have such a parameter. This is why you need to use $ErrorActionPreference to set the ErrorAction to Stop:

try {
  $ErrorActionPreference = 'Stop'
  net user willibald 2>&1
  }
  
catch {
  Write-Warning "Oops: $_"
}

If you do not like the default colors PowerShell uses for error messages, simply change them:

$Host.PrivateData.ErrorForegroundColor = "Red"
$Host.PrivateData.ErrorBackgroundColor = "White"

You can also find additional properties in the same location which enable you to change the colors of warning and debugging messages (like WarningForegroundColor and WarningBackgroundColor).

Understanding Exceptions

Exceptions work like bubbles in a fish tank. Whenever a fish gets sick, it burps, and the bubble bubbles up to the surface. If it reaches the surface, PowerShell notices the bubble and throws the exception: it outputs a red error message.

In this chapter, you learned how you can catch the bubble before it reaches the surface, so PowerShell would never notice the bubble, and you got the chance to replace the default error message with your own or take appropriate action to handle the error.

The level the fish swims in the fish tank resembles your code hierarchy. Each pair of braces resembles own «territory» or «scope», and when a scope emits an exception (a «bubble»), all upstream scopes have a chance to catch and handle the exception or even replace it with another exception. This way you can create complex escalation scenarios.

Handling Particular Exceptions

The code set by Trap is by default executed for any (visible) exception. If you’d prefer to use one or several groups of different error handlers, write several Trap (or Catch) statements and specify for each the type of exception it should handle:

function Test
{
  trap [System.DivideByZeroException] { "Divided by null!" continue }
  trap [System.Management.Automation.ParameterBindingException] {
"Incorrect parameter!";
continue
} 1/$null Dir -MacGuffin } Test Divided by null! Incorrect parameter!

Throwing Your Own Exceptions

If you develop functions or scripts and handle errors, you are free to output error information any way you want. You could output it as plain text, use a warning or write error information to a log file. With any of these, you take away the opportunity for the caller to respond to errors – because the caller has no longer a way of detecting the error. That’s why you can also throw your own exceptions. They can be caught by the caller using a trap or a try/catch-block.

function TextOutput([string]$text)
{
  if ($text -eq "")
  {
    Throw "You must enter some text."
  }
  else
  {
    "OUTPUT: $text"
  }
}

# An error message will be thrown if no text is entered:
TextOutput
You have to enter some text.
At line:5 char:10
+     Throw  <<<< "You have to enter some text."

# No error will be output in text output:
TextOutput Hello
OUTPUT: Hello

The caller can now handle the error your function emitted and choose by himself how he would like to respond to it:

PS> try { TextOutput } catch { "Oh, an error: $_" }
Oh, an error: You must enter some text.

Stepping And Tracing

Commercial PowerShell development environments like PowerShellPlus from Idera make it easy for you to set breakpoints and step through code to see what it actually does. In larger scripts, this is an important diagnostic feature to debug code.

However, PowerShell has also built-in methods to step code or trace execution. To enable tracing, use this:

PS> Set-PSDebug -trace 1
PS> dir
DEBUG:    1+  <<<< dir
DEBUG:    1+ $_.PSParentPath.Replace <<<< ("Microsoft.PowerShell.CoreFileSystem::", "")
DEBUG:    2+                                     [String]::Format <<<< ("{0,10}  {1,8}",
 $_.LastWriteTime.ToString("d"), $_.LastWriteTime.ToString("t"))


    Directory: C:Usersw7-pc9


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----        30.11.2009     12:54            Application data
DEBUG:    2+                                     [String]::Format <<<< ("{0,10}  {1,8}",
 $_.LastWriteTime.ToString("d"), $_.LastWriteTime.ToString("t"))
d-r--        04.08.2010     06:36            Contacts
(...)

Simple tracing will show you only PowerShell statements executed in the current context. If you invoke a function or a script, only the invocation will be shown but not the code of the function or script. If you would like to see the code, turn on detailed traced by using the -trace 2 parameter.

Set-PSDebug -trace 2

If you would like to turn off tracing again, select 0:

Set-PSDebug -trace 0

To step code, use this statement:

Set-PSDebug -step

Now, when you execute PowerShell code, it will ask you for each statement whether you want to continue, suspend or abort.

If you choose Suspend by pressing «H», you will end up in a nested prompt, which you will recognize by the «<<» sign at the prompt. The code will then be interrupted so you could analyze the system in the console or check variable contents. As soon as you enter Exit, execution of the code will continue. Just select the «A» operation for «Yes to All» in order to turn off the stepping mode.

Tip: You can create simple breakpoints by using nested prompts: call $host.EnterNestedPrompt() inside a script or a function.

Set-PSDebug has another important parameter called -strict. It ensures that unknown variables will throw an error. Without the Strict option, PowerShell will simply set a null value for unknown variables. On machines where you develop PowerShell code, you should enable strict mode like this:

Set-StrictMode -Version Latest

This will throw exceptions for unknown variables (possible typos), nonexistent object properties and wrong cmdlet call syntax.

Summary

To handle errors in your code, make sure you set the ErrorAction to Stop. Only then will cmdlets and native commands place errors in your control.

To detect and respond to errors, use either a local try/catch-block (to catch errors in specific regions of your code) or trap (to catch all errors in the current scope). With trap, make sure to also call Continue at the end of your error handler to tell PowerShell that you handled the error. Else, it would still bubble up to PowerShell and cause the default error messages.

To catch errors from console-based native commands, redirect their ErrOut channel to StdOut. PowerShell then automatically converts the custom error emitted by the command into a PowerShell exception.

Понравилась статья? Поделить с друзьями:
  • System identifier acquisition error sai 2
  • Supervisord socket error
  • System fault workshop touareg ошибка что это значит
  • Supervisor error no such file
  • Purgecomm function failed error 5