Sometimes the logic for the bit of work you're doing in PowerShell won't be packaged into a handy PowerShell module with cmdlets to perform the operations you need to perform. But what if there is a .NET package listed on NuGet that does contain the assemblies you need for your work? How can we import that into PowerShell and make use of its classes and methods?
This is the conundrum we recently came across while trying to update credentials for an on-prem Power BI data source using PowerShell. The tricky part in that scenario was some RSA-OAEP encryption logic that needed to be applied to the data source authentication credentials before sending the request payload to the Update Gateway Data Source API endpoint. The Power BI team had recently provided a brand new v3 .NET Power BI SDK which included helper classes for easier encryption when creating the credential objects, but these classes hadn't been translated into corresponding PowerShell cmdlets to be used as part of our deployment process. Trying to recreate those encryption helpers in PowerShell would have taken quite a bit of effort, so we really wanted to utilize this new SDK.
Once you know the method, it's really quite easy. It's how we came to this method that prompted us to write this blog, for the benefit of others that may want to do the same thing.
Installing and loading a NuGet package in a PowerShell session
If you run
Get-PackageSource in any of the latest versions of Windows PowerShell or PowerShell Core,
nuget.org should be a registered package source. Great.
So the following should be enough to install the Power BI package along with its required dependencies in a PowerShell session.
Install-Package -Name Microsoft.PowerBi.Api -ProviderName NuGet -Scope CurrentUser -RequiredVersion 3.18.1 -Destination . -Force
However, there is currently an issue with the NugGet provider within PowerShell when it comes to installing packages with dependencies which leads to a dependency loop for some packages. Some folks have managed to fix this by installing specific versions of certain dependencies before installing their target package, but I've not had the same luck with the Power BI library. So how else can this be solved?
Using the -SkipDependencies switch
Install-Package cmdlet offers a
-SkipDependencies flag which lets you install a package without installing its dependencies along with it. So this command does the trick:
Install-Package -Name Microsoft.PowerBi.Api -ProviderName NuGet -Scope CurrentUser -RequiredVersion 3.18.1 -SkipDependencies -Destination . -Force
Now to load that assembly into the session (the exact syntax here will be determined by where you specified the
-Destination of the package):
$pbipath = Resolve-Path ".\Microsoft.PowerBI.Api.3.18.1\lib\netstandard2.0\Microsoft.PowerBI.Api.dll" [System.Reflection.Assembly]::LoadFrom($pbipath)
Using classes from the imported assembly
With this setup, we can start consuming the classes from that assembly, for example:
$gatewayKeyObj = [Microsoft.PowerBI.Api.Models.GatewayPublicKey]::new("foo", "bar")
However, should you be using any classes that depend on other assemblies, you'll run into an error. For example,
$basicCredentials = [Microsoft.PowerBI.Api.Models.Credentials.BasicCredentials]::new("ab", "cd")
returns the error:
MethodInvocationException: Exception calling ".ctor" with "2" argument(s): "Could not load file or assembly 'Microsoft.Rest.ClientRuntime, Version=22.214.171.124, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The system cannot find the file specified."
As you've probably guessed, this is because of the
-SkipDependencies argument we specified when installing the initial package. We haven't installed the assemblies that some of the classes in the Power BI assembly depend on. So we do the same installation again, but for the depended-upon package:
Install-Package -Name Microsoft.Rest.ClientRuntime -ProviderName NuGet -Scope CurrentUser -RequiredVersion 2.3.22 -SkipDependencies -Destination . -Force $crpath = Resolve-Path ".\Microsoft.Rest.ClientRuntime.2.3.22\lib\netstandard2.0\Microsoft.Rest.ClientRuntime.dll" [System.Reflection.Assembly]::LoadFrom($crpath)
And once that's in the session, the previous command which was failing should run without a hitch.
This process then just needs to be repeated for each of the bits of code you're consuming that depend on other assemblies. Luckily, the Power BI assembly doesn't depend on many others (either the
net48 library or the
netstandard2.0 library) so the PowerShell doesn't get too messy. But if your target assembly has a large set of dependencies, prepare yourself for a lot of boilerplate code. You can check the dependencies of your package on the NuGet site, or using a tool like the NuGet Package Explorer.
Hope this helps!