Deploying an Azure static website through PowerShell

March 27th 2019

One option for hosting a static website within Azure is to use the 'Static Website' feature of a storage container.

To create this infrastructure in PowerShell, you can use the Azure REST API to enable the Static Website option within an existing storage container.

1
function Set-StorageAccountEnableStaticWebsite {
2
[CmdletBinding()]
3
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
4
param(
5
[Parameter(Mandatory = $true)] $StorageContext,
6
[Parameter()][string] $IndexDocument = "index.html",
7
[Parameter()][string] $ErrorDocument404Path = "404.html"
8
)
9
10
$token = New-AzureStorageAccountSASToken `
11
-Service Blob, File, Table, Queue `
12
-ResourceType Service, Container, Object `
13
-Permission "racwdlup" `
14
-Context $storageAccount.Context
15
16
$storageAccountName = $storageAccount.StorageAccountName
17
18
$uri = "https://$storageAccountName.blob.core.windows.net"
19
$uri = $uri + $token
20
$uri = $uri + "&restype=service&comp=properties"
21
$uri = $uri + "&api-version=2018-03-28"
22
23
$body = @"
24
<?xml version="1.0" encoding="utf-8"?>
25
<StorageServiceProperties>
26
<StaticWebsite>
27
<Enabled>true</Enabled>
28
<IndexDocument>$IndexDocument</IndexDocument>
29
<ErrorDocument404Path>$ErrorDocument404Path</ErrorDocument404Path>
30
</StaticWebsite>
31
</StorageServiceProperties>
32
"@
33
34
Invoke-RestMethod -Uri $uri -Method Put -Body $body
35
}

Files can be uploaded to the configured storage container:

1
function Set-BlobContentFromFolderRecursive {
2
[CmdletBinding()]
3
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
4
param(
5
[Parameter(Mandatory = $true)] $StorageContext,
6
[Parameter(Mandatory = $true)][string] $ContainerName,
7
[Parameter(Mandatory = $true)][string] $Folder,
8
[Parameter()][boolean] $RemoveAll = $false,
9
[Parameter()][boolean] $SetDefaultContentTypes = $false
10
)
11
12
If ($RemoveAll -eq $true) {
13
$blobs = Get-AzureStorageBlob -Context $StorageContext -Container $ContainerName
14
$blobs | Remove-AzureStorageBlob
15
}
16
17
$container = Get-AzureStorageContainer -Name $ContainerName -Context $StorageContext
18
19
$AbsoluteFolder = Resolve-Path -Path $Folder
20
if ($container) {
21
$filesToUpload = Get-ChildItem $AbsoluteFolder.Path -Recurse -File
22
23
foreach ($fileInfo in $filesToUpload) {
24
$filePath = $fileInfo.fullname
25
$targetPath = $filePath.Substring($AbsoluteFolder.Path.Length + 1).Replace("\", "/")
26
27
$fileUri = $($container.CloudBlobContainer.Uri.AbsoluteUri + "/" + $targetPath)
28
29
Set-AzureStorageBlobContent `
30
-File $filePath `
31
-Container $container.Name `
32
-Blob $targetPath `
33
-Context $StorageContext `
34
-Force:$true
35
}
36
37
If ($SetDefaultContentTypes -eq $true) {
38
Set-BlobContentType `
39
-StorageContext $StorageContext `
40
-ContainerName $ContainerName
41
}
42
43
return
44
}
45
46
throw "Container not found '$ContainerName'"
47
}
48
49
function Set-BlobContentType {
50
[CmdletBinding()]
51
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
52
param(
53
[Parameter(Mandatory = $true)] $StorageContext,
54
[Parameter(Mandatory = $true)][string] $ContainerName
55
)
56
57
$blobs = Get-AzureStorageBlob -Context $StorageContext -Container $ContainerName
58
59
foreach ($blob in $blobs) {
60
$extension = [IO.Path]::GetExtension($Blob.Name)
61
$contentType = ""
62
63
switch ($extension) {
64
".html" { $contentType = "text/html" }
65
".json" { $contentType = "application/json" }
66
".js" { $contentType = "application/javascript" }
67
".svg" { $contentType = "image/svg+xml" }
68
Default { $contentType = "" }
69
}
70
71
if ($contentType -ne "") {
72
$cloudBlockBlob = [Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob] $Blob.ICloudBlob
73
74
$cloudBlockBlob.Properties.ContentType = $ContentType
75
$cloudBlockBlob.SetProperties()
76
}
77
}
78
}