Skip to content

Commit 1cad10f

Browse files
authored
Merge pull request #620 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 45d0d99 + 8f8933e commit 1cad10f

File tree

7 files changed

+1306
-5
lines changed

7 files changed

+1306
-5
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Docs for the Azure Web Apps Deploy action: https://github.com/azure/functions-action
2+
# More GitHub Actions for Azure: https://github.com/Azure/actions
3+
4+
name: Build and deploy Powershell project to Azure Function App - cippwxl5o
5+
6+
on:
7+
push:
8+
branches:
9+
- dev
10+
workflow_dispatch:
11+
12+
env:
13+
AZURE_FUNCTIONAPP_PACKAGE_PATH: '.' # set this to the path to your web app project, defaults to the repository root
14+
15+
jobs:
16+
deploy:
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- name: 'Checkout GitHub Action'
21+
uses: actions/checkout@v4
22+
23+
- name: 'Run Azure Functions Action'
24+
uses: Azure/functions-action@v1
25+
id: fa
26+
with:
27+
app-name: 'cippwxl5o'
28+
slot-name: 'Production'
29+
package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}
30+
publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_9C426C0B5ADE471A98CEDB9F88EBD232 }}

Modules/CIPPCore/Public/Clear-CippDurables.ps1

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ function Clear-CippDurables {
22
[CmdletBinding(SupportsShouldProcess = $true)]
33
param()
44
# Collect info
5-
$StorageContext = New-AzStorageContext -ConnectionString $env:AzureWebJobsStorage
65
$FunctionName = $env:WEBSITE_SITE_NAME -replace '-', ''
76

87
# Get orchestrators
@@ -16,21 +15,22 @@ function Clear-CippDurables {
1615
Remove-AzDataTable @QueueTable
1716
Remove-AzDataTable @CippQueueTasks
1817

19-
$Queues = Get-AzStorageQueue -Context $StorageContext -Name ('{0}*' -f $FunctionName) | Select-Object -Property Name, ApproximateMessageCount, QueueClient
18+
$Queues = Get-CIPPAzStorageQueue -Name ('{0}*' -f $FunctionName)
2019

2120
$RunningQueues = $Queues | Where-Object { $_.ApproximateMessageCount -gt 0 }
2221
foreach ($Queue in $RunningQueues) {
2322
Write-Information "- Removing queue: $($Queue.Name), message count: $($Queue.ApproximateMessageCount)"
2423
if ($PSCmdlet.ShouldProcess($Queue.Name, 'Clear Queue')) {
25-
$Queue.QueueClient.ClearMessagesAsync()
24+
$null = Clear-CIPPAzStorageQueue -Name $Queue.Name
2625
}
2726
}
2827

2928
$BlobContainer = '{0}-largemessages' -f $FunctionName
30-
if (Get-AzStorageContainer -Name $BlobContainer -Context $StorageContext -ErrorAction SilentlyContinue) {
29+
$containerMatch = Get-CIPPAzStorageContainer -Name $BlobContainer | Where-Object { $_.Name -eq $BlobContainer }
30+
if ($containerMatch) {
3131
Write-Information "- Removing blob container: $BlobContainer"
3232
if ($PSCmdlet.ShouldProcess($BlobContainer, 'Remove Blob Container')) {
33-
Remove-AzStorageContainer -Name $BlobContainer -Context $StorageContext -Confirm:$false -Force
33+
$null = Remove-CIPPAzStorageContainer -Name $BlobContainer
3434
}
3535
}
3636

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
function Clear-CIPPAzStorageQueue {
2+
<#
3+
.SYNOPSIS
4+
Clears all messages from a specified Azure Storage Queue.
5+
.DESCRIPTION
6+
Issues a DELETE request to /<queue>/messages via New-CIPPAzStorageRequest.
7+
Returns a compact object with StatusCode, Headers, and Request Uri.
8+
.PARAMETER Name
9+
The name of the queue to clear.
10+
.PARAMETER ConnectionString
11+
Azure Storage connection string. Defaults to $env:AzureWebJobsStorage.
12+
.EXAMPLE
13+
Clear-CIPPAzStorageQueue -Name 'cippjta72-workitems'
14+
#>
15+
[CmdletBinding(SupportsShouldProcess)]
16+
param(
17+
[Parameter(Mandatory = $true, Position = 0)]
18+
[ValidateNotNullOrEmpty()]
19+
[string]$Name,
20+
21+
[Parameter(Mandatory = $false)]
22+
[string]$ConnectionString = $env:AzureWebJobsStorage
23+
)
24+
25+
if ($PSCmdlet.ShouldProcess($Name, 'Clear queue messages')) {
26+
try {
27+
$headers = @{ Accept = 'application/xml' }
28+
$resp = New-CIPPAzStorageRequest -Service 'queue' -Resource ("$Name/messages") -Method 'DELETE' -Headers $headers -ConnectionString $ConnectionString
29+
if ($null -eq $resp) {
30+
# Fallback when no object returned: assume 204 if no exception was thrown
31+
return [PSCustomObject]@{ StatusCode = 204; Headers = @{}; Uri = $null; Name = $Name }
32+
}
33+
# Normalize to concise output and include the queue name
34+
$status = $null; $uri = $null; $hdrs = @{}
35+
if ($resp.PSObject.Properties['StatusCode']) { $status = [int]$resp.StatusCode }
36+
if ($resp.PSObject.Properties['Uri']) { $uri = $resp.Uri }
37+
if ($resp.PSObject.Properties['Headers']) { $hdrs = $resp.Headers }
38+
return [PSCustomObject]@{ Name = $Name; StatusCode = $status; Headers = $hdrs; Uri = $uri }
39+
} catch {
40+
throw $_
41+
}
42+
}
43+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
function Get-CIPPAzStorageContainer {
2+
<#
3+
.SYNOPSIS
4+
Lists Azure Storage blob containers using Shared Key auth.
5+
.DESCRIPTION
6+
Uses New-CIPPAzStorageRequest to call the Blob service list API.
7+
- Uses server-side 'prefix' when Name ends with a single trailing '*'.
8+
- Builds container URIs from the connection string (standard, provided endpoint, emulator).
9+
- Passes through container Properties returned by the service.
10+
.PARAMETER Name
11+
Container name filter. Supports wildcards (e.g., 'cipp*'). Defaults to '*'.
12+
When the pattern ends with a single trailing '*' and contains no other wildcards,
13+
a server-side 'prefix' is used for listing; otherwise client-side filtering is applied.
14+
.PARAMETER ConnectionString
15+
Azure Storage connection string. Defaults to $env:AzureWebJobsStorage
16+
.EXAMPLE
17+
Get-CIPPAzStorageContainer -Name 'cipp*'
18+
#>
19+
[CmdletBinding()]
20+
param(
21+
[Parameter(Mandatory = $false, Position = 0)]
22+
[string]$Name = '*',
23+
24+
[Parameter(Mandatory = $false)]
25+
[string]$ConnectionString = $env:AzureWebJobsStorage
26+
)
27+
28+
begin {
29+
function Parse-ConnString {
30+
param([string]$Conn)
31+
$map = @{}
32+
if (-not $Conn) { return $map }
33+
foreach ($part in ($Conn -split ';')) {
34+
$p = $part.Trim()
35+
if ($p -and $p -match '^(.+?)=(.+)$') { $map[$matches[1]] = $matches[2] }
36+
}
37+
$map
38+
}
39+
40+
function Get-BlobBaseInfo {
41+
param([hashtable]$ConnParams)
42+
$service = 'blob'
43+
$svcCap = [char]::ToUpper($service[0]) + $service.Substring(1)
44+
$endpointKey = "${svcCap}Endpoint"
45+
$provided = $ConnParams[$endpointKey]
46+
$useDev = ($ConnParams['UseDevelopmentStorage'] -eq 'true')
47+
$account = $ConnParams['AccountName']
48+
49+
if ($provided) {
50+
$u = [System.Uri]::new($provided)
51+
return [PSCustomObject]@{
52+
Scheme = $u.Scheme
53+
Host = $u.Host
54+
Port = $u.Port
55+
Path = $u.AbsolutePath.TrimEnd('/')
56+
Mode = 'ProvidedEndpoint'
57+
Account = $account
58+
}
59+
}
60+
61+
if ($useDev) {
62+
return [PSCustomObject]@{
63+
Scheme = 'http'
64+
Host = '127.0.0.1'
65+
Port = 10000
66+
Path = $null
67+
Mode = 'Emulator'
68+
Account = ($account ?? 'devstoreaccount1')
69+
}
70+
}
71+
72+
$suffix = $ConnParams['EndpointSuffix']
73+
if (-not $suffix) { $suffix = 'core.windows.net' }
74+
$scheme = $ConnParams['DefaultEndpointsProtocol']
75+
if (-not $scheme) { $scheme = 'https' }
76+
return [PSCustomObject]@{
77+
Scheme = $scheme
78+
Host = "$account.blob.$suffix"
79+
Port = -1
80+
Path = $null
81+
Mode = 'Standard'
82+
Account = $account
83+
}
84+
}
85+
86+
function Build-ContainerUri {
87+
param([pscustomobject]$BaseInfo, [string]$ContainerName)
88+
$ub = [System.UriBuilder]::new()
89+
$ub.Scheme = $BaseInfo.Scheme
90+
$ub.Host = $BaseInfo.Host
91+
if ($BaseInfo.Port -and $BaseInfo.Port -ne -1) { $ub.Port = [int]$BaseInfo.Port }
92+
switch ($BaseInfo.Mode) {
93+
'ProvidedEndpoint' {
94+
$prefixPath = $BaseInfo.Path
95+
if ([string]::IsNullOrEmpty($prefixPath)) { $ub.Path = "/$ContainerName" }
96+
else { $ub.Path = ("$prefixPath/$ContainerName").Replace('//', '/') }
97+
}
98+
'Emulator' { $ub.Path = "$($BaseInfo.Account)/$ContainerName" }
99+
default { $ub.Path = "/$ContainerName" }
100+
}
101+
$ub.Uri.AbsoluteUri
102+
}
103+
}
104+
105+
process {
106+
$connParams = Parse-ConnString -Conn $ConnectionString
107+
$baseInfo = Get-BlobBaseInfo -ConnParams $connParams
108+
109+
# Determine server-side prefix optimization
110+
$serverPrefix = $null
111+
$pattern = $Name
112+
if ([string]::IsNullOrEmpty($pattern)) { $pattern = '*' }
113+
$canUsePrefix = $false
114+
if ($pattern.EndsWith('*') -and $pattern.IndexOfAny([char[]]@('*', '?')) -eq ($pattern.Length - 1)) {
115+
$serverPrefix = $pattern.Substring(0, $pattern.Length - 1)
116+
$canUsePrefix = $true
117+
}
118+
119+
$listParams = @{ Service = 'blob'; Component = 'list'; ConnectionString = $ConnectionString }
120+
if ($canUsePrefix -and $serverPrefix) { $listParams['QueryParams'] = @{ prefix = $serverPrefix } }
121+
122+
$containers = New-CIPPAzStorageRequest @listParams
123+
if (-not $containers) { return @() }
124+
125+
# Normalize to array of {Name, Properties}
126+
$items = @()
127+
foreach ($c in $containers) {
128+
if ($null -ne $c -and $c.PSObject.Properties['Name']) {
129+
$items += [PSCustomObject]@{ Name = $c.Name; Properties = $c.Properties }
130+
}
131+
}
132+
133+
# Client-side wildcard filtering when needed
134+
if (-not $canUsePrefix) {
135+
$items = $items | Where-Object { $_.Name -like $pattern }
136+
}
137+
138+
$results = @()
139+
foreach ($it in $items) {
140+
$uri = Build-ContainerUri -BaseInfo $baseInfo -ContainerName $it.Name
141+
$results += [PSCustomObject]@{
142+
Name = $it.Name
143+
Uri = $uri
144+
Properties = $it.Properties
145+
}
146+
}
147+
148+
# Optional banner for UX parity when displayed directly
149+
if ($results.Count -gt 0 -and $baseInfo.Account) {
150+
Write-Host "\n Storage Account Name: $($baseInfo.Account)\n" -ForegroundColor DarkGray
151+
}
152+
153+
$results
154+
}
155+
}

0 commit comments

Comments
 (0)