How do I create powershell 2.0 modules? - powershell

I've heard powershell 2.0 CTP has modules, but I can't find much example code or instructions. I've read what little help there seems to be online...
But I just keep getting "The term 'Add-Module' is not recognized as a cmdlet..." when I try and load a module.
Any help would be gratefully received!
Edit (July 2010)
Please note this question is based on powershell 2.0 CTP and is therefore a year and half out of date! Please see Samuel Jack's answer for help with the powershell 2.0 RTM.

With the Win7 build, Add-Module is gone. The new cmdlet is Import-Module. The easiest way to create a module is rename a PS1 file to a PSM1 file. From there you can do all sorts of things including the module manifest.

I'm no Powershell expert, but here's what I just figured out using PowerShell 2.0 RTM.
Suppose you want to create a module called MyModule:
Make sure that you have created the folder %My Documents%\WindowsPowershell\Modules
Create a folder inside Modules called MyModule
Put your code in a file inside MyModule and name the file MyModule.psm1
Remember to use the Export-ModuleMember command as the last thing in your script file. Export-ModuleMember -Function * -Alias * will export all functions and aliases
In scripts where you want to use the module, use the command Import-Module MyModule
By default Powershell is configured not to run any kinds of scripts from files, so you need to alter the security settings. Set-ExecutionPolicy Unrestricted will get you going if you're not concerned about scripts needing to be signed.

Here's a little bit of information.
http://huddledmasses.org/powershell-modules/
http://blogs.msdn.com/mediaandmicrocode/archive/2008/08/10/microcode-all-about-modules-windows-powershell-ctp2.aspx
Let's hope that the upcoming CTP3 has some useful documentation about modules.

Modules will hopefully solve a few problems. Right now, we can use dot sourcing to get functions, variables, and scripts into a PowerShell session's global scope.
The problem is that this can pollute your session with all kinds of global variables and helper functions that an end user may not want/need directly.
Modules will allow you as an author to build scripts and only make certain functions/variables avaiable to the end user of the module.
They also essentially replace the concept of a PSSnapin. You can use Add-Module Some.dll to add an assembly that has cmdlets in it.
What is really cool is what is called a Module Manifest. This is a hash table that basically specifies all kinds of dependcies as well as author, name, GUID Identifier, and version number. When a user loads a module that has a module manifest, it will check all the dependencies and run any scripts the module author deems necessary.
There should be some decent documentation on these when CTP3 ships.
Hope that helps a bit.
Andy

Windows PowerShell v2.0: TFM (sapienpress.com) has information and samples in one of the chapters. It's available as an ebook which is updated as new CTPs are released. I also blogged about them on ConcentratedTech.com, and there's been discussion on them at PowerShellCommunity.org in the forums.

Related

How does Powershell Auto-Load Modules?

We learn that Powershell introduced Module Auto-Loading in 3.0 :
... PowerShell imports modules automatically the first time that you
run any command in an installed module. You can now use the
commands in a module without any set-up or profile configuration, ...
And this is done via PSModulePath.
What the docs fail to explain is how Powershell can detect which commands are in a module without first loading the module.
That is, when I use Import-Module, I "know" that Powershell will execute (??!) the powershell code in my .psm1 file, exporting all functions, ... or whatever I spec with Export-Modulemember.
However, the Auto-Load feature has to know before hand that a certain command is available via a certain module without actually loading the module.
Since we had some misbehaving third party modules in PsModulePath and since we have a very few modules that we wrote ourselves that we like to anchor in PSModulePath, I would very much like to understand how the files in PSModulePath are processed.
This is a partial answer.
This is done/implemented via Get-Command and this seems to be enabled to "parse" module files without actually executing the PoSh Code there. See below.
From the powershell docs:
Implicitly Importing a Module
... works on any module in a directory that is included in the value
of the PSModulePath environment variable ...
To support automatic importing of modules, the Get-Command cmdlet
gets all cmdlets and functions in all installed modules, even if the
module is not imported into the session. ...
And then:
Get-Command
The Get-Command cmdlet gets all commands that are installed on the
computer ...
Get-Command that uses the exact name of the command, without
wildcard characters, automatically imports the module that contains
the command so that you can use the command immediately. ...
Get-Command gets its data directly from the command code, unlike
...
The docs do not explain how this is implemented, but one could possibly look up how it's done in the source code. (I wasn't so far able to find it, despite browsing the sources for a while.)
Incidentally I find mentioned that Powershell 3 was the first version to expose the AST, so it stands to reason that the posh code does exactly that: Parse the Scripts and inspect their AST in some way to determine if the command is provided.

PowerShell Core and AppX package management

I am using PowerShell 6.2 preview at the moment. In my script I am trying to do stuff with Windows 10 apps. To be able to use commands like Get-AppxPackage, I need to import Windows modules from previous PowerShell like so:
Import-Module C:\Windows\system32\WindowsPowerShell\v1.0\Modules\Appx\Appx.psd1 -SkipEditionCheck
Import-Module C:\Windows\system32\WindowsPowerShell\v1.0\Modules\dism\dism.psd1 -SkipEditionCheck
Does PowerShell core has its own modules to work with this? I found Get-Package for example, but that does not give me anything.
Since this is one of the top search results for PowerShell Core Get-AppxPackage, I'm going to take the information from the link provided in the comments and provide an answer, with example.
As LangsGalgEnRad pointed out in the comments, it's easiest just to do this from Windows PowerShell, but ultimately that's just-shy-of-deprecated at this point, with Microsoft stating that there are to be no more fixes or changes other than critical security issues. That said, it's still (afaik) universally available in Windows installations.
But for those of us who want to follow Microsoft's advice to use PowerShell Core, LangsGalgEnRad also points out in the comments the WindowsCompatibility module from Microsoft. Reading the blog post, this seems a bit safer than importing a Windows module (e.g. AppX) from PowerShell Core, since among other things ...
WindowsCompatibility is very careful to not overwrite native PowerShell core commands.
To install from PowerShell Gallery:
Install-Module WindowsCompatibility
Example usage for AppX:
Import-Module WindowsCompatibility
Import-WinModule AppX
Get-AppxPackage

How to create and install a powershell command package using chocolatey?

I have a few powershell commands in a script that I want to distribute to everyone on my team. This script may be updated and I would want an easy way for my team to update this script as well. Someone suggested Chocolatey which I have never used before. I found the following in the Chocolatey.org FAQ:
"What kind of package types does Chocolatey support?
Binary Packages – Installable/portable applications – This is 98% of the Chocolatey packages – most are pointers to the real deal native installers and/or zipped software.
PowerShell Command Packages – Packages that have the suffix .powershell will install PowerShell scripts as commands for you to call from anywhere.
Development Packages – Packages that have the suffix .dev. For instance dropkick.dev.
Coming soon – Virtual Packages – Packages that are like a category, and you just want one package from that category. Read more ..."
Does anyone have an example of using chocolatey to install a powershell script to the Path so that the commands in it can be executed from anyway on the machine? I am unable to find an example of how to do this online.
If this is an inappropriate use of chocolatey, please let me know and feel free to recommend an alternate solution.
Thank you very much for your time. Please let me know if I am being unclear or if you have any questions for me?
Look at the PowerShell Function Reference, which has all of the different functions you can call. Then take a look, specifically, at the Install-ChocolateyPowershellCommand helper. Here's an example of a package that installs a powershell script as a command (source).

Bug in Wix? Is ps:SnapIn writing to the wrong registry key with PowerShell 3.0?

We have a PowerShell snapin that requires version 3.0 of PowerShell to function. So we used the following file element in a WiX (3.8) file:
<File Id="MySnapin.dll"
Name="MySnapin.dll"
Assembly=".net"
KeyPath="yes"
Vital="no"
Checksum="yes"
DiskId="1"
Source="$(var.FilesPath)\Bin\MySnapin.dll"
AssemblyApplication="MySnapin.dll">
<ps:SnapIn Id="MySnapin"
Description="This is a PowerShell snap-in"
Vendor="My Company Inc."
RequiredPowerShellVersion="3.0">
<ps:FormatsFile FileId="MySnapin.format.ps1xml" />
</ps:SnapIn>
</File>
However, when installing this the snapin cannot be found in powershell (Get-PSSnapIn -Registered). When examining the registry it turns out that the snapin has been registered in HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\PowerShell\3\PowerShellSnapIns\MySnapin. But when running installutil.exe on the DLL, the registration ends up in HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\PowerShell\1\PowerShellSnapIns\MySnapin, and powershell finds it properly. Is this a bug in WiX Toolset, or am I doing something wrong here?
Where are the registrations really supposed to go?
Yea this sounds like a bug, so you might want to report it to the WiX maintainers, but there is better way.
The recommended way to add cmdlets and functions is through PowerShell Modules. Snap-ins are the older way to extend PowerShell and while still supported are not recommended. If you do not need to support adding your cmdlets to older versions of PowerShell use a module.
Modules are somewhat easier to deploy than snap-ins. Basically you can put them anywhere, however if you want users to be able to load them by name they need to exist on the PSModulePath environment variable. Your installer would add your files and update the PSModulePath variable to include a Modules folder from your install folder. Then users will simply be able to call Import-Module MyModule to load them. Also, see the documentation on PSModulePath.
This blog post contains a detailed walkthrough of how to write a WiX installer to do this. It also has instructions on how to check that the required PowerShell version is installed. Basically, you are going to check the under both those registry keys you mentioned for the PowerShellEngine\PowerShellVersion value.

How do I import a new PowerShell cmdlet?

I've written a PowerShell cmdlet in C#.
Where do I copy the library at this point?
And how do I import it into PowerShell so that I can use it?
There are two ways to load your new cmdlet.
Import Cmdlets Using Modules. Here you either put your cmdlet DLL into a system-recognized path that will allow you to load a module with a simple name (e.g. Import-Module MyModule), or you can put it in an arbitrary directory for which you need to specify a complete path (e.g. Import-Module C:\code\MyModule.dll). If you have only a single DLL and no dependencies, you can actually give the DLL as shown. Typically, though, you will also want to create a manifest using New-ModuleManifest (creating, e.g., a MyModule.psd1 file) then pass that psd1 file rather than the dll to Import-Module.
Create a Windows PowerShell Snap-in. This requires writing one additional C# class, quite small, that provides the glue necessary to treat your cmdlet as a snap-in. Then you have to register the snap-in with the installutil program and finally load the snapin with Add-SnapIn. (See also How to Register Snap-ins...)
Curiously, almost all articles that talk about writing cmdlets suggest the snap-in approach, but this is simply because that technique has been available since PowerShell version 1, while modules did not come along until version 2. Everything I have read, though, suggests essentially that the snap-in approach is deprecated to the simpler--and more flexible--module approach.