Skip to content

Commit 67ae4e2

Browse files
authored
Merge branch 'main' into feature/teams-boards
2 parents 4afb014 + ef852db commit 67ae4e2

4 files changed

Lines changed: 383 additions & 0 deletions

File tree

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
2+
function Get-AzDoExtension {
3+
<#
4+
.SYNOPSIS
5+
Retrieves installed Azure DevOps extensions for a given organization.
6+
7+
.DESCRIPTION
8+
The Get-AzDoExtension function retrieves installed extensions from an Azure DevOps organization.
9+
It supports filtering by extension name and extension ID. The function uses the Azure DevOps REST API
10+
to fetch the extensions and returns detailed information about each extension.
11+
12+
.PARAMETER CollectionUri
13+
The URI of the Azure DevOps organization collection. This parameter is mandatory and accepts a string.
14+
15+
.PARAMETER ExtensionName
16+
The name(s) of the extension(s) to look for. This parameter accepts an array of strings and is optional.
17+
18+
.PARAMETER ExtensionId
19+
The ID(s) of the extension(s) to look for. This parameter accepts an array of strings and is optional.
20+
21+
.EXAMPLE
22+
PS> Get-AzDoExtension -CollectionUri "https://dev.azure.com/organization" -ExtensionName "extension1"
23+
24+
Retrieves the extension named "extension1" from the specified Azure DevOps organization.
25+
26+
.EXAMPLE
27+
PS> Get-AzDoExtension -CollectionUri "https://dev.azure.com/organization" -ExtensionId "extension-id-123"
28+
29+
Retrieves the extension with the ID "extension-id-123" from the specified Azure DevOps organization.
30+
31+
.NOTES
32+
This function uses the Azure DevOps REST API to fetch the installed extensions.
33+
Ensure you have the necessary permissions to access the API.
34+
35+
.LINK
36+
https://learn.microsoft.com/en-us/rest/api/azure/devops/extensionmanagement/installed-extensions/get?view=azure-devops-rest-7.1&tabs=HTTP
37+
#>
38+
[CmdletBinding(SupportsShouldProcess)]
39+
param (
40+
# Collection Uri of the organization
41+
[Parameter(Mandatory, ValueFromPipelineByPropertyName)]
42+
[ValidateScript({ Validate-CollectionUri -CollectionUri $_ })]
43+
[string]
44+
$CollectionUri,
45+
46+
# Name(s) of the extension(s) to look for
47+
[Parameter(ValueFromPipelineByPropertyName, ValueFromPipeline)]
48+
[string[]]
49+
$ExtensionName,
50+
51+
# Id(s) of the extension(s) to look for
52+
[Parameter(ValueFromPipelineByPropertyName, ValueFromPipeline)]
53+
[string[]]
54+
$ExtensionId
55+
)
56+
57+
begin {
58+
Write-Verbose "Starting function: Get-AzDoExtension"
59+
}
60+
61+
process {
62+
# For extensions a different base URI is used: https://learn.microsoft.com/en-us/rest/api/azure/devops/extensionmanagement/installed-extensions/get?view=azure-devops-rest-7.1&tabs=HTTP
63+
$extensionCollectionUri = $CollectionUri -replace "//dev", "//extmgmt.dev"
64+
65+
$params = @{
66+
uri = "$extensionCollectionUri/_apis/extensionmanagement/installedextensions"
67+
version = "7.1-preview.1"
68+
method = "GET"
69+
}
70+
71+
if ($PSCmdlet.ShouldProcess($CollectionUri, "Get Extension(s) in $CollectionUri")) {
72+
$result = (Invoke-AzDoRestMethod @params).value | Where-Object { -not $ExtensionName -and -not $ExtensionId -or $_.extensionName -in $ExtensionName -or $_.extensionId -in $ExtensionId }
73+
} else {
74+
Write-Verbose "Calling Invoke-AzDoRestMethod with $($params| ConvertTo-Json -Depth 10)"
75+
}
76+
}
77+
end {
78+
if ($result) {
79+
$result | ForEach-Object {
80+
[PSCustomObject]@{
81+
CollectionURI = $CollectionUri
82+
ExtensionCollectionURI = $extensionCollectionUri
83+
ExtensionId = $_.extensionId
84+
ExtensionName = $_.extensionName
85+
ExtensionPublisherId = $_.PublisherId
86+
ExtensionPublisherName = $_.PublisherName
87+
ExtensionVersion = $_.version
88+
ExtensionBaseUri = $_.baseUri
89+
ExtensionFallbackBaseUri = $_.fallbackBaseUri
90+
}
91+
}
92+
}
93+
}
94+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
function New-AzDoExtension {
2+
<#
3+
.SYNOPSIS
4+
Installs an Azure DevOps extension in the specified organization.
5+
6+
.DESCRIPTION
7+
The New-AzDoExtension cmdlet installs an Azure DevOps extension in the specified organization.
8+
It uses the Azure DevOps REST API to perform the installation.
9+
10+
.PARAMETER CollectionUri
11+
The URI of the Azure DevOps organization.
12+
13+
.PARAMETER ExtensionId
14+
The ID of the extension to install.
15+
16+
.PARAMETER ExtensionPublisherId
17+
The publisher ID of the extension to install.
18+
19+
.PARAMETER ExtensionVersion
20+
The version of the extension to install. If not specified, the latest version will be installed.
21+
22+
.EXAMPLE
23+
PS> New-AzDoExtension -CollectionUri "https://dev.azure.com/yourorganization" -ExtensionId "extensionId" -ExtensionPublisherId "publisherId"
24+
25+
This command installs the specified extension in the given Azure DevOps organization.
26+
27+
.EXAMPLE
28+
PS> New-AzDoExtension -CollectionUri "https://dev.azure.com/yourorganization" -ExtensionId "extensionId" -ExtensionPublisherId "publisherId" -ExtensionVersion "1.0.0"
29+
30+
This command installs version 1.0.0 of the specified extension in the given Azure DevOps organization.
31+
32+
.NOTES
33+
This cmdlet requires the Azure DevOps REST API and appropriate permissions to install extensions.
34+
35+
.LINK
36+
https://learn.microsoft.com/en-us/rest/api/azure/devops/extensionmanagement/installed-extensions/get?view=azure-devops-rest-7.1&tabs=HTTP
37+
#>
38+
[CmdletBinding(SupportsShouldProcess)]
39+
param (
40+
# Collection Uri of the organization
41+
[Parameter(Mandatory, ValueFromPipelineByPropertyName)]
42+
[ValidateScript({ Validate-CollectionUri -CollectionUri $_ })]
43+
[string]
44+
$CollectionUri,
45+
46+
# Name(s) of the extension(s) to look for
47+
[Parameter(Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline)]
48+
[string]
49+
$ExtensionId,
50+
51+
# Id(s) of the extension(s) to look for
52+
[Parameter(Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline)]
53+
[string]
54+
$ExtensionPublisherId,
55+
56+
# Version of the extension to install
57+
[Parameter(ValueFromPipelineByPropertyName, ValueFromPipeline)]
58+
[string]
59+
$ExtensionVersion
60+
)
61+
62+
begin {
63+
Write-Verbose "Starting function: New-AzDoExtensions"
64+
}
65+
66+
process {
67+
# For extensions a different base URI is used: https://learn.microsoft.com/en-us/rest/api/azure/devops/extensionmanagement/installed-extensions/get?view=azure-devops-rest-7.1&tabs=HTTP
68+
$extensionCollectionUri = $CollectionUri -replace "//dev", "//extmgmt.dev"
69+
70+
if ($ExtensionVersion) {
71+
$uri = "$extensionCollectionUri/_apis/extensionmanagement/installedextensionsbyname/$ExtensionPublisherId/$ExtensionId/$ExtensionVersion"
72+
} else {
73+
$uri = "$extensionCollectionUri/_apis/extensionmanagement/installedextensionsbyname/$ExtensionPublisherId/$ExtensionId"
74+
}
75+
76+
$params = @{
77+
uri = $uri
78+
version = "7.1-preview.1"
79+
method = "POST"
80+
}
81+
82+
if ($PSCmdlet.ShouldProcess($CollectionUri, "Install Extension $ExtensionName in $CollectionUri")) {
83+
$result = (Invoke-AzDoRestMethod @params).value
84+
} else {
85+
Write-Verbose "Calling Invoke-AzDoRestMethod with $($params| ConvertTo-Json -Depth 10)"
86+
}
87+
}
88+
end {
89+
$result
90+
}
91+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
function Remove-AzDoExtension {
2+
<#
3+
.SYNOPSIS
4+
Removes an Azure DevOps extension from an organization.
5+
6+
.DESCRIPTION
7+
The `Remove-AzDoExtension` cmdlet removes an Azure DevOps extension from a specified organization.
8+
It uses the Azure DevOps REST API to perform the deletion.
9+
10+
.PARAMETER CollectionUri
11+
Specifies the URI of the Azure DevOps organization. This parameter is mandatory and accepts a string.
12+
13+
.PARAMETER ExtensionId
14+
Specifies the ID of the extension to be removed. This parameter is mandatory and accepts a string.
15+
16+
.PARAMETER ExtensionPublisherId
17+
Specifies the publisher ID of the extension to be removed. This parameter is mandatory and accepts a string.
18+
19+
.EXAMPLE
20+
PS> Remove-AzDoExtension -CollectionUri "https://dev.azure.com/yourorganization" -ExtensionId "yourExtensionId" -ExtensionPublisherId "yourPublisherId"
21+
22+
This command removes the specified extension from the specified Azure DevOps organization.
23+
24+
.NOTES
25+
For more information on the Azure DevOps REST API, see:
26+
https://learn.microsoft.com/en-us/rest/api/azure/devops/extensionmanagement/installed-extensions/get?view=azure-devops-rest-7.1&tabs=HTTP
27+
#>
28+
[CmdletBinding(SupportsShouldProcess)]
29+
param (
30+
# Collection Uri of the organization
31+
[Parameter(Mandatory, ValueFromPipelineByPropertyName)]
32+
[ValidateScript({ Validate-CollectionUri -CollectionUri $_ })]
33+
[string]
34+
$CollectionUri,
35+
36+
# Name(s) of the extension(s) to look for
37+
[Parameter(Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline)]
38+
[string]
39+
$ExtensionId,
40+
41+
# Id(s) of the extension(s) to look for
42+
[Parameter(Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline)]
43+
[string]
44+
$ExtensionPublisherId
45+
)
46+
47+
begin {
48+
Write-Verbose "Starting function: Remove-AzDoExtension"
49+
}
50+
51+
process {
52+
# For extensions a different base URI is used: https://learn.microsoft.com/en-us/rest/api/azure/devops/extensionmanagement/installed-extensions/get?view=azure-devops-rest-7.1&tabs=HTTP
53+
$extensionCollectionUri = $CollectionUri -replace "//dev", "//extmgmt.dev"
54+
55+
$params = @{
56+
uri = "$extensionCollectionUri/_apis/extensionmanagement/installedextensionsbyname/$ExtensionPublisherId/$ExtensionId"
57+
version = "7.1-preview.1"
58+
method = "DELETE"
59+
}
60+
61+
if ($PSCmdlet.ShouldProcess($CollectionUri, "Remove $ExtensionId from organization $CollectionUri")) {
62+
$result = (Invoke-AzDoRestMethod @params).value
63+
} else {
64+
Write-Verbose "Calling Invoke-AzDoRestMethod with $($params| ConvertTo-Json -Depth 10)"
65+
}
66+
}
67+
end {
68+
$result
69+
}
70+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
BeforeDiscovery {
2+
$ModuleName = 'AzureDevOpsPowerShell'
3+
Get-Module $ModuleName | Remove-Module -Force -ErrorAction Ignore
4+
$path = Join-Path -Path $PSScriptRoot -ChildPath "..\..\..\..\$ModuleName\$ModuleName.psm1" | Resolve-Path
5+
Import-Module -Name $path -Verbose:$false -ErrorAction Stop
6+
}
7+
8+
InModuleScope $ModuleName {
9+
BeforeAll {
10+
$collectionUri = "https://dev.azure.com/AzureDevOpsPowerShell"
11+
12+
$params = @{
13+
CollectionUri = $collectionUri
14+
Confirm = $false
15+
}
16+
}
17+
18+
Describe "Get-AzDoExtension" -Tag Local {
19+
BeforeAll {
20+
Mock Invoke-AzDoRestMethod {
21+
@{
22+
value = @(
23+
[PSCustomObject]@{
24+
CollectionURI = $CollectionUri
25+
ExtensionCollectionURI = $extensionCollectionUri
26+
ExtensionId = 'vss-testextension'
27+
ExtensionName = 'extensionTest'
28+
ExtensionPublisherId = 'rbnmk'
29+
ExtensionPublisherName = 'RobinM'
30+
ExtensionVersion = '0.0.1'
31+
ExtensionBaseUri = 'baseUri'
32+
ExtensionFallbackBaseUri = 'fallbackBaseUri'
33+
}
34+
[PSCustomObject]@{
35+
CollectionURI = $CollectionUri
36+
ExtensionCollectionURI = $extensionCollectionUri
37+
ExtensionId = 'vss-testextension2'
38+
ExtensionName = 'extensionTest2'
39+
ExtensionPublisherId = 'rbnmk2'
40+
ExtensionPublisherName = 'RobinM2'
41+
ExtensionVersion = '0.0.1'
42+
ExtensionBaseUri = 'baseUri2'
43+
ExtensionFallbackBaseUri = 'fallbackBaseUri2'
44+
}
45+
[PSCustomObject]@{
46+
CollectionURI = $CollectionUri
47+
ExtensionCollectionURI = $extensionCollectionUri
48+
ExtensionId = 'vss-testextension3'
49+
ExtensionName = 'extensionTest3'
50+
ExtensionPublisherId = 'rbnmk3'
51+
ExtensionPublisherName = 'RobinM3'
52+
ExtensionVersion = '0.0.1'
53+
ExtensionBaseUri = 'baseUri3'
54+
ExtensionFallbackBaseUri = 'fallbackBaseUri3'
55+
}
56+
)
57+
}
58+
}
59+
}
60+
61+
It "It provides users with feedback via ShouldProcess when using WhatIf" {
62+
Get-AzDoExtension @params -WhatIf -Verbose 4>&1 | Out-String | Should -BeLike "*Calling Invoke-AzDoRestMethod with {*"
63+
}
64+
65+
It "Outputs all extensions when no value to ExtensionName or ExtensionId was provided" {
66+
(Get-AzDoExtension @params | Measure-Object).Count | Should -BeGreaterThan 1
67+
}
68+
69+
It "Outputs extension which matches the name of ExtensionName" {
70+
(Get-AzDoExtension @params -ExtensionName "extensionTest3").ExtensionName | Should -Be "extensionTest3"
71+
}
72+
73+
It "Outputs extension which matches the Id of ExtensionId" {
74+
(Get-AzDoExtension @params -ExtensionId "vss-testextension2").ExtensionId | Should -Be "vss-testextension2"
75+
}
76+
77+
It "Outputs extensions which matches the Id of ExtensionId AND ExtensionName" {
78+
(Get-AzDoExtension @params -ExtensionId "vss-testextension2" -ExtensionName "extensionTest3" | Measure-Object).count | Should -BeExactly 2
79+
}
80+
81+
}
82+
83+
Describe "New-AzDoExtension" -Tag Local {
84+
BeforeAll {
85+
86+
$params.Add("ExtensionId", "vss-testextension")
87+
$params.Add("ExtensionPublisherId", "rbnmk")
88+
89+
Mock Invoke-AzDoRestMethod { $null }
90+
91+
}
92+
93+
It "It provides users with feedback via ShouldProcess when using WhatIf" {
94+
New-AzDoExtension @params -WhatIf -Verbose 4>&1 | Out-String | Should -BeLike "*Calling Invoke-AzDoRestMethod with {*"
95+
}
96+
97+
It "Installs AzDo extension when ExtensionId and ExtensionPublisherId are provided and returns null or empty" {
98+
(New-AzDoExtension @params) | Should -BeNullOrEmpty
99+
}
100+
101+
It "Installs AzDo extension when ExtensionId, ExtensionPublisherId and ExtensionVersion are provided and returns null or empty" {
102+
$params.Add("ExtensionVersion", "0.0.1")
103+
(New-AzDoExtension @params) | Should -BeNullOrEmpty
104+
}
105+
106+
It "Throws exception when ExtensionId/PublisherName is already installed" {
107+
Mock Invoke-AzDoRestMethod { throw "Extension already installed" }
108+
{ New-AzDoExtension @params } | Should -Throw -Because "Extension already installed"
109+
}
110+
111+
112+
}
113+
114+
Describe "Remove-AzDoExtension" -Tag Local {
115+
BeforeAll {
116+
Mock Invoke-AzDoRestMethod { $null }
117+
$params.Remove("ExtensionVersion")
118+
}
119+
120+
It "It provides users with feedback via ShouldProcess when using WhatIf" {
121+
Remove-AzDoExtension @params -ExtensionId "vss-testextension" -ExtensionPublisherid "pesterpublisher" -WhatIf -Verbose 4>&1 | Out-String | Should -BeLike "*Calling Invoke-AzDoRestMethod with {*"
122+
}
123+
124+
It "Removes AzDo extension when ExtensionId and ExtensionPublisherId are provided and returns null or empty" {
125+
(New-AzDoExtension @params -ExtensionId "vss-testextension" -ExtensionPublisherid "pesterpublisher") | Should -BeNullOrEmpty
126+
}
127+
}
128+
}

0 commit comments

Comments
 (0)