Skip to content

Commit 65ea918

Browse files
committed
version 2.4
- azure.datafactory.tools - ver.1.15.0 - Az.DataFactory - ver.1.19.7
1 parent 4d8bea0 commit 65ea918

52 files changed

Lines changed: 1254 additions & 787 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,18 @@ The purpose of this task is to ensure such checking. It works exactly the same a
190190

191191
# Related modules
192192
These tasks include the following modules:
193-
- [azure.datafactory.tools - ver.1.13.0](https://www.powershellgallery.com/packages/azure.datafactory.tools/1.13.0)
194-
- [Az.DataFactory - ver.1.19.2](https://www.powershellgallery.com/packages/Az.DataFactory/1.19.2)
193+
- [azure.datafactory.tools - ver.1.15.0](https://www.powershellgallery.com/packages/azure.datafactory.tools/1.15.0)
194+
- [Az.DataFactory - ver.1.19.7](https://www.powershellgallery.com/packages/Az.DataFactory/1.19.7)
195195

196196
# History
197+
197198
## Version 2.*
199+
200+
- 28 May 2026 - v.2.4 Update [adftools v.1.15.0](https://github.com/Azure-Player/azure.datafactory.tools/releases/tag/v1.15.0)
201+
- New: Credential type of ADF objects is now supported for deployment via REST API
202+
- Fixed: Starting blob event trigger fails with 'Resource cannot be updated during provisioning' - now waits for provisioning to complete before retrying #484, #474, #463
203+
- Fixed: REST API calls failing with 401 Unauthorized due to Az.Accounts 5.x returning SecureString from Get-AzAccessToken
204+
- Fixed: DryRun not loading deployment state from storage for hash comparison #476
198205
- 03 Jun 2025 - v.2.3 Update [adftools v.1.13.0](https://github.com/Azure-Player/azure.datafactory.tools/releases/tag/v1.13.0)
199206
- New: Az.DataFactory module is required to import adftools
200207
- New: Added function `Set-AdfToolsAuthToken` to enable changing URL to API when target environment is different the default Global Azure #356 #441
@@ -209,7 +216,8 @@ These tasks include the following modules:
209216
- Test Connection Task is no longer Preview. ClientID & Secret fields are optional for SPN auth.
210217

211218
## Version 1.*
212-
- 13 Jun 2024 - v.1.35
219+
220+
- 13 Jun 2024 - v.1.35
213221
- 06 Jun 2024 - v.1.33 Update [adftools v.1.9.0](https://github.com/Azure-Player/azure.datafactory.tools/releases/tag/v1.9.0)
214222
- 27 Jan 2024 - v.1.32 - Added dry run option (advanced). Thanks [@LiquoriChris](https://github.com/LiquoriChris)!
215223
- 12 Sep 2023 - v.1.31 Update [adftools v.1.8.0](https://github.com/Azure-Player/azure.datafactory.tools/releases/tag/v1.8.0):

buildDataFactoryTask/buildDataFactoryTaskV1/ps_modules/azure.datafactory.tools/azure.datafactory.tools.psd1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
RootModule = 'azure.datafactory.tools.psm1'
1313

1414
# Version number of this module.
15-
ModuleVersion = '1.13.0'
15+
ModuleVersion = '1.15.0'
1616

1717
# Supported PSEditions
1818
# CompatiblePSEditions = @()
@@ -27,7 +27,7 @@
2727
CompanyName = 'SQLPlayer'
2828

2929
# Copyright statement for this module
30-
Copyright = '(c) 2020-2025 Kamil Nowinski. All rights reserved.'
30+
Copyright = '(c) 2020-2026 Kamil Nowinski. All rights reserved.'
3131

3232
# Description of the functionality provided by this module
3333
Description = 'PowerShell module to help with CI&CD for Azure Data Factory, mainly to publish to ADF service in multiple environments. Check https://github.com/Azure-Player/azure.datafactory.tools/ & https://azureplayer.net/adf/'
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
function ConvertTo-AdfCollection {
2+
[CmdletBinding()]
3+
param (
4+
[parameter(Mandatory = $true)]
5+
[String] $AzType
6+
)
7+
8+
$resType = ""
9+
10+
switch -Exact ($AzType)
11+
{
12+
'Microsoft.DataFactory/factories/pipelines' { $resType = 'Pipelines' }
13+
'Microsoft.DataFactory/factories/linkedservices' { $resType = 'LinkedServices' }
14+
'Microsoft.DataFactory/factories/datasets' { $resType = 'Datasets' }
15+
'Microsoft.DataFactory/factories/dataflows' { $resType = 'Dataflows' }
16+
'Microsoft.DataFactory/factories/triggers' { $resType = 'Triggers' }
17+
'Microsoft.DataFactory/factories/integrationruntimes' { $resType = 'IntegrationRuntimes' }
18+
'Microsoft.DataFactory/factories' { $resType = 'Factories' }
19+
'Microsoft.DataFactory/factories/managedVirtualNetworks' { $resType = 'ManagedVirtualNetworks' }
20+
'Microsoft.DataFactory/factories/managedVirtualNetworks/managedPrivateEndpoints' { $resType = 'ManagedPrivateEndpoints' }
21+
'Microsoft.DataFactory/factories/credentials' { $resType = 'Credentials' }
22+
default { Write-Error "ADFT0030: AzType '$AzType' is not supported." }
23+
}
24+
25+
return $resType
26+
}

buildDataFactoryTask/buildDataFactoryTaskV1/ps_modules/azure.datafactory.tools/private/Deploy-AdfObjectOnly.ps1

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,16 @@ function Deploy-AdfObjectOnly {
123123
}
124124
'credential'
125125
{
126-
Write-Warning "Credentials are not yet supported. The deployment for the object is skipped."
127-
Write-Warning "Any reference to the object causes error, unless to deploy it before."
126+
$resType = Get-AzureResourceType $obj.Type
127+
$resName = $obj.AzureResourceName()
128+
129+
New-AzResource `
130+
-ResourceType $resType `
131+
-ResourceGroupName $ResourceGroupName `
132+
-ResourceName "$resName" `
133+
-ApiVersion "2018-06-01" `
134+
-Properties $json `
135+
-IsFullObject -Force | Out-Null
128136
}
129137
'AzResource'
130138
{

buildDataFactoryTask/buildDataFactoryTaskV1/ps_modules/azure.datafactory.tools/private/Get-AzDFV2Credential.ps1

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ function Get-AzDFV2Credential {
55
)
66
Write-Debug "BEGIN: Get-AzDFV2Credential"
77

8+
# Retrieve all credentials via API without parsing
9+
$token = Get-AzAccessToken -ResourceUrl 'https://management.azure.com'
10+
$tokenStr = [System.Net.NetworkCredential]::new('', $token.Token).Password
11+
$authHeader = @{
12+
'Content-Type' = 'application/json'
13+
'Authorization' = 'Bearer ' + $tokenStr
14+
}
815
$url = "$($script:BaseApiUrl)$($adfi.DataFactoryId)/credentials?api-version=2018-06-01"
916

1017
# Retrieve all credentials via Rest API
@@ -14,7 +21,7 @@ function Get-AzDFV2Credential {
1421
return $null
1522
}
1623

17-
[System.Collections.ArrayList] $items = @{}
24+
[System.Collections.ArrayList] $items = @()
1825
($r.Content | ConvertFrom-Json).value | ForEach-Object { $i = [AdfPSCredential]::New($_); $items.Add($i) | Out-Null; }
1926

2027
Write-Debug "END: Get-AzDFV2Credential()"

buildDataFactoryTask/buildDataFactoryTaskV1/ps_modules/azure.datafactory.tools/private/Read-CsvConfigFile.ps1

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,36 @@ function Read-CsvConfigFile {
2222
if ($csv.Count -eq 1) {
2323
Write-Warning "Config file is empty."
2424
}
25+
26+
# Get actual line numbers for accurate error reporting
27+
$fileLines = Get-Content $configFileName
2528
$i = 0
2629
$csv | ForEach-Object {
2730
if ($i -gt 0 -and !$_.type.StartsWith("#") ) {
28-
if ($_.type -eq "" -or $null -eq $_.type) { Write-Error -Exception ([System.Data.DataException]::new("ADFT0021: Config file, row $i : Value in column 'Type' is empty.")) }
29-
if ($_.type -notin $ADF_FOLDERS) { Write-Error -Exception ([System.Data.DataException]::new("ADFT0022: Config file, row $i : Type ($($_.type)) is not supported.")) }
30-
if ($_.name -eq "" -or $null -eq $_.name) { Write-Error -Exception ([System.Data.DataException]::new("ADFT0023: Config file, row $i : Value in column 'Name' is empty.")) }
31-
if ($_.path -eq "" -or $null -eq $_.path) { Write-Error -Exception ([System.Data.DataException]::new("ADFT0024: Config file, row $i : Value in column 'Path' is empty.")) }
31+
# Find the actual line number by counting non-empty, non-comment lines up to current CSV row
32+
$actualLineNumber = 1 # Start with header line
33+
$csvRowCount = 0
34+
for ($lineIndex = 1; $lineIndex -lt $fileLines.Count; $lineIndex++) {
35+
$line = $fileLines[$lineIndex].Trim()
36+
if ($line -ne "" -and !$line.StartsWith("#")) {
37+
$csvRowCount++
38+
if ($csvRowCount -eq $i) {
39+
$actualLineNumber = $lineIndex + 1 # Convert to 1-based line number
40+
break
41+
}
42+
}
43+
}
44+
45+
if ($_.type -eq "" -or $null -eq $_.type) { Write-Error -Exception ([System.Data.DataException]::new("ADFT0021: Config file, row $actualLineNumber : Value in column 'Type' is empty.")) }
46+
if ($_.type -notin $ADF_FOLDERS) { Write-Error -Exception ([System.Data.DataException]::new("ADFT0022: Config file, row $actualLineNumber : Type ($($_.type)) is not supported.")) }
47+
if ($_.name -eq "" -or $null -eq $_.name) { Write-Error -Exception ([System.Data.DataException]::new("ADFT0023: Config file, row $actualLineNumber : Value in column 'Name' is empty.")) }
48+
if ($_.path -eq "" -or $null -eq $_.path) { Write-Error -Exception ([System.Data.DataException]::new("ADFT0024: Config file, row $actualLineNumber : Value in column 'Path' is empty.")) }
3249
if ($_.value -eq "" -or $null -eq $_.value) {
3350
if (!$_.path.StartsWith('-')) {
34-
Write-Warning -Message "Config file, row $i : Value in column 'Value' is empty."
51+
Write-Warning -Message "Config file, row $actualLineNumber : Value in column 'Value' is empty."
3552
}
3653
}
37-
if ($null -ne $_.empty) { Write-Error -Exception ([System.Data.DataException]::new("ADFT0025: Config file, row $i has too many columns.")) }
54+
if ($null -ne $_.empty) { Write-Error -Exception ([System.Data.DataException]::new("ADFT0025: Config file, row $actualLineNumber has too many columns.")) }
3855
}
3956
$i++
4057
}

buildDataFactoryTask/buildDataFactoryTaskV1/ps_modules/azure.datafactory.tools/private/Remove-AdfObjectRestAPI.ps1

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ function Remove-AdfObjectRestAPI {
88

99
Write-Debug "BEGIN: Remove-AdfObjectRestAPI()"
1010

11+
$token = Get-AzAccessToken -ResourceUrl 'https://management.azure.com'
12+
$tokenStr = [System.Net.NetworkCredential]::new('', $token.Token).Password
13+
$authHeader = @{
14+
'Content-Type' = 'application/json'
15+
'Authorization' = 'Bearer ' + $tokenStr
16+
}
1117
$url = "$($script:BaseApiUrl)$($adfInstance.Id)/$type_plural/$($name)?api-version=2018-06-01"
1218

1319
# Delete given object via Rest API

buildDataFactoryTask/buildDataFactoryTaskV1/ps_modules/azure.datafactory.tools/private/Start-Trigger.ps1

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,38 @@ function Start-Trigger {
1919
-DataFactoryName $DataFactoryName `
2020
-Name $Name `
2121
-Force | Out-Null
22+
# If successful, break out of the loop
23+
break
2224
}
2325
catch {
26+
$errMsg = $_.Exception.Message
2427
if ($i -lt $attempts)
2528
{
26-
Write-Verbose "Attempt #$i of starting trigger failed. Retry in 2 seconds."
27-
Start-Sleep -Seconds 2
28-
}
29-
else
29+
if ($errMsg -like "*cannot be updated during provisioning*") {
30+
Write-Verbose "Attempt #${i}: Trigger '$Name' is still provisioning. Waiting for provisioning to complete..."
31+
$provisioningTimeout = 300
32+
$pollInterval = 10
33+
$elapsed = 0
34+
while ($elapsed -lt $provisioningTimeout) {
35+
Start-Sleep -Seconds $pollInterval
36+
$elapsed += $pollInterval
37+
$trigger = Get-AzDataFactoryV2Trigger `
38+
-ResourceGroupName $ResourceGroupName `
39+
-DataFactoryName $DataFactoryName `
40+
-Name $Name
41+
$provState = $trigger.Properties.ProvisioningState
42+
Write-Verbose "Trigger provisioning state: $provState ($elapsed sec elapsed)"
43+
if ($provState -ne 'Provisioning') { break }
44+
}
45+
} else {
46+
Write-Verbose "Attempt #$i of starting trigger failed. Retry in 2 seconds."
47+
Start-Sleep -Seconds 2
48+
}
49+
}
50+
else
3051
{
3152
Write-Host "Failed starting trigger after $attempts attempts."
32-
Write-Warning -Message $_.Exception.Message
53+
Write-Warning -Message $errMsg
3354
}
3455
}
3556
}

buildDataFactoryTask/buildDataFactoryTaskV1/ps_modules/azure.datafactory.tools/public/Get-AdfDocDiagram.ps1

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ Object of adf class represents all adf objects from code.
1111
.PARAMETER direction
1212
Diagram direction: LR - Left to Right (default), TD - Top to Down
1313
14+
.PARAMETER exclude
15+
Array of object names to exclude from diagram. Wildcards are supported.
16+
17+
.PARAMETER include
18+
Array of object names to include in diagram. Wildcards are supported. If this parameter is used, only the specified objects and their dependencies will be included in the diagram.
19+
1420
.EXAMPLE
1521
$RootFolder = "c:\GitHub\AdfName\"
1622
$adf = Import-AdfFromFolder -RootFolder $RootFolder -FactoryName 'whatever'
@@ -32,7 +38,10 @@ function Get-AdfDocDiagram {
3238
[Adf] $adf,
3339

3440
[ValidateSet("LR", "TD")]
35-
[String] $direction = 'LR'
41+
[String] $direction = 'LR',
42+
43+
[Array] $exclude = $null,
44+
[Array] $include = $null
3645
)
3746
Write-Debug "BEGIN: Get-AdfDocDiagram(adf=$adf, direction=$direction)"
3847

@@ -42,12 +51,25 @@ function Get-AdfDocDiagram {
4251

4352
$adf.AllObjects() | ForEach-Object {
4453
$o = $_
54+
$n1 = $o.FullName().Replace(' ', '_')
55+
Write-Verbose "Analyse: $($o.FullName())"
4556
foreach ($d in $o.DependsOn) {
46-
$n1 = $o.FullName().Replace(' ', '_')
4757
$n2 = $d.Replace(' ', '_')
4858
$n2 = $n2.ToLower()[0] + $n2.Substring(1)
49-
$line = "$n1 --> $n2"
50-
$diag += $line + "`n"
59+
Write-Verbose "- $d"
60+
$show = $true
61+
if ($include) {
62+
$show = ($include | ForEach-Object { if ($n1 -ilike $_ -or $n2 -ilike $_) {1} else {0} } | Measure-Object -Maximum).Maximum -gt 0
63+
} else
64+
{
65+
$show = -not ($exclude | ForEach-Object { if ($n1 -ilike $_ -or $n2 -ilike $_) {1} else {0} } | Measure-Object -Maximum).Maximum -gt 0
66+
}
67+
if ($show) {
68+
$line = "$n1 --> $n2"
69+
$diag += $line + "`n"
70+
} else {
71+
Write-Verbose "$d - excluded."
72+
}
5173
}
5274
}
5375
$diag += ":::"

buildDataFactoryTask/buildDataFactoryTaskV1/ps_modules/azure.datafactory.tools/public/Publish-AdfV2FromJson.ps1

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,6 @@ function Publish-AdfV2FromJson {
154154
$targetAdf = Get-AzDataFactoryV2 -ResourceGroupName "$ResourceGroupName" -Name "$DataFactoryName" -ErrorAction:Ignore
155155
if ($targetAdf) {
156156
Write-Host "Azure Data Factory exists."
157-
if ($opt.IncrementalDeployment -and !$DryRun.IsPresent) {
158-
Write-Host "Loading Deployment State from Storage..."
159-
$ds = Get-StateFromStorage -DataFactoryName $DataFactoryName -LocationUri $opt.IncrementalDeploymentStorageUri
160-
}
161157
}
162158
else {
163159
$msg = "Azure Data Factory instance does not exist."
@@ -175,13 +171,19 @@ function Publish-AdfV2FromJson {
175171

176172
if ($null -eq $targetAdf) {
177173
Write-Host "ADFT0032: The process is exiting the function. Do fix the issue and run again."
178-
return
174+
return
179175
}
180176
}
181177
else {
182178
Write-Host "DRY RUN: Skipping ADF existence verification..."
183179
}
184180

181+
# Load deployment state from storage for incremental deployment (needed for both DryRun and actual deployment)
182+
if ($opt.IncrementalDeployment) {
183+
Write-Host "Loading Deployment State from Storage..."
184+
$ds = Get-StateFromStorage -DataFactoryName $DataFactoryName -LocationUri $opt.IncrementalDeploymentStorageUri
185+
}
186+
185187
Write-Host "===================================================================================";
186188
Write-Host "STEP: Reading Azure Data Factory from JSON files..."
187189
$adf = Import-AdfFromFolder -FactoryName $DataFactoryName -RootFolder "$RootFolder"

0 commit comments

Comments
 (0)