Import new (or update existing) PowerShell module (including its dependencies!) into Azure Automation Account using PowerShell

Import new (or update existing) PowerShell module (including its dependencies!) into Azure Automation Account using PowerShell

ยท

5 min read

I bet you would agree that importing PowerShell modules to Azure Automation Account using GUI is super annoying.

Moreover, if such a module has some dependencies, you have to import them one by one beforehand and often in the correct order too. Not to mention that such modules can have their own dependencies ๐Ÿ˜ฑ.

And the same pain goes for module updating.

These were the reasons why I created the PowerShell function New-AzureAutomationModule (part of my AzureResourceStuff module) which do all this heavy lifting for you ๐Ÿ‘.


How does it work?

There is a (very simplified) diagram that can help you to understand how the function works

flow diagram

Let's say you want to import the module Microsoft.Graph.Groups. Therefore we will use the following command:

New-AzureAutomationModule -moduleName "Microsoft.Graph.Groups" -runtimeVersion "5.1" -resourceGroupName "<resourceGroupName>" -automationAccountName "<automationAccountName>"

We haven't specified the module version therefore the newest supported one will be imported. Right now it is 2.11.1.

Function New-AzureAutomationModule leverages built-in command Find-Module to find all dependencies of the Microsoft.Graph.Groups module directly from https://www.powershellgallery.com/. In this particular case, there is only one dependency and that is Microsoft.Graph.Authentication module in version 2.11.1, which will be installed automatically beforehand.

dependencies as can be seen on Gallery site

Because Microsoft.Graph.Authentication doesn't have any dependencies, no other modules will be imported.

Function therefore checks whether there is already an imported module Microsoft.Graph.Authentication in the version 2.11.1 and imports/updates it in case it isn't. The same goes for module Microsoft.Graph.Groups.

๐Ÿ’ก
If you don't specify moduleVersion parameter, the newest supported version will be imported!
๐Ÿ’ก
To avoid unnecessary dependent module updates, if a module with a supported version already exists, it won't be updated to the newest one.

What "supported" version mean?

PSH modules should contain in their manifest what PSH version (runtime) they support.

So when I am talking about "supported" version. I mean version of the module that officially supports given runtime (by default 5.1).

๐Ÿ’ก
Because Azure Runbooks support more PSH runtime versions (5.1, 7.2), New-AzureAutomationModule searches only for modules that support given runtime ๐Ÿ‘
๐Ÿ‘Ž
Runtime 7.1 is shown in Runbook GUI, but official commands don't support it, nor do I.

Unfortunately, there can be a situation where the module author forgot to update the manifest file. Hence even though requires PSH Core (7.x) it doesn't say it. This breaks my function because if no specific version is specified, it searches for the newest one that supports a given runtime.

Like PnP.PowerShell module in versions 2.1.1 and 2.2.0. Those modules require PSH Core, but it is required in the manifest since 2.3.0 version.

To avoid this issue, there is a function parameter overridePSGalleryModuleVersion which by default forces the use of 1.12.0 module PnP.PowerShell version for 5.1 runtime, so in the case of PnP.PowerShell , you don't have to worry about it ๐Ÿ‘.

But there can be other modules with the same problem too, so don't forget about this parameter ๐Ÿ™‚.


How to use it

Prepare the environment

Install AzureResourceStuff module

Install-Module AzureResourceStuff

Connect to your Azure subscription where Automation Account is placed

Connect-AzAccount -Tenant "<contoso.onmicrosoft.com>" -SubscriptionName "<NameOfYourAutomationSubscription>"

Import/Update module to the newest supported version

# without specifying moduleVersion parameter, newest possible will be imported
New-AzureAutomationModule -resourceGroupName '<resourceGroupName>' -automationAccountName '<automationAccountName>' -moduleName Microsoft.Graph.Groups -runtimeVersion 5.1

And you should see something like this

Import/Update module to a specific version

New-AzureAutomationModule -resourceGroupName '<resourceGroupName>' -automationAccountName '<automationAccountName>' -moduleName Microsoft.Graph.Groups -moduleVersion 2.11.1 -runtimeVersion 5.1

Import fails, what can I do?

If you get the error "New-AzureAutomationModule : Import failed"

Search for the imported module in Azure Portal >> Automation Account >> Modules >> <nameOfTheModule>. And check its details.

In this particular case, the error says that the imported module isn't supported in the used 5.1 runtime.

๐Ÿ’ก
If there is no error, try to import the module manually through GUI. Once it fails again, there should be some error message.

Bonus: Analyze Runbook code dependencies to import just the right ones ๐Ÿ˜Ž

OK, so now you have the right tool to import your modules to the Azure Automation Account, but what about getting the list of the modules your Runbook code depends on? Don't worry I have you covered.

Let's meet the function Get-CodeDependency (part of DependencySearch module) which I will talk about in more detail another time.

This function allows you to analyze a given code to get all its dependencies (modules, pssnapins, admin privileges,...).

How to get the code dependencies

Install-Module DependencySearch
  • Save your runbook code locally to the ps1 file

    • Let's say this is how the Runbook looks like

    • And I will save it to C:\temp\runbookcode.ps1

  • Get the code dependencies using Get-CodeDependency function

Get-CodeDependency -scriptPath C:\temp\runbookcode.ps1 -unknownDependencyAsObject -Verbose
  • And you should see something like this

  • Which means that my example code requires three modules Microsoft.Graph.Authentication, Microsoft.Graph.Users, Microsoft.Graph.Identity.DirectoryManagement which I can easily import to my Azure Automation Account using the following command

$resourceGroupName = '<resourceGroupName>'
$automationAccountName = '<automationAccountName>'

'Microsoft.Graph.Authentication', 'Microsoft.Graph.Users', 'Microsoft.Graph.Identity.DirectoryManagement' | % {
    New-AzureAutomationModule -moduleName $_ -resourceGroupName $resourceGroupName -automationAccountName $automationAccountName
}

Summary

Now when you can use the function New-AzureAutomationModule (part of the AzureResourceStuff module), you should be no longer afraid of importing or updating any module into your Azure Automation Account anymore.

And at the same time using the function Get-CodeDependency (part of the DependencySearch module) you know, which modules your Runbooks need.

๐Ÿ˜Ž

Did you find this article valuable?

Support Ondrej Sebela by becoming a sponsor. Any amount is appreciated!

ย