2019-12-13 09:48:00 -05:00
$ErrorActionPreference = 'Stop'
enum ImageType {
Windows2016 = 0
Windows2019 = 1
Ubuntu1604 = 2
Ubuntu1804 = 3
2020-08-04 20:32:35 +03:00
Ubuntu2004 = 4
2019-12-13 09:48:00 -05:00
}
Function Get-PackerTemplatePath {
param (
[ Parameter ( Mandatory = $True ) ]
[ string ] $RepositoryRoot ,
[ Parameter ( Mandatory = $True ) ]
[ ImageType ] $ImageType
)
switch ( $ImageType ) {
( [ ImageType ] :: Windows2016 ) {
2020-10-19 18:51:09 +03:00
$relativeTemplatePath = Join-Path " win " " windows2016.json "
2019-12-13 09:48:00 -05:00
}
( [ ImageType ] :: Windows2019 ) {
2020-10-19 18:51:09 +03:00
$relativeTemplatePath = Join-Path " win " " windows2019.json "
2019-12-13 09:48:00 -05:00
}
( [ ImageType ] :: Ubuntu1604 ) {
2020-10-19 18:51:09 +03:00
$relativeTemplatePath = Join-Path " linux " " ubuntu1604.json "
2019-12-13 09:48:00 -05:00
}
( [ ImageType ] :: Ubuntu1804 ) {
2020-10-19 18:51:09 +03:00
$relativeTemplatePath = Join-Path " linux " " ubuntu1804.json "
2019-12-13 09:48:00 -05:00
}
2020-08-04 20:32:35 +03:00
( [ ImageType ] :: Ubuntu2004 ) {
2020-10-19 18:51:09 +03:00
$relativeTemplatePath = Join-Path " linux " " ubuntu2004.json "
2020-08-04 20:32:35 +03:00
}
2020-10-19 18:51:09 +03:00
default { throw " Unknown type of image " }
2019-12-13 09:48:00 -05:00
}
2020-10-19 18:51:09 +03:00
$imageTemplatePath = [ IO.Path ] :: Combine ( $RepositoryRoot , " images " , $relativeTemplatePath )
if ( -not ( Test-Path $imageTemplatePath ) ) {
throw " Template for image ' $ImageType ' doesn't exist on path ' $imageTemplatePath ' "
}
return $imageTemplatePath ;
}
Function Get-LatestCommit {
[ CmdletBinding ( ) ]
param ( )
process {
Write-Host " Latest commit: "
git - -no -pager log - -pretty = format : " Date: %cd; Commit: %H - %s; Author: %an <%ae> " -1
}
2019-12-13 09:48:00 -05:00
}
Function GenerateResourcesAndImage {
<#
. SYNOPSIS
A helper function to help generate an image .
. DESCRIPTION
Creates Azure resources and kicks off a packer image generation for the selected image type .
. PARAMETER SubscriptionId
The Azure subscription Id where resources will be created .
. PARAMETER ResourceGroupName
The Azure resource group name where the Azure resources will be created .
. PARAMETER ImageGenerationRepositoryRoot
The root path of the image generation repository source .
. PARAMETER ImageType
The type of the image being generated . Valid options are: {"Windows2016", "Windows2019", "Ubuntu1604", "Ubuntu1804"} .
. PARAMETER AzureLocation
The location of the resources being created in Azure . For example "East US" .
. PARAMETER Force
Delete the resource group if it exists without user confirmation .
2020-01-23 14:14:05 +03:00
. PARAMETER GithubFeedToken
GitHub PAT to download tool packages from GitHub Package Registry
2019-12-13 09:48:00 -05:00
. EXAMPLE
2020-01-08 07:56:32 -05:00
GenerateResourcesAndImage -SubscriptionId {YourSubscriptionId} -ResourceGroupName "shsamytest1" -ImageGenerationRepositoryRoot "C:\virtual-environments" -ImageType Ubuntu1604 -AzureLocation "East US"
2019-12-13 09:48:00 -05:00
#>
param (
[ Parameter ( Mandatory = $True ) ]
[ string ] $SubscriptionId ,
[ Parameter ( Mandatory = $True ) ]
[ string ] $ResourceGroupName ,
[ Parameter ( Mandatory = $True ) ]
[ ImageType ] $ImageType ,
[ Parameter ( Mandatory = $True ) ]
[ string ] $AzureLocation ,
[ Parameter ( Mandatory = $False ) ]
2020-10-19 18:51:09 +03:00
[ string ] $ImageGenerationRepositoryRoot = $pwd ,
[ Parameter ( Mandatory = $False ) ]
2019-12-13 09:48:00 -05:00
[ int ] $SecondsToWaitForServicePrincipalSetup = 30 ,
2020-01-24 10:55:32 +03:00
[ Parameter ( Mandatory = $False ) ]
2020-01-23 14:14:05 +03:00
[ string ] $GithubFeedToken ,
2019-12-13 09:48:00 -05:00
[ Parameter ( Mandatory = $False ) ]
[ Switch ] $Force
)
2020-01-24 10:49:02 +03:00
if ( ( [ string ] :: IsNullOrEmpty ( $GithubFeedToken ) ) )
2020-01-23 14:14:05 +03:00
{
2020-01-24 10:55:32 +03:00
Write-Error " '-GithubFeedToken' parameter is not specified. You have to specify valid GitHub PAT to download tool packages from GitHub Package Registry "
2020-01-24 10:49:02 +03:00
exit 1
2020-01-23 14:14:05 +03:00
}
2019-12-13 09:48:00 -05:00
$builderScriptPath = Get-PackerTemplatePath -RepositoryRoot $ImageGenerationRepositoryRoot -ImageType $ImageType
$ServicePrincipalClientSecret = $env:UserName + [ System.GUID ] :: NewGuid ( ) . ToString ( ) . ToUpper ( ) ;
$InstallPassword = $env:UserName + [ System.GUID ] :: NewGuid ( ) . ToString ( ) . ToUpper ( ) ;
2020-09-22 09:46:15 +02:00
Connect-AzAccount
Set-AzContext -SubscriptionId $SubscriptionId
2019-12-13 09:48:00 -05:00
$alreadyExists = $true ;
try {
2020-09-22 09:46:15 +02:00
Get-AzResourceGroup -Name $ResourceGroupName
2019-12-13 09:48:00 -05:00
Write-Verbose " Resource group was found, will delete and recreate it. "
}
catch {
Write-Verbose " Resource group was not found, will create it. "
$alreadyExists = $false ;
}
if ( $alreadyExists ) {
if ( $Force -eq $true ) {
# Cleanup the resource group if it already exitsted before
2020-09-22 09:46:15 +02:00
Remove-AzResourceGroup -Name $ResourceGroupName -Force
New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation
2019-12-13 09:48:00 -05:00
} else {
$title = " Delete Resource Group "
$message = " The resource group you specified already exists. Do you want to clean it up? "
$yes = New-Object System . Management . Automation . Host . ChoiceDescription " &Yes " , `
" Delete the resource group including all resources. "
$no = New-Object System . Management . Automation . Host . ChoiceDescription " &No " , `
" Keep the resource group and continue. "
$stop = New-Object System . Management . Automation . Host . ChoiceDescription " &Stop " , `
" Stop the current action. "
$options = [ System.Management.Automation.Host.ChoiceDescription[] ] ( $yes , $no , $stop )
$result = $host . ui . PromptForChoice ( $title , $message , $options , 0 )
switch ( $result )
{
2020-09-22 09:46:15 +02:00
0 { Remove-AzResourceGroup -Name $ResourceGroupName -Force ; New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation }
2019-12-13 09:48:00 -05:00
1 { <# Do nothing #> }
2 { exit }
}
}
} else {
2020-09-22 09:46:15 +02:00
New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation
2019-12-13 09:48:00 -05:00
}
# This script should follow the recommended naming conventions for azure resources
$storageAccountName = if ( $ResourceGroupName . EndsWith ( " -rg " ) ) {
$ResourceGroupName . Substring ( 0 , $ResourceGroupName . Length -3 )
} else { $ResourceGroupName }
# Resource group names may contain special characters, that are not allowed in the storage account name
$storageAccountName = $storageAccountName . Replace ( " - " , " " ) . Replace ( " _ " , " " ) . Replace ( " ( " , " " ) . Replace ( " ) " , " " ) . ToLower ( )
$storageAccountName + = " 001 "
2020-09-22 09:46:15 +02:00
New-AzStorageAccount -ResourceGroupName $ResourceGroupName -AccountName $storageAccountName -Location $AzureLocation -SkuName " Standard_LRS "
2019-12-13 09:48:00 -05:00
$spDisplayName = [ System.GUID ] :: NewGuid ( ) . ToString ( ) . ToUpper ( )
2020-09-25 15:00:21 +03:00
$credentialProperties = @ { StartDate = Get-Date ; EndDate = Get-Date -Year 2024 ; Password = $ServicePrincipalClientSecret }
$credentials = New-Object -TypeName Microsoft . Azure . Commands . ActiveDirectory . PSADPasswordCredential -Property $credentialProperties
2020-09-25 14:08:34 +03:00
$sp = New-AzADServicePrincipal -DisplayName $spDisplayName -PasswordCredential $credentials
2019-12-13 09:48:00 -05:00
$spAppId = $sp . ApplicationId
$spClientId = $sp . ApplicationId
$spObjectId = $sp . Id
Start-Sleep -Seconds $SecondsToWaitForServicePrincipalSetup
2020-09-22 09:46:15 +02:00
New-AzRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $spAppId
2019-12-13 09:48:00 -05:00
Start-Sleep -Seconds $SecondsToWaitForServicePrincipalSetup
2020-09-22 09:46:15 +02:00
$sub = Get-AzSubscription -SubscriptionId $SubscriptionId
2019-12-13 09:48:00 -05:00
$tenantId = $sub . TenantId
# "", "Note this variable-setting script for running Packer with these Azure resources in the future:", "==============================================================================================", "`$spClientId = `"$spClientId`"", "`$ServicePrincipalClientSecret = `"$ServicePrincipalClientSecret`"", "`$SubscriptionId = `"$SubscriptionId`"", "`$tenantId = `"$tenantId`"", "`$spObjectId = `"$spObjectId`"", "`$AzureLocation = `"$AzureLocation`"", "`$ResourceGroupName = `"$ResourceGroupName`"", "`$storageAccountName = `"$storageAccountName`"", "`$install_password = `"$install_password`"", ""
2020-08-24 12:31:51 +03:00
Get-LatestCommit -ErrorAction SilentlyContinue
2020-10-19 18:51:09 +03:00
$packerBinary = Get-Command " packer "
if ( -not ( $packerBinary ) ) {
throw " 'packer' binary is not found on PATH "
}
& $packerBinary build -on -error = ask `
2020-01-23 14:14:05 +03:00
-var " client_id= $( $spClientId ) " `
-var " client_secret= $( $ServicePrincipalClientSecret ) " `
-var " subscription_id= $( $SubscriptionId ) " `
-var " tenant_id= $( $tenantId ) " `
-var " object_id= $( $spObjectId ) " `
-var " location= $( $AzureLocation ) " `
-var " resource_group= $( $ResourceGroupName ) " `
-var " storage_account= $( $storageAccountName ) " `
-var " install_password= $( $InstallPassword ) " `
-var " github_feed_token= $( $GithubFeedToken ) " `
$builderScriptPath
2019-12-13 09:48:00 -05:00
}