新版Azure Automation Account 浅析(二) --- 更新Powershell模块和创建Runbook
前篇我们讲了怎样创建一个自动化账户以及创建时候“Run As Account”选项背后的奥秘。这一篇针对在Azure自动化账户中使用Powershell Runbook的用户讲一下怎样更新powershell 模块。
更新Powershell模块
首先,我们需要先了解一下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
相关的模块安装呢?
点击“浏览库”,选择“AzureRM”,点击“导入”。“确定”按钮是灰色的,显然在Azure Portal中不支持有依赖关系的模块集中导入。
记得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 ) {
$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 ) {
$Dependencies = $Dependencies.Split("|") # parse depencencies, which are in the format: module1name:module1version:|module2name:module2version:
$Dependencies | ForEach-Object { if($_ -and $_.Length -gt ) {
$Parts = $_.Split(":")
$DependencyName = $Parts[]
$DependencyVersion = $Parts[] # 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("[")[].Split("]")[]
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 -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
$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自动化账户
新版Azure Automation Account 浅析(二) --- 更新Powershell模块和创建Runbook的更多相关文章
- 新版Azure Automation Account 浅析(三) --- 用Runbook管理AAD Application Key
新版Azure Automation Account 浅析(三) --- 用Runbook管理AAD应用的Key 前篇讲过有一个面向公众的Runbook库,社区和微软一直往其中加入新的Runbook, ...
- 新版Azure Automation Account 浅析(一) --- 创建和Run As Account
去年年底Azure中国的Automation Account悄悄做了升级.新版本不管从功能还是end user experience方面都让人耳目一新.如果说升级前只是一个运行脚本的小工具,升级后的A ...
- 利用Azure Automation实现云端自动化运维(1)
Azure Automation是Azure上的一个自动化工作流引擎,基于Powershell,来帮助用户简化,集成和自动化Azure上的运维工作,例如: 实现定时开关虚拟机,节约成本 实现定时创建删 ...
- Step by Step 用Azure Automation 来开虚机(ARM)
使用Azure Automation来自动化处理各种重复的耗时的云管理任务从而帮助云运维人员提升效率,帮助降低运营成本. 具体相关的介绍以及怎样利用Azure Automation来完成定期开关虚拟机 ...
- 【Azure Developer】Azure Automation 自动化账号生成的时候怎么生成连接 与证书 (Connection & Certificate)
Azure Automation :The Azure Automation service provides a highly reliable and scalable workflow exec ...
- Azure Automation (1) 入门
<Windows Azure Platform 系列文章目录> 通过Azure Automation(自动化),开发人员可以自动完成通常要在云环境中执行的手动.长时间进行.易出错且重复性高 ...
- Azure Automation (2) 定期删除存储账号中的文件
<Windows Azure Platform 系列文章目录> 本文介绍的是国内由世纪互联运维的Azure China. 本文是对笔者之前的文档Azure Backup (1) 将SQL ...
- Azure Automation:存储帐户之间blob拷贝
在两个存储帐户之间进行blob拷贝,在客户端,使用Azue PowerShell脚本, 用存储帐户上下文(New-AzureStorageContext)来获取某个StorageAccount中的Co ...
- 如何利用Azure Automation以及Tag自动开关VM
这是本博客第一篇技术相关的小贴士,在这里我不会详细介绍所涉及的技术组件的具体使用细节,因为我相信这些大家都可以通过官方文档了解到.如果你是一个看了官方文档依然一脸茫然的IT小白,个人建议是先从基础重新 ...
随机推荐
- linux odbc连接sql server2014
首先坑爹呀!由于配置Zabbix 用到这个,网上资料一顿搜,一顿报错,调各种参数,依然无法连接,我竟无言以对: 这个只是项目的一小部分,只提供成功案例,没做深入研究,可以让遇到的兄弟少走弯路: 建议第 ...
- sql server 错误号大全
0 操作成功完成. 1 功能错误. 2 系统找不到指定的文件. 3 系统找不到指定的路径. 4 系统无法打开文件. 5 拒绝访问. 6 句柄无效. 7 存储控制块被损坏. 8 存储空间不足,无法处理此 ...
- Git上传项目到GitHub
1.注册账户 https://github.com/ 2.创建仓库 3.需要安装 Git http://msysgit.github.com/ 4.本地创建ssh key(不是必要,不创建ssh可 ...
- 前端工程之CDN部署
之前发的一篇文章<变态的静态资源缓存与更新>中提到了静态资源和页面部署之间的时间间隙问题,这个问题会迫使前端静态资源发布必须采用非覆盖式. 那篇文章中没有详细解释为什么会产生不可忍受的时间 ...
- eclipse常用快捷设置
1.代码自动提示 在我们忘记方法名或者想偷懒时,代码自动提示很管用.不过Eclipse默认是输入"."后才会出现包或类成员的提示,也就意味着我们必须先输入一个完整的类名,提示才能出 ...
- Android查缺补漏(View篇)--事件分发机制
事件分发机制是Android中非常重要的一个知识点,同时也是难点,相信到目前为止很多Android开发者对事件分发机制并没有一个非常系统的认识,当然也包括博主个人在内.可能在平时的开发工作中我们并没有 ...
- Debian9 配置之旅
注:在安装的过程中,要选择网络镜像,不然要出大问题...(我选择了网易163的源) 注:下面的操作发生在我apt-get update,更新出现了错误,做的处理. _Stretch_ - Offici ...
- jdbc+servlet+jsp实现登录验证
基础知识准备:sql的增删改查. 新增:insert into 表名称(字段名.....)values(字段名....). 修改:update 表名称 set 字段名="新值" ...
- 一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](四)
前言 上一篇<一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](三)>,我们完成了: * 引用SqlSugar * ...
- 浴室沉思:聊聊DAL和Repository
这是一个由DDD群引发的随笔 在写了上一篇随笔<关于ORM的浴室沉思>后一些朋友私聊我,很多刚接触DDD的朋友会对Repository(仓储层)这东西有点疑惑,为什么要叫仓储层?是不是三层 ...