From 1b04df89984fc25f237ce45a71d33f2ef09c6f93 Mon Sep 17 00:00:00 2001 From: Tristan Wrubleski Date: Wed, 9 Sep 2020 23:05:04 -0400 Subject: [PATCH 1/6] Added parameter $AzureModulesOnly, updated Get-ModuleDependencyAndLatestVersion to use the parameter --- Update-AutomationAzureModulesForAccount.ps1 | 41 ++++++++++++--------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/Update-AutomationAzureModulesForAccount.ps1 b/Update-AutomationAzureModulesForAccount.ps1 index fe93005..86bc745 100644 --- a/Update-AutomationAzureModulesForAccount.ps1 +++ b/Update-AutomationAzureModulesForAccount.ps1 @@ -44,6 +44,11 @@ or .PARAMETER PsGalleryApiUrl (Optional) PowerShell Gallery API URL. +.PARAMETER AzureModulesOnly +(Optional) If $false all modules, including user added will be updated. +If $true, only modules which are part of the Azure SDK will be updated. +The default value is $true. + .LINK https://docs.microsoft.com/en-us/azure/automation/automation-update-azure-modules #> @@ -63,10 +68,12 @@ param( [string] $AzureEnvironment = 'AzureCloud', [bool] $Login = $true, - + [string] $ModuleVersionOverrides = $null, - - [string] $PsGalleryApiUrl = 'https://www.powershellgallery.com/api/v2' + + [string] $PsGalleryApiUrl = 'https://www.powershellgallery.com/api/v2', + + [bool] $AzureModulesOnly = $true ) $ErrorActionPreference = "Continue" @@ -109,12 +116,12 @@ function Login-AzureAutomation([bool] $AzModuleOnly) { try { $RunAsConnection = Get-AutomationConnection -Name "AzureRunAsConnection" Write-Output "Logging in to Azure ($AzureEnvironment)..." - + if (!$RunAsConnection.ApplicationId) { $ErrorMessage = "Connection 'AzureRunAsConnection' is incompatible type." - throw $ErrorMessage + throw $ErrorMessage } - + if ($AzModuleOnly) { Connect-AzAccount ` -ServicePrincipal ` @@ -150,7 +157,7 @@ function Login-AzureAutomation([bool] $AzModuleOnly) { function Get-ModuleDependencyAndLatestVersion([string] $ModuleName) { $ModuleUrlFormat = "$PsGalleryApiUrl/Search()?`$filter={1}&searchTerm=%27{0}%27&targetFramework=%27%27&includePrerelease=false&`$skip=0&`$top=40" - + $ForcedModuleVersion = $ModuleVersionOverridesHashTable[$ModuleName] $CurrentModuleUrl = @@ -175,7 +182,7 @@ function Get-ModuleDependencyAndLatestVersion([string] $ModuleName) { $PackageDetails = Invoke-RestMethod -Method Get -UseBasicParsing -Uri $SearchResult.id # Ignore the modules that are not published as part of the Azure SDK - if ($PackageDetails.entry.properties.Owners -ne $script:AzureSdkOwnerName) { + if ($PackageDetails.entry.properties.Owners -ne $script:AzureSdkOwnerName -and $AzureModulesOnly) { Write-Warning "Module : $ModuleName is not part of azure sdk. Ignoring this." } else { $ModuleVersion = $PackageDetails.entry.properties.version @@ -218,7 +225,7 @@ function Import-AutomationModule([string] $ModuleName, [bool] $UseAzModule = $fa $ModuleContentUrl = Get-ModuleContentUrl $ModuleName # Find the actual blob storage location of the module do { - $ModuleContentUrl = (Invoke-WebRequest -Uri $ModuleContentUrl -MaximumRedirection 0 -UseBasicParsing -ErrorAction Ignore).Headers.Location + $ModuleContentUrl = (Invoke-WebRequest -Uri $ModuleContentUrl -MaximumRedirection 0 -UseBasicParsing -ErrorAction Ignore).Headers.Location } while (!$ModuleContentUrl.Contains(".nupkg")) $CurrentModule = & $GetAutomationModule ` @@ -275,14 +282,14 @@ function AreAllModulesAdded([string[]] $ModuleListToAdd) { # the ':' character. The explicit intent of this runbook is to always install the latest module versions, # so we want to completely ignore version specifications here. $ModuleNameToAdd = $ModuleToAdd -replace '\:.*', '' - + foreach($AlreadyIncludedModules in $ModuleImportMapOrder) { if ($AlreadyIncludedModules -contains $ModuleNameToAdd) { $ModuleAccounted = $true break } } - + if (!$ModuleAccounted) { $Result = $false break @@ -295,7 +302,7 @@ function AreAllModulesAdded([string[]] $ModuleListToAdd) { # Creates a module import map. This is a 2D array of strings so that the first # element in the array consist of modules with no dependencies. # The second element only depends on the modules in the first element, the -# third element only dependes on modules in the first and second and so on. +# third element only dependes on modules in the first and second and so on. function Create-ModuleImportMapOrder([bool] $AzModuleOnly) { $ModuleImportMapOrder = $null $ProfileOrAccountsModuleName = $null @@ -330,7 +337,7 @@ function Create-ModuleImportMapOrder([bool] $AzModuleOnly) { do { $NextAutomationModuleList = $null $CurrentChainVersion = $null - # Add it to the list if the modules are not available in the same list + # Add it to the list if the modules are not available in the same list foreach ($Module in $CurrentAutomationModuleList) { $Name = $Module.Name @@ -402,14 +409,14 @@ function Wait-AllModulesImported( } if ($AutomationModule.ProvisioningState -ne "Succeeded") { - Write-Error ("Failed to import module : {0}. Status : {1}" -f $Module, $AutomationModule.ProvisioningState) + Write-Error ("Failed to import module : {0}. Status : {1}" -f $Module, $AutomationModule.ProvisioningState) } else { Write-Output ("Successfully imported module : {0}" -f $Module) } - } + } } -# Uses the module import map created to import modules. +# Uses the module import map created to import modules. # It will only import modules from an element in the array if all the modules # from the previous element have been added. function Import-ModulesInAutomationAccordingToDependency([string[][]] $ModuleImportMapOrder, [bool] $UseAzModule) { @@ -437,7 +444,7 @@ function Import-ModulesInAutomationAccordingToDependency([string[][]] $ModuleImp } function Update-ProfileAndAutomationVersionToLatest([string] $AutomationModuleName) { - # Get the latest azure automation module version + # Get the latest azure automation module version $VersionAndDependencies = Get-ModuleDependencyAndLatestVersion $AutomationModuleName # Automation only has dependency on profile From 5d985c6f07845bec1cd58df3cd9cfc2607c561c6 Mon Sep 17 00:00:00 2001 From: Tristan Wrubleski Date: Thu, 10 Sep 2020 09:09:19 -0400 Subject: [PATCH 2/6] Changed ? to Where-Object --- Update-AutomationAzureModulesForAccount.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update-AutomationAzureModulesForAccount.ps1 b/Update-AutomationAzureModulesForAccount.ps1 index 86bc745..b76c721 100644 --- a/Update-AutomationAzureModulesForAccount.ps1 +++ b/Update-AutomationAzureModulesForAccount.ps1 @@ -321,7 +321,7 @@ function Create-ModuleImportMapOrder([bool] $AzModuleOnly) { $CurrentAutomationModuleList = & $GetAutomationModule ` -ResourceGroupName $ResourceGroupName ` -AutomationAccountName $AutomationAccountName | - ?{ + Where-Object{ ($AzModuleOnly -and ($_.Name -eq 'Az' -or $_.Name -like 'Az.*')) -or (!$AzModuleOnly -and ($_.Name -eq 'AzureRM' -or $_.Name -like 'AzureRM.*' -or $_.Name -eq 'Azure' -or $_.Name -like 'Azure.*')) From 08c07025fa10c4c6ba37950112a4dc5a2fc4232e Mon Sep 17 00:00:00 2001 From: Tristan Wrubleski Date: Thu, 10 Sep 2020 12:12:46 -0400 Subject: [PATCH 3/6] Updated fl to Format-List --- Update-AutomationAzureModulesForAccount.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update-AutomationAzureModulesForAccount.ps1 b/Update-AutomationAzureModulesForAccount.ps1 index b76c721..bebabac 100644 --- a/Update-AutomationAzureModulesForAccount.ps1 +++ b/Update-AutomationAzureModulesForAccount.ps1 @@ -143,7 +143,7 @@ function Login-AzureAutomation([bool] $AzModuleOnly) { } } catch { if (!$RunAsConnection) { - $RunAsConnection | fl | Write-Output + $RunAsConnection | Format-List | Write-Output Write-Output $_.Exception $ErrorMessage = "Connection 'AzureRunAsConnection' not found." throw $ErrorMessage From eea1e52b672089a575993a8627a72bb83e2071c2 Mon Sep 17 00:00:00 2001 From: Tristan Wrubleski Date: Thu, 10 Sep 2020 12:18:53 -0400 Subject: [PATCH 4/6] Add AzureModulesOnly logic to function Create-ModuleImportMapOrder --- Update-AutomationAzureModulesForAccount.ps1 | 28 +++++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/Update-AutomationAzureModulesForAccount.ps1 b/Update-AutomationAzureModulesForAccount.ps1 index bebabac..b14a8ff 100644 --- a/Update-AutomationAzureModulesForAccount.ps1 +++ b/Update-AutomationAzureModulesForAccount.ps1 @@ -318,14 +318,26 @@ function Create-ModuleImportMapOrder([bool] $AzModuleOnly) { } # Get all the non-conflicting modules in the current automation account - $CurrentAutomationModuleList = & $GetAutomationModule ` - -ResourceGroupName $ResourceGroupName ` - -AutomationAccountName $AutomationAccountName | - Where-Object{ - ($AzModuleOnly -and ($_.Name -eq 'Az' -or $_.Name -like 'Az.*')) -or - (!$AzModuleOnly -and ($_.Name -eq 'AzureRM' -or $_.Name -like 'AzureRM.*' -or - $_.Name -eq 'Azure' -or $_.Name -like 'Azure.*')) - } + if ($AzureModulesOnly) { + $CurrentAutomationModuleList = & $GetAutomationModule ` + -ResourceGroupName $ResourceGroupName ` + -AutomationAccountName $AutomationAccountName | + Where-Object{ + ($AzModuleOnly -and ($_.Name -eq 'Az' -or $_.Name -like 'Az.*')) -or + (!$AzModuleOnly -and ($_.Name -eq 'AzureRM' -or $_.Name -like 'AzureRM.*' -or + $_.Name -eq 'Azure' -or $_.Name -like 'Azure.*')) + } + } + else { + $CurrentAutomationModuleList = & $GetAutomationModule ` + -ResourceGroupName $ResourceGroupName ` + -AutomationAccountName $AutomationAccountName | + Where-Object{ + (!$AzModuleOnly -and !($_.Name -eq 'Az' -or $_.Name -like 'Az.*')) -or + ($AzModuleOnly -and !($_.Name -eq 'AzureRM' -or $_.Name -like 'AzureRM.*' -or + $_.Name -eq 'Azure' -or $_.Name -like 'Azure.*')) + } + } # Get the latest version of the AzureRM.Profile OR Az.Accounts module $VersionAndDependencies = Get-ModuleDependencyAndLatestVersion $ProfileOrAccountsModuleName From 02c8025ddde56557bcc8e5f9945e5a008c54ac22 Mon Sep 17 00:00:00 2001 From: Tristan Wrubleski Date: Thu, 10 Sep 2020 14:54:02 -0400 Subject: [PATCH 5/6] Funciton Wait-AllModulesImported added Created condition for IsTerminalProvisoningState --- Update-AutomationAzureModulesForAccount.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Update-AutomationAzureModulesForAccount.ps1 b/Update-AutomationAzureModulesForAccount.ps1 index b14a8ff..bfbbeb6 100644 --- a/Update-AutomationAzureModulesForAccount.ps1 +++ b/Update-AutomationAzureModulesForAccount.ps1 @@ -410,7 +410,8 @@ function Wait-AllModulesImported( -AutomationAccountName $AutomationAccountName $IsTerminalProvisioningState = ($AutomationModule.ProvisioningState -eq "Succeeded") -or - ($AutomationModule.ProvisioningState -eq "Failed") + ($AutomationModule.ProvisioningState -eq "Failed") -or + ($AutomationModule.ProvisioningState -eq "Created") if ($IsTerminalProvisioningState) { break From f251e2a6f33f96b8d0ab98fd21edf379e9b2ec37 Mon Sep 17 00:00:00 2001 From: Tristan Wrubleski Date: Thu, 10 Sep 2020 15:04:24 -0400 Subject: [PATCH 6/6] Updated parameter name AzureModulesOnly to UpdateAzureModulesOnly and parameter description. --- Update-AutomationAzureModulesForAccount.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Update-AutomationAzureModulesForAccount.ps1 b/Update-AutomationAzureModulesForAccount.ps1 index bfbbeb6..e33cd6f 100644 --- a/Update-AutomationAzureModulesForAccount.ps1 +++ b/Update-AutomationAzureModulesForAccount.ps1 @@ -44,9 +44,9 @@ or .PARAMETER PsGalleryApiUrl (Optional) PowerShell Gallery API URL. -.PARAMETER AzureModulesOnly -(Optional) If $false all modules, including user added will be updated. -If $true, only modules which are part of the Azure SDK will be updated. +.PARAMETER UpdateAzureModulesOnly +(Optional) If $false all modules added from PowerShell Gallery will be updated. +If $true, only AzureRM or Az modules will be updated. The default value is $true. .LINK @@ -73,7 +73,7 @@ param( [string] $PsGalleryApiUrl = 'https://www.powershellgallery.com/api/v2', - [bool] $AzureModulesOnly = $true + [bool] $UpdateAzureModulesOnly = $true ) $ErrorActionPreference = "Continue" @@ -182,7 +182,7 @@ function Get-ModuleDependencyAndLatestVersion([string] $ModuleName) { $PackageDetails = Invoke-RestMethod -Method Get -UseBasicParsing -Uri $SearchResult.id # Ignore the modules that are not published as part of the Azure SDK - if ($PackageDetails.entry.properties.Owners -ne $script:AzureSdkOwnerName -and $AzureModulesOnly) { + if ($PackageDetails.entry.properties.Owners -ne $script:AzureSdkOwnerName -and $UpdateAzureModulesOnly) { Write-Warning "Module : $ModuleName is not part of azure sdk. Ignoring this." } else { $ModuleVersion = $PackageDetails.entry.properties.version @@ -318,7 +318,7 @@ function Create-ModuleImportMapOrder([bool] $AzModuleOnly) { } # Get all the non-conflicting modules in the current automation account - if ($AzureModulesOnly) { + if ($UpdateAzureModulesOnly) { $CurrentAutomationModuleList = & $GetAutomationModule ` -ResourceGroupName $ResourceGroupName ` -AutomationAccountName $AutomationAccountName |