Use PowerShell
The Shell Is Calling
The Shell Is Calling
Jul 21st
I started looking a little deeper at error handling in PowerShell after this StackOverflow question.
PowerShell has two kinds of errors – terminating errors and non-terminating errors.
Terminating errors are the errors that can stop command execution cold. Non-terminating errors provided an additional challenge, as you need to be notified of failed operations and continue with pipeline operations. To deal with this issue and to provide additional output options, PowerShell employs the concept of streams. There are three additional streams (other than the primary pipeline stream) available in PowerShell – Verbose, Warning, and Error (and . We’ll be concerning ourselves with the output from the Error stream.
There are some automatic variables in the shell that deal with errors as well. $ErrorActionPreference is a variable that describes how PowerShell will treat non-terminating errors. $ErrorActionPreference has four options: “Continue” (the default), “SilentlyContinue”, “Inquire”, and “Stop”. $error is an array of all the errors that have occurred in the current session up to the number specified in $MaximumErrorCount. $? is a boolean value that is $true if the previous operation succeeded and $false if it did not.
PowerShell does have some built in flexibility to turn non-terminating errors into terminating errors. Based on our setting of $ErrorActionPreference, PowerShell will treat a non-terminating error differently. If $ErrorActionPreference is set to ‘”Stop”, PowerShell will treat the errors from that scope and all sub scopes (unless explicitly overridden) as terminating errors. If “Inquire” is chosen as the $ErrorActionPreference, then PowerShell will prompt the user at the console upon each error to ask whether it should continue (treat as non-terminating) or halt (treat as terminating), as well as providing an option to drop into a nested prompt.
$ErrorActionPreference is a global preference that can be set, but the PowerShell runtime also allows more granular control by providing common parameters for -ErrorAction and -ErrorVariable (shorthand -EA and –EV) which allow you to determine per cmdlet (and in V2 per advanced function) how errors should be handled. The –ErrorAction parameter takes the same options as $ErrorActionPreference.
So what happens when you encounter an error?
If you hit a terminating error, your script, function, or command will stop. The error will be logged to the $error variable and written to the error stream. The $? will be set to false. You can use the trap construct (or the try/catch/finally construct in V2) to deal with terminating errors and we’ll cover that further in the fourth post in this series.
If you hit a non-terminating error, the result will depend on the $ErrorActionPreference in the scope or the –ErrorAction parameter. If the $ErrorActionPreference or –ErrorAction parameter is set to ‘Continue’, the error will be written to the error stream, added to the $error array, and the $? will be set to $false. ‘SilentlyContinue’ will not write an error to the Error stream, but $error and $? are updated. Finally, ‘Inquire’ provides you an option at each error as to whether to treat it as terminating or non-terminating. If treated as a non-terminating error, the error will be treated like the $ErrorActionPreference or –ErrorAction parameter is ‘Continue’.
Now, I’ve mentioned that some terminating and non-terminating errors both write to the Error stream, so where does that actually get reported back to the user? If an error has been written to the error stream, it will be written to the output stream (which may surface differently based on the PowerShell host) separately from the pipeline output unless it is redirected. This means that the exception objects, which are how the errors are represented, are not saved to a variable if you are assigning the pipeline output to a variable.
For example:
$results = Get-WMIObject Win32_Bios –ComputerName localhost, ComputerThatDoesNotExist
Get-WmiObject : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At line:1 char:22
+ $results = Get-WmiObject <<<< Win32_Bios -ComputerName localhost, ComputerThatDoesNotExist
creates this output to the screen, but $results will only hold the results of the successful WMI query. This is where the –ErrorVariable comes in. You can specify a variable to hold the exceptions generated by a particular cmdlet (or in V2 advanced function). Specifying a variable does not remove an item from being written to the error stream and displayed as output.
In a console session, you can redirect the error stream with the redirection operators ( 2> or 2>>) or you can merge the error stream with the output stream (2>&1) and write the output to a file, the pipeline, or assign it to a variable.
Up next:
Other great PowerShell Error Handling posts:
Apr 27th
One concept that is central to the understanding of the layout of classes in the Base Class Libraries is the Namespace. Namespaces are a method of providing context for classes (and other constructs like Enums and Structs), allowing developers to group related classes and not worry about name collisions with development in other areas.
In the Base Class Libraries, the root namespace is the System namespace. The System namespace defines a large amount of the base types, like Object (which all classes derive from), String, DateTime, Boolean, and numerous others. When you specify types, PowerShell can infer the “System” part.
Example:
PS C:\scripts\PowerShell> $random = New-Object –TypeName Random
is the same as
PS C:\scripts\PowerShell> $random = New-Object –TypeName System.Random
Namespaces are hierarchical, except in naming convention. The representation of a file in PowerShell is a great example. A file object is represented in PowerShell as a System.IO.FileInfo object. The FileInfo class lives in the System.IO namespace, which is a separate namespace than the System namespace. There is a hierarchical impression implied, but that is solely through naming convention.
The CLR (Common Language Runtime) does not care about namespaces, only the fully qualified name of the class, so why use namespaces at all?
Namespaces are a convenience for developers, as languages like C# and VB.NET have language constructs that allow the developer to not have to use the fully qualified type name every time that is needed to be referenced. C# provides the “using” syntax and VB.NET has the “imports” syntax.
How does this apply to PowerShell?
PowerShell does not currently have a “using” or “imports” syntax or language feature, but there are a couple of workarounds. You can use variables holding the namespace and string concatenation to save some typing
PS C:\scripts\PowerShell> $netinfo = ‘System.Net.NetworkInformation’
PS C:\scripts\PowerShell> $ping = New-Object “$netinfo.ping”
PS C:\scripts\PowerShell> $ping.gettype()
IsPublic IsSerial Name BaseType
——– ——– —- ——–
True False Ping System.ComponentModel.Component
This doesn’t work with type accelerators though (at least in V1).. V2 CTP3 has some other options and Oisin Grehan has a great discussion on how to find the type accelerators and add your own.
Another option would be to create a function to wrap the creation of objects for particular namespaces.
Use-Namespace is a function I came up with to create a function to wrap New-Object for specific namespaces.
The useage of Use-Namespace is
PS C:\scripts\PowerShell>Use-Namespace System.IO, System.Net
PS C:\scripts\PowerShell>$memorystream = New-System.IOObject MemoryStream
PS C:\scripts\PowerShell>$memorystream.GetType()
PS C:\scripts\PowerShell> $memorystream.gettype()
IsPublic IsSerial Name BaseType
——– ——– —- ——–
True True MemoryStream System.IO.Stream
And the function is here..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | function Use-Namespace() { param ([string[]]$Namespace) BEGIN { if ($Namespace.length -gt 0) { $Namespace | Use-Namespace } } PROCESS { if ($_ -ne $null) { $NS = $_ $NSObject = "$NS" + "Object" $function = @" param (`$Class, [string[]]`$ArgumentList) if (`$ArgumentList.length -gt 0) { return New-Object -TypeName "$NS.`$Class" -ArgumentList `$ArgumentList } else { return New-Object -TypeName "$NS.`$Class" } "@ Set-Item -Path "function:global:New-$NSObject" -Value $function -force Write-Debug "Created function:global:New-$NSObject " } } } |
PSMDTAG:FAQ CLR
PSMDTAG:FAQ Namespace
PSMDTAG:FAQ .NET Framework
Mar 24th
Since PowerShell is built on .NET, there is a AppDomain (I’ll go into more detail in a later post) which has a lot of information about the .NET environment (what assemblies are loaded, etc..).
One feature that the AppDomain has is to store globally accessible name/value pairs. Normally, variables in PowerShell should handle most of your “in-process” storage needs, but for the times that they don’t, you have your AppDomain.
To access the AppDomain object, you can use the static property CurrentDomain on the System.AppDomain class.
(NOTE: Though I usually refer use the fully qualified namespace, PowerShell does allow you to skip the “System” portion of the namespace. I’m using the full namespace for clarity on the blog, but when typing on the command line, it is easier to skip that.)
PS C:\> [system.appdomain]::CurrentDomain
To save a name/value pair to your AppDomain, you can use the SetData method.
PS C:\> [system.appdomain]::CurrentDomain.SetData(‘ThisIsMyNameOrKey’, (‘This’,'Can’,'Be’,'Any’,'Object’,'Or’,'Collection’) )
Any object or collection can be saved in the AppDomain, and you are not limited to just one.
Accessing those values is just as easy, using the GetData method.
PS C:\> [system.appdomain]::CurrentDomain.GetData(‘ThisIsMyNameOrKey’)
This
Can
Be
Any
Object
Or
Collection
And there we have our collection back.
PSMDTAG:.Net AppDomain
Mar 20th
In our Exploring the .NET Framework series, we’ve covered some terminology, creating instances of objects and calling methods. In today’s installment, we are going to look at using static members – methods and properties. Static methods are methods that a class (or type) make available without needing to create an instance of the class. Similarly, static properties are properties that you can access without needing an instance of the class.
Many classes provide static members supply functionality where it doesn’t make sense to need an object.
The System.Math class contains a couple of static properties, PI and E.
PS C:\scripts\PowerShell> [math]::E
2.71828182845905
PS C:\scripts\PowerShell> [math]::PI
3.14159265358979
Constant values are not the only type of property that you’ll find. The System.AppDomain class has a static property, CurrentDomain, which is an AppDomain instance referring to the current application domain.
PS C:\scripts\PowerShell> [AppDomain]::CurrentDomain.gettype()
IsPublic IsSerial Name BaseType
——– ——– —- ——–
True False AppDomain System.MarshalByRefObject
System.Math also contains a number of static methods that provide a great deal of basic mathematical function.
PS C:\scripts\PowerShell>[Math] | get-member –static –membertype method | select name
Name
—-
Abs
Acos
Asin
Atan
Atan2
BigMul
Ceiling
Cos
Cosh
DivRem
Equals
Exp
Floor
IEEERemainder
Log
Log10
Max
Min
Pow
ReferenceEquals
Round
Sign
Sin
Sinh
Sqrt
Tan
Tanh
Truncate
I wrote a little helper function to get the static method definitions (Get-StaticMethodDefinition), which you can grab from PoshCode.org.
(V2 CTP3 – We can use the trick of using the method name without parenthesis following to get additional information on each of the methods that we are interested in.)
One type of static method that I would like to highlight is the factory method. A factory method is a common way of controlling object creation. At its most basic level, a factory pattern is a method that creates objects of a specified type.
An example of this is the System.Net.WebRequest’s Create method.
PS C:\scripts\PowerShell> $web = [net.webrequest]::create(‘http://www.google.com‘)
PS C:\scripts\PowerShell> $web.gettype()
IsPublic IsSerial Name BaseType
——– ——– —- ——–
True True HttpWebRequest System.Net.WebReq…
The factory method Create used the argument (‘http://www.google.com’) to determine the type of WebRequest object to create. In this case, it created an HttpWebRequest object, which is a more specialized version of the WebRequest for HTTP requests.
Let’s see how it would respond if we passed the Create method a URI with FTP.
PS C:\scripts\PowerShell> $web = [net.webrequest]::create(‘ftp://ftp.google.com’)
PS C:\scripts\PowerShell> $web.gettype()
IsPublic IsSerial Name BaseType
——– ——– —- ——–
True False FtpWebRequest System.Net.WebReq…
As we can see, the WebRequest class created an FtpWebRequest object.
Factory methods provide developers a way to more flexibly support different operations by allowing the static method to determine which object to return.
UPDATE: Joel “Jaykul” Bennet added a V2 advanced function to convert static methods to functions to PoShCode.org and pointed out Oisin Grehan’s blog post about creating functions from static methods (V1 compatible).
I’ve been really happy to receive some of the feedback (positive and constructive criticism) on this series. There is a lot of the .NET Framework to cover, and I’m open to suggestions as to what you would like to know. Please post a comment on the blog or email me at Steve at UsePowerShell.Com.