If your PowerShell repository is hosted on a public Azure Artifacts, working with that repository is no different from regular operations with PowerShell Gallery, for example. However, many enterprises prefer to keep their code base along with build artifacts private for multiple reasons: legal, security, intellectual property, internal policies and others. In this case, you might choose to go with a private Artifacts feed, and here the challenge begins.

Hosting private PowerShell repository on Azure Artifacts

Microsoft, thanks to the community effort, already published a detailed guide on how to Use Azure Artifacts as a private PowerShell repository. Also, if you examine the cmdlets from the PowerShellGet module, you can notice that many of them accept a PSCredential object as a means for authentication. You can create a PSCredential object from your personal access token (PAT) and use that object as an input parameter for registering a private repository, look for modules in it and install them.

Accessing private PowerShell repository from Azure Pipelines

When working with a private PowerShell repository hosted on Azure Artifacts from the console, the documented approach with credentials works just fine. Basically, the command logic is quite simple:

As you might see, the only difference from working with public PowerShell repositories is using the optional Credential parameter. You create your credential using your email and your generated personal access token and pass it to cmdlets.

However, if you try to run the same script in the pipeline context, you might encounter the following error:

[Minimal] [CredentialProvider]DeviceFlow: <YOUR REPOSITORY_FEED_URL>
[Minimal] [CredentialProvider]ATTENTION: User interaction required.
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code <AUTH_CODE> to authenticate.
[Error] [CredentialProvider]Device flow authentication failed. User was presented with device flow, but didn't react within 90 seconds.

When running in the pipeline, PowerShell switches to the device flow to authenticate. To be honest, I don’t know the exact reason for such behavior as of now, and I can only assume that is might be related to the way NuGet authentication plugin works.

What is strange, after a few unsuccessful attempts, the cmdlet manages to complete authentication and register the repository. However, this still negatively impacts the build process in terms of increasing the overall pipeline run time.

To mitigate this issue, a workaround is to switch from using Register-PSRepository to a more versatile Register-PackageSource. Apart from that, you can use the ‘System.AccessToken’ variable to authenticate a pipeline to a private Azure Artifacts feed so that to not worry about PAT expiration. For example, to register a private repository:

After implementing that workaround, the PowerShell cmdlets execute without any exceptions or errors, and you can register your private PowerShell repository on a build agent and install the module your build process depends on.