.NET Framework
Integration
Most shells operate in a
text-based environment, which means you typically have to manipulate the
output for automation purposes. For example, if you need to pipe data
from one command to the next, the output from the first command usually
must be reformatted to meet the second command’s requirements. Although
this method has worked for years, dealing with text-based data can be
difficult and frustrating.
Often, a lot of work is
necessary to transform text data into a usable format. Microsoft has set
out to change the standard with PowerShell, however. Instead of
transporting data as plain text, PowerShell retrieves data in the form
of .NET Framework objects, which makes it possible for commands (or
cmdlets) to access object properties and methods directly. This change
has simplified shell use. Instead of modifying text data, you can just
refer to the required data by name. Similarly, instead of writing code
to transform data into a usable format, you can simply refer to objects
and manipulate them as needed.
Reflection
Reflection is a feature in the
.NET Framework that enables developers to examine objects and retrieve
their supported methods, properties, fields, and so on. Because
PowerShell is built on the .NET Framework, it provides this feature,
too, with the Get-Member cmdlet. This cmdlet analyzes an object or
collection of objects you pass to it via the pipeline. For example, the
following command analyzes the objects returned from the Get-Process
cmdlet and displays their associated properties and methods:
PS C:\> get-process | get-member
Developers often refer to
this process as “interrogating” an object. This method of accessing and
retrieving information about an object can be very useful in
understanding its methods and properties without referring to MSDN
documentation or searching the Internet.
Extended Type System
(ETS)
You might think that
scripting in PowerShell is typeless because you rarely need to specify
the type for a variable. PowerShell is actually type driven, however,
because it interfaces with different types of objects from the
less-than-perfect .NET to Windows Management Instrumentation (WMI),
Component Object Model (COM), ActiveX Data Objects (ADO), Active
Directory Service Interfaces (ADSI), Extensible Markup Language (XML),
and even custom objects. However, you don’t need to be concerned about
object types because PowerShell adapts to different object types and
displays its interpretation of an object for you.
In a sense, PowerShell tries
to provide a common abstraction layer that makes all object interaction
consistent, despite the type. This abstraction layer is called the
PSObject, a common object used for all object access in PowerShell. It
can encapsulate any base object (.NET, custom, and so on), any instance
members, and implicit or explicit access to adapted and type-based
extended members, depending on the type of base object. Furthermore,
it can state its type and add members dynamically. To do this,
PowerShell uses the Extended Type System (ETS), which provides an
interface that allows PowerShell cmdlet and script developers to
manipulate and change objects as needed.
Note
When you use the Get-Member
cmdlet, the information returned is from PSObject. Sometimes PSObject
blocks members, methods, and properties from the original object. If you
want to view the blocked information, use the BaseObject property with the PSBase standard name. For
example, you could use the $Procs.PSBase | get-member command to view blocked information for
the $Procs object collection.
Needless to say, this topic is
fairly advanced, as PSBase is hidden from view. The only time you
should need to use it is when the PSObject doesn’t interpret an object
correctly or you’re digging around for hidden jewels in PowerShell.
Static Classes and
Methods
Certain .NET Framework classes
cannot be used to create new objects. For example, if you try to create a
System.Math typed object using the
New-Object cmdlet, the following error occurs:
PS C:\> New-Object System.Math
New-Object : Constructor not found. Cannot find an appropriate constructor for type
System.Math.
At line:1 char:11
+ New-Object <<<< System.Math
+ CategoryInfo : ObjectNotFound: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : CannotFindAppropriateCtor,Microsoft.PowerShell.
Commands.NewObjectCommand
PS C:\>
The reason this occurs is
because static members are shared across all instances of a class and
don’t require a typed object to be created before being used. Instead,
static members are accessed simply by referring to the class name as if
it were the name of the object followed by the static operator (::), as
follows:
PS > [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
In the previous example, the DirectoryServices.ActiveDirectory.Forest class is used to retrieve information about the
current forest. To complete this task, the class name is enclosed within
the two square brackets ([...]). Then, the GetCurrentForest method is invoked by using the static operator
(::).
Note
To retrieve a list of static
members for a class, use the Get-Member cmdlet: Get-Member
-inputObject ([System.String]) -Static.
Type Accelerators
A type accelerator is simply an alias for
specifying a .NET type. Without a type accelerator, defining a variable
type requires entering a fully qualified class name, as shown here:
PS C:\> $User = [System.DirectoryServices.DirectoryEntry]"LDAP:
//CN=Fujio Saitoh,OU=Accounts,OU=Managed Objects,DC=companyabc,DC=com"
PS C:\> $User
distinguishedname:{CN=Fujio Saitoh,OU=Accounts,OU=Managed
Objects,DC=companyabc,DC=com}
path : LDAP:
//CN=Fujio Saitoh,OU=Accounts,OU=Managed Objects,DC=companyabc,DC=com
PS C:\>
Instead of typing the entire
class name, you just use the [ADSI] type accelerator to define the
variable type, as in the following example:
PS C:\> $User = [ADSI]"LDAP://CN=Fujio Saitoh,OU=Accounts, OU=Managed
Objects,DC=companyabc,DC=com"
PS C:\> $User
distinguishedname:{CN=Fujio Saitoh,OU=Accounts,OU=Managed
Objects,DC=companyabc,DC=com}
path : LDAP:
//CN=Fujio Saitoh,OU=Accounts,OU=Managed Objects,DC=companyabc,DC=com
PS C:\>
Type accelerators have
been included in PowerShell mainly to cut down on the amount of typing
to define an object type. However, for some reason, type accelerators
aren’t covered in the PowerShell documentation, even though the [WMI],
[ADSI], and other common type accelerators are referenced on many web
blogs.
Regardless of the lack of
documentation, type accelerators are a fairly useful feature of
PowerShell. Table 2 lists some of the more commonly
used type accelerators.
Table 2. Important Type Accelerators in
PowerShell
Name | Type |
---|
Int | System.Int32 |
Long | System.Int64 |
String | System.String |
Char | System.Char |
Byte | System.Byte |
Double | System.Double |
Decimal | System.Decimal |
Float | System.Float |
Single | System.Single |
Regex | System.Text.RegularExpressions.Regex |
Array | System.Array |
Xml | System.Xml.XmlDocument |
Scriptblock | System.Management.Automation.ScriptBlock |
Switch | System.Management.Automation.SwitchParameter |
Hashtable | System.Collections.Hashtable |
Type | System.Type |
Ref | System.Management.Automation.PSReference |
Psobject | System.Management.Automation.PSObject |
pscustomobject | System.Management.Automation.PSCustomObject |
Psmoduleinfo | System.Management.Automation.PSModuleInfo |
Powershell | System.Management.Automation.PowerShell |
runspacefactory | System.Management.Automation.Runspaces.RunspaceFactory |
Runspace | System.Management.Automation.Runspaces.Runspace |
Ipaddress | System.Net.IPAddress |
Wmi | System.Management.ManagementObject |
Wmisearcher | System.Management.ManagementObjectSearcher |
Wmiclass | System.Management.ManagementClass |
Adsi | System.DirectoryServices.DirectoryEntry |
Adsisearcher | System.DirectoryServices.DirectorySearcher |