From c25066d0a74eb81dcad473e1631f4437325ad320 Mon Sep 17 00:00:00 2001 From: Peter Bajurny Date: Mon, 27 May 2019 15:09:05 -0500 Subject: [PATCH 1/2] Azure Automation --- PSDeploy/PSDeploy.yml | 4 ++ PSDeploy/PSDeployScripts/AzureAutomation.ps1 | 73 ++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 PSDeploy/PSDeployScripts/AzureAutomation.ps1 diff --git a/PSDeploy/PSDeploy.yml b/PSDeploy/PSDeploy.yml index d21e85d..da2f961 100644 --- a/PSDeploy/PSDeploy.yml +++ b/PSDeploy/PSDeploy.yml @@ -15,6 +15,10 @@ ARM: Script: ARM.ps1 Description: Uses Azure Resource Manager PowerShell cmdlets to deploy a template to Microsoft Azure or Azure Stack +AzureAutomation: + Script: AzureAutomation.ps1 + Description: Deploy a runbook to Azure Automation + Chocolatey: Script: Chocolatey.ps1 Description: Uses Chocolatey on the local computer to push packages to a Chocolatey repository. diff --git a/PSDeploy/PSDeployScripts/AzureAutomation.ps1 b/PSDeploy/PSDeployScripts/AzureAutomation.ps1 new file mode 100644 index 0000000..4b4f1e3 --- /dev/null +++ b/PSDeploy/PSDeployScripts/AzureAutomation.ps1 @@ -0,0 +1,73 @@ +<# + .SYNOPSIS + Deploy a Powershell Runbook to Azure Automation. + .DESCRIPTION + Deploy a Powershell Runbook to Azure Automation. + .PARAMETER Deployment + Deployment to run + .PARAMETER ResourceGroupName + Resource Group to deploy to + .PARAMETER AutomationAccountName + Automation Account to deploy to + .PARAMETER AzureServicePrincipalCredential + Credential of Azure Service Principal + + +#> +[cmdletbinding()] +param ( + [ValidateScript({ $_.PSObject.TypeNames[0] -eq 'PSDeploy.Deployment' })] + [psobject[]]$Deployment, + + [Parameter(Mandatory)][string]$ResourceGroupName, + + [Parameter(Mandatory)][string]$AutomationAccountName, + + [Parameter(Mandatory)][pscredential]$AzureServicePrincipalCredential, + + [Parameter(Mandatory)][string]$AzureTenantID, + + [Parameter(Mandatory)] + [ValidateSet("PowerShell","GraphicalPowerShell","PowerShellWorkflow","GraphicalPowerShellWorkflow","Python2")] + [string]$RunbookType, + + [switch]$CreateRunbook +) + +try +{ + Write-Verbose "Connecting to Azure" + $null = Connect-AzAccount -Credential $AzureServicePrincipalCredential -ServicePrincipal -Tenant $AzureTenantID -ErrorAction Stop +} +catch +{ + throw "Unable to connect to Azure with credentials provided $_" +} + foreach ($deploy in $Deployment) + { + If ($deploy.SourceExists) + { + $rbname = (Split-Path $deploy.source -Leaf).split('.')[0] + Write-Verbose "looking for runbook $rbname" + $get = Get-AzAutomationRunbook -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -ErrorAction SilentlyContinue -Name $rbname + Write-Verbose "got $($get.count) runbooks" + if ((-not $get) -and (-not $CreateRunbook)) + { + Write-Warning "Runbook $rbname does not exist, please create before deploying or specify CreateRunbook" + } + else + { + try + { + Write-Verbose "Import-AzAutomationRunbook -Path $($deploy.source) -Type $RunbookType -Published -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -Force -ErrorAction Stop" + $null = Import-AzAutomationRunbook -Path $deploy.source -Type $RunbookType -Published -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -Force -ErrorAction Stop + } + catch + { + Write-Warning "Unable to update Runbook $_" + } + } + } + } + + $null = Disconnect-AzAccount \ No newline at end of file From 4dddbab73898180af2020d4d87b6c24fe4a88060 Mon Sep 17 00:00:00 2001 From: Peter Bajurny Date: Mon, 27 May 2019 17:25:35 -0500 Subject: [PATCH 2/2] documentation --- PSDeploy/PSDeployScripts/AzureAutomation.ps1 | 47 +++++++++++++------- docs/Example-AzureAutomation-Deployment.md | 44 ++++++++++++++++++ 2 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 docs/Example-AzureAutomation-Deployment.md diff --git a/PSDeploy/PSDeployScripts/AzureAutomation.ps1 b/PSDeploy/PSDeployScripts/AzureAutomation.ps1 index 4b4f1e3..e3db64c 100644 --- a/PSDeploy/PSDeployScripts/AzureAutomation.ps1 +++ b/PSDeploy/PSDeployScripts/AzureAutomation.ps1 @@ -11,6 +11,14 @@ Automation Account to deploy to .PARAMETER AzureServicePrincipalCredential Credential of Azure Service Principal + User is Application (client) ID + Password is Secret string / Application Password + .PARAMETER AzureTenantID + Tenant ID of Service Principal + .PARAMETER RunbookType + Type of runbook being deployed, one of "PowerShell", "GraphicalPowerShell", "PowerShellWorkflow", "GraphicalPowerShellWorkflow", "Python2" + .PARAMETER CreateRunbook + If true, will create runbook if it doesn't already exist, otherwise runbook must already exist #> @@ -28,10 +36,10 @@ param ( [Parameter(Mandatory)][string]$AzureTenantID, [Parameter(Mandatory)] - [ValidateSet("PowerShell","GraphicalPowerShell","PowerShellWorkflow","GraphicalPowerShellWorkflow","Python2")] + [ValidateSet("PowerShell", "GraphicalPowerShell", "PowerShellWorkflow", "GraphicalPowerShellWorkflow", "Python2")] [string]$RunbookType, - [switch]$CreateRunbook + [bool]$CreateRunbook ) try @@ -47,26 +55,33 @@ catch { If ($deploy.SourceExists) { - $rbname = (Split-Path $deploy.source -Leaf).split('.')[0] - Write-Verbose "looking for runbook $rbname" - $get = Get-AzAutomationRunbook -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -ErrorAction SilentlyContinue -Name $rbname - Write-Verbose "got $($get.count) runbooks" - if ((-not $get) -and (-not $CreateRunbook)) + if($Deploy.SourceType -eq 'File') { - Write-Warning "Runbook $rbname does not exist, please create before deploying or specify CreateRunbook" - } - else - { - try + $rbname = (Split-Path $deploy.source -Leaf).split('.')[0] + Write-Verbose "looking for runbook $rbname" + $get = Get-AzAutomationRunbook -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -ErrorAction SilentlyContinue -Name $rbname + Write-Verbose "got $($get.count) runbooks" + if ((-not $get) -and (-not $CreateRunbook)) { - Write-Verbose "Import-AzAutomationRunbook -Path $($deploy.source) -Type $RunbookType -Published -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -Force -ErrorAction Stop" - $null = Import-AzAutomationRunbook -Path $deploy.source -Type $RunbookType -Published -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -Force -ErrorAction Stop + Write-Warning "Runbook $rbname does not exist, please create before deploying or specify CreateRunbook" } - catch + else { - Write-Warning "Unable to update Runbook $_" + try + { + Write-Verbose "Import-AzAutomationRunbook -Path $($deploy.source) -Type $RunbookType -Published -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -Force -ErrorAction Stop" + $null = Import-AzAutomationRunbook -Path $deploy.source -Type $RunbookType -Published -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -Force -ErrorAction Stop + } + catch + { + Write-Warning "Unable to update Runbook $_" + } } } + else + { + Write-Warning "This can ony be used to deploy individual scripts, not directories" + } } } diff --git a/docs/Example-AzureAutomation-Deployment.md b/docs/Example-AzureAutomation-Deployment.md new file mode 100644 index 0000000..56dff8d --- /dev/null +++ b/docs/Example-AzureAutomation-Deployment.md @@ -0,0 +1,44 @@ +# Azure Automation + +## Prerequisites + +This DeploymentType uses the [Az module](https://docs.microsoft.com/en-us/powershell/azure/new-azureps-module-az) to connect to Azure and deploy runbooks. +Because it's meant to run as part of a build pipeline, it requires a service principal to be created with a password (not certificate). + +[Creating a Service Principal with the Az module](https://docs.microsoft.com/en-us/powershell/azure/create-azure-service-principal-azureps) + +[Creating a Service Principal with the Azure Portal](https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal) + +## Options + +All options, except the CreateRunbook switch, are Mandatory + +* **ResourceGroupName:** Resource Group to deploy runbook to +* **AutomationAccountName:** Automation Account to deploy runbook to +* **AzureServicePrincipalCredential:** Credential of Azure Service Principal, User is Application (client) ID, Password is Secret string / Application Password +* **AzureTenantID:** Tenant ID of Service Principal +* **RunbookType:** Type of runbook being deployed, one of "PowerShell", "GraphicalPowerShell", "PowerShellWorkflow", "GraphicalPowerShellWorkflow", "Python2" +* **CreateRunbook:** Boolean, if true, will create runbook if it doesn't already exist, otherwise runbook must already exist + +## Examples + +```Powershell +Deploy ExampleDeployment { + By AzureAutomation { + $cred = Get-Credential + FromSource Runbook.ps1 + To AzureAutomation + WithOptions @{ + ResourceGroupName = "examplegroup" + AutomationAccountName = "example-account" + AzureServicePrincipalCredential = $cred + AzureTenantID = "6b3607b4-375b-447f-9fa1-34e452e1a91b" + RunbookType = "PowerShell" + } + } +} +``` + +Because each runbook requires a runbook type, FromSource can only be an individual script, not a whole directory. +The To will always be AzureAutomation. +This example gets the login credentials interactively, to use this in a pipeline you would need to generate the credential object another way.