Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Added function `Update-FabricCapacity`
- Added Error Detailed Info in `Test-FabricApiResponse` (Debug mode) when `response.error` exists

### Changed

- Version of `Microsoft.PowerShell.PSResourceGet` and `Microsoft.PowerShell.PlatyPS` updated
Expand Down
16 changes: 12 additions & 4 deletions source/Private/Test-FabricApiResponse.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,19 @@ function Test-FabricApiResponse {
default {
Write-Message -Message "Test-FabricApiResponse::default" -Level Debug
Write-Message -Message "Unexpected response code: $statusCode from the API." -Level Error
Write-Message -Message "Error: $($response.message)" -Level Error
if ($response.moreDetails) {
Write-Message -Message "More Details: $($response.moreDetails)" -Level Error

if ($null -ne $Response.error) {
Write-Message -Message "Error Code: $($Response.error.code)" -Level Error
Write-Message -Message "Error Msg: $($Response.error.message)" -Level Error
$errorJson = $Response.error | ConvertTo-Json -Depth 10
Write-Message -Message "Error Detailed Info:`n$errorJson" -Level Debug
} else {
Write-Message -Message "Error Code: $($Response.errorCode)" -Level Error
Write-Message -Message "Error Msg: $($Response.message)" -Level Error
if ($Response.moreDetails) {
Write-Message -Message "More Details: $($Response.moreDetails)" -Level Error
}
}
Write-Message "Error Code: $($response.errorCode)" -Level Error
throw "API request failed with status code $statusCode."
}
}
Expand Down
155 changes: 155 additions & 0 deletions source/Public/Capacity/Update-FabricCapacity.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
function Update-FabricCapacity
{
<#
.SYNOPSIS
Creates or updates a Microsoft Fabric capacity.

.DESCRIPTION
The `Update-FabricCapacity` function sends a PATCH request to the Microsoft Fabric API to create or update a capacity
in the specified Azure subscription and resource group. It supports parameters for capacity administration,
SKU details, and optional tags.

.PARAMETER SubscriptionId
The ID of the target subscription. The value must be a UUID.

.PARAMETER ResourceGroupName
The name of the resource group. The name is case insensitive.

.PARAMETER CapacityName
The name of the Microsoft Fabric capacity. It must be a minimum of 3 characters, and a maximum of 63.
Must match pattern: ^[a-z][a-z0-9]*$

.PARAMETER SkuName
The name of the SKU level (e.g., "F2").

.PARAMETER Location
The Azure region where the capacity is located (e.g., "uksouth").

.PARAMETER AdministrationMembers
An array of administrator user identities for the capacity administration.

.PARAMETER Tags
Optional resource tags as a hashtable.

.PARAMETER NoWait
If specified, the function will not wait for the operation to complete and will return immediately.

.EXAMPLE
```powershell
$azureResource = @{
subscriptionID = 'GUID-GUID'
ResourceGroup = 'TestRG'
CapacityName = 'fabricblogdemof4'
Location = 'uksouth'
}
Update-FabricCapacity @azureResource -SkuName 'F8' -AdministrationMembers '[email protected]' -Debug -Confirm:$false
```

.EXAMPLE
```powershell
$azureResource = @{
subscriptionID = 'GUID-GUID'
ResourceGroup = 'TestRG'
CapacityName = 'fabricblogdemof4'
Location = 'uksouth'
SkuName = 'F8'
AdministrationMembers = '[email protected]'
}
Update-FabricCapacity @azureResource -Tags @{Environment="Production"; Owner="IT Team"} -Confirm:$false
```

.NOTES
- Calls `Confirm-TokenState` to ensure token validity before making the API request.
- Uses Azure Resource Manager API endpoint for capacity management.

Author: Kamil Nowinski

#>
[CmdletBinding(SupportsShouldProcess)]
param (
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[guid]$SubscriptionId,

[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[ValidateLength(1, 90)]
[string]$ResourceGroupName,

[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[ValidateLength(3, 63)]
[ValidatePattern('^[a-z][a-z0-9]*$')]
[string]$CapacityName,

[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]$SkuName,

[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]$Location,

[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string[]]$AdministrationMembers,

[Parameter(Mandatory = $false)]
[hashtable]$Tags,

[switch]$NoWait = $false
)

$SkuTier = "Fabric"

try
{
# Step 1: Ensure token validity
Confirm-TokenState

# Step 2: Construct the API URL
$apiEndpointUrl = "$($AzureSession.BaseApiUrl)/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Fabric/capacities/{2}?api-version=2023-11-01" -f $SubscriptionId, $ResourceGroupName, $CapacityName

# Step 3: Construct the request body
$body = @{
properties = @{
administration = @{
members = $AdministrationMembers
}
}
sku = @{
name = $SkuName
tier = $SkuTier
}
location = $Location
}

if ($Tags)
{
$body.tags = $Tags
}

# Step 4: Make the API request
if ($PSCmdlet.ShouldProcess($apiEndpointUrl, "Update Fabric Capacity"))
{
$apiParams = @{
Uri = $apiEndpointUrl
Method = 'PUT'
Body = $body
TypeName = 'Fabric Capacity'
NoWait = $NoWait
HandleResponse = $true
ObjectIdOrName = $CapacityName
}
$response = Invoke-FabricRestMethod @apiParams
$response
}
}
catch
{
# Step 5: Handle and log errors
$errorDetails = $_.Exception.Message
Write-Message -Message "Failed to update Fabric Capacity. Error: $errorDetails" -Level Error
throw
}
}
6 changes: 6 additions & 0 deletions source/Public/Invoke-FabricRestMethod.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@ Function Invoke-FabricRestMethod {
Write-Message -Message "PowerBIApi param is ignored when full Uri is provided." -Level Warning
}

$Headers = $FabricSession.HeaderParams
if ($Uri.StartsWith($AzureSession.BaseApiUrl)) {
$Headers = $AzureSession.HeaderParams
Write-Message -Message "Using AzureSession headers for request." -Level Debug
}

if ($Body -is [hashtable]) {
$Body = $Body | ConvertTo-Json -Depth 10
Write-Message -Message "Request Body: $Body" -Level Debug
Expand Down
3 changes: 2 additions & 1 deletion tests/QA/module.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ Describe 'Quality for module' -Tags 'TestQuality' {
$Result = (Invoke-ScriptAnalyzer -Path $functionFile.FullName)
$report = $Result | Format-Table -AutoSize | Out-String -Width 110
$Errors = if ($Result) { $Result | Where-Object { $_.Severity -ne 'Warning' } } else { @() }
$Errors | Should -BeNullOrEmpty -Because "some rule triggered.`r`n`r`n $report" }
$Errors | Should -BeNullOrEmpty -Because "some rule triggered.`r`n`r`n $report"
}
}

Describe 'Help for module' -Tags 'helpQuality' {
Expand Down
138 changes: 138 additions & 0 deletions tests/Unit/Update-FabricCapacity.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#Requires -Module @{ ModuleName="Pester"; ModuleVersion="5.0"}
param(
$ModuleName = "FabricTools",
$expectedParams = @(
"SubscriptionId"
"ResourceGroupName"
"CapacityName"
"SkuName"
"Location"
"AdministrationMembers"
"Tags"
"NoWait"
"WhatIf"
"Confirm"
"Verbose"
"Debug"
"ErrorAction"
"WarningAction"
"InformationAction"
"ProgressAction"
"ErrorVariable"
"WarningVariable"
"InformationVariable"
"OutVariable"
"OutBuffer"
"PipelineVariable"
)
)

Describe "Update-FabricCapacity" -Tag "UnitTests" {

BeforeDiscovery {
$command = Get-Command -Name Update-FabricCapacity
$expected = $expectedParams
}

Context "Parameter validation" {
BeforeAll {
$command = Get-Command -Name Update-FabricCapacity
$expected = $expectedParams
}

It "Has parameter: <_>" -ForEach $expected {
$command | Should -HaveParameter $PSItem
}

It "Should have exactly the number of expected parameters $($expected.Count)" {
$hasParams = $command.Parameters.Values.Name
Compare-Object -ReferenceObject $expected -DifferenceObject $hasParams | Should -BeNullOrEmpty
}
}

Context "Parameter validation rules" {
BeforeAll {
$command = Get-Command -Name Update-FabricCapacity
}

It "SubscriptionId should be mandatory" {
$command.Parameters['SubscriptionId'].Attributes.Mandatory | Should -Be $true
}

It "ResourceGroupName should be mandatory" {
$command.Parameters['ResourceGroupName'].Attributes.Mandatory | Should -Be $true
}

It "CapacityName should be mandatory" {
$command.Parameters['CapacityName'].Attributes.Mandatory | Should -Be $true
}

It "SkuName should be mandatory" {
$command.Parameters['SkuName'].Attributes.Mandatory | Should -Be $true
}

It "AdministrationMembers should be mandatory" {
$command.Parameters['AdministrationMembers'].Attributes.Mandatory | Should -Be $true
}

It "Tags should not be mandatory" {
$command.Parameters['Tags'].Attributes.Mandatory | Should -Be $false
}

It "NoWait should not be mandatory" {
$command.Parameters['NoWait'].Attributes.Mandatory | Should -Be $false
}

It "SubscriptionId should be of type Guid" {
$command.Parameters['SubscriptionId'].ParameterType.Name | Should -Be "Guid"
}

It "ResourceGroupName should be of type String" {
$command.Parameters['ResourceGroupName'].ParameterType.Name | Should -Be "String"
}

It "CapacityName should be of type String" {
$command.Parameters['CapacityName'].ParameterType.Name | Should -Be "String"
}

It "SkuName should be of type String" {
$command.Parameters['SkuName'].ParameterType.Name | Should -Be "String"
}

It "AdministrationMembers should be of type String array" {
$command.Parameters['AdministrationMembers'].ParameterType.Name | Should -Be "String[]"
}

It "Tags should be of type Hashtable" {
$command.Parameters['Tags'].ParameterType.Name | Should -Be "Hashtable"
}

It "NoWait should be of type SwitchParameter" {
$command.Parameters['NoWait'].ParameterType.Name | Should -Be "SwitchParameter"
}
}

Context "Parameter validation attributes" {
BeforeAll {
$command = Get-Command -Name Update-FabricCapacity
}

It "ResourceGroupName should have ValidateLength attribute with max length 90" {
$validateLengthAttr = $command.Parameters['ResourceGroupName'].Attributes | Where-Object { $_.GetType().Name -eq "ValidateLengthAttribute" }
$validateLengthAttr | Should -Not -BeNullOrEmpty
$validateLengthAttr.MaxLength | Should -Be 90
}

It "CapacityName should have ValidateLength attribute with min length 3 and max length 63" {
$validateLengthAttr = $command.Parameters['CapacityName'].Attributes | Where-Object { $_.GetType().Name -eq "ValidateLengthAttribute" }
$validateLengthAttr | Should -Not -BeNullOrEmpty
$validateLengthAttr.MinLength | Should -Be 3
$validateLengthAttr.MaxLength | Should -Be 63
}

It "CapacityName should have ValidatePattern attribute" {
$validatePatternAttr = $command.Parameters['CapacityName'].Attributes | Where-Object { $_.GetType().Name -eq "ValidatePatternAttribute" }
$validatePatternAttr | Should -Not -BeNullOrEmpty
}
}
}
Loading