Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
247de51
update workflow
eriqua Sep 12, 2022
777c913
test draft dep
eriqua Sep 12, 2022
6d76d1b
test draft dep sa
eriqua Sep 12, 2022
4712885
readme
eriqua Sep 12, 2022
7b7eae6
role assignment
eriqua Sep 12, 2022
dd0957a
2 dep
eriqua Sep 13, 2022
ee9ed8c
disable pester
eriqua Sep 13, 2022
51f5cde
managedIdentityResourceId
eriqua Sep 13, 2022
628c425
customize
eriqua Sep 13, 2022
2f621a4
customize restart
eriqua Sep 13, 2022
a5000e9
distribute
eriqua Sep 13, 2022
6196339
rbac
eriqua Sep 13, 2022
a5fd2be
basetime
eriqua Sep 13, 2022
1ddaf22
imageTemplateNamePrefix
eriqua Sep 13, 2022
b6f8eb6
managedIdentityName var
eriqua Sep 13, 2022
9890f83
triggerImageDeploymentScript
eriqua Sep 13, 2022
a89c697
copyVhdDeploymentScript
eriqua Sep 13, 2022
eb9f12d
validation
eriqua Sep 13, 2022
bd52394
readme
eriqua Sep 13, 2022
4cfba9c
output and dependson
eriqua Sep 13, 2022
5445c2b
dep descriptions
eriqua Sep 13, 2022
d77989a
container
eriqua Sep 13, 2022
0652b93
ps version
eriqua Sep 14, 2022
fe96963
cleanup
eriqua Sep 14, 2022
81413eb
Get-AzImageBuilderTemplateRunOutput
eriqua Sep 14, 2022
a2f6209
Merge branch 'main' into users/erikag/1921-images-newdep
eriqua Sep 18, 2022
31655ac
Update modules/Microsoft.Compute/images/.test/common/deploy.test.bicep
eriqua Sep 18, 2022
bc7446a
Update modules/Microsoft.Compute/images/.test/common/deploy.test.bicep
eriqua Sep 18, 2022
1e08317
Update modules/Microsoft.Compute/images/.test/common/deploy.test.bicep
eriqua Sep 27, 2022
3e1a492
no img
eriqua Sep 28, 2022
5add289
Merge branch 'users/erikag/1921-images-newdep' of https://github.com/…
eriqua Sep 28, 2022
3c392dd
test remove rolea prio
eriqua Sep 28, 2022
dd09e91
Merge branch 'main' into users/erikag/1921-images-newdep
eriqua Sep 30, 2022
3732640
reenable
eriqua Sep 30, 2022
4d5de12
Proposal 1 (#2136)
AlexanderSehr Sep 30, 2022
ee1340e
update naming
eriqua Sep 30, 2022
2c5ecc7
readme
eriqua Sep 30, 2022
b4d618b
no version update
eriqua Sep 30, 2022
fd0e17d
hosting env draft new dependencies
elanzel Sep 30, 2022
f43c1b9
Merge branch 'users/erikag/1921-images-newdep' of https://github.com/…
elanzel Sep 30, 2022
4e06cd3
added nsg
elanzel Sep 30, 2022
e0ce6c9
description .
elanzel Sep 30, 2022
1b724a0
Merge branch 'main' into users/erikag/1921-images-newdep
eriqua Sep 30, 2022
26046e5
rollback ase
eriqua Sep 30, 2022
a816d84
rollback ase pipeline
eriqua Sep 30, 2022
7f82d64
remove comment
eriqua Oct 3, 2022
b343454
add metadata to nested rbac param
eriqua Oct 3, 2022
2b989f5
Update deploy.test.bicep
eriqua Oct 3, 2022
14f0b54
Update dependencies.bicep
eriqua Oct 3, 2022
e382558
Update deploy.test.bicep
eriqua Oct 3, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/ms.compute.images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,7 @@ jobs:
- name: 'Using test file [${{ matrix.moduleTestFilePaths }}]'
uses: ./.github/actions/templates/validateModuleDeployment
with:
templateFilePath: '${{ env.modulePath }}/deploy.bicep'
parameterFilePath: '${{ env.modulePath }}/${{ matrix.moduleTestFilePaths }}'
templateFilePath: '${{ env.modulePath }}/${{ matrix.moduleTestFilePaths }}'
location: '${{ env.location }}'
resourceGroupName: '${{ env.resourceGroupName }}'
subscriptionId: '${{ secrets.ARM_SUBSCRIPTION_ID }}'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<#
.SYNOPSIS
Copy a VHD baked from a given image template to a given destination storage account blob container

.DESCRIPTION
Copy a VHD baked from a given image template to a given destination storage account blob container

.PARAMETER ImageTemplateName
Mandatory. The name of the image template

.PARAMETER ImageTemplateResourceGroup
Mandatory. The resource group name of the image template

.PARAMETER DestinationStorageAccountName
Mandatory. The name of the destination storage account

.PARAMETER DestinationContainerName
Optional. The name of the existing destination blob container

.PARAMETER VhdName
Optional. Specify a different name for the destination VHD file

.PARAMETER WaitForComplete
Optional. Run the command synchronously. Wait for the completion of the copy.

.EXAMPLE
Copy-VhdToStorageAccount -ImageTemplateName 'vhd-img-template-001-2022-07-29-15-54-01' -ImageTemplateResourceGroup 'validation-rg' -DestinationStorageAccountName 'vhdstorage001'

Copy a VHD created by image template 'vhd-img-template-001-2022-07-29-15-54-01' in resource group 'validation-rg' to destination storage account 'vhdstorage001' in blob container named 'vhds'. Save the VHD file as 'vhd-img-template-001-2022-07-29-15-54-01.vhd'.

.EXAMPLE
Copy-VhdToStorageAccount -ImageTemplateName 'vhd-img-template-001-2022-07-29-15-54-01' -ImageTemplateResourceGroup 'validation-rg' -DestinationStorageAccountName 'vhdstorage001' -VhdName 'vhd-img-template-001' -WaitForComplete

Copy a VHD baked by image template 'vhd-img-template-001-2022-07-29-15-54-01' in resource group 'validation-rg' to destination storage account 'vhdstorage001' in a blob container named 'vhds' and wait for the completion of the copy. Save the VHD file as 'vhd-img-template-001.vhd'.
#>

[CmdletBinding(SupportsShouldProcess)]
param (
[Parameter(Mandatory = $true)]
[string] $ImageTemplateName,

[Parameter(Mandatory = $true)]
[string] $ImageTemplateResourceGroup,

[Parameter(Mandatory = $true)]
[string] $DestinationStorageAccountName,

[Parameter(Mandatory = $false)]
[string] $DestinationContainerName = 'vhds',

[Parameter(Mandatory = $false)]
[string] $VhdName = $ImageTemplateName,

[Parameter(Mandatory = $false)]
[switch] $WaitForComplete
)

begin {
Write-Debug ('{0} entered' -f $MyInvocation.MyCommand)

# Install required modules
$currentVerbosePreference = $VerbosePreference
$VerbosePreference = 'SilentlyContinue'
$requiredModules = @(
'Az.ImageBuilder',
'Az.Storage'
)
foreach ($moduleName in $requiredModules) {
if (-not ($installedModule = Get-Module $moduleName -ListAvailable)) {
Install-Module $moduleName -Repository 'PSGallery' -Force -Scope 'CurrentUser'
if ($installed = Get-Module -Name $moduleName -ListAvailable) {
Write-Verbose ('Installed module [{0}] with version [{1}]' -f $installed.Name, $installed.Version) -Verbose
}
} else {
Write-Verbose ('Module [{0}] already installed in version [{1}]' -f $installedModule[0].Name, $installedModule[0].Version) -Verbose
}
}
$VerbosePreference = $currentVerbosePreference
}

process {
# Retrieving and initializing parameters before the blob copy
Write-Verbose 'Initializing source storage account parameters before the blob copy' -Verbose
Write-Verbose ('Retrieving source storage account from image template [{0}] in resource group [{1}]' -f $imageTemplateName, $imageTemplateResourceGroup) -Verbose
Get-InstalledModule
$imgtRunOutput = Get-AzImageBuilderTemplateRunOutput -ImageTemplateName $imageTemplateName -ResourceGroupName $imageTemplateResourceGroup | Where-Object ArtifactUri -NE $null
$sourceUri = $imgtRunOutput.ArtifactUri
$sourceStorageAccountName = $sourceUri.Split('//')[1].Split('.')[0]
$storageAccountList = Get-AzStorageAccount
$sourceStorageAccount = $storageAccountList | Where-Object StorageAccountName -EQ $sourceStorageAccountName
$sourceStorageAccountContext = $sourceStorageAccount.Context
$sourceStorageAccountRGName = $sourceStorageAccount.ResourceGroupName
Write-Verbose ('Retrieving artifact uri [{0}] stored in resource group [{1}]' -f $sourceUri, $sourceStorageAccountRGName) -Verbose

Write-Verbose 'Initializing destination storage account parameters before the blob copy' -Verbose
$destinationStorageAccount = $storageAccountList | Where-Object StorageAccountName -EQ $destinationStorageAccountName
$destinationStorageAccountContext = $destinationStorageAccount.Context
$destinationBlobName = "$vhdName.vhd"
Write-Verbose ('Planning for destination blob name [{0}] in container [{1}] and storage account [{2}]' -f $destinationBlobName, $destinationContainerName, $destinationStorageAccountName) -Verbose

# Copying the VHD to a destination blob container
$resourceActionInputObject = @{
AbsoluteUri = $sourceUri
Context = $sourceStorageAccountContext
DestContext = $destinationStorageAccountContext
DestBlob = $destinationBlobName
DestContainer = $destinationContainerName
Force = $true
}

if ($PSCmdlet.ShouldProcess('Storage blob copy of VHD [{0}]' -f $destinationBlobName, 'Start')) {
$destBlob = Start-AzStorageBlobCopy @resourceActionInputObject
Write-Verbose ('Copied/initialized copy of VHD from URI [{0}] to container [{1}] in storage account [{2}]' -f $sourceUri, $destinationContainerName, $destinationStorageAccountName) -Verbose
}

if ($WaitForComplete) {
$destBlob | Get-AzStorageBlobCopyState -WaitForComplete
}
}

end {
Write-Debug ('{0} exited' -f $MyInvocation.MyCommand)
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<#
.SYNOPSIS
Create image artifacts from a given image template

.DESCRIPTION
Create image artifacts from a given image template

.PARAMETER ImageTemplateName
Mandatory. The name of the image template

.PARAMETER ImageTemplateResourceGroup
Mandatory. The resource group name of the image template

.PARAMETER NoWait
Optional. Run the command asynchronously

.EXAMPLE
Start-AzImageBuilderTemplate -ImageTemplateName 'vhd-img-template-001-2022-07-29-15-54-01' -ImageTemplateResourceGroup 'validation-rg'

Create image artifacts from image template 'vhd-img-template-001-2022-07-29-15-54-01' in resource group 'validation-rg' and wait for their completion

.EXAMPLE
Start-AzImageBuilderTemplate -ImageTemplateName 'vhd-img-template-001-2022-07-29-15-54-01' -ImageTemplateResourceGroup 'validation-rg' -NoWait

Start the creation of artifacts from image template 'vhd-img-template-001-2022-07-29-15-54-01' in resource group 'validation-rg' and do not wait for their completion
#>

[CmdletBinding(SupportsShouldProcess)]
param (
[Parameter(Mandatory = $true)]
[string] $ImageTemplateName,

[Parameter(Mandatory = $true)]
[string] $ImageTemplateResourceGroup,

[Parameter(Mandatory = $false)]
[switch] $NoWait
)

begin {
Write-Debug ('{0} entered' -f $MyInvocation.MyCommand)

# Install required modules
$currentVerbosePreference = $VerbosePreference
$VerbosePreference = 'SilentlyContinue'
$requiredModules = @(
'Az.ImageBuilder'
)
foreach ($moduleName in $requiredModules) {
if (-not ($installedModule = Get-Module $moduleName -ListAvailable)) {
Install-Module $moduleName -Repository 'PSGallery' -Force -Scope 'CurrentUser'
if ($installed = Get-Module -Name $moduleName -ListAvailable) {
Write-Verbose ('Installed module [{0}] with version [{1}]' -f $installed.Name, $installed.Version) -Verbose
}
} else {
Write-Verbose ('Module [{0}] already installed in version [{1}]' -f $installedModule[0].Name, $installedModule[0].Version) -Verbose
}
}
$VerbosePreference = $currentVerbosePreference
}

process {
# Create image artifacts from existing image template
$resourceActionInputObject = @{
ImageTemplateName = $imageTemplateName
ResourceGroupName = $imageTemplateResourceGroup
}
if ($NoWait) {
$resourceActionInputObject['NoWait'] = $true
}
if ($PSCmdlet.ShouldProcess('Image template [{0}]' -f $imageTemplateName, 'Start')) {
$null = Start-AzImageBuilderTemplate @resourceActionInputObject
Write-Verbose ('Created/initialized creation of image artifacts from image template [{0}] in resource group [{1}]' -f $imageTemplateName, $imageTemplateResourceGroup) -Verbose
}
}

end {
Write-Debug ('{0} exited' -f $MyInvocation.MyCommand)
}
149 changes: 149 additions & 0 deletions modules/Microsoft.Compute/images/.test/common/dependencies.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
@description('Optional. The location to deploy to.')
param location string = resourceGroup().location

@description('Required. The name of the Managed Identity to create.')
param managedIdentityName string

@description('Required. The name of the Storage Account to create and to copy the VHD into.')
param storageAccountName string

@description('Required. The name prefix of the Image Template to create.')
param imageTemplateNamePrefix string

@description('Generated. Do not provide a value! This date value is used to generate a unique image template name.')
param baseTime string = utcNow('yyyy-MM-dd-HH-mm-ss')

@description('Required. The name of the Deployment Script to create for triggering the image creation.')
param triggerImageDeploymentScriptName string

@description('Required. The name of the Deployment Script to copy the VHD to a destination storage account.')
param copyVhdDeploymentScriptName string

resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
name: managedIdentityName
location: location
}

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = {
name: storageAccountName
location: location
kind: 'StorageV2'
sku: {
name: 'Standard_LRS'
}
properties: {
allowBlobPublicAccess: false
}
resource blobServices 'blobServices@2021-09-01' = {
name: 'default'
resource container 'containers@2021-09-01' = {
name: 'vhds'
properties: {
publicAccess: 'None'
}
}
}
}

module roleAssignment 'dependencies_rbac.bicep' = {
name: '${deployment().name}-MSI-roleAssignment'
scope: subscription()
params: {
managedIdentityPrincipalId: managedIdentity.properties.principalId
managedIdentityResourceId: managedIdentity.id
}
}

// Deploy image template
resource imageTemplate 'Microsoft.VirtualMachineImages/imageTemplates@2022-02-14' = {
name: '${imageTemplateNamePrefix}-${baseTime}'
location: location
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${managedIdentity.id}': {}
}
}
properties: {
buildTimeoutInMinutes: 0
vmProfile: {
vmSize: 'Standard_D2s_v3'
osDiskSizeGB: 127
}
source: {
type: 'PlatformImage'
publisher: 'MicrosoftWindowsDesktop'
offer: 'Windows-10'
sku: '19h2-evd'
version: 'latest'
}
distribute: [
{
type: 'VHD'
runOutputName: '${imageTemplateNamePrefix}-VHD'
artifactTags: {}
}
]
customize: [
{
restartTimeout: '30m'
type: 'WindowsRestart'
}
]
}
}

// Trigger VHD creation
resource triggerImageDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = {
name: triggerImageDeploymentScriptName
location: location
kind: 'AzurePowerShell'
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${managedIdentity.id}': {}
}
}
properties: {
azPowerShellVersion: '8.0'
retentionInterval: 'P1D'
arguments: '-ImageTemplateName \\"${imageTemplate.name}\\" -ImageTemplateResourceGroup \\"${resourceGroup().name}\\"'
scriptContent: loadTextContent('../.scripts/Start-ImageTemplate.ps1')
cleanupPreference: 'OnSuccess'
forceUpdateTag: baseTime
}
dependsOn: [
roleAssignment
]
}

// Copy VHD to destination storage account
resource copyVhdDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = {
name: copyVhdDeploymentScriptName
location: location
kind: 'AzurePowerShell'
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${managedIdentity.id}': {}
}
}
properties: {
azPowerShellVersion: '8.0'
retentionInterval: 'P1D'
arguments: '-ImageTemplateName \\"${imageTemplate.name}\\" -ImageTemplateResourceGroup \\"${resourceGroup().name}\\" -DestinationStorageAccountName \\"${storageAccount.name}\\" -VhdName \\"${imageTemplateNamePrefix}\\" -WaitForComplete'
scriptContent: loadTextContent('../.scripts/Copy-VhdToStorageAccount.ps1')
cleanupPreference: 'OnSuccess'
forceUpdateTag: baseTime
}
dependsOn: [ triggerImageDeploymentScript ]
}

@description('The URI of the created VHD.')
output vhdUri string = 'https://${storageAccount.name}.blob.core.windows.net/vhds/${imageTemplateNamePrefix}.vhd'

@description('The principal ID of the created Managed Identity.')
output managedIdentityPrincipalId string = managedIdentity.properties.principalId

@description('The resource ID of the created Managed Identity.')
output managedIdentityResourceId string = managedIdentity.id
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
targetScope = 'subscription'

@description('Required. The resource ID of the created Managed Identity.')
param managedIdentityResourceId string

@description('Required. The principal ID of the created Managed Identity.')
param managedIdentityPrincipalId string

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(subscription().subscriptionId, 'Contributor', managedIdentityResourceId)
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') // Contributor
principalId: managedIdentityPrincipalId
principalType: 'ServicePrincipal'
}
}
Loading