Upgrade AzureRM Powershell on Hosted 2017 Agent (VSTS - Visual Studio Team Services)

Thanks to Murray for the initial point in the right direction, to show what I was hoping to do wasn't impossible!

I initially tried to do this within the Azure PowerShell task and got pretty far but hit a dead end with AzureRm.Profile as you cannot unload an old version.

The trick was to understanding how the AzureRM VSTS task does it's dependency setup, it effectively takes the "Azure Powershell Version" string in the VSTS UI and uses it to define an additional search path in the PSModules environmental variable i.e. C:\Modules\azurerm_5.1.1.

It will look in that directory, before searching the user profile, then the global modules path.

As soon as it finds the module it performs the Azure login, which will hamper any hope of removing the module after.

So if you instead use a plain powershell task i.e. one that AzureRM isn't loaded into (as Murray also concluded):

Plain Powershell Task

Install-PackageProvider -Name NuGet -Force -Scope CurrentUser
Install-Module -Name AzureRM -RequiredVersion 6.2.1 -Force -Scope CurrentUser -AllowClobber

Notably install-module won't be installing to c:\modules like the vsts image generation project.

I seemed to need AllowClobber to get around problems overriding old powershell versions when experimenting, but I suspect I don't need that anymore.

The elegant solution kicks in when next using the Azure PowerShell script.

Azure PowerShell Task

The preferred powershell version field filled in with 6.2.1 will add C:\Modules\azurerm_6.2.1 to the PSModules path. This doesn't exist, but thankfully because PSModules still includes the user specific modules path, so our 6.2.1 is loaded by itself!

Luckily the AzureRM.Profile from 5.1.1 is forwards compatible enough that the service principal login performed by the Azure Powershell task still works.

Running

Get-Module AzureRm 
Get-AzureRmContext

Will output the versions you are hoping for:

VSTS azure rm powershell versions

Notably if it weren't able to login, I think System.AccessToken could be used (if the option is switched on in the agent phase level).

Diagnostic Techniques if the workaround needs tweaking:

Things that helped greatly, reading through the code that loads in AzureRM in the task:

https://github.com/Microsoft/vsts-tasks/blob/master/Tasks/AzurePowerShellV3/AzurePowerShell.ps1#L80

https://github.com/Microsoft/vsts-tasks/blob/0703b8869041d64db994934bde97de167787ed2e/Tasks/Common/VstsAzureHelpers_/ImportFunctions.ps1

https://github.com/Microsoft/vsts-tasks/blob/master/Tasks/AzurePowerShellV3/Utility.ps1#L18

And also how the VSTS image is generated:

https://github.com/Microsoft/vsts-image-generation/blob/2f57db26dc30ae0f257a3415d26eaa8eea0febf9/images/win/scripts/Installers/Install-AzureModules.ps1

Enabing System.Debug = true as a environment release variable. Then using VSCode's Log File Highlighter plugin


I'd encourage anyone who's interested to vote in: https://github.com/Microsoft/vsts-image-generation/issues/149

As the AzureRM version at the time of writing is waaaay out of date on the VSTS Hosted 2017 agent.

Unfortunately I can't submit a PR to upgrade it, as it's pulled in via a zip file hosted privately.


I finally figured it out - adding an answer for anyone else that suffers the same.

The key is to login after the AzureRM module is upgraded.

PowerShell code:

    Write-Output "------------------ Start: Upgrade AzureRM on build host ------------------"

    Write-Output "- - - - - Install package provider"
    Install-PackageProvider -Name NuGet -Force -Scope CurrentUser

    Write-Output "- - - - - List Modules Before"
    Get-Module -ListAvailable| where {$_.Name -Like “*AzureRM*”}  | Select Name, Version

    Write-Output "- - - - - Remove alll existing AzureRM Modules" 
    Get-Module -ListAvailable | Where-Object {$_.Name -like '*AzureRM*'} | Remove-Module -Force 

    Write-Output "- - - - - Install AzureRM 6.0.1"
    Install-Module -Name AzureRM -RequiredVersion 6.0.1 -Force -Scope CurrentUser

    Write-Output "- - - - - Import AzureRM 6.0.1"
    Import-Module AzureRM -Force -Verbose -Scope Local

    Write-Output "- - - - - List Modules After"
    Get-Module -ListAvailable| where {$_.Name -Like “*AzureRM*”}  | Select Name, Version

    Write-Output "------------------ End: Upgrade AzureRM on build host ------------------"

    Write-Output "------------------ Start: LoginToAzure ------------------"

    $SecurePassword = ConvertTo-SecureString $AdminPassword -AsPlainText -Force
    $AdminCredential = New-Object System.Management.Automation.PSCredential ($AdminUserEmailAddress, $SecurePassword)
    Login-AzureRmAccount -Credential $AdminCredential

    Get-AzureRmSubscription –SubscriptionId $SubscriptionId | Select-AzureRmSubscription

    Write-Output "------------------ End: LoginToAzure ------------------"