新版Azure Automation Account 淺析(二) --- 更新Powershell模塊和建立Runbook

 

前篇咱們講了怎樣建立一個自動化帳戶以及建立時候「Run As Account」選項背後的奧祕。這一篇針對在Azure自動化帳戶中使用Powershell Runbook的用戶講一下怎樣更新powershell 模塊。shell

 

更新Powershell模塊api

首先,咱們須要先了解一下Azure Automation的系統架構。咱們已經知道用戶能夠經過運行Runbook來實現自動化運維,Runbook運行則是在Azure Automation的沙盒裏執行的,沙盒是一組由Azure管理的虛機資源, 咱們能夠把其當作是Azure的一個PaaS服務。Pass服務天然是須要提供可伸縮高可用多租客隔離的運行環境。顯然,咱們須要可以爲Runbook的運行環境指定所須要的Powershell模塊和版本。同時,咱們還須要可以升級更新相關的powershell模塊。瀏覽器

打開咱們前面建立的azpoctest自動化帳戶,在左邊菜單選擇「共享的資源」-》「模塊」。架構

很是好,用戶能夠添加自定義的模塊「添加模塊」,也能夠升級已有模塊版本「更新Azure模塊」。用戶還能夠瀏覽powershell模塊庫來導入新模塊。運維

 

仔細研究一下這個頁面,目測建立自動化帳戶時候自帶的模塊遠少於目前Azure已經release的Powershell模塊。若是須要運行Runbook來自動化運維Azure資源的話,目前這些模塊是遠遠不夠的。編輯器

記得光是ARM相關的powershell模塊就有幾十個,一個個導入的話工做量實在太大,那咱們能不能像在powershell 命令行那樣,用Install-Module和Import-Module兩條命令就能夠完成全部AzureRM測試

相關的模塊安裝呢?this

點擊「瀏覽庫」,選擇「AzureRM」,點擊「導入」。「肯定」按鈕是灰色的,顯然在Azure Portal中不支持有依賴關係的模塊集中導入。spa

 

記得16年在Global作Automation Account的時候,毫無怨言地填坑,手動一個個把這些模塊導入。今天咱們換個填坑的法子命令行

接下來咱們會寫一個Runbook,用腳原本導入AzureRM的Powershell模塊

 

建立Runbook

在自動化帳戶左邊菜單選取「流程自動化」-》「Runbook」-》「添加Runbook「 ,建立一個新的Runbook

 

 

 建立成功後,瀏覽器會自動跳轉到Runbook編輯器,咱們能夠開始寫Powershell腳本了

首先,由於Runbook是運行在一個多租戶的沙盒中,咱們須要登陸這個自動化帳戶所在的Azure訂閱才能爲這個自動化帳戶導入模塊。

登陸的代碼能夠reuse咱們在上一篇提到的Runbook模板

$connectionName = "AzureRunAsConnection"
try
{
    # Get the connection "AzureRunAsConnection "
    $servicePrincipalConnection=Get-AutomationConnection -Name $connectionName

    "Logging in to Azure..."
    Add-AzureRmAccount `
        -ServicePrincipal `
        -TenantId $servicePrincipalConnection.TenantId `
        -ApplicationId $servicePrincipalConnection.ApplicationId `
        -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint `
        -EnvironmentName AzureChinaCloud
 }
catch {
    if (!$servicePrincipalConnection)
    {
        $ErrorMessage = "Connection $connectionName not found."
        throw $ErrorMessage
    } else{
        Write-Error -Message $_.Exception
        throw $_.Exception
    }
}

  

接下來,咱們須要在Powershell Gallery裏查找導入模塊及其版本,若是存在,咱們會先去找一個模塊實際存儲的Blob Storage地址,用New-AzureRmAutomationModule這條命令來導入

若是有Dependency的模塊,腳本會首先去導入Dependency模塊。下文腳本包含了資源組,自動化帳戶,模塊(AzureRM)和模塊版本(最新),考慮到模塊和模塊版本在不一樣時期可能有變化,這2部分其實能夠作參數化,由Automation的variable來存儲。那樣腳本就不須要常常修改。

param(
    [Parameter(Mandatory=$true)]
    [String] $ResourceGroupName,

    [Parameter(Mandatory=$true)]
    [String] $AutomationAccountName,
    
    [Parameter(Mandatory=$true)]
    [String] $ModuleName,

    [Parameter(Mandatory=$false)]
    [String] $ModuleVersion
)

$ModulesImported = @()

function _doImport {
    param(
        [Parameter(Mandatory=$true)]
        [String] $ResourceGroupName,

        [Parameter(Mandatory=$true)]
        [String] $AutomationAccountName,
    
        [Parameter(Mandatory=$true)]
        [String] $ModuleName,

        # if not specified latest version will be imported
        [Parameter(Mandatory=$false)]
        [String] $ModuleVersion
    )

    $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.Length -and $SearchResult.Length -gt 1) {
        $SearchResult = $SearchResult | Where-Object -FilterScript {
            return $_.properties.title -eq $ModuleName
        }
    }

    if(!$SearchResult) {
        Write-Error "Could not find module '$ModuleName' on PowerShell Gallery."
    }
    else {
        $ModuleName = $SearchResult.properties.title # get correct casing for the module name
        $PackageDetails = Invoke-RestMethod -Method Get -UseBasicParsing -Uri $SearchResult.id 
    
        if(!$ModuleVersion) {
            # get latest version
            $ModuleVersion = $PackageDetails.entry.properties.version
        }

        $ModuleContentUrl = "https://www.powershellgallery.com/api/v2/package/$ModuleName/$ModuleVersion"

        # Make sure module dependencies are imported
        $Dependencies = $PackageDetails.entry.properties.dependencies

        if($Dependencies -and $Dependencies.Length -gt 0) {
            $Dependencies = $Dependencies.Split("|")

            # parse depencencies, which are in the format: module1name:module1version:|module2name:module2version:
            $Dependencies | ForEach-Object {

                if($_ -and $_.Length -gt 0) {
                    $Parts = $_.Split(":")
                    $DependencyName = $Parts[0]
                    $DependencyVersion = $Parts[1]

                    # check if we already imported this dependency module during execution of this script
                    if(!$ModulesImported.Contains($DependencyName)) {

                        $AutomationModule = Get-AzureRmAutomationModule `
                            -ResourceGroupName $ResourceGroupName `
                            -AutomationAccountName $AutomationAccountName `
                            -Name $DependencyName `
                            -ErrorAction SilentlyContinue
    
                        # check if Automation account already contains this dependency module of the right version
                        if((!$AutomationModule) -or $AutomationModule.Version -ne $DependencyVersion) {
                            $DependencyVersion = $DependencyVersion.Split("[")[0].Split("]")[0]    
                            Write-Output "Importing dependency module $DependencyName of version $DependencyVersion first."
                            

                            # this dependency module has not been imported, import it first
                            _doImport `
                                -ResourceGroupName $ResourceGroupName `
                                -AutomationAccountName $AutomationAccountName `
                                -ModuleName $DependencyName `
                                -ModuleVersion $DependencyVersion

                            $ModulesImported += $DependencyName
                        }
                    }
                }
            }
        }
            
        # 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.Contains(".nupkg"))

        $ActualUrl = $ModuleContentUrl

        Write-Output "Importing $ModuleName module of version $ModuleVersion from $ActualUrl to Automation"

        $AutomationModule = New-AzureRmAutomationModule `
            -ResourceGroupName $ResourceGroupName `
            -AutomationAccountName $AutomationAccountName `
            -Name $ModuleName `
            -ContentLink $ActualUrl

        while(
            $AutomationModule.ProvisioningState -ne "Created" -and
            $AutomationModule.ProvisioningState -ne "Succeeded" -and
            $AutomationModule.ProvisioningState -ne "Failed"
        )
        {
            Write-Verbose -Message "Polling for module import completion"
            Start-Sleep -Seconds 10
            $AutomationModule = $AutomationModule | Get-AzureRmAutomationModule
        }

        if($AutomationModule.ProvisioningState -eq "Failed") {
            Write-Error "Importing $ModuleName module to Automation failed."
        }
        else {
            Write-Output "Importing $ModuleName module to Automation succeeded."
        }
    }
}

_doImport `
    -ResourceGroupName "chdaiAC" `
    -AutomationAccountName "acpoctest" `
    -ModuleName "AzureRM" `
    -ModuleVersion $ModuleVersion

 

編輯完成,點擊保存。隨後繼續點擊「測試窗格」。這個功能將測試咱們剛完成的Runbook。

在輸出窗口會看到後臺沙盒運行腳本把AzureRM的dependency模塊一個個被導入到自動化帳戶

 

 最後導入AzureRM的時候運行會報錯,這個沒有關係。AzureRM模塊自己不包含任何功能。因此ARM管理的Powershell命令都在AzureRM的Dependency 模塊裏。

如今回到模塊列表,能夠看到AzureRM相關模塊已經所有導入了

 

 如今萬事具有,下一篇咱們能夠開始在平常工做中運用Azure自動化帳戶

相關文章
相關標籤/搜索