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

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](https://www.powershellgallery.com/packages/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](https://cdn.hashnode.com/res/hashnode/image/upload/v1705413442487/ede74da2-3a6a-4875-ab16-c19145e87026.png align="center")

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

```powershell
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](https://www.powershellgallery.com/packages/Microsoft.Graph.Groups/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/](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](https://cdn.hashnode.com/res/hashnode/image/upload/v1705413973232/6aee71ce-c313-47a6-bd4b-74377781e1ea.png align="left")

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`.

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">If you don't specify <code>moduleVersion</code> parameter, the newest supported version will be imported!</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">To avoid unnecessary dependent module updates, if a module with a supported version already exists, it won't be updated to the newest one.</div>
</div>

## 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).

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Because Azure Runbooks support more PSH runtime versions (<code>5.1</code>, <code>7.2</code>), <code>New-AzureAutomationModule</code> searches only for modules that support given runtime 👍</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">👎</div>
<div data-node-type="callout-text">Runtime <code>7.1</code> is shown in Runbook GUI, but official commands don't support it, nor do I.</div>
</div>

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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1705401734789/7fd4e310-034e-493a-bb33-97eded2c4974.png align="center")

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

```powershell
Install-Module AzureResourceStuff
```

## Connect to your Azure subscription where Automation Account is placed

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

## Import/Update module to the newest supported version

```powershell
# 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

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1705425225612/07e2663a-9be2-411c-8971-bab4996ce25d.png align="center")

## Import/Update module to a specific version

```powershell
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`"

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1705402848756/1eac3bd3-e310-473c-8ef9-f076cd9dafcd.png align="center")

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

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1705403153956/b715c111-4856-43c1-aaff-12e2dd62f9cc.png align="left")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1705403162088/63c3b617-4633-475c-a57e-2dc1760d8c36.png align="left")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1705403169371/d230119a-5768-4a24-8693-da1471b6ad5e.png align="left")

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

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">If there is no error, try to import the module manually through GUI. Once it fails again, there should be some error message.</div>
</div>

---

# 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](https://www.powershellgallery.com/packages/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 [DependencySearch](https://www.powershellgallery.com/packages/DependencySearch) module
    

```powershell
Install-Module DependencySearch
```

* Save your runbook code locally to the `ps1` file
    
    * Let's say this is how the Runbook looks like
        
    * ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1705932901114/ab8c44c2-bb33-40c8-81d5-bc40404802bc.png align="center")
        
    * And I will save it to `C:\temp\runbookcode.ps1`
        
* Get the code dependencies using `Get-CodeDependency` function
    

```powershell
Get-CodeDependency -scriptPath C:\temp\runbookcode.ps1 -unknownDependencyAsObject -Verbose
```

* And you should see something like this
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1705933291297/8d6649c1-c280-47a7-a263-7a2a4b9300be.png align="center")
    
* 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
    

```powershell
$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](https://www.powershellgallery.com/packages/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](https://www.powershellgallery.com/packages/DependencySearch) module) you know, **which modules** your Runbooks need.

😎
