Use an Azure Artifacts feed as a private PowerShell repository
Azure DevOps Services
Azure Artifacts provides a convenient solution for sharing PowerShell scripts. By using Azure Artifacts feeds, you can seamlessly publish your PowerShell modules from the command line and control access to them through your feed settings. This article guides you through setting up your Azure Artifacts feed as a private PowerShell repository to store and share your PowerShell modules.
In this article, you'll learn how to:
- Create a Personal Access Token
- Create a PowerShell module
- Create a SecretStore vault and register a repository
- Publish and consume packages from a feed
Prerequisites
Create an Azure DevOps organization and a project if you haven't already.
Create a new feed if you don't have one already.
Install PowerShell 6.0 or later to ensure you have the required PowerShellGet version needed for installing PSResourceGet.
Install PSResourceGet.
Install the SecretManagement and SecretStore modules.
Note
Azure Artifacts Credential Provider is not supported with PSResourceGet.
Create a personal access token
A personal access token acts as your digital identity and serves as an alternative password to authenticate you with Azure DevOps.
Navigate to your Azure DevOps organization
https://dev.azure.com/<ORGANIZATION_NAME>/
Select the user settings icon, select Personal access tokens, and then select New Token.
Enter a name for your PAT, set an Expiration date, select Custom defined, and then select Packaging > Read, write & manage.
Select Create when you're done, and make sure you copy and store your PAT in a safe location.
Create a PowerShell module
If you don't have your own module, follow the instructions in this section to create a sample PowerShell module. Otherwise, skip to the next step:
Create a new folder PowerShell-Demo. Navigate into your folder and create a new file PowerShell-Demo.psm1.
Paste the following script into your PowerShell-Demo.psm1 file:
Function PowerShell-Demo{ Write-Host "Hello World!" }
Generate the module manifest by running the following command in your PowerShell-Demo directory:
New-ModuleManifest -Path .\PowerShell-Demo.psd1
Open your PowerShell-Demo.psd1 file and locate the
RootModule
variable. This setting specifies the main script file that PowerShell loads when the module is imported. Replace the empty string with the path to your PowerShell-Demo.psm1 file:RootModule = 'PowerShell-Demo.psm1'
The
FunctionsToExport
section specifies which functions are accessible to users when they import your module. Include your PowerShell-Demo function:FunctionsToExport = @('PowerShell-Demo')
Locate the
FileList
section, which lists the files included when packaging the module. Add the file you wish to package with your module:FileList = @('./PowerShell-Demo.psm1')
Register a repository
Run the following command to create a credential object. Replace the placeholders with the correct information.
$username = "<USER_NAME>" $patToken = "<PERSONAL_ACCESS_TOKEN>" | ConvertTo-SecureString -AsPlainText -Force $credentials = New-Object System.Management.Automation.PSCredential($username, $patToken)
Ensure that SecretManagement and SecretStore are installed, then run the following command to create a vault and add a secret:
Register-SecretVault -Name "MySecretVault" -ModuleName Microsoft.PowerShell.SecretStore -DefaultVault Set-Secret -Name "MyCredential" -Secret $credentials -Vault "MySecretVault" $CredentialInfo = [Microsoft.PowerShell.PSResourceGet.UtilClasses.PSCredentialInfo]::new('MySecretVault', 'MyCredential')
To verify if the vault and secret were successfully created, run the following command to list all your secrets:
PS > Get-SecretInfo Name Type VaultName ---- ---- --------- MyCredential PSCredential MySecretVault
Run the following command to register your PowerShell repository. You can find the
SourceLocation
link by navigating to Artifacts > Connect to Feed > NuGet.exe, under the Project setup section > source URL.Project-scoped feed:
Register-PSResourceRepository -Name "PowershellPSResourceRepository" ` -Uri "https://pkgs.dev.azure.com/<ORGANIZATION_NAME>/<PROJECT_NAME>/_packaging/<FEED_NAME>/nuget/v3/index.json" ` -Trusted ` -CredentialInfo $CredentialInfo
Organization-scoped feed:
Register-PSResourceRepository -Name "PowershellPSResourceRepository" ` -Uri "https://pkgs.dev.azure.com/<ORGANIZATION_NAME>/_packaging/<FEED_NAME>/nuget/v3/index.json" ` -Trusted ` -CredentialInfo $CredentialInfo
Tip
Some versions of PowerShell may require starting a new session after running the
Register-PSResourceRepository
cmdlet to prevent encountering the Unable to resolve package source warning.To verify if the repository was successfully registered, run the following command to retrieve all registered repositories for the current user:
Get-PSResourceRepository
Note
If you encounter the error: Response status code does not indicate success: 404 (Not Found)., make sure that your source URL points to nuget/v3/index.json
instead of nuget/v2
.
Publish a package
Run the following command to publish the package to your feed:
Publish-PSResource -Path <PACKAGE_PATH> -Repository <REPOSITORY_NAME> -ApiKey (Get-Secret <SECRET_NAME>)
Example:
PS C:\AzureDevOps\Demos\PowerShellDemo> Publish-PSResource -Path .\scripts\ -Repository FabrikamFiberFeed -ApiKey (Get-Secret MyNewCredential) -verbose
VERBOSE: Performing the operation "Publish-PSResource" on target "Publish resource
'C:\AzureDevOps\Demos\PowerShellDemo\scripts\' from the machine".
VERBOSE: The newly created nuspec is:
C:\Users\xxxx\AppData\Local\Temp\xxxxxxxxx\PowerShell-Demo.nuspec
VERBOSE: credential successfully read from vault and set for repository: FabrikamFiberFeed
VERBOSE: Successfully packed the resource into a .nupkg
VERBOSE: Successfully published the resource to
'https://pkgs.dev.azure.com/ramiMSFTDevOps/DemoProject/_packaging/FabrikamFiberFeed/nuget/v3/index.json'
VERBOSE: Deleting temporary directory 'C:\Users\xxxx\AppData\Local\Temp\xxxxxxx'
Install a package
To confirm if the module is available in your repository, use the following command to search for it:
Find-PSResource -Name <RESOURCE_NAME> -Repository <REPOSITORY_NAME> -verbose
Run the following command to install the latest stable version of your module:
Install-PSResource <MODULE_NAME>
Tip
If you encounter the error: Exception calling "WriteObject"., start a new PowerShell window and run Get-SecretInfo
. Enter your vault password before running Find-PSResource and Install-PSResource, as the SecretStore timeout period can expire. The default PasswordTimeout is 900 seconds, but you can modify this value as needed. See Use the SecretStore in automation for more details.
In this article, you'll learn how to:
- Create a Personal Access Token
- Create, package, and publish a PowerShell module
- Connect to a feed as a PowerShell repository
- Register and install a PowerShell module using Azure Pipelines
Prerequisites
Create an Azure DevOps organization and a project if you haven't already.
Create a new feed if you don't have one already.
Install the Azure Artifacts Credential Provider.
Install Windows MSBuild using one of the following options:
Install the NuGet(.exe) version 4.8.0.5385 or later.
Install the dotnet runtime version 8.0.x or later.
Install PowerShell 6.0 or later to ensure you have the appropriate PowerShellGet and PackageManagement versions.
Create a personal access token
A personal access token acts as your digital identity and serves as an alternative password to authenticate you with Azure DevOps.
Navigate to your Azure DevOps organization
https://dev.azure.com/<ORGANIZATION_NAME>/
Select the user settings icon, select Personal access tokens, and then select New Token.
Enter a name for your PAT, set an Expiration date, select Custom defined, and then select Packaging > Read, write & manage.
Select Create when you're done, and make sure you copy and store your PAT in a safe location.
Create a PowerShell module
If you don't have your own module, follow the instructions in this section to create a sample PowerShell module. Otherwise, skip to the next step:
Create a new folder Get-Hello. Navigate into your folder and create a new file Get-Hello.psm1.
Paste the following script into your Get-Hello.psm1 file:
Function Get-Hello{ Write-Host "Hello Azure DevOps!" }
Generate the module manifest by running the following command in your Get-Hello directory:
New-ModuleManifest -Path .\Get-Hello.psd1
Open your Get-Hello.psd1 file and locate the
RootModule
variable. This setting specifies the main script file that PowerShell loads when the module is imported. Replace the empty string with the path to your Get-Hello.psm1 file:RootModule = 'Get-Hello.psm1'
The
FunctionsToExport
section specifies which functions are accessible to users when they import your module. Include your Get-Hello function:FunctionsToExport = @('Get-Hello')
Find the
FileList
section, which specifies the files included when packaging the module. Add the file you wish to package with your module:FileList = @('./Get-Hello.psm1')
Package and publish a module
Generate a nuspec file for your module. This command creates a Get-Hello.nuspec file containing the necessary metadata for packing the module:
nuget spec Get-Hello
Run the following command to package your module:
nuget pack Get-Hello.nuspec
Run the following command to add your feed source URL. Make sure that you use V2 in your feed source URL, as NuGet V3 is not supported.
Organization-scoped feed:
nuget sources Add -Name "<FEED_NAME>" -Source "https://pkgs.dev.azure.com/<ORGANIZATION_NAME>/_packaging/<FEED_NAME>/nuget/v2" -username "<USER_NAME>" -password "<PERSONAL_ACCESS_TOKEN>"
Project-scoped feed:
nuget sources Add -Name "<FEED_NAME>" -Source "https://pkgs.dev.azure.com/<ORGANIZATION_NAME>/<PROJECT_NAME>/_packaging/<FEED_NAME>/nuget/v2" -username "<USER_NAME>" -password "<PERSONAL_ACCESS_TOKEN>"
Publish the package to your feed:
nuget push -Source "<FEED_NAME>" -ApiKey "<ANY_STRING>" "<PACKAGE_PATH>"
Important
The version number in your Module Manifest (.psd1) must be identical to the version number in your .nuspec file.
Connect to a feed as a PowerShell repository
This section guides you through authenticating with a feed as a PowerShell repository and consuming a module hosted in your feed:
In a PowerShell prompt window, run the following command to set up your credentials. Replace the placeholders with the appropriate information.
$patToken = "<PERSONAL_ACCESS_TOKEN>" | ConvertTo-SecureString -AsPlainText -Force $credsAzureDevopsServices = New-Object System.Management.Automation.PSCredential("<USER_NAME>", $patToken)
Register your PowerShell repository. You can find the
SourceLocation
link by navigating to Artifacts > Connect to Feed > NuGet.exe, under the Project setup section > source URL.Project-scoped feed:
Register-PSRepository -Name <REPOSITORY_NAME> -SourceLocation "https://pkgs.dev.azure.com/<ORGANIZATION_NAME>/<PROJECT_NAME>/_packaging/<FEED_NAME>/nuget/v2" -PublishLocation "https://pkgs.dev.azure.com/<ORGANIZATION_NAME>/<PROJECT_NAME>/_packaging/<FEED_NAME>/nuget/v2" -InstallationPolicy Trusted -Credential $credsAzureDevopsServices
Organization-scoped feed:
Register-PSRepository -Name <REPOSITORY_NAME> -SourceLocation "https://pkgs.dev.azure.com/<ORGANIZATION_NAME>/_packaging/<FEED_NAME>/nuget/v2" -PublishLocation "https://pkgs.dev.azure.com/<ORGANIZATION_NAME>/_packaging/<FEED_NAME>/nuget/v2" -InstallationPolicy Trusted -Credential $credsAzureDevopsServices
Tip
Some versions of PowerShell may require starting a new session after running the
Register-PSRepository
cmdlet to prevent encountering the Unable to resolve package source warning.Register your package source:
Project-scoped feed:
Register-PackageSource -Name <REPOSITORY_NAME> -Location "https://pkgs.dev.azure.com/<ORGANIZATION_NAME>/<PROJECT_NAME>/_packaging/<FEED_NAME>/nuget/v2" -ProviderName NuGet -Trusted -SkipValidate -Credential $credsAzureDevopsServices
Organization-scoped feed:
Register-PackageSource -Name <REPOSITORY_NAME> -Location "https://pkgs.dev.azure.com/<ORGANIZATION_NAME>/_packaging/<FEED_NAME>/nuget/v2" -ProviderName NuGet -Trusted -SkipValidate -Credential $credsAzureDevopsServices
Note
- Register-PSRepository: Used for registering a PowerShell repository to find and install modules.
- Register-PackageSource: Used to register a package source for finding and publishing packages.
To verify if the repository was successfully registered, run the following command to retrieve all registered repositories for the current user:
Get-PSRepository
Run the following command to install the Get-Hello module.
Install-Module -Name <PACKAGE_NAME> -Repository <REPOSITORY_NAME>
Note
If your organization uses a firewall or a proxy server, make sure that you allow access to Azure Artifacts Domain URLs and IP addresses.
Install a package from your pipeline
This example walks you through authenticating with an Azure Artifacts feed and installing a PowerShell module from your pipeline. To use your personal access token, add it as a pipeline variable, as shown below:
Sign in to your Azure DevOps organization, and then navigate to your project.
Select Pipelines, select your pipeline definition, and then select Edit to modify your pipeline.
Select Variables at the top right corner, and then select New variable.
Enter a Name for your variable, and then paste your personal access token into the Value textbox.
Make sure that you select the Keep this value secret checkbox. Select Ok when you're done.
Add a second variable for your userName. Enter a Name for your variable, then input your userName in the Value textbox.
Select Save when you're done.
trigger:
- main
pool:
vmImage: 'Windows-latest'
variables:
PackageFeedEndpoint: 'https://pkgs.dev.azure.com/<ORGANIZATION_NAME>/<PROJECT_NAME>/_packaging/<FEED_NAME>/nuget/v2' ## For organization scoped feeds use'https://pkgs.dev.azure.com/<ORGANIZATION_NAME>/_packaging/<FEED_NAME>/nuget/v2'
steps:
- powershell: |
$pat = ConvertTo-SecureString ${env:pat_token} -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential("${env:userName}", $pat)
Register-PSRepository -Name <REPOSITORY_NAME> -SourceLocation "$(PackageFeedEndpoint)" -InstallationPolicy Trusted -Credential $credential
displayName: 'Register PSRepository'
env:
pat_token: $patToken
userName: $userName
- powershell: |
nuget install <PACKAGE_NAME> -Source "https://pkgs.dev.azure.com/<ORGANIZATION_NAME>/<PROJECT_NAME>/_packaging/<FEED_NAME>/nuget/v3/index.json"
displayName: 'Install module'