none
Updating Modules - in Azure RRS feed

  • Question

  • Would like to know if there is a simple or already baked script to ensure modules are up to date in your Automation account in Azure?

    thanx in advance. 

    Thursday, May 12, 2016 4:10 PM

Answers

  • Hi Thom,

    Yes you could use the following runbook to ensure all modules in your Automation account are up to date. Running this on a schedule will ensure your modules are always the latest version.

    param(
        [Parameter(Mandatory=$true)]
        [String] $ResourceGroupName,
    
        [Parameter(Mandatory=$true)]
        [String] $AutomationAccountName,
    
        [Parameter(Mandatory=$false)]
        [String] $AzureConnectionName = "AzureRunAsConnection"
    )
    
    try {
        $ServicePrincipalConnection = Get-AutomationConnection -Name $AzureConnectionName         
    
        "Logging in to Azure..."
        Add-AzureRmAccount `
            -ServicePrincipal `
            -TenantId $servicePrincipalConnection.TenantId `
            -ApplicationId $servicePrincipalConnection.ApplicationId `
            -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint 
    }
    catch {
        if(!$ServicePrincipalConnection) {
            throw "Connection $AzureConnectionName not found."
        }
        else {
            throw $_.Exception
        }
    }
    
    $Modules = Get-AzureRmAutomationModule `
        -ResourceGroupName $ResourceGroupName `
        -AutomationAccountName $AutomationAccountName
    
    $AzureRMProfileModule = Get-AzureRmAutomationModule `
        -ResourceGroupName $ResourceGroupName `
        -AutomationAccountName $AutomationAccountName `
        -Name "AzureRM.Profile"
    
    # Force AzureRM.Profile to be evaluated first since some other modules depend on it 
    # being there / up to date to import successfully
    $Modules = @($AzureRMProfileModule) + $Modules
    
    foreach($Module in $Modules) {
    
        $Module = $Modules = Get-AzureRmAutomationModule `
            -ResourceGroupName $ResourceGroupName `
            -AutomationAccountName $AutomationAccountName `
            -Name $Module.Name
        
        $ModuleName = $Module.Name
        $ModuleVersionInAutomation = $Module.Version
    
        Write-Output "Checking if module '$ModuleName' is up to date in your automation account"
    
        $Url = "https://www.powershellgallery.com/api/v2/Search()?`$filter=IsLatestVersion&searchTerm=%27$ModuleName%27&targetFramework=%27%27&includePrerelease=false&`$skip=0&`$top=40" 
        $SearchResult = Invoke-RestMethod -Method Get -Uri $Url -UseBasicParsing
    
        if(!$SearchResult) {
            Write-Error "Could not find module '$ModuleName' on PowerShell Gallery."
        }
        elseif($SearchResult.Length -and $SearchResult.Length -gt 1) {
            Write-Error "Module name '$ModuleName' returned multiple results. Please specify an exact module name."
        }
        else {
            $PackageDetails = Invoke-RestMethod -Method Get -UseBasicParsing -Uri $SearchResult.id 
            $LatestModuleVersionOnPSGallery = $PackageDetails.entry.properties.version
    
            if($ModuleVersionInAutomation -ne $LatestModuleVersionOnPSGallery) {
                Write-Output "Module '$ModuleName' is not up to date. Latest version on PS Gallery is '$LatestModuleVersionOnPSGallery' but this automation account has version '$ModuleVersionInAutomation'"
                Write-Output "Importing latest version of '$ModuleName' into your automation account"
    
                $ModuleContentUrl = "https://www.powershellgallery.com/api/v2/package/$ModuleName/$ModuleVersion"
    
                # Find the actual blob storage location of the module
                do {
                    $ActualUrl = $ModuleContentUrl
                    $ModuleContentUrl = (Invoke-WebRequest -Uri $ModuleContentUrl -MaximumRedirection 0 -UseBasicParsing -ErrorAction Ignore).Headers.Location 
                } while($ModuleContentUrl -ne $Null)
    
                $Module = New-AzureRmAutomationModule `
                    -ResourceGroupName $ResourceGroupName `
                    -AutomationAccountName $AutomationAccountName `
                    -Name $ModuleName `
                    -ContentLink $ActualUrl
                    
                while($Module.ProvisioningState -ne "Succeeded" -and $Module.ProvisioningState -ne "Failed") {
                    Start-Sleep -Seconds 10
                
                    $Module = Get-AzureRmAutomationModule `
                        -ResourceGroupName $ResourceGroupName `
                        -AutomationAccountName $AutomationAccountName `
                        -Name $ModuleName
    
                    Write-Output "Polling for import completion..."
                }
    
                if($Module.ProvisioningState -eq "Succeeded") {
                    Write-Output "Successfully imported latest version of $ModuleName"
                }
                else {
                    Write-Error "Failed to import latest version of $ModuleName"
                }   
            }
            else {
                Write-Output "Module '$ModuleName' is up to date."
            }
       }
    }


    Joe Levy
    Twitter: @Jodoglevy
    Blog: http://jodoglevy.com

    If this post was helpful to you, please upvote it and/or mark it as an answer so others can more easily find it in the future.

    • Marked as answer by Joe Levy_ Monday, May 16, 2016 1:07 AM
    Monday, May 16, 2016 1:06 AM

All replies

  • Hi Thom,

    Yes you could use the following runbook to ensure all modules in your Automation account are up to date. Running this on a schedule will ensure your modules are always the latest version.

    param(
        [Parameter(Mandatory=$true)]
        [String] $ResourceGroupName,
    
        [Parameter(Mandatory=$true)]
        [String] $AutomationAccountName,
    
        [Parameter(Mandatory=$false)]
        [String] $AzureConnectionName = "AzureRunAsConnection"
    )
    
    try {
        $ServicePrincipalConnection = Get-AutomationConnection -Name $AzureConnectionName         
    
        "Logging in to Azure..."
        Add-AzureRmAccount `
            -ServicePrincipal `
            -TenantId $servicePrincipalConnection.TenantId `
            -ApplicationId $servicePrincipalConnection.ApplicationId `
            -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint 
    }
    catch {
        if(!$ServicePrincipalConnection) {
            throw "Connection $AzureConnectionName not found."
        }
        else {
            throw $_.Exception
        }
    }
    
    $Modules = Get-AzureRmAutomationModule `
        -ResourceGroupName $ResourceGroupName `
        -AutomationAccountName $AutomationAccountName
    
    $AzureRMProfileModule = Get-AzureRmAutomationModule `
        -ResourceGroupName $ResourceGroupName `
        -AutomationAccountName $AutomationAccountName `
        -Name "AzureRM.Profile"
    
    # Force AzureRM.Profile to be evaluated first since some other modules depend on it 
    # being there / up to date to import successfully
    $Modules = @($AzureRMProfileModule) + $Modules
    
    foreach($Module in $Modules) {
    
        $Module = $Modules = Get-AzureRmAutomationModule `
            -ResourceGroupName $ResourceGroupName `
            -AutomationAccountName $AutomationAccountName `
            -Name $Module.Name
        
        $ModuleName = $Module.Name
        $ModuleVersionInAutomation = $Module.Version
    
        Write-Output "Checking if module '$ModuleName' is up to date in your automation account"
    
        $Url = "https://www.powershellgallery.com/api/v2/Search()?`$filter=IsLatestVersion&searchTerm=%27$ModuleName%27&targetFramework=%27%27&includePrerelease=false&`$skip=0&`$top=40" 
        $SearchResult = Invoke-RestMethod -Method Get -Uri $Url -UseBasicParsing
    
        if(!$SearchResult) {
            Write-Error "Could not find module '$ModuleName' on PowerShell Gallery."
        }
        elseif($SearchResult.Length -and $SearchResult.Length -gt 1) {
            Write-Error "Module name '$ModuleName' returned multiple results. Please specify an exact module name."
        }
        else {
            $PackageDetails = Invoke-RestMethod -Method Get -UseBasicParsing -Uri $SearchResult.id 
            $LatestModuleVersionOnPSGallery = $PackageDetails.entry.properties.version
    
            if($ModuleVersionInAutomation -ne $LatestModuleVersionOnPSGallery) {
                Write-Output "Module '$ModuleName' is not up to date. Latest version on PS Gallery is '$LatestModuleVersionOnPSGallery' but this automation account has version '$ModuleVersionInAutomation'"
                Write-Output "Importing latest version of '$ModuleName' into your automation account"
    
                $ModuleContentUrl = "https://www.powershellgallery.com/api/v2/package/$ModuleName/$ModuleVersion"
    
                # Find the actual blob storage location of the module
                do {
                    $ActualUrl = $ModuleContentUrl
                    $ModuleContentUrl = (Invoke-WebRequest -Uri $ModuleContentUrl -MaximumRedirection 0 -UseBasicParsing -ErrorAction Ignore).Headers.Location 
                } while($ModuleContentUrl -ne $Null)
    
                $Module = New-AzureRmAutomationModule `
                    -ResourceGroupName $ResourceGroupName `
                    -AutomationAccountName $AutomationAccountName `
                    -Name $ModuleName `
                    -ContentLink $ActualUrl
                    
                while($Module.ProvisioningState -ne "Succeeded" -and $Module.ProvisioningState -ne "Failed") {
                    Start-Sleep -Seconds 10
                
                    $Module = Get-AzureRmAutomationModule `
                        -ResourceGroupName $ResourceGroupName `
                        -AutomationAccountName $AutomationAccountName `
                        -Name $ModuleName
    
                    Write-Output "Polling for import completion..."
                }
    
                if($Module.ProvisioningState -eq "Succeeded") {
                    Write-Output "Successfully imported latest version of $ModuleName"
                }
                else {
                    Write-Error "Failed to import latest version of $ModuleName"
                }   
            }
            else {
                Write-Output "Module '$ModuleName' is up to date."
            }
       }
    }


    Joe Levy
    Twitter: @Jodoglevy
    Blog: http://jodoglevy.com

    If this post was helpful to you, please upvote it and/or mark it as an answer so others can more easily find it in the future.

    • Marked as answer by Joe Levy_ Monday, May 16, 2016 1:07 AM
    Monday, May 16, 2016 1:06 AM
  • I switched mine to an account that I have been using instead of the Service principal you have in your script.

    In addition I had to add a Set-AzureRmContext to change to the proper Subscription since I have a few :)

        
    param(
        [Parameter(Mandatory=$true)]
        [String] $ResourceGroupName,
    
        [Parameter(Mandatory=$true)]
        [String] $AutomationAccountName,
    
        [Parameter(Mandatory=$false)]
        [String] $AzCredential = 'MyAccount',
    
        [Parameter(Mandatory=$false)]
        [string] $subscriptionName = 'Azure Testing'
    
    )
    
    try {
     
        'Logging in to Azure...'
        $cred = Get-AutomationPSCredential -Name $AzCredential
        Add-AzureRmAccount -Credential $cred
    }
    catch {
        if(!$cred) {
            throw "Connection $AzCredential not found."
        }
        else {
            throw $_.Exception
        }
    }
    set-azurermContext -SubscriptionName $subscriptionName
    
    $Modules = Get-AzureRmAutomationModule `
        -ResourceGroupName $ResourceGroupName `
        -AutomationAccountName $AutomationAccountName
    
    $AzureRMProfileModule = Get-AzureRmAutomationModule `
        -ResourceGroupName $ResourceGroupName `
        -AutomationAccountName $AutomationAccountName `
        -Name 'AzureRM.Profile'
    
    # Force AzureRM.Profile to be evaluated first since some other modules depend on it 
    # being there / up to date to import successfully
    $Modules = @($AzureRMProfileModule) + $Modules
    
    foreach($Module in $Modules) {
    
        $Module = $Modules = Get-AzureRmAutomationModule `
            -ResourceGroupName $ResourceGroupName `
            -AutomationAccountName $AutomationAccountName `
            -Name $Module.Name
        
        $ModuleName = $Module.Name
        $ModuleVersionInAutomation = $Module.Version
    
        Write-Output "Checking if module '$ModuleName' is up to date in your automation account"
    
        $Url = "https://www.powershellgallery.com/api/v2/Search()?`$filter=IsLatestVersion&searchTerm=%27$ModuleName%27&targetFramework=%27%27&includePrerelease=false&`$skip=0&`$top=40" 
        Write-output $Url
        $SearchResult = Invoke-RestMethod -Method Get -Uri $Url -UseBasicParsing
    
        if(!$SearchResult) {
            Write-Error "Could not find module '$ModuleName' in PowerShell Gallery."
        }
        elseif($SearchResult.Length -and $SearchResult.Length -gt 1) {
            Write-Error "Module name '$ModuleName' returned multiple results. Please specify an exact module name."
        }
        else {
            $PackageDetails = Invoke-RestMethod -Method Get -UseBasicParsing -Uri $SearchResult.id 
            $LatestModuleVersionOnPSGallery = $PackageDetails.entry.properties.version
    
            if($ModuleVersionInAutomation -ne $LatestModuleVersionOnPSGallery) {
                Write-Output "Module '$ModuleName' is not up to date. Latest version on PS Gallery is '$LatestModuleVersionOnPSGallery' but this automation account has version '$ModuleVersionInAutomation'"
                Write-Output "Importing latest version of '$ModuleName' into your automation account"
    
                $ModuleContentUrl = "https://www.powershellgallery.com/api/v2/package/$ModuleName/$ModuleVersion"
    
                # Find the actual blob storage location of the module
                do {
                    $ActualUrl = $ModuleContentUrl
                    $ModuleContentUrl = (Invoke-WebRequest -Uri $ModuleContentUrl -MaximumRedirection 0 -UseBasicParsing -ErrorAction Ignore).Headers.Location 
                } while($ModuleContentUrl -ne $Null)
    
                $Module = New-AzureRmAutomationModule `
                    -ResourceGroupName $ResourceGroupName `
                    -AutomationAccountName $AutomationAccountName `
                    -Name $ModuleName `
                    -ContentLink $ActualUrl
                    
                while($Module.ProvisioningState -ne 'Succeeded' -and $Module.ProvisioningState -ne 'Failed') {
                    Start-Sleep -Seconds 10
                
                    $Module = Get-AzureRmAutomationModule `
                        -ResourceGroupName $ResourceGroupName `
                        -AutomationAccountName $AutomationAccountName `
                        -Name $ModuleName
    
                    Write-Output 'Polling for import completion...'
                }
    
                if($Module.ProvisioningState -eq 'Succeeded') {
                    Write-Output "Successfully imported latest version of $ModuleName"
                }
                else {
                    Write-Error "Failed to import latest version of $ModuleName"
                }   
            }
            else {
                Write-Output "Module '$ModuleName' is up to date."
            }
       }
    }
    

    Thom

    Monday, May 16, 2016 5:43 PM