Idera nSoftware Compellent

Chapter 12. Command Discovery and Scriptblocks

In previous chapters you learned step by step how to use various PowerShell command types and mechanisms. After 11 chapters, we have reached the end of the list. You'll now put together everything you've seen. All of it can actually be reduced to just two PowerShell basic principles: command discovery and scriptblocks.

The purpose of this chapter is to tie up the many loose ends of previous chapters and to weave them into a larger whole: the basics are complete and the remaining chapters will put the knowledge gained to the test of daily tasks.

Topics Covered:

Command Discovery

From the user's point of view, it's rather easy to assign tasks to PowerShell: you type the command in the console, press (Enter), and the command is immediately carried out. But much more complex things are happening behind the scenes. PowerShell has to first find out which command you actually meant. This operation is called command discovery and is usually performed automatically. Use the Get-Command cmdlet if you want to run command discovery yourself to understand what is actually taking place.

If you'd like to know what the Dir command actually is, pass it to Get-Command:

Get-Command Dir
CommandType Name Definition
----------- ---- ----------
Alias Dir Get-ChildItem

Get-Command correctly identifies your command in the CommandType column as Alias and reports in the Definition column which actual command PowerShell invoked. Basically, this is the way it functions for all commands—even if you invoke the external programs:

Get-Command ping
CommandType Name Definition
----------- ---- ----------
Application PING.EXE C:\Windows\system32\PING.EXE

This time the CommandType column reports the Application type, and in the definition the exact path is output to the external program.

In fact, Get-Command returns a CommandInfo object that contains much more information. From Chapter 5 you know how to make all object properties visible: send the object to a formatting cmdlet like Format-List and type an asterisk after it:

# Get-Command returns a CommandInfo object that exists
# in various subtypes:
$info = Get-Command ping
$info.GetType().FullName
System.Management.Automation.ApplicationInfo

# Send the object to Format-List and append an asterisk
# to see all properties:
$info | Format-List *
FileVersionInfo : File: C:\Windows\system32\PING.EXE
InternalName: ping.exe
OriginalFilename: ping.exe.mui
FileVersion: 6.0.6000.16386 (vista_rtm.061101-2205)
FileDescription: TCP/IP Ping Command
Product: Microsoft® Windows® operating system
ProductVersion: 6.0.6000.16386
Debug: False
Patched: False
PreRelease: False
PrivateBuild: False
SpecialBuild: False
Language: English (United States)

Path : C:\Windows\system32\PING.EXE
Extension : .EXE
Definition : C:\Windows\system32\PING.EXE
Name : PING.EXE
CommandType : Application

Command discovery gets really interesting when there are several commands that have the same name. The question is which of these commands PowerShell is executing:

Get-Command more
CommandType Name Definition
----------- ---- ----------
Function more param([string[]]$paths); If(($paths -ne...
Application more.com C:\Windows\system32\more.com

As you see, there are two commands called more. One is a PowerShell function (CommandType: Function) and the other an external program called more.com (CommandType: Application). If you use more as a command, PowerShell will automatically choose the one it uses based on its own internal priority list from among several commands having the same name. Because PowerShell functions have a higher priority than external applications, the internal PowerShell functions will always be the first in line:

Dir | more

If you'd prefer using the external program more.com, you must specify it explicitly:

Dir | more.com

That works because if you specify the command name more.com there's no danger of confusing the names:

Get-Command more.com
CommandType Name Definition
----------- ---- ----------
Application more.com C:\Windows\system32\more.com

However, there's no guarantee because there could be an alias called more.com on your system. That's why you'll soon learn better methods to execute exactly the command you want to execute with utter precision. But first you'll have to know how PowerShell actually invokes commands.

The Call Operator "&"

The little call operator "&" gives you great discretionary power over the execution of PowerShell commands. If you place this operator in front of a string (or a string variable), the string will be interpreted as a command and executed just as if you had input it directly into the console.

# Store a command in a variable:
$command = "Dir"

# If you output the contents of the variable,
# only string will be output:
$command
Dir

# If you type the call operator "&" in front of it,
# the command will be executed:
& $command
Directory: Microsoft.PowerShell.Core\FileSystem::C:\Users\Tobias Weltner
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 10.01.2007 16:09 Application Data
d---- 07.26.2007 11:03 Backup
(...)

The call operator also comes to the rescue when the command name contains special characters like white space and can't be input directly into the console. Put the name in quotation marks to turn it into string and use the call operator to run it:

& "A command with whitespace"

The Call Operator Only Accepts Single Commands

However, the call operator won't run an entire instruction line but always precisely one command. If you had assigned not just a single command, like Dir in the variable but several commands, or if you had also specified arguments for the command, an error would have been generated:

$command = "Dir C:\"
& $command
The term "Dir c:\" is not recognized as a cmdlet, function,
operable program, or script file. Verify the term and try again.
At line:1 Char:2
+ & <<<< $command

Why is that? The reason: in the murky depths of PowerShell, the call operator calls Get-Command to find out what it is supposed to actually be running. Get-Command always gets only a single command, never entire instruction lines:

# A single command is recognized correctly:
Get-Command "Dir"
CommandType Name Definition
----------- ---- ----------
Alias Dir Get-ChildItem

# A command with arguments or several commands is not recognized:
Get-Command "Dir C:\"
Get-Command : The term "Dir c:\" is not recognized as a
cmdlet, function, operable program, or script file. Verify
the term and try again.
At line:1 Char:12
+ Get-Command <<<< "Dir C:\"

The Call Operator Executes CommandInfo Objects

The call operator initially passes what you specify as a command to Get-Command, which returns a CommandInfo object that the call operator then executes. In fact, the call operator can also accept a CommandInfo object directly and save itself the roundabout Get-Command:

# Get the CommandInfo object of a command:
$command = Get-Command ping
$command
CommandType Name Definition
----------- ---- ----------
Application PING.EXE C:\Windows\system32\PING.EXE

# Use the call operator "&" to call the CommandInfo object:
& $command -n 1 -w 100 10.10.10.10
Pinging 10.10.10.10 with 32 bytes of data:
Reply from 10.10.10.10: Bytes=32 Time<1ms TTL=128
Ping statistics for 10.10.10.10:
Packets: Sent = 1, Received = 1, Lost = 0 (0% Loss),
Ca. time in millisec:
Minimum = 2ms, Maximum = 2ms, Average = 2ms

The & $command calls the command in $command. You may specify any arguments after it, but you can't wrap the arguments directly in $command because the call operator always executes only one single command without arguments.

# not allowed:
& "Dir C:\"

Did you just have a little déjà-vu experience? Aliases behave exactly the same way and can provide only single commands under another name, but not commands with arguments. Aliases are nothing more than named call operators. If you input the alias, PowerShell will internally invoke the call operator for the command that you assigned to the alias.

Identically Named Commands: Which is Running?

PowerShell supports a great many commands of the most diverse types, cmdlets, functions, aliases, or external commands. Within this range of command types, command names should not be ambiguous as there can never be more than one function or alias having the same name. However, among the various command types, names can be identical; usually, that's even highly desirable.

If there are several commands having identical names, PowerShell will examine its own internal priority list (Table 12.1) and decide which command will be executed. For example, you can use aliases to set up "command redirection" because aliases have a higher priority than external programs.

# Run an external command:
ping -n 1 10.10.10.10
Pinging 10.10.10.10 with 32 bytes of data:
Reply from 10.10.10.10: Bytes=32 Time<1ms TTL=128
Ping statistics for 10.10.10.10:
Packets: Sent = 1, Received = 1, Lost = 0 (0% Loss),
Ca. time in millisec:
Minimum = 2ms, Maximum = 2ms, Average = 2ms

# Create a function having the same name:
function Ping { "Ping is not allowed." }

# Function has priority over external program and turns off command:
ping -n 1 10.10.10.10
Ping is not allowed.

PowerShell functions have a higher priority than external commands, and that's why PowerShell has executed its new Ping function instead of the old Ping command. You have seemingly brought the Ping command to a halt. Instead of a function, you could also have created an alias, which has an even higher priority so that your newly created function would then no longer be invoked.

Set-Alias ping echo
ping -n 1 10.10.10.10
-n
1
10.10.10.10

Now, Ping calls the Echo command, which is an alias for Write-Output and simply outputs the parameters that you may have specified after Ping in the console.

If you'd like to see all the commands of a particular type, specify the -commandType parameter. The next statement lists all commands of the Filter type:

Get-Command -commandType Filter
CommandType Description Priority
Alias An alias for another command added by using Set-Alias 1
Function A PowerShell function defined by using function 2
Filter A PowerShell filter defined by using filter (a function with a process block) 2
Cmdlet A PowerShell cmdlet from a registered snap-in 3
Application An external Win32 application 4
ExternalScript An external script file with the file extension ".ps1" 5
Script A scriptblock -

Table 12.1: Various PowerShell command types

If you enter the Ping command in this example, Get-Command will first find out which commands are possible:

Get-Command Ping
CommandType Name Definition
----------- ---- ----------
Function Ping "Ping is not allowed."
Alias ping echo
Application PING.EXE C:\Windows\system32\PING.EXE

Based on the internal PowerShell priority list, the command of the alias type is selected from these three commands and executed. If you'd rather run another Ping command, you will have to circumvent automatic selection.

You've seen that the call operator accepts commands in two ways: either as a string (in which case it tasks Get-Command with automatically choosing an appropriate command) or as a CommandInfo object (in which case it is clear which command is meant). So, if you'd like to run a particular command yourself, get its CommandInfo object. That will retrieve Get-Command. If you'd like to run the original Ping command, the third array element is suitable:

# Get all commands named "Ping":
$commands = Get-Command Ping

# Call the third command (array index 2):
& $commands[2] -n 1 10.10.10.10
Pinging 10.10.10.10 with 32 bytes of data:
Reply from 10.10.10.10: Bytes=32 Time<1ms TTL=128
Ping statistics for 10.10.10.10:
Packets: Sent = 1, Received = 1, Lost = 0 (0% Loss),
Ca. time in millisec:
Minimum = 2ms, Maximum = 2ms, Average = 2ms

However, calling by means of an array index is usually not a good idea because you don't know whether several identically named commands exist, and if they do, in which order the commands were defined. It's better to specify right from the beginning the type you want, which Get-Command always reports in the CommandType column. Name conflicts are out of the question because there can be only one command having a particular name for each type.

The original Ping command is of the Application type. So, if you'd like to invoke this command, instruct Get-Command to retrieve for you the Ping command of the Application type. It shouldn't be important to you at all whether there are any other identically named commands of other types. PowerShell will start the original Ping command in any case:

# Return and then start the "Ping" command of the "Application" type:
$command = Get-Command -commandType Application Ping
& $command -n 1 10.10.10.10
Pinging 10.10.10.10 with 32 bytes of data:
Reply from 10.10.10.10: Bytes=32 Time<1ms TTL=128
Ping statistics for 10.10.10.10:
Packets: Sent = 1, Received = 1, Lost = 0 (0% Loss),
Ca. time in millisec:
Minimum = 2ms, Maximum = 2ms, Average = 2ms

# Call in only one line:
& (Get-Command -commandType Application Ping) -n 1 10.10.10.10
Pinging 10.10.10.10 with 32 bytes of data:
Reply from 10.10.10.10: Bytes=32 Time<1ms TTL=128
Ping statistics for 10.10.10.10:
Packets: Sent = 1, Received = 1, Lost = 0 (0% Loss),
Ca. time in millisec:
Minimum = 2ms, Maximum = 2ms, Average = 2ms

You now know how PowerShell finds out which command is supposed to be run and how you can use the call operator to invoke your own commands. However, the call operator does have one nasty limitation: it can never execute more than one single command, nor can it execute any instruction lines, nor commands with arguments. If the call operator is calling the shots behind the scenes, how can it execute the entire instruction lines that you type in the console? To clear that up, you'll need another very important PowerShell basic element - scriptblocks.

Using Scriptblocks

The scriptblock is a special form of command. The scriptblock can contain as much PowerShell code as you like. It is defined by braces. The smallest possible scriptblock is just the minimal amount of PowerShell code in braces. You can use the previously described call operator to execute a scriptblock:

& { "Today's date: " + (get-date) }
Today's date: 10/07/2007 12:32:39

Executing Entire Instruction Lines

Perhaps you're beginning to realize how scriptblocks enable the call operator to execute not just single commands, but entire instruction lines. The call operator normally runs just single commands, but among the permitted commands, according to Table 12.1, are commands of the script type, the scriptblocks. This is the solution to running whole lines of instructions since scriptblocks can consist of any number of commands. In the next example, the call operator runs several statements in the line:

# The call operator "&" can run several commands
# if these are enclosed in braces:
& {Get-Process | Where-Object { $_.Name -like 'a*'}}

This is the way command entry works in the PowerShell console: if you type an instruction line in the console, PowerShell will turn the line into a scriptblock and execute it just the way it did in the previous example. Scriptblocks are the universal basic element of PowerShell. Many PowerShell commands and structures, upon closer examination, are nothing more than scriptblocks. Let's take a look at all the places where scriptblocks are hidden in PowerShell.

Invoke-Expression

You've seen above that the call operator can process whole instruction lines with the help of a scriptblock. Actually, this function corresponds to the Invoke-Expression cmdlet, which is nothing more than a scriptblock that is passed to the call operator:

Invoke-Expression 'Get-Process | Where-Object { $_.Name -like "a*"}'
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
36 2 712 48 21 2616 agrsmsvc
311 9 10988 3324 112 464 AppSvc32
105 3 1044 736 37 1228 Ati2evxx
130 5 2056 3916 48 1732 Ati2evxx
79 4 4612 1092 58 2,75 2064 ATSwpNav
99 3 11892 7600 45 1432 audiodg

Just remember to put code after Invoke-Expression in single quotation marks. If you use double quotation marks, PowerShell will replace all the variable names in the string with the variable contents. Because part of the $_ variable in the last example is part of the code to be executed, it would be incorrectly replaced with "null" and generate an error:

# Don't enclose the string after Invoke-Expression
# in double quotation marks:
Invoke-Expression "Get-Process |
Where-Object { $_.Name -like 'a*'}"
The term ".Name" is not recognized as a cmdlet,
function, operable program, or script file. Verify
the term and try again.
At line:1 Char:35
+ Get-Process | Where-Object { .Name <<<< -like 'a*'}

The following statement is completely identical:

& {Get-Process | Where-Object { $_.Name -like 'a*'}}

Pipeline: ForEach-Object

In Chapter 5, you used the ForEach-Object cmdlet in the pipeline, which loops over every pipeline object one by one. PowerShell code follows ForEach-Object in braces, so it is actually a scriptblock. The following scriptblock was executed for every object in the pipeline:

Get-Process | ForEach-Object { $_.name }

Loops: If and For

Do you remember Chapter 7? You worked with conditions, which also use scriptblocks, as they do in this example:

$age = 21
If ($age -lt 21)
{
"You're too young."
}
Else
{
"You may drink a wine."
}

The If statement uses two scriptblocks. The first is executed if the condition after If is met; the second, if it is not met. You saw much the same thing for the loops in Chapter 8:

For ($x=1; $x -le 10; $x++)
{
$x
}

Again, here's a scriptblock in braces that iterates until the termination condition of the loop is met.

Functions Are Named "Scriptblocks"

A new light is shed on the functions from Chapter 9, because functions and scriptblocks are basically identical. Functions are nothing more than named scriptblocks that you can call directly through a set name. Take a look:

function Test { "Hello world!" }

The identifier function sets a name for the scriptblock that follows it in braces. That's why this scriptblock will be run when you specify the assigned name:

Test
Hello world!

You can see that the function actually consists of just one conventional scriptblock when you get the scriptblock of the function:

$scriptblock = $function:Test
$scriptblock
"Hello world!"
$scriptblock.GetType().Name
ScriptBlock

You could reprogram the function by allocating another scriptblock to it:

# Allocate scriptblock in braces:
$function:Test = { "Morning!" }
Test
Morning!

# String will be automatically changed to a scriptblock type:
$function:Test = ' "Morning!" '
Test
Morning!

# Don't use braces inside a string:
$function:Test = "{ 'Morning!' }"
Test
'Morning!'

Just remember not to use braces in a string. If you do anyway the braces will not delimit the scriptblock but ensure that any special characters in the string are not evaluated as special characters. That's why the Test function in the last example outputs a string along with the quotation marks.

If you like, you could use your newly acquired skills to even create functions entirely without the Function statement:

# Directly create a new function:
New-Item function:newFunction -value {"Hello world!"} -force
CommandType Name Definition
----------- ---- ----------
Function newFunction "Hello world!"

newFunction
Hello world!

Building Scriptblocks

Because functions are nothing more than named scriptblocks, which support all the features that distinguish functions. Let's see whether that's really true.

Passing Arguments to Scriptblocks

Parameters may be specified in parentheses after the name of a function so that the user of the function can pass additional arguments to it later. The following simple function example defines a parameter called $text and outputs only what was passed to the function as an argument:

function TextOutput($text)
{
$text
}
TextOutput "Hello"
Hello

How can a scriptblock offer the same functionality? After all, a scriptblock doesn't have a function statement after which you could define a parameter. In reality, every function is only a scriptblock. Have a look here to see how a scriptblock embeds parameters:

$function:TextOutput
param($text) $text

A scriptblock uses the param statement to define a parameter. Think of Chapter 10 and scripts, which do precisely the same thing. So scripts are also nothing more than scriptblocks, although they tend to be very extensive ones. You could easily define your own anonymous scriptblock (i.e., one you don't have to name) that processes arguments. The following scriptblock accepts two parameters and multiplies them:

{ param($value1, $value2) $value1 * $value2 }

To invoke the scriptblock, use the call operator again:

& { param($value1, $value2) $value1 * $value2 } 10 5
50
& { param($value1, $value2) $value1 * $value2 } "Hello" 10
HelloHelloHelloHelloHelloHelloHelloHelloHelloHello

Begin, Process, End Pipeline Blocks

A further characteristic of functions is their ability to define three blocks called begin, process, and end in order to process PowerShell pipeline results in real time. Do you still remember Chapter 9? If a function is used inside a pipeline, it initially runs code in the begin block, then once again in the process block for every pipeline object, and finally in the end block. If the three blocks aren't defined, the function can't process pipeline results in real time, but blocks the pipeline until all results are available.

Scriptblocks can also define these three blocks and be used in the pipeline. In fact, the ForEach-Object cmdlet is basically nothing more than a scriptblock that has in itself a process block:

# The ForEach-Object cmdlet...
Get-Process | ForEach-Object { $_.Name }

# ...is a scriptblock that has a process block in itself:
Get-Process | & { process { $_.Name } }

The Where-Object cmdlet works in a similar way:

# The Where-Object cmdlet...
Get-Process | Where-Object { $_.Name -like "a*" }

# ...is a scriptblock with a process and a condition:
Get-Process | & { process { If ($_.Name -like "a*") { $_ } } }

Validity of Variables

All the variables that are created inside a function are private and valid (only inside the function) unless you expressly specify another validity in the variable name. In the following example, the Test function defines two variables. The variable $value1 is created without any particular validity identifier and consequently is private. This variable is valid only inside the function. On the other hand, the variable $value2, is created with the global: validity identifier and consequently is also valid outside the function:

function Test
{
$value1 = 10
$global:value2 = 20
}
Test
$value1
$value2
20

Let's try the same thing with a scriptblock:

& { $value1 = 10; $global:value2 = 20 }
$value1
$value2
20

As it turns out, scriptblocks determine the validity of variables. All the variables that you define without any particular validity identifier inside a scriptblock are valid only inside the scriptblock. This behavior is not confined to functions but applies in all scriptblocks invoked by using the "&" call operator. In contrast, PowerShell runs scriptblocks executed inside loops or conditions in the current context. That's why the $text variable is valid outside the condition as well:

If ($age -ge 18)
{
$text = "You are of age"
}
Else
{
$text = "You are under age"
}
$text
You are under age

ExecutionContext

PowerShell provides a very special object, the automatic variable $ExecutionContext, which you will rarely need but which will help you better understand PowerShell internal operations. This object offers two main properties:InvokeCommand and SessionState.

InvokeCommand

By now, you should be familiar with three important special characters that PowerShell uses in the console. Double quotation marks define not only a string but also ensure at the same time that variable names in the string are replaced with variable contents. The ampersand, "&", is the call operator and runs commands. Finally, braces create new scriptblocks.

In fact, behind these special characters are internal methods that perform the actual tasks. You can control these methods directly. The automatic variable $ExecutionContext makes these methods accessible through its InvokeCommand property. It is important to know how PowerShell works internally, even though you usually won't need these methods because the special characters are easier to get to.

Special Character Definition Internal Method
" Resolves variables in a string ExpandString()
& Executes commands InvokeScript()
{} Creates a new scriptblock NewScriptBlock()

Table 12.2: Important special characters and the internal methods underlying them

Resolving Variables

Whenever you assign a string in double quotation marks to a variable, PowerShell resolves the variable and replaces it with matching variable contents:

$name = 'Tobias Weltner'

# String variables in double quotation marks will be resolved:
$text = "Your name is $name"
$text
Your name is Tobias Weltner

The method ExpandString() carries out this resolution internally. This means that variables can also be resolved in the following way:

$name = 'Tobias Weltner'

# String variables in single quotation marks will not be resolved:
$text = 'Your name is $name'
$text
Your name is $name

# The method ExpandString() actually resolves the variable:
$executioncontext.InvokeCommand.ExpandString($text)
Your name is Tobias Weltner

Creating Scriptblocks

If you place PowerShell code in braces, PowerShell will make a scriptblock out of the code. You've seen how you can either use the call operator to immediately execute a scriptblock or to assign it to a function. The method NewScriptBlock() is used to generate new scriptblocks:

# Create a new scriptblock
$sb = { 4*5 }
$sb.GetType().Name
ScriptBlock

& $sb
20

# Do the same using the low level function NewScriptBlock():
$sb = $executioncontext.InvokeCommand.NewScriptBlock('4*5')
$sb.GetType().Name
ScriptBlock

& $sb
20

Executing Instruction Lines

Input instruction lines are executed internally by the InvokeScript() method. The following three commands accomplish the same thing:

Invoke-Expression '4*5'
20

& { 4*5 }
20

$executioncontext.InvokeCommand.InvokeScript('4*5')
20

SessionState

SessionState is an object that reflects the current state of your PowerShell environment. You can likewise locate this object in the $ExecutionContext automatic variable:

$executioncontext.SessionState | Format-List *
Drive : System.Management.Automation.DriveManagementIntrinsics
Provider : System.Management.Automation.CmdletProviderManagementIntrinsics
Path : System.Management.Automation.PathIntrinsics
PSVariable : System.Management.Automation.PSVariableIntrinsics

The four properties Drive, Provider, Path and PSVariable, are subobjects that you can use to query the current state of these PowerShell areas as well as to modify them.

Managing Variables

PSVariable will retrieve the value of any variable and can also be used to modify variables:

$value = "Test"

# Retrieve variable contents:
$executioncontext.SessionState.PSVariable.GetValue("value")
Test

# Modify variable contents:
$executioncontext.SessionState.PSVariable.Set("value", 100)
$value
100

Managing Drives

Drive manages drives in PowerShell. You could define the current drive in the following way:

$executioncontext.SessionState.Drive.Current
Name Provider Root CurrentLocation
---- -------- ---- ---------------
C FileSystem C:\ Users\Tobias Weltner

GetAll() lists all available drives and as such is equivalent to the Get-PSDrive cmdlet:

$executioncontext.SessionState.Drive.GetAll()
Name Provider Root CurrentLocation
---- -------- ---- ---------------
Alias Alias
Env Environment
C FileSystem C:\ Users\Tobias Weltner
D FileSystem D:\
Function Function
HKLM Registry HKEY_LOCAL_MACHINE
HKCU Registry HKEY_CURRENT_USER
Variable Variable
cert Certificate \

If you are interested only in the drives of a particular provider, such as only in genuine data file drives, use GetAllForProvider() and specify the provider you want:

$executioncontext.SessionState.Drive.GetAllForProvider("FileSystem")
Name Provider Root CurrentLocation
---- -------- ---- ---------------
C FileSystem C:\ Users\Tobias Weltner
D FileSystem

Path Specifications

Path returns several methods that cover all aspects of path names that are usually taken care of by cmdlets (Table 12.3). Moreover, the object offers some additional methods that you can use:

# Put together a path name from a directory part and a file part:
$executioncontext.SessionState.Path.Combine("C:", "test.txt")
C:\test.txt
Method Description Cmdlet
CurrentLocation Current working directory Get-Location
PopLocation() Retrieve stored directory Pop-Location
PushCurrentLocation() Store current working directory Push-Location
SetLocation() Set new directory as current working directory Set-Location
GetResolvedPSPathFromPSPath() Return absolute path name for specified relative path name Resolve-Path

Table 12.3: Path cmdlets and underlying low-level methods of the SessionState object

Summary

Whenever you assign the task of running a command to PowerShell, it relies on command discovery to look up which command is intended. If the command is unclear because several commands have the same name, PowerShell uses a priority list (Table 12.1) and automatically selects a command from it.

You can use the call operator character, "&", to run commands that you do not directly input in the console. The call operator carries out the same command discovery process as the console does for direct command inputs. Alternatively, you can use Get-Command to carry out command discovery and to pass the result directly to the call operator. This allows you to determine which identically named commands should be executed so that the choice is made by you and not by the integrated PowerShell priority list.

Put everything together in a scriptblock if you would like to invoke more than a single command or to pass arguments to a command. Scriptblocks are nothing more than any piece of PowerShell code enclosed in braces. You can run scriptblocks by using the call operator. It is interesting to note that scriptblocks are the foundation of PowerShell. They provide the basis for many cmdlets and are the "soul" of every function and script.

If you'd like to take a look behind the scenes to see how PowerShell actually does run commands or create scriptblocks, you will need the object in the $ExecutionContext automatic variable. It offers you access to many low-level functions, which actually perform the tasks involved when you create scriptblocks or use the call operator (Table 12.2).


Posted Mar 30 2009, 08:03 AM by ps1

Comments

Chapter 12. Command Discovery and Scriptblocks - Master-PowerShell | With Dr. Tobias Weltner - PowerShell.com wrote Chapter 12. Command Discovery and Scriptblocks - Master-PowerShell | With Dr. Tobias Weltner - PowerShell.com
on 04-01-2009 2:33 PM

Pingback from  Chapter 12. Command Discovery and Scriptblocks - Master-PowerShell | With Dr. Tobias Weltner - PowerShell.com

Master-PowerShell | With Dr. Tobias Weltner wrote Chapter 15. The File System
on 04-01-2009 2:34 PM

The file system has special importance within the PowerShell console. One obvious reason is that administrators perform many tasks that involve the file system. Another is that the file system is the prototype of a hierarchically structured information

Chapter 5. The PowerShell Pipeline - Master-PowerShell | With Dr. Tobias Weltner - PowerShell.com wrote Chapter 5. The PowerShell Pipeline - Master-PowerShell | With Dr. Tobias Weltner - PowerShell.com
on 04-30-2009 12:54 AM

Pingback from  Chapter 5. The PowerShell Pipeline - Master-PowerShell | With Dr. Tobias Weltner - PowerShell.com

Master-PowerShell | With Dr. Tobias Weltner wrote Chapter 11. Finding and Avoiding Errors
on 04-30-2009 1:04 AM

The more complex your commands, pipelines, functions, or scripts become, the more often that errors can creep in. PowerShell has its own remedies for finding and correcting errors at various levels of complexity. In simple cases, use "what-if"

Copyright 2010 PowerShell.com. All rights reserved.