I have created a runbook on my Octopus server that is intended to update the version of the PowerShell Az module installed on the server. The script is very simple:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Write-Host "Current version:"
Get-InstalledModule -Name Az -AllVersions | select Name,Version
Write-Host "Running update..."
Update-Module -Name Az
Write-Host "Updated version:"
Get-InstalledModule -Name Az -AllVersions | select Name,Version
When I run it, I get the following error:
Current version:
July 23rd 2021 16:17:24Error
ObjectNotFound: No match was found for the specified search criteria and module names ‘Az’.
July 23rd 2021 16:17:24Error
At C:\program files\powershell\7\Modules\PowerShellGet\PSModule.psm1:9445 char:9
July 23rd 2021 16:17:24Error
July 23rd 2021 16:17:24Error
July 23rd 2021 16:17:24Error
at Get-InstalledModule, C:\program files\powershell\7\Modules\PowerShellGet\PSModule.psm1: line 9445
July 23rd 2021 16:17:24Error
at , C:\Octopus\Work\20210723211647-82642-60\Script.ps1: line 4
July 23rd 2021 16:17:24Error
at , C:\Octopus\Work\20210723211647-82642-60\Bootstrap.Script.ps1: line 1654
July 23rd 2021 16:17:24Error
at , : line 1
July 23rd 2021 16:17:24Error
at , : line 1
July 23rd 2021 16:17:25Fatal
The remote script failed with exit code 1
July 23rd 2021 16:17:25Fatal
The action Update Az Module on the Octopus Server failed
I have the runbook configured to run locally on the Octopus server and to use PowerShell Core. This script runs fine locally in a PowerShell console on the server itself.
What is causing the issue? Is this possible?
Thanks!
Hi David,
Yes, that is completely possible. In fact, a lot of our step templates will install PS modules for you.
In looking at the code for some of them I see these functions:
$ModulesFolder = "$Home\Documents\WindowsPowerShell\Modules"
Write-Host "Modules will be installed into $ModulesFolder"
$LocalModules = (New-Item "$ModulesFolder" -ItemType Directory -Force).FullName
Write-Host "LocalModules: $LocalModules"
$env:PSModulePath = "$LocalModules;$env:PSModulePath"
Write-Host $env:PSModulePath
function GetHighestInstalledModule {
[CmdletBinding()]
Param(
[Parameter(Mandatory = $true, Position = 0)]
[string] $moduleName,
)
return Get-Module $moduleName -ListAvailable |
Sort -Property @{Expression = {[System.Version]($_.Version)}; Descending = $True} |
Select -First 1
}
function GetHighestInstallableModule {
[CmdletBinding()]
Param(
[Parameter(Mandatory = $true, Position = 0)]
[string] $moduleName
)
try {
InstallPowerShellGet
Find-Module $moduleName -AllVersions |
Sort -Property @{Expression = {[System.Version]($_.Version)}; Descending = $True} |
Select -First 1
}
catch {
Write-Warning "Could not find any suitable versions of $moduleName from any registered PSRepository"
}
}
function InstallPowerShellGet {
[CmdletBinding()]
Param()
$psget = GetHighestInstalledModule PowerShellGet
if (!$psget)
{
Write-Warning @"
Cannot access the PowerShell Gallery because PowerShellGet is not installed.
To install PowerShellGet, either upgrade to PowerShell 5 or install the PackageManagement MSI.
See https://docs.microsoft.com/en-us/powershell/gallery/installing-psget for more details.
"@
throw "PowerShellGet is not available"
}
if ($psget.Version -lt [Version]'1.6') {
#Bootstrap the NuGet package provider, which updates NuGet without requiring admin rights
Write-Debug "Installing NuGet package provider"
Get-PackageProvider NuGet -ForceBootstrap | Out-Null
#Use the currently-installed version of PowerShellGet
Import-PackageProvider PowerShellGet
#Download the version of PowerShellGet that we actually need
Write-Debug "Installing PowershellGet"
Save-Module -Name PowerShellGet -Path $LocalModules -MinimumVersion 1.6 -Force -ErrorAction SilentlyContinue
}
Write-Debug "Importing PowershellGet"
Import-Module PowerShellGet -MinimumVersion 1.6 -Force
#Make sure we're actually using the package provider from the imported version of PowerShellGet
Import-PackageProvider ((Get-Module PowerShellGet).Path) | Out-Null
}
function InstallLocalModule {
[CmdletBinding()]
Param(
[Parameter(Mandatory = $true)]
[string]$moduleName,
[Parameter(Mandatory = $true)]
[string]$localModules
)
try {
InstallPowerShellGet
Write-Debug "Install $moduleName $requiredVersion"
Save-Module -Name $moduleName -Path $LocalModules -Force -AcceptLicense -ErrorAction Stop
}
catch {
Write-Warning "Could not install $moduleName $requiredVersion from any registered PSRepository"
}
}
Putting that together:
$installedModule = GetHighestInstalledModule $moduleName
if (!$installedModule) {
Write-Verbose "$moduleName not available - attempting to download from gallery"
InstallLocalModule -moduleName $moduleName
}
else {
$newest = GetHighestInstallableModule $moduleName
if ($newest -and ($installedModule.Version -lt $newest.Version)) {
Write-Verbose "Updating $moduleName to version $($newest.Version)"
InstallLocalModule -moduleName $moduleName
}
}
I hope those examples help!