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

I am using release management through Visual Studio Teams Services (online). We use Hosted build Agents and I really want to avoid the overhead of managing custom agents.
One item I do need is the AzureRM PowerShell module. Versions up to 5.1.1 are available on the agent but I need 6.0.0.
What I would like to do is use a step in my release process (PowerShell) to aquire version 6.0.0 and use thart instead, however I cant quite get it to work. I have tried a few approaches that have all come unstuck, the current one is:
Write-Output "------------------ Install package provider ------------------"
Find-PackageProvider -Name "NuGet" | Install-PackageProvider -Scope CurrentUser -Force
Write-Output "------------------ Remove Modules ------------------"
Get-Module -ListAvailable | Where-Object {$_.Name -like 'AzureRM*'} | Remove-Module
Write-Output "------------------ Install the AzureRM version we want - 6.0.1! ------------------"
Install-Package AzureRM -RequiredVersion 6.0.1 -Scope CurrentUser -Force
Write-Output "------------------ Import AzureRM 6.0.1 ------------------"
Import-Module AzureRM -RequiredVersion 6.0.1
This all works fine (i.e. does not crash...) but then when I try and use one of the 6.0.1 cmdlets I get an error.
Get-AzureRmADGroup : The Azure PowerShell session has not been
properly initialized. Please import the module and try again.
Any idea of where I am going wrong or alternate strategies I can use to deploy AzureRM 6.0.1 and use it on a hosted agent?

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):
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.
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:
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 ------------------"

Related

Powershell: Unable to update PowerShellGet , error: The version '1.4.7' of module 'PackageManagement' is currently in use

Win10 laptop, in service for a couple years.
I have been stuck on this for a couple of days.
I try this command:
Install-Module –Name PowerShellGet –Force -AllowClobber
Which throws this error:
WARNING: The version '1.4.7' of module 'PackageManagement'
is currently in use. Retry the operation after closing the applications.
I can see in task manager there are no other sessions of powershell running.
I can exit all the sessions, and run this from a plain cmd:
powershell -NoProfile -Command "Install-Module -Name PowerShellGet -Force -AllowClobber"
And I get the SAME error.
OK, so I exit all powershell instances (as seen in Details tab of taskmgr) and do this:
powershell -NoProfile -Command "Uninstall-Module PowerShellGet"
powershell -NoProfile -Command "Install-Module -Name PowerShellGet -Force -AllowClobber"
And I get the same error.
So I do the uninstall again, (which runs without messages or errors). And I take out the big guns... powershell.exe is not running, and I navigate to:
C:\Users\$user\Documents\WindowsPowerShell\Modules\PackageManagement\1.4.7
And I delete the 1.4.7 directory.
And the commands above run with the same behavior and same error.
How do I move past this?
Additional Background:
PS C:\WINDOWS\system32> Get-Module -ListAvailable PowerShellGet,PackageManagement
Directory: C:\Program Files\WindowsPowerShell\Modules
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 1.4.7 PackageManagement {Find-Package, Get-Package, Get-PackageProvider, Get-Packa...
Binary 1.0.0.1 PackageManagement {Find-Package, Get-Package, Get-PackageProvider, Get-Packa...
Script 2.2.5 PowerShellGet {Find-Command, Find-DSCResource, Find-Module, Find-RoleCap...
Script 1.0.0.1 PowerShellGet {Install-Module, Find-Module, Save-Module, Update-Module...}
PS C:\WINDOWS\system32> Get-Module -ListAvailable PowerShellGet,PackageManagement | % path
C:\Program Files\WindowsPowerShell\Modules\PackageManagement\1.4.7\PackageManagement.psd1
C:\Program Files\WindowsPowerShell\Modules\PackageManagement\1.0.0.1\PackageManagement.psd1
C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\2.2.5\PowerShellGet.psd1
C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\1.0.0.1\PowerShellGet.psd1
Also Tried
Limiting scope to current user:
PS C:\WINDOWS\system32> Install-Module -Name PowerShellGet -Force -Scope CurrentUser
WARNING: The version '1.4.7' of module 'PackageManagement' is currently in use. Retry the operation after closing the
applications.
PS C:\WINDOWS\system32> exit
# OK, check taskmgr that all powershell.exe have exited, and run the below
C:\WINDOWS\system32>powershell -command "Install-Module -Name PowerShellGet -Force -Scope CurrentUser"
WARNING: The version '1.4.7' of module 'PackageManagement' is currently in use. Retry the operation after closing the
applications.
SOLUTION
I did not track exactly the step, but one of the comments below led to a path that did resolve.
One of the tricks was to watch the process list, and to be sure that all vscode and other powershell-loading process were terminated prior to doing the update.
Apologies I cannot document the exact step that resolved. (I was kind of toast working on this.)
I was able to fix this by running the command below in an admin PowerShell:
Update-Module -Name PowerShellGet -RequiredVersion 2.2.5
Hope this helps others!
Source: https://github.com/PowerShell/PowerShellGetv2/issues/599
I don't have the rep to post a comment, but James Graham's post suggesting using the Update-Module worked for me too. Exact same issue, with the exact same version numbers, almost a year later. Yet, I just checked and there's now a 3.0.12 beta available which requires the code below:
Install-Module -Name PowerShellGet -AllowPrerelease -Force
I tried for a while to figure out the syntax highlighting but to no avail.
I'm using PS 7 and was having the same problem.
Steps I followed to fix the issue...:
Listed module folders using $env:PSModulePath -split ';'. Result was list of paths where modules are stored as per scope (read here for more on the topic).
List of Paths:
- C:\Users\**USER**\OneDrive - Microsoft\Documents\PowerShell\Modules
- C:\ProgramFiles\PowerShell\Modules
- **c:\program files\powershell\7\Modules**
- C:\Program Files\WindowsPowerShell\Modules
- C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules
- C:\Program Files (x86)\Microsoft Azure Information Protection\Powershell
look for the folder called PackageManagement (it was in C:\Program Files\PowerShell\7\Modules in my case)
Rename it (don't recommend deleting!)
Get-InstalledModule to make sure I PackageManagement is not there anymore
Install-Module -name PowerShellGet -RequiredVersion 2.2.5 -Force to install PowerShellGet.
and job's a good'un! At least for me :)

How to install PowerShell module pushed to Azure Artifacts in Pipelines?

Following this article I set up Pipelines to push a PowerShell module to my Artifacts feed.
I can install the module on my local machine, but I was wondering how I can do the same in Pipelines? It seems adding the NuGet source is an interactive process, so how can Pipelines add the Artifacts feed as a source?
The issue is that I don't want to have any user interaction in a CI environment.
If you are using self-hosted agent, you need to configure the folder module permission, self-hosted agent run the cmd via service account instead of personal account.
If you are using hosted agent, add the task power shell and enter below script to install the module.
$patToken = "$(pat)" | ConvertTo-SecureString -AsPlainText -Force
$credsAzureDevopsServices = New-Object System.Management.Automation.PSCredential("xxx", $patToken)
Register-PSRepository -Name "PowershellAzureDevopsServices" -SourceLocation "https://pkgs.dev.azure.com/{Org name}/{project name}/_packaging/{feed name}/nuget/v2" -PublishLocation "https://pkgs.dev.azure.com/{Org name}/{project name}/_packaging/{feed name}/nuget/v2" -InstallationPolicy Trusted -Credential $credsAzureDevopsServices
Get-PSRepository
Find-Module -Repository PowershellAzureDevopsServices -Credential $credsAzureDevopsServices
Install-Module -Name Get-Hello -Repository PowershellAzureDevopsServices -Credential $credsAzureDevopsServices
Get-Module -ListAvailable Get-Hello
Result:
Update1
We need to enter the code during the registration of the power supply enclosure repository, the method is Register-PSRepository
This is a certification issue, If we change the authentication method, maybe we don’t need to enter the code.
In addition, We could also install the module via the cmd Install-Module Get-Hello -Scope CurrentUser -Force

Issues with PowerShell Repositories on Azure DevOps Agents

Sorry for the very long post, but I am really stuck and hope someone can help.
I've been back and forth so many times and I am hitting many issues with everything that has to do with PowerShell repositories and Azure DevOps agents.
The end goal is to have the latest versions of some PowerShell modules installed as part of a pipeline.
I write various PowerShell modules, package them as NuGets and push them to different repositories (Azure DevOps artifacts, SonaType Nexus OSS)
I then need these modules installed as part of other pipelines.
As there is no built-in way in Azure DevOps to handle PowerShell repositories and import modules, I wrote a script that takes the repository location, name and credentials as parameters, verifies it is registered and installs the module.
When I run this script on ANY machine, it works perfectly
When this script is a PowerShell task on any pipeline - it has various failures, always with cmdlets from PackageManagement
I thought this is because the agent is running it with -NoProfile, but it works for me when I run the script exactly how the agent runs it - "powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command ". 'C:.....'"
I also tried running a cmd task and calling PowerShell to run the script but had the exact same results
The problems I am hitting are:
Get-PSRepository returns NOTHING. Not even PSGallery
When I try to register a repository (using either Register-PSRepository or Register-PackageSource) it throws an error:
PackageManagement\Register-PackageSource : The property 'Values' cannot be found on this object. Verify that the property exists.
as part of my script, I am running these cmdlets to make sure all the required modules are there:
$webclient=New-Object System.Net.WebClient; $webclient.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials; [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; Install-PackageProvider -Name NuGet -RequiredVersion 2.8.5.208 -Force -Confirm:$false -Verbose; Install-Module PowerShellGet -RequiredVersion 2.2.4 -SkipPublisherCheck -Verbose -Force;
Another error that comes up is this:
PackageManagement\Get-PackageSource : Unable to find repository 'PSGallery'. Use Get-PSRepository to see all available repositories.
I spent hours on this.
What is the correct way to install PS modules from a 3rd party repository (NuGet-based)
Thanks
I noticed that you have push your nuget package to Azure Artifacts.
You could add Powershell tasks to the pipeline and run the following scripts:
Register-PSRepository:
$patToken = "PAT" | ConvertTo-SecureString -AsPlainText -Force
$credsAzureDevopsServices = New-Object System.Management.Automation.PSCredential("email address", $patToken)
Register-PSRepository -Name "PowershellAzureDevopsServices" -SourceLocation "https://pkgs.dev.azure.com/<org_name>/<project_name>/_packaging/<feed_name>/nuget/v2" -PublishLocation "https://pkgs.dev.azure.com/<org_name>/<project_name>/_packaging/<feed_name>/nuget/v2" -InstallationPolicy Trusted -Credential $credsAzureDevopsServices
Then you could register successfully.
Note: I suggest that you could create a Project Scope feed. Or you may get some issues.
Then you could run the following scripts to install the module.
Find-Module -Repository PowershellAzureDevopsServices
Install-Module -Name Get-Hello -Repository PowershellAzureDevopsServices
For more detailed information, you could refer to this Guidance Document.

Installing Azure Powershell error after installation

Good Morning,
I was trying to install Azure powershell to connect to my server. I made sure I was up to date on all my versions. Then I ran the: Install-Module -Name AzureRM -AllowClobber command. Everything downloaded perfectly and was unzipped successfully.
*Then I know I have to load the AzureRM module so I ran the command: Import-Module -Name AzureRM
*After I ran the command nothing happens! I press ENTER but I just get brought down one line like the command does not even exist.
*I ran the (get-command -module azurerm).count and it showed count of 0.
**So from what I gathered it downloaded/unzipped/installed/but will not actually load?
*To make more sense I followed the instructions from the following youtube video: https://www.youtube.com/watch?v=3Q0jG1Doa-s&t=181s
**Any help will be greatly appreciated. Trying to install it to be able to change email names for office 365. Thanks!
PS: I made sure I have version 5.0 of power shell
Version Of Powershell Picture
: https://i.stack.imgur.com/e7ffr.jpg
[Blanks I get after running command. (nothing happens!)]
: https://i.stack.imgur.com/td9Jv.jpg
On the off chance you had the AzureRM module installed already, either open a new Powershell session or run...
Import-Module -Name AzureRM -Force
To double check the module was installed correct, enter...
Get-Module -Name Azure*
Ensure the version is what you want.
When I install AzureRM on a fresh machine, I do...
Get-Module -Name PowerShellGet -ListAvailable | Select-Object -Property Name,Version,Path
Install-Module PowerShellGet -Force
Install-Module -Name AzureRM -AllowClobberso
Import-Module -Name AzureRM
This worked for me on a fresh Windows 10 15063-build.

PowerShell package source confirmation

I'm trying to create a function that will automatically install, update and import on demand a PowerShell module from repository PSGallery and this will be run on a build server so I have to avoid any kind of confirmation prompts. This function will be called quite often and will not try to install or update modules if the module is already loaded to the session (only the first time).
# Already imported? Let's not go further with updates and import again...
if (Get-Module -Name $moduleName)
{
Write-Host "'$moduleName' is already imported to the current session!"
return
}
If the module is not already installed, I will try to install it. The problem is when I get to the step that I have to install the NuGet PackageManagement provider (before importing PowerShellGet module needed to install modules from PSGallery). I do the following cmdlet:
Install-PackageProvider -Name "NuGet" -Confirm:$false -Verbose
But I get the following confirmation prompt:
I could solve this issue by using the -Force parameter like that:
Install-PackageProvider -Name "NuGet" -Confirm:$false -Force -Verbose
But the problem I see with that solution (might not be a big deal) is that using -Force will download and install again NuGet every time even if the installed version is up to date. Without the -Force parameter, it will just skip it if the version is up to date and I would much rather that.
Is there a way to set the package source 'https://oneget.org/nuget-2.8.5.208.package.swidtag' as trusted so I don't get the confirmation prompt again without having to use -Force parameter?
Actually, if you run Get-PackageProvider -Name "NuGet" -Force it will automatically download and install it if its not installed. If it is installed, it returns NuGet as an object. My PowerShell version is 5.1.14393.1480.
Original Response:
Maybe you could just check to see if its available and then run your command?
$NuGetProvider = Get-PackageProvider -Name "NuGet" -ErrorAction SilentlyContinue
if ( -not $NugetProvider )
{
Install-PackageProvider -Name "NuGet" -Confirm:$false -Force -Verbose
}
Not sure if this will help, but here goes nothing:
Can you use the cmd version of try-catch using errorlevel?
Install-PackageProvider -Name "NuGet" -Confirm:$false -Verbose
if errorlevel 1 GOTO Forced
exit /b
:Forced
Install-PackageProvider -Name "NuGet" -Confirm:$false -Force -Verbose
How about using the -ForceBoostrap parameter on Get-PackageProvider, e.g.
Get-PackageProvider -Name "nuget" -ForceBootstrap