Publishing Your Tools
Inevitably, you’ll come to a point where you’re ready to share your tools. Hopefully, you’ve put those into a PowerShell module, as we’ve been advocating throughout this book because in most cases it’s a module that you’ll share.
Begin with a Manifest
You’ll typically need to ensure that your module has a .psd1 manifest file since most repositories will use information from that to populate repository metadata. Here’s the manifest from our downloadable sample code.
#
# Module manifest for module 'PowerShell-Toolmaking'
#
# Generated by: Don Jones & Jeffery Hicks
#
@{
# Script module or binary module file associated with this manifest.
RootModule = 'PowerShell-Toolmaking.psm1'
# Version number of this module.
ModuleVersion = '2.0.0.0'
# Supported PSEditions
CompatiblePSEditions = @("Desktop")
# ID used to uniquely identify this module
GUID = '3926b244-469c-4434-a4b1-70ce3b0bfb5d'
# Author of this module
Author = 'Don Jones & Jeffery Hicks'
# Company or vendor of this module
CompanyName = 'Unknown'
# Copyright statement for this module
Copyright = '(c) 2024 Don Jones & Jeffery Hicks. All rights reserved.'
# Description of the functionality provided by this module
Description = "Sample for for 'The PowerShell Scripting and Toolmaking Book' by Don \
Jones and Jeffery Hicks published on Leanpub.com."
# Minimum version of the Windows PowerShell engine required by this module
# PowerShellVersion = ''
# Name of the Windows PowerShell host required by this module
# PowerShellHostName = ''
# Minimum version of the Windows PowerShell host required by this module
# PowerShellHostVersion = ''
# Minimum version of Microsoft .NET Framework required by this module. This prerequi\
site is valid for the PowerShell Desktop edition only.
# DotNetFrameworkVersion = ''
# Minimum version of the common language runtime (CLR) required by this module. This\
prerequisite is valid for the PowerShell Desktop edition only.
# CLRVersion = ''
# Processor architecture (None, X86, Amd64) required by this module
# ProcessorArchitecture = ''
# Modules that must be imported into the global environment prior to importing this \
module
# RequiredModules = @()
# Assemblies that must be loaded prior to importing this module
# RequiredAssemblies = @()
# Script files (.ps1) that are run in the caller's environment prior to importing th\
is module.
# ScriptsToProcess = @()
# Type files (.ps1xml) to be loaded when importing this module
# TypesToProcess = @()
# Format files (.ps1xml) to be loaded when importing this module
# FormatsToProcess = @()
# Modules to import as nested modules of the module specified in RootModule/ModuleTo\
Process
# NestedModules = @()
# Functions to export from this module, for best performance, do not use wildcards a\
nd do not delete the entry, use an empty array if there are no functions to export.
FunctionsToExport = '*'
# Cmdlets to export from this module, for best performance, do not use wildcards and\
do not delete the entry, use an empty array if there are no cmdlets to export.
CmdletsToExport = '*'
# Variables to export from this module
VariablesToExport = '*'
# Aliases to export from this module, for best performance, do not use wildcards and\
do not delete the entry, use an empty array if there are no aliases to export.
AliasesToExport = '*'
# DSC resources to export from this module
# DscResourcesToExport = @()
# List of all modules packaged with this module
# ModuleList = @()
# List of all files packaged with this module
# FileList = @()
# Private data to pass to the module specified in RootModule/ModuleToProcess. This m\
ay also contain a PSData hashtable with additional module metadata used by PowerShel\
l.
PrivateData = @{
PSData = @{
# Tags applied to this module. These help with module discovery in online ga\
lleries.
# Tags = @()
# A URL to the license for this module.
# LicenseUri = ''
# A URL to the main website for this project.
# ProjectUri = ''
# A URL to an icon representing this module.
# IconUri = ''
# ReleaseNotes of this module
# ReleaseNotes = ''
} # End of PSData hashtable
} # End of PrivateData hashtable
# HelpInfo URI of this module
# HelpInfoURI = ''
# Default prefix for commands exported from this module. Override the default prefix\
using Import-Module -Prefix.
# DefaultCommandPrefix = ''
}
A lot of this is commented out, which is the default when you use New-ModuleManifest. The specifics you must provide will differ based on your repository’s requirements, but in general, we recommend at least the following be completed:
-
RootModule. This is mandatory for the .psd1 to work, and it should point to the “main” .psm1 file of your module. -
ModuleVersion. This is generally mandatory, too, and is at the very least a very good idea. -
GUID. This is mandatory and generated automatically byNew-ModuleManifest. -
Author. This could be your or your organization. You might even include an email address. -
Description. Don’t be skimpy here. This is what people will read to decide if they want to use your module. Write a meaningful description that explains what your module does and why it’s useful.
These are, incidentally, the minimums for publishing to PowerShell Gallery. we also recommend, in the strongest possible terms, that you specify the FunctionsToExport array, as well as VariablesToExport, CmdletsToExport, and AliasesToExport if those are applicable. Ours, as you’ll see above, are set to *, which is a bad idea. In our specific example here, it makes sense, because our root module is empty - we aren’t exporting anything; the module is just a kind of container for our sample code to live in. But in your case, the recommended best practice is to explicitly list function, alias, and variable (without the $ sign) names which will achieve two benefits:
- Auto-discovery of your commands will be faster since PowerShell can just read the .psd1 rather than parsing the entire .psm1.
- Some repositories may be able to provide per-command search capabilities if you specify which commands your module offers.
Publishing to PowerShell Gallery
PowerShellGallery.com is a Microsoft-owned, public NuGet repository for released code. It can host PowerShell modules, DSC resources, and other artifacts. Start by heading over to PowerShellGallery.com and logging in or registering, using your Microsoft ID. Once signed in, click on your name. As part of your Gallery profile, you’ll be able to request, view, and see your API key. This is a long hexadecimal identifier that you’ll need when publishing code. Keep this secure.
With your API key in hand, it’s literally as easy as going into PowerShell and running Publish-Module (which is part of the PowerShellGet module, which ships with PowerShell v5 and later and can be downloaded from PowerShellGallery.com for other PowerShell versions). Provide the name of your module, and your API key (via the -NuGetApiKey parameter), and you’re good to go.
Publish-Module -path c:\scripts\MyAwesomeModule -nugetapikey $mykey
You may be prompted for additional information if it can’t be found in your module manifest.
You’ll likely receive a confirmation email from the Gallery, which may include a few PSScriptAnalyzer notifications. As we describe in the chapter on Analyzing Your Script, the Gallery automatically runs several PSScriptAnalyzer best practices rules on all submitted code, and you should try hard to confirm with these unless you have a specific reason not to.
So what’s appropriate for PowerShell Gallery publication?
- Production-ready code. Don’t submit untested, pre-release code unless you’re doing so as part of a public beta test, and be sure to clearly indicate that the code isn’t production-ready (for example, using
Write-Warningto display a message when the module is loaded). - Open-source code. Gallery code is, by implication, open-source; you should consider hosting your development code in a public OSS repository like GitHub, and only publish “released” code to the Gallery. Be sure not to include any proprietary information.
- Useful code. There are like thirty-seven million 7Zip modules in the Gallery. More are likely not needed. Try to publish code that provides unique value.
Items can be removed from Gallery if you change your mind, but Microsoft can’t go out and delete whatever people may have already downloaded. Bear that in mind before contributing.
Publishing to Private Repositories or Galleries
Microsoft’s vision is that organizations will host private and internal repositories. You may want to use a private repository merely for testing purposes. Ideally, these internal repositories will be based on Nuget. Setting up one of these is outside the scope of this book. However, you can set up a repository with a simple file share.
We’ve created a local file share and made sure that the admins group has write access.
New-SMBShare -name MyRepo -path c:\MyRepo -FullAccess Administrators `
-ReadAccess Everyone
Next, you can register this file share as a repository.
Register-PSRepository -name MyRepo -SourceLocation c:\MyRepo `
-InstallationPolicy Trusted
We set the repository to be trusted because we know what is going in it, and we don’t want to be bothered later when we try to install from it. If you forget, you can modify the repository later:
Set-PSRepository -Name MyRepo -InstallationPolicy Trusted
Now you can publish locally:
Publish-Module -Path c:\scripts\onering -Repository MyRepo
This local repository can be used just like the PowerShell gallery.
PS C:\> Find-Module -Repository MyRepo
Version Name Type Repository Description
------- ---- ---- ---------- -----------
0.0.1.0 onering Module MyRepo The module that ...
You can even install locally to verify everything works as expected.
PS C:\> Install-Module onering -Repository MyRepo
PS C:\> Get-Command -module OneRing -ListImported
CommandType Name Version Source
----------- ---- ------- ------
Function Disable-Ring 0.0.1.0 OneRing
Function Enable-Ring 0.0.1.0 OneRing
Function Get-Ring 0.0.1.0 OneRing
Function Remove-Ring 0.0.1.0 OneRing
Function Set-Ring 0.0.1.0 OneRing
We set this up locally as a proof of concept. It shouldn’t take that much more work to set up a repository on a company file share. Just mind your permissions.
Your Turn
We aren’t going to offer a real hands-on lab in this chapter, mainly because we think it’s a bad idea to use a public repo like PowerShell Gallery as a “lab environment!” It’s also non-trivial to set up your private repository, and if you go through that trouble, we think you’ll want it to be in production, not in a lab so that you can benefit from that work.
That said, we do want to encourage you to sign into the PowerShell Gallery and create your API key, as we’ve described in this chapter. It’s a first step toward getting ready to publish your code.
Let’s Review
We aren’t going to ask you to publish anything to the gallery. You may never need to publish or share your work. But let’s see if you picked up anything in this chapter.
- The Microsoft PowerShell Gallery is based on what technology?
- What important file is required to publish to the gallery that contains critical module metadata?
- What should you publish to any repository?
Review Answers
Hopefully, you came up with answers like this:
- Nuget
- A module manifest.
- Any unique project that offers value and is production-ready. You can publish your project that might be in beta or under development but that should be made clear to any potential consumer such as through version numbering.