Skip to content

Cmdlet Update-AzModule #12832

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tools/Az.Tools.Installer/Az.Tools.Installer.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
FunctionsToExport = '*'

# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
CmdletsToExport = @('Install-AzModule', 'Uninstall-AzModule')
CmdletsToExport = @('Install-AzModule', 'Uninstall-AzModule', 'Update-AzModule')

# Variables to export from this module
# VariablesToExport = @()
Expand Down
24 changes: 19 additions & 5 deletions tools/Az.Tools.Installer/Az.Tools.Installer.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,22 @@ elseif ($null -eq $module) {
Import-Module PowerShellGet -MinimumVersion 2.1.3 -Scope Global
}

$exportedPS1Files = Get-ChildItem -Path $PSScriptRoot/exports -Recurse -Include '*.ps1' -File
$internalPS1Files = Get-ChildItem -Path $PSScriptRoot/internal -Recurse -Include '*.ps1' -File
$exportedPS1Files | ForEach-Object { . $_.FullName }
$internalPS1Files | ForEach-Object { . $_.FullName }
Export-ModuleMember -Function $exportedPS1Files.Basename
$exportedFunctions = @( Get-ChildItem -Path $PSScriptRoot/exports/*.ps1 -Recurse -ErrorAction SilentlyContinue )
$internalFunctions = @( Get-ChildItem -Path $PSScriptRoot/internal/*.ps1 -ErrorAction SilentlyContinue )

$allFunctions = $exportedFunctions + $internalFunctions
foreach($function in $allFunctions) {
try {
. $function.Fullname
}
catch {
Write-Error -Message "Failed to import function $($function.fullname): $_"
}
}
Export-ModuleMember -Function $exportedFunctions.Basename

$commandsWithRepositoryParameter = @(
"Install-AzModule"
)

Add-RepositoryArgumentCompleter -Cmdlets $commandsWithRepositoryParameter -ParameterName "Repository"
124 changes: 124 additions & 0 deletions tools/Az.Tools.Installer/exports/Get-AzModuleUpdateList.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# ----------------------------------------------------------------------------------
#
# Copyright Microsoft Corporation
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ----------------------------------------------------------------------------------

function Get-AzModuleUpdateList {
[OutputType([System.Collections.ArrayList])]
[CmdletBinding(DefaultParameterSetName = 'Default', PositionalBinding = $false)]
param(
[Parameter(HelpMessage = 'The module name.')]
[ValidateNotNullOrEmpty()]
[string[]]
${Name},

[Parameter(HelpMessage = 'The Registered Repostory.')]
[ValidateNotNullOrEmpty()]
[string]
${Repository}
)

process {

$modules = New-Object System.Collections.ArrayList

Write-Debug "Retrieving installed Az modules"
$installModules = @{}
try {
(PowerShellGet\Get-InstalledModule -Name "Az*" -ErrorAction Stop).Where({
($_.Author -eq 'Microsoft Corporation' -or $_.CompanyName -eq 'Microsoft Corporation') -and ($_.Name -match "Az(\.[a-zA-Z0-9]+)?$")
}) | ForEach-Object {
$installModules[$_.Name] = @()
}
}
catch {
Write-Warning $_
}

Write-Debug "The Az modules currently installed: $($installModules.Keys)"

if ($installModules.Keys) {
foreach ($key in $installModules.Keys.Clone()) {
$installedModules = (PowerShellGet\Get-InstalledModule -Name $key -AllVersions).Where( { -not $_.AdditionalMetadata.IsPrerelease })
foreach ($installed in $installedModules) {
$installModules[$key] += [System.Tuple]::Create($installed.Version, $installed.Repository)
}
if($installModules[$key].Count -gt 1) {
$installModules[$key] = ($installModules[$key] | Sort-Object -Property @{Expression={[Version]$_.Item1}} -Descending)
}
}
}

$modulesToCheck = @()
$modulesToCheck += if ($Name) {
#Fixme:Damien
$Name.Foreach({
if ($installModules.ContainsKey($_) -and $installModules[$_]) {
[System.Tuple]::Create($_, $installModules[$_][0].Item2)
}
})
} else {
$installModules.Keys.ForEach({[System.Tuple]::Create($_, $installModules[$_][0].Item2)})
}

$moduleSet = [System.Collections.Generic.HashSet[string]]::new()
$null = $modulesToCheck | ForEach-Object {$moduleSet.Add($_.Item1)}

$index = 0
while($index -lt $modulesToCheck.Count) {
$moduleName = $modulesToCheck[$index].Item1
$repo = if ($Repository) {$Repository} else {$modulesToCheck[$index].Item2}
if($repo) {
$module = PowerShellGet\Find-Module -Name $moduleName -Repository $repo
if ($module) {
Write-Progress -Activity "Find Module" -CurrentOperation "$($module.Name) with the latest version $($module.Version)" -PercentComplete ($index / $modulesToCheck.Count * 100)
$null = $modules.Add($module)
foreach ($dep in $module.Dependencies.Name) {
if (!$moduleSet.Contains($dep)) {
$modulesToCheck += [System.Tuple]::Create($dep, $repo)
$null = $moduleSet.Add($dep)
}
}
}
}
else {
Write-Warning "Failed to find Repository of $moduleName. The module cannot be updated."
}
$index += 1
}
Write-Progress -Activity "Find Module" -Completed
$modules = ($modules | Sort-Object -Property Name -Unique)

Write-Debug "The modules to check for update: $($modules.Name)"

$modulesToUpdate = $modules.Where({ !$installModules.ContainsKey($_.Name) -or !$installModules[$_.Name] -or [Version]($_.Version) -gt [Version]$installModules[$_.Name][0].Item1 })
if ("Az" -eq ($modulesToUpdate | Select-Object -First 1).Name) {
$first, $rest = $modulesToUpdate
$modulesToUpdate = (@() + $rest + $first)
}

If (-not $modulesToUpdate) {
Write-Warning "None of your specifed module needs upgrading."
}
else {
Write-Debug "The modules contain update: $($modulesToUpdate.Name)"
}
Write-Output ($modulesToUpdate | ForEach-Object {
New-Object -Type PSObject -Property @{
'Name' = $_.Name
'VersionToUpgrade' = $_.Version
'InstalledVersion' = if ($installModules.ContainsKey($_.Name)) {$installModules[$_.Name].Item1} else {@()}
'Repository' = $_.Repository
}
})
}
}
63 changes: 0 additions & 63 deletions tools/Az.Tools.Installer/exports/Get-AzModuleWithUpdate.ps1

This file was deleted.

89 changes: 89 additions & 0 deletions tools/Az.Tools.Installer/exports/Update-AzModule.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# ----------------------------------------------------------------------------------
#
# Copyright Microsoft Corporation
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ----------------------------------------------------------------------------------

function Update-AzModule {
[OutputType([PSCustomObject[]])]
[CmdletBinding(DefaultParameterSetName = 'Default', PositionalBinding = $false, SupportsShouldProcess = $true)]
param(
[Parameter(HelpMessage = 'The module names.')]
[ValidateNotNullOrEmpty()]
[string[]]
${Name},

[Parameter(HelpMessage = 'Present to decide whether to remove the previous versions of the modules.')]
[switch]
${RemovePrevious},

[Parameter(HelpMessage = 'Update modules and override warning messages about module installation conflicts. If a module with the same name already exists on the computer, Force allows for multiple versions to be installed. If there is an existing module with the same name and version, Force overwrites that version.')]
[ValidateNotNullOrEmpty()]
[Switch]
${Force}
)

process {
$ppsedition = $PSVersionTable.PSEdition
Write-Host "Powershell $ppsedition Version $($PSVersionTable.PSVersion)"

if ($ppsedition -eq "Core") {
$allPahts = (Microsoft.PowerShell.Core\Get-Module -Name "Az*" -ListAvailable -ErrorAction Stop).Where({$_.Author -eq "Microsoft Corporation" -and $_.Name -match "Az(\.[a-zA-Z0-9]+)?$"}).Path
$allPahts = ($allPahts | Select-String -Pattern "WindowsPowerShell")
if ($allPahts) {
Write-Warning "Az modules are also installed in WindowsPowerShell. Please update them using WindowsPowerShell."
}
}

$parameters = @{}
if ($Name) {
$Name = $Name.Foreach({"Az." + $_}) | Sort-Object -Unique
$parameters['Name'] = $Name
}

Write-Debug "Time Elapsed: $((Measure-Command { $allToUpdate = Get-AzModuleUpdateList @parameters }).TotalSeconds)s"

Write-Host -ForegroundColor DarkGreen "The modules to Upddate:$($allToUpdate | Out-String)"

if($allToUpdate.Count) {
foreach ($module in $allToUpdate) {
if ($Force -or $PSCmdlet.ShouldProcess($module.Name, "Upgrade to the latest version $($module.VersionToUpgrade) from $($module.Repository)")) {
if ($Force) {
Write-Debug "Upgrade $($module.Name) to the latest version $($module.VersionToUpgrade) from $($module.Repository)."
}
PowerShellGet\Update-Module -Name $module.Name -Force:$Force
}
if ($RemovePrevious) {
if ($module.InstalledVersion -and ($Force -or $PSCmdlet.ShouldProcess($module.Name, "Uninstall the versions: $($module.InstalledVersion)"))) {
if ($Force) {
Write-Debug "Uninstall $($module.Name) of versions $($module.InstalledVersion)."
}
foreach($version in $module.InstalledVersion) {
PowerShellGet\Uninstall-Module -Name $module.Name -RequiredVersion $version
}
}
}
}

$output = @()
foreach($name in $allToUpdate.Name) {
try {
$output += (Get-InstalledModule -Name $name -ErrorAction Stop)
}
catch {
Write-Warning $_
}
}
Write-Output $output
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
function Add-RepositoryArgumentCompleter()
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string[]]$cmdlets,

[Parameter(Mandatory=$true)]
[string]$parameterName
)

try
{
if(Get-Command -Name Register-ArgumentCompleter -ErrorAction SilentlyContinue)
{
Register-ArgumentCompleter -CommandName $cmdlets -ParameterName $parameterName -ScriptBlock {
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)

Get-PSRepository -Name "$wordTocomplete*"-ErrorAction SilentlyContinue -WarningAction SilentlyContinue | Foreach-Object {
[System.Management.Automation.CompletionResult]::new($_.Name, $_.Name, 'ParameterValue', $_.Name)
}
}
}
}
catch
{
# All this functionality is optional, so suppress errors
Write-Debug -Message "Error registering argument completer: $_"
}
}
26 changes: 26 additions & 0 deletions tools/Az.Tools.Installer/internal/Add-RepositoryDefaultValue.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
function Add-RepositoryDefaultValue()
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string[]]$cmdlets,

[Parameter(Mandatory=$true)]
[string]$parameterName
)

$defaultValueMap = Get-Variable PSDefaultParameterValues -Scope Global -ValueOnly
try
{
foreach($cmdlet in $cmdlets) {
$defaultValueMap.Add("${cmdlet}:$parameterName", {(Get-PSRepository).Where( {$_.SourceLocation.Contains('www.powershellgallery.com')}).Name})
}
}
catch
{
# All this functionality is optional, so suppress errors
Write-Debug -Message "Error registering argument completer: $_"
}

Set-Variable -Scope Global -Name "PSDefaultParameterValues" -Value $defaultValueMap
}