# Tuesday, December 30, 2008

A module manifest file is a PowerShell data file (.psd1) with the same name as the module directory. For example, the FileTransfer module installed with CTP3 -- which contains Cmdlets for BITS -- is in a directory called $pshome\Modules\FileTransfer and contains a manifest file called $pshome\Modules\FileTransfer\FileTransfer.psd1. Module manifests are optional, but highly recommended.

A module manifest contains a hashtable declared using the @{} hashtable literal syntax. Valid keys are listed in the following table:

Key

Required

Type

Description

ModuleToProcess

Optional

String

Script module or binary module file associated with this manifest which also becomes the root module for nested modules. If no module is specified, the manifest itself becomes the root module for nested modules.

A binary module is the new name for a snap-in DLL. v1 style snapins can be loaded this way, without having to register them first with installutil.exe; A binary module does NOT need a PSSnapIn class defined.

ModuleVersion

Required

String convertible to System.Version

Version of the module

GUID

Optional

String

Unique identifier for the module which can be used to verify against the module name

Author

Optional

String

Identifies the author of the module

CompanyName

Optional

String

Identifies the company that created the module

Copyright

Optional

String

Module copyright

Description

Optional

String

Describes the contents of the module

PowerShellVersion

Optional

String convertible to System.Version

Minimum required version of the PowerShell engine

CLRVersion

Optional

String convertible to System.Version

Minimum required version of the CLR

RequiredModules

Optional

List of module names

List of modules that must already be loaded globally (note: required modules are not loaded automatically - this could optionally be done using a script in ScriptsToProcess).

RequiredAssemblies

Optional

String array

List of assemblies that will be loaded using the same algorithm as Add-Type

ScriptsToProcess

Optional

String array

Identifies the list of scripts to process when the module is imported. These scripts are dot sourced into the caller’s environment. Only .ps1 files can be specified.

TypesToProcess

Optional

String array

List of .ps1xml type files to process using Update-TypeData

FormatsToProcess

Optional

String array

List of .ps1xml format files to process using Update-FormatData

NestedModules

Optional

String array

List of .ps1, .psm1, .psd1, and .dll files to process on Import-Module. Files are processed in the order listed. DLLs are scraped for cmdlets/providers and .ps1 script files are dot sourced into the module’s session state.

ExportedFunctions

Optional

String array, wildcards supported

List of functions to export. If not defined or if asterisk is specified, all functions imported from nested modules are re‑exported. To prevent export, use the empty string ‘’.

ExportedCmdlets

Optional

String array, wildcards supported

List of cmdlets to export. If not defined or if asterisk is specified, all cmdlets imported from nested modules are re‑exported. To prevent export, use the empty string ‘’.

A big change in CTP3 is that binary Cmdlets can now be scoped – previously they were always global.

ExportedVariables

Optional

String array, wildcards supported

List of variables to export. If not defined or if asterisk is specified, all variables imported from nested modules are re‑exported. To prevent export, use the empty string ‘’.

ExportedAliases

Optional

String array, wildcards supported

List of aliases to export. If not defined or if asterisk is specified, all aliases imported from nested modules are re‑exported. To prevent export, use the empty string ‘’.

PrivateData

Optional

Object

Data to be passed to the module via the manifest file.

I’ve highlighted certain things in the description that are important to note. These are the things that might trip you up.

Have fun!

posted on Tuesday, December 30, 2008 11:48:20 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Saturday, December 27, 2008

Meson tweeted a request asking if it was possible to get a list of language keywords from PowerShell itself. The answer is officially “No,” but like most things of this nature, there’s always a sneaky way:

  1. [type]::gettype("System.Management.Automation.KeywordTokenReader")|%{$_.InvokeMember("_keywordTokens", "NonPublic,Static,GetField", $null, $_,@())}  

More interestingly this list turned up a new script keyword, dynamicparam. I haven’t seen it in action yet but it sounds like another “advanced function” feature to bring functions and cmdlets closer to parity. I may need to add another article to my dynamic parameter series ;-)

posted on Saturday, December 27, 2008 12:21:38 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Thursday, December 25, 2008

This is an interesting exercise to show the power of PowerShell’s language to explore and manipulate object models, specifically its own. You all should be familiar with Type Accelerators: The short name syntax for accessing commonly used .NET Types. An example would be [wmi] – this is the same as typing [System.Management.ManagementObject]. So, how can we find all of the current existing Type Accelerators? Well, after cracking open PowerShell with our favourite decompilation tool, Reflector, the class in question is System.Management.Automation.TypeAccelerators. Here’s what it looks like:

  1. internal static class TypeAccelerators  
  2. {  
  3.     // Fields  
  4.     private static Dictionary<string, Type> allTypeAccelerators;  
  5.     internal static Dictionary<string, Type> builtinTypeAccelerators;  
  6.     internal static Dictionary<string, Type> userTypeAccelerators;  
  7.  
  8.     // Methods  
  9.     static TypeAccelerators();  
  10.     public static void Add(string typeName, Type type);  
  11.     internal static void FillCache(Dictionary<string, Type> cache);  
  12.     internal static string FindBuiltinAccelerator(Type type);  
  13.     public static bool Remove(string typeName);  
  14.  
  15.     // Properties  
  16.     public static Dictionary<string, Type> Get { get; }  
  17. }  
  18.  

Interestingly, the methods that let you add and remove your own accelerators are marked Public. The Type itself is internal, but the dictionary named “userTypeAccelerators” is positively tantalizing. It looks like perhaps the team have plans to let people add their own accelerators! Then again, this is a CTP, and this may change in the future. Well, let’s see if we can finish off what the team half started ;-)

First thing we need to do is get a reference to the internal class. The C# heads amongst you will start thinking about using reflection to get your hands on the type, but actually there’s an easier way. PowerShell’s language is incredibly flexible and through sneakiness, you can use System.Type’s GetType method to invoke any public method without reverting to tricky reflection calls. First of all, lets add our own user-defined Type Accelerator which is aliased to this internal class itself:

  1. # get a reference to the Type   
  2. $acceleratorsType = [type]::gettype("System.Management.Automation.TypeAccelerators")  
  3.  
  4. # add an accelerator for this type ;-)  
  5. $acceleratorsType::Add("accelerators", $acceleratorsType)  
  6.  
  7. # will return all built-in accelerators (property)  
  8. [accelerators]::get 
  9.  
  10. # add a user-defined accelerator  
  11. [accelerators]::add([string], [type])  
  12.  
  13. # remove a user-defined accelerator  
  14. [accelerators]::remove([string])  

I’ve split the Type retrieval and Add methods into two lines for brevity. The parser is actually flexible enough to understand the more pithy ([type]::gettype("System.Management.Automation.TypeAccelerators"))::Add(…).

So what do we have in CTP3?

Name Type
int System.Int32
long System.Int64
string System.String
char System.Char
bool System.Boolean
byte System.Byte
double System.Double
decimal System.Decimal
float System.Single
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.PSObject
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
accelerators System.Management.Automation.TypeAccelerators

Btw, I generated the above list with this one liner:

  1. [accelerators]::Get.getenumerator() | `  
  2.     select @{Name="Name"; expression={$_.key}},  
  3.            @{name="Type"; expression={$_.value}} | `  
  4.     convertto-html -fragment > .\accelerators.html  

Have fun!

posted on Thursday, December 25, 2008 3:29:55 PM (Eastern Standard Time, UTC-05:00)  #    Comments [1] Trackback
# Tuesday, December 23, 2008

Just to be completely silly, I thought I’d do a series of posts on CTP3 features themed around Christmas. Hmm. That might read better as a series of Christmas posts themed around CTP3. A very original idea I’m sure, but hey, those who know me will know that I never pass up the opportunity to make a bad joke. So, without further adieu:

On the first day of Christmas, Jeffrey gave to me:

Nested Here-Strings

Here-Strings can now be embedded within each other to make it even easier to construct literal documents! Delimit any nested code between $( and ) and then continue to use a nested string within that as if it was completely stand alone. It just works! Cool, eh?

  1. function Get-CommandDefinitionHtml {  
  2.       
  3.     # this tells powershell to allow advanced features,  
  4.     # like the [validatenotnullorempty()] attribute below.  
  5.     [CmdletBinding()]  
  6.     param(  
  7.         [ValidateNotNullOrEmpty()]  
  8.         [string]$name 
  9.     )  
  10.  
  11.     $command = get-command $name 
  12.       
  13.     # Look mom! I'm a cmdlet!  
  14.     $PSCmdlet.WriteVerbose("Dumping HTML for " + $command)  
  15.       
  16. @"  
  17.     <html>  
  18.         <head>  
  19.             <title>$($command.name)</title>  
  20.         </head>  
  21.         <body>  
  22.             <table border="1">  
  23. $(  
  24.     $command.parametersets | % {  
  25. @" 
  26.  
  27.             <tr>  
  28.                 <td>$($_.name)</td>  
  29.                 <td>  
  30.                     <table border="1">  
  31.                         <tr>  
  32.                             <th colspan="8">Parameters</th>  
  33.                               
  34. $(  
  35.         $count = 0  
  36.         $_.parameters | % {  
  37.             if (0 -eq ($count % 8)) {  
  38. @"  
  39.                         </tr>  
  40.                         <tr>  
  41. "@  
  42.             }                  
  43. @"  
  44.                             <td>$($_.name)</td>  
  45. "@              
  46.             $count++  
  47.     }  
  48. )  
  49.                         </tr>                          
  50.                     </table>  
  51.                 </td>  
  52.             </tr>  
  53. "@  
  54.     }  
  55. )  
  56.             </table>          
  57.         </body>  
  58.     </html>  
  59. "@      
  60. }  
  61.  
  62. Get-CommandDefinitionHtml get-item > out.html  
  63.  
  64. # show in browser  
  65. invoke-item out.html 
posted on Tuesday, December 23, 2008 4:16:03 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Monday, December 22, 2008

To quote the completely understated download blurb:

Windows PowerShell V2 CTP3 introduces several significant features to Windows PowerShell 1.0 and Windows PowerShell V2 CTPs that extends its use, improves its usability, and allows you to control and manage the Windows environment more easily and comprehensively.

The release notes are quite extensive. Here is the section on breaking changes from CTP2:

Breaking Changes to Windows PowerShell V2 (CTP2)

The following changes in Windows PowerShell V2.0 CTP3 might prevent features designed for Windows PowerShell 2.0 CTP2 from working correctly.

  • Following cmdlets have been renamed
    • Add-Module to Import-Module
    • Get-Event to Get-WinEvent
    • *-Runspace to *-PSSession
    • Push-Runspace to Enter-PSSession
    • Pop-Runspace to Exit-PSSession
    • *-PSEvent to *-Event
    • Register-PSEvent to Register-EngineEvent
    • *-PSTransaction to *-Transaction
    • *-PSJob to *-Job
    • *-PSEventSubscriber to *-EventSubscriber
    • *-Bite to *-FileTransfer

  • Following parameters have been renamed
    • Import-LocalizedData: Culture to UICulture
    • Invoke-Command: Runspace to Session, Shell to ConfigurationName
    • Get-Job: SessionId to Id
    • Receive-Job: Runspace to Session, SessionId to Id
    • Remove-Job: SessionId to Id
    • Start-Job: Command to Scriptblock
    • Stop-Job: SessionId to Id
    • Wait-Job: SessionId to Id
    • Get-PSSession: RemoteRunspaceID to InstanceId, SessionId to Id
    • New-PSSession: Runspace to Session, Shell to ConfigurationName
    • Enter-PSSession: Runspace to Session, RemoteRunspaceID to InstanceId, SessionId to Id, Shell to ConfigurationName
    • Remove-PSSession: Runspace to Session, RemoteRunspaceID to InstanceId, SessionId to Id

  • Following parameters have been deleted
    • Export-ModuleMember: Update, ExportList
    • Set-Service: Include, Exclude

  • Following variables have been renamed
    • $CommandLineParameters to $PSBoundParameters
    • $PSPackagePath to $PSModulePath

  • Packages have been renamed to Modules. Packages folder is now renamed to Modules folder. A module imported into another module is now treated as a nested module instead of a peer module. This allows a new module to wrap or repackage one or more existing modules.

  • "Script cmdlets" have been renamed to "advanced functions." The “cmdlet” keyword has been replaced with the “function” keyword. For script cmdlet functionality, use CmdletBinding attribute in the function’s param block. For more information, see about_functions_advanced.
  • The Config-WSMan.ps1 script in the $pshome directory has been replaced by the Enable-PSRemoting function. To configure your system for WS-Management remoting, use the following command:

Enable-PSRemoting –force

Note: If you have upgraded from the Windows PowerShell V2 CTP2 release to the Windows PowerShell V2 CTP3 release, to configure your system for WS-Management remoting, type:

Unregister-PSSessionConfiguration * -force;

Register-PSSessionConfiguration Microsoft.PowerShell –force;

Enable-PSRemoting –force

  • In the Out-GridView cmdlet, the drop-down list used to filter objects is now called “Query” instead of “Filter”.

  • The following changes have been made to Windows PowerShell Integrated Scripting Environment (ISE):
    • The name of the application has changed from “Graphical Windows PowerShell” to “Windows PowerShell Integrated Scripting Environment (ISE)”
    • The executable name has changed from “gpowershell.exe” to “powershell_ise.exe”
    • The profile name has changed from “\Users\<username>\Documents\WindowsPowerShell\Microsoft.GPowerShell_profile.ps1” to “\Users\<username>\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1”
    • The term “runspace” has been replaced with “PowerShell tab”.

Get it from http://www.microsoft.com/downloads/details.aspx?FamilyID=c913aeab-d7b4-4bb1-a958-ee6d7fe307bc – piping hot!

posted on Monday, December 22, 2008 9:59:52 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback