PSAzureUtils.psm1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
<#
.SYNOPSIS
    Create a new Resource Group.
.DESCRIPTION
    New-ResourceGroup create a new Azure Resource Group if an existing Resource Group with the same name cannot be found.
#>

function New-ResourceGroup {
    [CmdletBinding()]
    [OutputType([Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.PSResourceGroup])]
    param (
        # The name of the Resource Group. Can be an existing or new Resource Group.
        [Parameter(Mandatory=$true)]
        $Name,

        # The location to deploy the Resource Group. If the Resource Group already exists this parameter does not apply.
        [Parameter(Mandatory=$true)]
        $Location
    )

    # Only create the resource group if it doesn't already exist
    $resourceGroup = Get-AzResourceGroup -Name $Name -ErrorAction SilentlyContinue
    if(!$resourceGroup) {
        Write-Verbose "$Name does not existing and will be created."
        $resourceGroup = New-AzResourceGroup -Name $Name -Location $Location -ErrorAction Stop
    }
    else {
        Write-Warning "$Name already exists."
    }

    Write-Output $resourceGroup
}

<#
.SYNOPSIS
    Generate a name for ARM deployments.
.DESCRIPTION
    Get-DeploymentName is a helper function to generate a unique name for ARM template deployment.
 
    Either ResourceGroupName or Name can be specified, not both. The current date and time are
    appended in the format yyyyMMdd-HHmm and returned as Name_DateTime.
 
    Eg. Production_20170227-0034
#>

function Get-DeploymentName {
    [CmdletBinding(DefaultParameterSetName="RG")]
    [OutputType([string])]
    param (
        # The name of the Resource Group.
        [Parameter(Mandatory=$true,ParameterSetName="RG")]
        $ResourceGroupName,

        # The name of the deployment.
        [Parameter(Mandatory=$true,ParameterSetName="Name")]
        $Name
    )

    $utcNow = ((Get-Date).ToUniversalTime()).ToString('yyyyMMdd-HHmm')
    $deploymentName = "{0}_{1}"

    if ($PsCmdlet.ParameterSetName -eq "RG") {
        Write-Output ($deploymentName -f $ResourceGroupName, $utcNow)
    }
    else {
        Write-Output ($deploymentName -f $Name, $utcNow)
    }
}

<#
.SYNOPSIS
    Validate a given subscription is the expected subscription.
.DESCRIPTION
    Test-Subscription is a helper function to validate that the given subscription
    matches the expected subscription.
 
    The name from the subscription object is compared with the given subscription name.
    Note that Subscription is a PSAzureContext object.
#>

function Test-Subscription {
    [CmdletBinding()]
    param (
        # The Azure subscription obtained from Get-AzContext or a similar cmdlet.
        [Parameter(Mandatory=$true)]
        [ValidateNotNull()]
        [Microsoft.Azure.Commands.Profile.Models.PSAzureContext]
        $Subscription,

        # The name of the Azure Subscription.
        [Parameter(Mandatory=$true)]
        [string]
        $SubscriptionName
    )

    $givenSubscriptionName = $Subscription.Subscription.SubscriptionName
    if($givenSubscriptionName -eq $SubscriptionName)
    {
        Write-Error ("Given subscription is `"{0}`", Expecting `"{1}`"." -f $givenSubscriptionName, $SubscriptionName)
        Write-Output $false
    }
    else{
        Write-Output $true
        Write-Verbose ("Subscription: {0}, SubscriptionId: {1}, TenantId: {2}" -f $SubscriptionName, $Subscription.Subscription.Id, $Subscription.Tenant.Id)
    }
}

<#
.SYNOPSIS
    Get an Azure Access token.
.DESCRIPTION
    Get-AccessToken attempts to dump an access token for the give resource identifier to the console.
#>

function Get-AccessToken {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false, Position=0)]
        [ValidateNotNullOrEmpty()]
        $Context=(Get-AzContext),

        [Parameter(Mandatory=$false, Position=1)]
        [string]
        $Resource = "https://management.azure.com"
    )

    if ($null -eq $Context) {
        throw [System.ArgumentNullException]::new("Context")
    }

    $authenticationFactory = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory
    $token = $authenticationFactory.Authenticate($Context.Account, $Context.Environment, $Context.Tenant.Id, $null, "Never", $null, $Resource)
    Write-Output $token.AccessToken

}

<#
.SYNOPSIS
    Connect to Azure
.DESCRIPTION
    Connect-Azure connects to the given tenant or subscription.
.EXAMPLE
    PS C:\> Connect-Azure -SubscriptionId '12202988-c8c0-46a8-b43f-df4f5217a28d'
    Connects to the Azure subscription with the SubscriptionId 12202988-c8c0-46a8-b43f-df4f5217a28d
.EXAMPLE
    PS C:\> Connect-Azure -TenantId '64b7dfc8-f9c4-49c9-b663-799896ce4ee2'
    Connects to the Azure subscription with the TenantId 64b7dfc8-f9c4-49c9-b663-799896ce4ee2.
#>

function Connect-Azure
{
    [CmdletBinding(DefaultParameterSetName="Subscription")]
    Param
    (
        # TenantId
        [Parameter(Mandatory=$true, Position=0, ParameterSetName="Subscription")]
        [string]
        $SubscriptionId,

        # TenantId
        [Parameter(Mandatory=$true, Position=0, ParameterSetName="Tenant")]
        [string]
        $TenantId
    )

    if ($PsCmdlet.ParameterSetName -eq "Subscription") {
        Connect-AzureSubscription -SubscriptionId $SubscriptionId
    }else {
        Connect-AzureTenant -TenantId $TenantId
    }
}

function Connect-AzureTenant
{
    [CmdletBinding()]
    Param
    (
        # TenantId
        [Parameter(Mandatory=$true, Position=0)]
        [string]
        $TenantId
    )

    ## Attempt to connect to Azure
    $subscriptions = $null
    try {
        $subscriptions = Get-AzSubscription -TenantId $tenantId
    }
    catch [System.Management.Automation.PSInvalidOperationException] {
        Write-Warning "No existing connection to TenantId: $tenantId"
    }

    if (!$subscriptions) {
        $azAccount = Connect-AzAccount -Tenant $tenantId -ErrorAction Stop

        if (($null -eq $azAccount) -or ($azAccount.Context.Tenant.Id -ne $tenantId)) {
            Write-Error "Could not connect to Azure." -ErrorAction Stop
        }
    }

    Write-Output (Get-AzContext)
}

function Connect-AzureSubscription
{
    [CmdletBinding()]
    Param
    (
        # TenantId
        [Parameter(Mandatory=$true, Position=0)]
        [string]
        $SubscriptionId
    )

    ## Attempt to connect to Azure
    $subscriptions = $null
    try {
        $subscriptions = Get-AzSubscription -SubscriptionId $SubscriptionId
    }
    catch [System.Management.Automation.PSInvalidOperationException] {
        Write-Warning "No existing connection to TenantId: $tenantId"
    }

    if (!$subscriptions) {
        $azAccount = Connect-AzAccount -ErrorAction Stop

        if (($null -eq $azAccount) -or ($azAccount.Context.Subscription.Id -ne $SubscriptionId)) {
            Write-Error "Could not connect to Azure." -ErrorAction Stop
        }
    }

    Write-Output (Get-AzContext)
}