Publishing PowerShell modules
How to use the PowerShellGet module to publish a PowerShell module
Published in Articles on by Michiel van Oosterhout ~ 6 min read
About a year ago we looked at how to publish a PowerShell script package using the PowerShellGet package provider. This package provider can also publish modules, which are more suitable for distributing a large set of features (for example, a set of cmdlets for a cloud service like Azure App Service or AWS S3).

Creating a PowerShell module
A PowerShell module is a set of files (typically PowerShell scripts and/or .NET assemblies) in a directory, with a manifest describing those files, packaged into a NuGet package, distributed via a repository, and installed into one of the directories in $Env:PSModulePath
.
Module types
There are three types of modules:
- script modules, having a primary
.psm1
script; - binary modules, having a primary
.dll
assembly; - and manifest modules, having no primary file and only a
.psd1
manifest file.
The name of the module's directory is the module's base name, and the primary script or assembly, as well as the manifest file should have the same base name. The manifest is a data file that describes the module using many settings. Although the manifest is optional for script and binary modules, it becomes required when you want to distribute the module via a repository.
Using a local package source
For testing purposes we can publish a module to a temporary local repository. The Windows PowerShell script below creates and registers one:
# Create a temporary directory
$packageSourcePath = "$Env:USERPROFILE\Desktop\Temp"
$_ = New-Item -ItemType Directory -Path $packageSourcePath
# Register a temporary repository
$_ = Register-PackageSource -Trusted -Provider PowerShellGet -Name Temp -Location $packageSourcePath
The Temp
directory on the desktop will contain a new NuGet package file (.nupkg
) after a module is published to the Temp
repository.
The Windows PowerShell script below completely removes the temporary repository:
# Unregister the temporary repository
Unregister-PackageSource -ProviderNam PowerShellGet -Source Temp
# Delete the temporary directory and its contents
$packageSourcePath = "$Env:USERPROFILE\Desktop\Temp"
Remove-Item -Force -Path $packageSourcePath -Recurse
Creating the module
The steps to create a module are similar to the steps to create a script package:
- Create the directory and files
- Add the manifest (
.psd1
file) withModuleVersion
,Author
, andDescription
set - Validate the manifest using
Test-ModuleManifest
- Update the version in the manifest using
Update-ModuleManifest
Note: This will setGUID
,CompanyName
,Copyright
,FunctionsToExport
,CmdletsToExport
, andAliasesToExport
if not already set. - Publish the module using
Publish-Module
A PowerShell module is created and published by invoking Publish-Module
. This will validate the manifest, create a NuGet package (.nupkg
) file, and upload the NuGet package to the repository referred to by the -Repository
parameter.
# Publish the Test module to the Temp repository
Publish-Module -Path "$Env:USERPROFILE\Desktop\Test" -Repository Temp
When using the -Path
parameter, its value should be the path of the module's directory.
Using NuGet Package Explorer to inspect the module
Publishing the module to a local package source gives us an opportunity to inspect the package file (.nupkg
). The easiest way to do that is by installing NuGet Package Explorer:
# Install NuGet Package Explorer from the Microsoft Store
winget install "NuGet Package Explorer" --accept-source-agreements --accept-package-agreements
Now you can open the NuGet package (e.g. Test.1.0.0.nupkg
) that you can find in the temporary package source's directory, and check its contents and metadata.

All files from the module's directory should be included, and some of the settings in the module's manifest will have been mapped to the corresponding NuGet package metadata. In addition, the following rules apply:
CompanyName
maps to Owners;RequiredModules
maps to Dependencies;RequiredModules
is an array of module specifications 1;RequiredModules
entries must be in the global session state at the time of publishing;RequiredModules
entries must be available in the repository;PrivateData.PSData.ExternalModuleDependencies
is an array of strings;PrivateData.PSData.ExternalModuleDependencies
should contain the names of thoseRequiredModules
that are not available in the package source;PrivateData.PSData.ExternalModuleDependencies
entries are excluded from Dependencies;PrivateData.PSData.Prerelease
can contain a prerelease label since PowerShellGet 1.6;PrivateData.PSData.Prerelease
prerelease labels are not semver 1.0.0 compatible 2;- the
PSModule
tag is added automatically to Tags; - the
PSIncludes_Cmdlet
tag is added automatically to Tags if the module exports a cmdlet; - the
PSIncludes_Function
tag is added automatically to Tags if the module exports a function; - a
PSCommand_
tag is added automatically to Tags for each exported alias, cmdlet, or function; - a
PSCmdlet_
tag is added automatically to Tags for each exported cmdlet; - a
PSFunction_
tag is added automatically to Tags for each exported function;
What is exported by a module can be controlled by RootModule
, which designates the primary file, whose cmdlets and functions will be exported by default. CmdletsToExport
and FunctionsToExport
can be used to override the default exports from the primary file, as well as to export from other files included in the module.
NestedModules
can be used to import additional script (.psm1
) or binary (.dll
) modules into the root module's session state. Those modules are in control of their own exports. The exports from nested modules are only available to the root module. When a script file (.ps1
) is specified it simply runs in the root module's session state on import of the root module. (Use ScriptsToProcess
to run scripts in the caller's session.)
Consuming a PowerShell module
The lifecycle of a distributed module on some system is managed by this list of cmdlets:
Find-Module
, to verify that the module is available for installation;Install-Module
, to install the module;Get-InstalledModule
, to verify the installation;Import-Module
, to import the module into the current session;Get-Module
, to verify that the module was imported;Remove-Module
, to remove the module from the current session;- and finally
Uninstall-Module
, to uninstall the module.
Summary
A PowerShell module is suitable to distribute a larger set of features, and can have a dependency on other modules. The package format is based on NuGet with limited support for semantic versioning. Consuming PowerShell modules distributed this way is enabled via a set of cmdlets using the Module
noun.