380
CHAPTER 10
M
ODULE
MANIFESTS
AND
METADATA
Okay, you know how to get and set state in the module, so let’s try altering the 
code. First look at the body of the 
Get-Count
function:
PS (10) > & $m Get-Item function:Get-Count
CommandType     Name                     Definition 
-----------     ----                     ----------
Function        Get-Count                ...
Now redefine the function in the module. Instead of simply adding the increment, 
add the increment times 2:
PS (11) > & $m { 
>>     function script:Get-Count 
>>     { 
>>         return $script:count += $increment * 2 
>>     } 
>> } 
>>
Although you’ve redefined the function in the module, you have to reimport the 
module in order to get the new definition into your function table:
PS (12) > Import-Module .\counter.psm1
Now you can call the function again to make sure you’re getting what you expected:
PS (13) > Get-Count 
36 
PS (14) > Get-Count 
38
Yes, 
Get-Count
is now incrementing by 2 instead of 1.
All of these tweaks on the module only affect the module in memory. The module 
file on disk hasn’t changed:
PS (15) > Get-Content counter.psm1 | select -First 8 
$script:count = 0 
$script:increment = 1
function Get-Count 
{
return $script:count += $increment 
}
If you use  the 
-Force
parameter on 
Import-Module
, you’ll force  the  system  to 
reload the file from disk, reinitializing everything to the way it was:
PS (16) > Import-Module .\counter.psm1 -Force
Verify this by running 
Get-Count
:
PS (17) > Get-Count 
PS (18) > Get-Count 
2
Pdf rearrange pages - re-order PDF pages in C#.net, ASP.NET, MVC, Ajax, WinForms, WPF
Support Customizing Page Order of PDF Document in C# Project
how to move pages in pdf acrobat; pdf reorder pages
Pdf rearrange pages - VB.NET PDF Page Move Library: re-order PDF pages in vb.net, ASP.NET, MVC, Ajax, WinForms, WPF
Sort PDF Document Pages Using VB.NET Demo Code
reorder pages in a pdf; move pages in pdf acrobat
A
DVANCED
MODULE
OPERATIONS
381
PS (19) > Get-Count 
3
Again this is one of the characteristics of dynamic languages: the ability of programs 
to modify themselves in a profound way at runtime and then restore the original 
state. In the next section we’ll look at how to use properties on the 
PSModuleInfo
to 
access the members of a module without importing them.
Accessing modules exports using the PSModuleInfo object
The  exported  members  of  a  module  are  discoverable  through  properties  on  the 
PSModuleInfo
object that represents the module. This gives you a way to look at the 
exported members without having to import them into your environment. For exam-
ple, the list of exported functions is available in the 
ExportedFunctions
member. 
These properties are hash tables, indexed by the name of the exported member. Let’s 
look at some examples of what you can do using these properties.
As always, you need a module to work with. In this case, you’ll use a dynamic 
module, which we’ll cover in more detail in chapter 11. Dynamic modules don’t 
require a file on disk, which makes them easy to use for experiments. You’ll create a 
dynamic module and save the 
PSModuleInfo
object in a variable called 
$m
:
PS (1) > $m = New-Module { 
>> function foo {"In foo x is $x"} 
>> $x=2 
>> Export-ModuleMember -func foo -var x } 
>> 
Now you can use the export lists on the 
PSModuleInfo
to see what was exported:
PS (2) > $m | Format-List exported*
ExportedCommands    : {foo}
ExportedFunctions   : {[foo, foo]}
ExportedCmdlets     : {}
ExportedVariables   : {[x, System.Management.Automation.PSVariable]} 
ExportedAliases     : {}
ExportedFormatFiles : {}
ExportedTypeFiles   : {}
In the output, you see that one function and one variable were exported. You also see 
the function turn up in the 
ExportedCommands
member. Modules can export more 
than one type of command—functions, aliases, or cmdlets—and this property exists 
to provide a convenient way to see all commands regardless of type.
NOTE
By  implementing  the  exported  member  properties  as  hash 
tables, you can access and manipulate the state of the module in a fairly 
convenient  way.  The  downside  is  that  the  default  output  for  the 
exported members is a bit strange, especially for functions where you 
see things like 
[foo, foo]
. These tables map the name of a command
C# TIFF: How to Reorder, Rearrange & Sort TIFF Pages Using C# Code
C# TIFF - Sort TIFF File Pages Order in C#.NET. Reorder, Rearrange and Sort TIFF Document Pages in C#.NET Application. C# TIFF Page Sorting Overview.
how to reorder pages in a pdf document; how to move pages within a pdf
VB.NET TIFF: Modify TIFF File by Adding, Deleting & Sort TIFF
you want to change or rearrange current TIFF &ltsummary> ''' Sort TIFF document pages in designed powerful & profession imaging controls, PDF document, image
how to move pages in pdf; pdf rearrange pages
382
CHAPTER 10
M
ODULE
MANIFESTS
AND
METADATA
to the 
CommandInfo
object for that command. When the contents of 
the table are displayed, both the key and the value are displayed as 
strings, and because the presentation of a 
CommandInfo
object as a 
string is the name of the object, you see the name twice.
Let’s use the 
ExportedFunctions
property to see how the function 
foo
is easier to write:
PS (3) > $m.ExportedFunctions.foo
CommandType     Name                       Definition 
-----------     ----                       ----------
Function        foo                        "In foo x is $x"
The value returned from the expression is a 
CommandInfo
object. This means that 
you can use the call operator, 
&,
to invoke this function:
PS (4) > & $m.ExportedFunctions.foo 
In foo x is 2 
You can also use the 
PSModuleInfo
object to change the value of the exported vari-
able 
$x
:
PS (5) > $m.ExportedVariables.x.value = 3
Call the function again to validate this change:
PS (6) > & $m.ExportedFunctions.foo 
In foo x is 3 
The return value from the call is the updated value as expected. Next, we’ll look at 
some of the methods on 
PSModuleInfo
objects.
10.7.2
Using the PSModuleInfo methods
The call operator isn’t the only way to use the module information object. The object 
itself has a number of methods that can be useful. Take a look at some of these methods:
PS (20) > [psmoduleinfo].GetMethods() | 
>>     Select-String -notmatch '(get_|set_)' 
>>
System.Management.Automation.ScriptBlock NewBoundScriptBlock(
System.Management.Automation.ScriptBlock)
System.Object Invoke(System.Management.Automation.ScriptBlock,
System.Object[]) 
System.Management.Automation.PSObject AsCustomObject()
We’ll cover the first two listed, 
Invoke()
and 
NewBoundScriptBlock()
, and save 
AsCustomObject()
for chapter 11.
The Invoke() method 
This method is essentially a .
NET
programmer way of doing what you did earlier 
with the call operator. Assuming you still have the 
counter
module loaded, let’s use
VB.NET PDF File & Page Process Library SDK for vb.net, ASP.NET
page directly. Moreover, when you get a PDF document which is out of order, you need to rearrange the PDF document pages. In these
how to reorder pdf pages; rearrange pages in pdf
Online Merge PDF files. Best free online merge PDF tool.
the button below and download your PDF. The perfect conversion tool. By dragging your pages in the editor area you can rearrange them or delete single pages.
move pages in pdf reader; how to move pdf pages around
A
DVANCED
MODULE
OPERATIONS
383
this method to reset the count and change the increment to 5. First get the module 
information object:
PS (21) > $m = Get-Module counter
Now invoke a script block in the module context using this method:
PS (22) > $m.Invoke({$script:count = 0; $script:increment = 5})
The corresponding invocation using the call operator would be
& $m {$script:count = 0; $script:increment = 5}
This is scripter-friendly, but either way, let’s try to verify the result:
PS (23) > Get-Count 
PS (24) > Get-Count 
10 
PS (25) > Get-Count 
15 
PS (26) >
And the count was reset and 
Get-Count
now increments by 5 instead of 1. Next let’s 
look at a way to attach modules to a script block.
The NewBoundScriptBlock() method
In this topic, we’re jumping ahead a bit as we won’t cover script blocks in depth until 
chapter 11. Next we’ll explore module-bound script blocks.
A module-bound script block is a piece of code—a script block—that has the 
module context to use attached to it. Normally an unbound script block is executed 
in the caller’s context, but once a script block is bound to a module, it always executes 
in the module context. In fact, that’s how exported functions work—they’re implic-
itly bound to the module that defined them. 
Let’s use this mechanism to define a script block that will execute in the context of 
the 
counter
module. First you need to get the module (again). You could use 
Get-
Module
as before, but now that you know that exported functions are bound to a 
module, you can just use the 
Module
property on an exported command to get the 
module information object. Do so with 
Get-Count
:
PS (26) > $gcc = Get-Command Get-Count
Now you can get the module for this command:
PS (27) > $gcc.module
ModuleType Name                      ExportedCommands 
---------- ----                      ----------------
Script     counter                   {setIncrement, Get-Count...
Next you need to define the script block you’re going to bind. Do this and place the 
script block into a variable:
PS (28) > $sb = {param($incr) $script:increment = $incr}
C# PowerPoint - How to Process PowerPoint
pages simply with a few lines of C# code. C# Codes to Sort Slides Order. If you want to use a very easy PPT slide dealing solution to sort and rearrange
pdf rearrange pages online; rearrange pdf pages
VB.NET Word: How to Process MS Word in VB.NET Library in .NET
well programmed Word pages sorter to rearrange Word pages in extracting single or multiple Word pages at one & profession imaging controls, PDF document, image
change page order pdf; how to move pages around in pdf
384
CHAPTER 10
M
ODULE
MANIFESTS
AND
METADATA
This  script block  takes a single  parameter,  which  it uses  to  set the module-level 
$increment
variable. Now you’ll bind it to the target module. Note that this doesn’t 
bind the module to the original script block; instead it creates a new script block with 
the module attached.
PS (29) > $setIncrement = $gcc.Module.NewBoundScriptblock( $sb )
Now test using the script block to set the increment. Invoke the script block with the 
call operator passing in an increment of 10:
PS (30) > & $setIncrement 10
And verify that the increment has been changed.
PS (31) > Get-Count 
110 
PS (32) > Get-Count 
120
Okay, good. But if you want to use this mechanism frequently, it would be useful to 
have  a  named  function.  You  can  do  this  by  assigning  the  scriptblock  to 
Set-
Increment
in the function: drive:
PS (33) > ${function:Set-CountIncrement} = $setIncrement
Let’s test the function:
PS (34) > Set-CountIncrement 100 
PS (35) > Get-Count 
220 
PS (36) > Get-Count 
320
And now the increment is 100 per the argument to the 
Set-CountIncrement
. Now 
use 
Get-Command
to look at the function you’ve defined:
PS (37) > Get-Command Set-CountIncrement | Format-Table name, module
Name                             Module 
----                             ------
Set-CountIncrement               counter
Similar to 
Get-Count
, it’s listed as being associated with the 
counter
module. Now 
that you’ve introduced the idea of a function being dynamically attached to a module, 
you should learn about the context where a function gets evaluated—which we’ll 
cover in the next section.
10.7.3
The defining module versus the calling module
In this section we’ll go into greater detail about how the execution context for a mod-
ule is established. We covered module scoping in section 9.4.4. By providing you 
with a deeper understanding of the details of how this works, we’re setting the stage 
for some of the more advanced topics we’ll cover in chapter 11.
VB.NET PowerPoint: Sort and Reorder PowerPoint Slides by Using VB.
page will teach you to rearrange and readjust amount of robust PPT slides/pages editing methods and powerful & profession imaging controls, PDF document, image
rearrange pdf pages in reader; reverse page order pdf online
Process Images in Web Image Viewer | Online Tutorials
used document types are supported, including PDF, multi-page easy to process image and file pages with the deleting a thumbnail, and you can rearrange the file
reordering pages in pdf document; reorder pages in pdf file
A
DVANCED
MODULE
OPERATIONS
385
Commands  always  have  two  module  contexts:  the  context  where  they  were 
defined and the context where they were called from. This is a somewhat subtle con-
cept. Before PowerShell had modules, this wasn’t terribly interesting except for get-
ting filename and line number information for where the function was called and 
where  it  was  defined. With  modules,  this  distinction  becomes  more  significant. 
Among other things, the module where the command was defined contains the mod-
ule-specific resources like the manifest 
PrivateData
element mentioned in section
10.5. For functions,  the ability to access the two contexts allows the function to 
access the caller’s variables instead of the module variables.
Accessing the defining module
The module that a function was defined in can be retrieved by using the expression 
$MyInvocation.MyCommand.Module
. Similarly, the module a cmdlet was defined in 
is available through the instance property 
this.MyInvocation.MyCommand.Module
If the function is defined in the global scope (or top level), the module field will be 
$null
. Let’s try this. First define a function at the top level:
PS (1) > function Test-ModuleContext { 
>>     $MyInvocation.MyCommand.Module 
>> } 
>>
Then run it, formatting the result as a list showing the module name and 
Private-
Data
fields:
PS (2) > Test-ModuleContext | fl name,privatedata 
PS (3) >
Nothing was output because the defining module at the top level is always 
$null
Now let’s define the function inside a module. Use a here-string to create a .psm1 file:
PS (4) > @'
>> function Test-ModuleContext { 
>>     $MyInvocation.MyCommand.Module 
>> } 
>> '@ > TestModuleContext.psm1 
>>
Now load the file and run the same test command as you did previously:
PS (5) > Import-Module ./TestModuleContext.psm1 
PS (6) > Test-ModuleContext | fl name,privatedata
Name        : TestModuleContext 
PrivateData :
This time the result of the function was not 
$null
—you see the module name and, 
of course, the 
PrivateData
field is empty because there was no module manifest to 
provide this data. You can remedy this by creating a module manifest to go along
386
CHAPTER 10
M
ODULE
MANIFESTS
AND
METADATA
with the .psm1 file. This abbreviated manifest defines the minimum—the module 
version, the module to process, and a hash table for 
PrivateData
:
PS (7) > @' 
>> @{ 
>>     ModuleVersion = '1.0.0.0' 
>>     ModuleToProcess = 'TestModuleContext.psm1' 
>>     PrivateData = @{a = 1; b = 2 } 
>> } 
>> '@ > TestModuleContext.psd1 
>>
Load  the  module  using  the  manifest  and 
-Force
to make sure everything gets 
updated:
PS (8) > Import-Module -Force ./TestModuleContext.psd1
And run the test command:
PS (9) > Test-ModuleContext | fl name,privatedata
Name        : TestModuleContext 
PrivateData : {a, b}
You see that the 
PrivateData
field is now also filled in.
Accessing the calling module
The module that a function was called from can be retrieved by using the expression 
$PSCmdlet.SessionState.Module
. Similarly, the module a cmdlet is called from is 
available through 
this.SessionState.Module
. In either case, if the command is 
being invoked from the top level, this value will be 
$null
because there is no “global 
module.” 
NOTE
It’s unfortunate that we didn’t get a chance to wrap the global 
session state in a module before we shipped. This means that this kind 
of code has to be special case for the module being 
$null
some of the time.
Working with both contexts
Now let’s look at a tricky scenario where you access both contexts at once. This is 
something that’s rarely necessary but, when needed, is absolutely required.
In functions and script modules, accessing the module session is trivial since unqual-
ified variables are resolved in the module context by default. To access the caller’s con-
text you need to use the caller’s session state, which is available as a property on 
$PS-
Cmdlet
. Let’s update the 
Test-ModuleContext
module to access a variable, 
$testv
both in the caller’s context and the module context. Here’s the module definition:
PS (1) > @' 
>> $testv = 123 
>> function Test-ModuleContext { 
>>     [CmdletBinding()] param()
A
DVANCED
MODULE
OPERATIONS
387
>>     "module testv is $testv" 
>>     $ctestv = $PSCmdlet.SessionState.PSVariable.Get("testv").Value; 
>>     "caller's testv is $ctestv" 
>> } 
>> '@ > TestModuleContext.psm1 
>>
This defines your test function, specifying that the cmdlet binding be used so you can 
access 
$PSCmdlet
. The module body also defines a module-scoped variable, 
$testv
The test function will emit the value of this variable and then use the expression
$PSCmdlet.SessionState.PSVariable.Get("testv").Value
to get the value of the caller’s 
$testv
variable. Next load the module:
PS (2) > Import-Module -Force ./TestModuleContext.psm1
Now define a global 
$testv
:
PS (3) > $testv = "456"
Next, run the command:
PS (4) > Test-ModuleContext 
module testv is 123 
caller's testv is 456
And you see the module 
$testv
was correctly displayed as 123 and the caller’s vari-
able is the global value 456. Now wait a minute, you say, you could’ve done this 
much more easily by specifying 
$global:testv
. This is true if you were only inter-
ested in accessing variables at the global level. But sometimes you want to get the 
local variable in the caller’s dynamic scope. Let’s try this. Define a new function, 
nested
, that will set a local 
$testv
PS (5) > function nested { 
>>     $testv = "789" 
>>     Test-ModuleContext 
>> } 
>>
This function-scoped 
$testv
variable is the caller’s variable you want to access so you 
should get 789 instead of the global value 456:
PS (6) > nested 
module testv is 123 
caller's testv is 789
It works. The module 
$testv
was returned as 123 and the caller’s 
$testv
returned 
the value of the function-scoped variable instead of the global variable. 
So when would you need this functionality? If you want to write a function that 
manipulates the caller’s scope—say something like the 
Set-Variable
cmdlet imple-
mented as a function—then you’d need this capability. The other time you might 
need to do this is when you want to access the value of locally scoped configuration 
variables, such as 
$OFS
388
CHAPTER 10
M
ODULE
MANIFESTS
AND
METADATA
10.7.4
Setting module properties from inside a script module
We’ve talked at length about how manifests are required to set metadata on a module, 
but there’s a way for the script module to do some of this itself during the module 
load operation. To do this it needs to have access to its own 
PSModuleInfo
object 
during the load. This can be retrieved using the rather awkward expression
$MyInvocation.MyCommand.ScriptBlock.Module
But once you have the 
PSModuleInfo
object, the rest is easy. Try it out by setting the 
Description
property on your own module.
Setting the module description
In this example, you’ll set the 
Description
property for a module from within the 
module itself. You’ll create a module file in the current directory called setdescrip-
tion.psm1. Here are the contents of this file:
PS (1) > Get-Content .\setdescription.psm1 
$mInfo = $MyInvocation.MyCommand.ScriptBlock.Module 
$mInfo.Description = "My Module's Description on $(Get-Date)"
On the first line of the module, you copy the reference to the 
PSModuleInfo
object 
into a variable, 
$mInfo
. On the second line, you assign a value to the 
Description 
property on that object. Import the module:
PS (2) > Import-Module .\setdescription.psm1
Then, call 
Get-Module
, piping into 
Format-List
so you can just see the module 
name and its description:
PS (3) > Get-Module setdescription | 
>> Format-List name, description 
>>
Name        : setdescription 
Description : My Module's Description on 01/16/2010 21:33:13
And there you go. You’ve dynamically set the 
Description
property on your module.
Along with being able to set this type of metadata entry on the 
PSModuleInfo 
object, there are a couple of behaviors you can control as well. You’ll see how this 
works in the next two sections.
10.7.5
Controlling when modules can be unloaded
The  module 
AccessMode
feature allows you to restrict when a module can be 
unloaded. There are two flavors of restriction: static and constant. A static module is a 
module that can’t be removed unless the 
-Force
option is used on the 
Remove-
Module
cmdlet. A constant module can never be unloaded and will remain in memory 
until the session that loaded it ends. This model parallels the pattern for making vari-
ables and functions constant.
A
DVANCED
MODULE
OPERATIONS
389
To make a module either static or constant, you need to set the 
AccessMode 
property on the module’s 
PSModuleInfo
object to the appropriate setting. Set it to 
ReadOnly
for static modules and 
Constant
for constant modules. Let’s see how this 
is done. Here’s an example  script module called readonly.psm1  that makes  itself 
ReadOnly
:
PS (1) > Get-Content .\readonly.psm1 
$mInfo = $MyInvocation.MyCommand.ScriptBlock.Module 
$mInfo.AccessMode = "readonly"
The first line of the module is the same as the example in the previous section and 
retrieves the 
PSModuleInfo
object. The next line sets the 
AccessMode
to 
readonly
Now load this module and verify the behavior:
PS (2) > Import-Module .\readonly.psm1 
PS (3) > Get-Module
ModuleType Name                      ExportedCommands 
---------- ----                      ----------------
Script     readonly                  {}
You’ve verified that it’s been loaded, so now try to remove it:
PS (5) > Remove-Module readonly 
Remove-Module : Unable to remove module 'readonly' because it is 
read-only. Use the -force flag to remove read-only modules.
At line:1 char:14 
+ Remove-Module <<<<  readonly
+ CategoryInfo          : PermissionDenied: (readonly:PSModuleInfo)
[Remove-Module], InvalidOperationException
+ FullyQualifiedErrorId :
Modules_ModuleIsReadOnly,
Microsoft.PowerShell.Commands.RemoveModuleCommand
When you try to remove the module, you get an error stating that 
-Force
must be 
used to remove it. So do that:
PS (6) > Remove-Module readonly -Force
This time you don’t get an error. You verify that the module has been removed by 
calling 
Get-Module
:
PS (7) > Get-Module 
PS (8) >
Nothing was returned, confirming that the module has been removed. The same 
approach is used to mark a module as constant.
And now, the final feature we’re going to cover: how to run an action when a 
module is unloaded. 
10.7.6
Running an action when a module is removed
Sometimes you need to do some cleanup when a module is unloaded. For example, if 
the  module  establishes  a  persistent  connection  to  a  server,  when  the  module  is
Documents you may be interested
Documents you may be interested