|
| 1 | +# Make sure run PowerShell cmd with administrator |
| 2 | + |
| 3 | +param ( |
| 4 | + [Parameter(Mandatory = $true)] |
| 5 | + [string]$SubscriptionId, |
| 6 | + |
| 7 | + [Parameter(Mandatory = $true)] |
| 8 | + [string]$TenantId |
| 9 | +) |
| 10 | + |
| 11 | +# Disable warning for get access token |
| 12 | +function Get-PlainAccessToken { |
| 13 | + $prev = $WarningPreference |
| 14 | + $WarningPreference = 'SilentlyContinue' |
| 15 | + $token = (Get-AzAccessToken).Token |
| 16 | + $WarningPreference = $prev |
| 17 | + |
| 18 | + $plainToken = [Runtime.InteropServices.Marshal]::PtrToStringBSTR( |
| 19 | + [Runtime.InteropServices.Marshal]::SecureStringToBSTR($token) |
| 20 | + ) |
| 21 | + return $plainToken |
| 22 | +} |
| 23 | + |
| 24 | +function Get-AllLinkedServices { |
| 25 | + param ( |
| 26 | + [string]$Uri |
| 27 | + ) |
| 28 | + |
| 29 | + $allLinkedServices = New-Object System.Collections.ArrayList |
| 30 | + $nextUri = $Uri |
| 31 | + $token = Get-PlainAccessToken |
| 32 | + |
| 33 | + $headers = @{ |
| 34 | + Authorization = "Bearer $token" |
| 35 | + "Content-Type" = "application/json" |
| 36 | + } |
| 37 | + |
| 38 | + while ($nextUri) { |
| 39 | + try { |
| 40 | + $response = Invoke-RestMethod -Method GET -Uri $nextUri -Headers $headers |
| 41 | + } |
| 42 | + catch { |
| 43 | + Write-Warning "Failed to fetch: $nextUri" |
| 44 | + break |
| 45 | + } |
| 46 | + |
| 47 | + if ($response.value -ne $null -and $response.value.Count -gt 0) { |
| 48 | + #Write-Host " Retrieved $($response.value.Count) linked services" |
| 49 | + foreach ($item in $response.value) { |
| 50 | + [void]$allLinkedServices.Add($item) |
| 51 | + } |
| 52 | + } |
| 53 | + else { |
| 54 | + #Write-Warning "No linked services found in current batch." |
| 55 | + break |
| 56 | + } |
| 57 | + |
| 58 | + $nextUri = if ($response.PSObject.Properties.Name -contains 'nextLink') { $response.nextLink } else { $null } |
| 59 | + |
| 60 | + # # Optional: delay to avoid throttling |
| 61 | + # Start-Sleep -Milliseconds 300 |
| 62 | + } |
| 63 | + |
| 64 | + return $allLinkedServices |
| 65 | +} |
| 66 | + |
| 67 | +function Print-Result { |
| 68 | + param ( |
| 69 | + [string]$dfName, |
| 70 | + [string]$lsName, |
| 71 | + [string]$lsType, |
| 72 | + [string]$outputFileName |
| 73 | + ) |
| 74 | + Write-Host "$dfName, $lsName, $lsType" |
| 75 | + |
| 76 | + |
| 77 | + # Output it to a file |
| 78 | + $data = [PSCustomObject]@{ |
| 79 | + DataFactoryName = $dfName |
| 80 | + LinkedServiceName = $lsName |
| 81 | + Type = $lsType |
| 82 | + } |
| 83 | + $data | Export-Csv -Path $outputFileName -NoTypeInformation -Append |
| 84 | +} |
| 85 | + |
| 86 | +# Step 1: Install/Update Required Modules |
| 87 | +Write-Host "Checking for Az modules..." -ForegroundColor Cyan |
| 88 | +Install-Module -Name Az.DataFactory -Force -AllowClobber |
| 89 | +Import-Module Az.DataFactory |
| 90 | +# If you hit incompatible version, try Install-Module -Name Az.Accounts -RequiredVersion <your version>, and reopen the cmd |
| 91 | + |
| 92 | +# Show the version in use |
| 93 | +$module = Get-Module -Name Az.DataFactory |
| 94 | +if ($module) { |
| 95 | + Write-Host "Az.DataFactory version in use: $($module.Version)" -ForegroundColor Green |
| 96 | +} else { |
| 97 | + Write-Host "Az.DataFactory module not loaded." -ForegroundColor Red |
| 98 | +} |
| 99 | + |
| 100 | +# Step 2: Log into Azure |
| 101 | +Write-Host "Connecting to Azure..." -ForegroundColor Cyan |
| 102 | +Connect-AzAccount -ErrorAction Stop -subscription $SubscriptionId -tenantId $TenantId |
| 103 | + |
| 104 | +# Step 3: Get all Data Factories in the subscription |
| 105 | +Write-Host "Retrieving Data Factories..." -ForegroundColor Cyan |
| 106 | +$dataFactories = Get-AzDataFactoryV2 |
| 107 | + |
| 108 | +if ($dataFactories.Count -eq 0) { |
| 109 | + Write-Host "No Data Factories found in subscription $SubscriptionId" |
| 110 | + exit |
| 111 | +} |
| 112 | + |
| 113 | +#Step 4: Found legacy linked services, we can extend this list |
| 114 | +$LegacyV1LSTypes = @( |
| 115 | + # Disabled: |
| 116 | + "AmazonMWS", |
| 117 | + # End of support: |
| 118 | + "Zoho", |
| 119 | + "SalesforceMarketingCloud", |
| 120 | + "Phoenix", |
| 121 | + "PayPal", |
| 122 | + "OracleServiceCloud", |
| 123 | + "Responsys", |
| 124 | + "Eloqua", |
| 125 | + "Marketo", |
| 126 | + "Magento", |
| 127 | + "HBase", |
| 128 | + "Drill", |
| 129 | + "Couchbase", |
| 130 | + "Concur", |
| 131 | + "AzureMariaDB", |
| 132 | + "GoogleBigQuery", |
| 133 | + "PostgreSql", |
| 134 | + |
| 135 | + # To be end of support |
| 136 | + "ServiceNow", |
| 137 | + "Snowflake", |
| 138 | + "Salesforce", |
| 139 | + "SalesforceServiceCloud" |
| 140 | +) |
| 141 | + |
| 142 | +$LegacyV1VersionLSTypes = @( |
| 143 | + # End of support |
| 144 | + "MySql", |
| 145 | + "MariaDB", |
| 146 | + # V2 GA |
| 147 | + "Vertica", |
| 148 | + "Oracle", |
| 149 | + "Greenplum", |
| 150 | + "AzurePostgreSql", |
| 151 | + # V2 Preview |
| 152 | + "Spark", |
| 153 | + "Presto", |
| 154 | + "Cassandra" |
| 155 | +) |
| 156 | + |
| 157 | +$timestamp = Get-Date -Format "yyyyMMdd_HHmmss" |
| 158 | +$filename = "output_$timestamp.csv" |
| 159 | + |
| 160 | +foreach ($df in $dataFactories) { |
| 161 | + $resourceGroup = $df.ResourceGroupName |
| 162 | + $dataFactoryName = $df.DataFactoryName |
| 163 | + |
| 164 | + $uri = "https://management.azure.com/subscriptions/$SubscriptionId/resourceGroups/$resourceGroup/providers/Microsoft.DataFactory/factories/$dataFactoryName/linkedservices?api-version=2018-06-01" |
| 165 | + |
| 166 | + try { |
| 167 | + $response = Invoke-AzRestMethod -Method GET -Uri $uri |
| 168 | + $linkedServices = Get-AllLinkedServices -Uri $uri |
| 169 | + |
| 170 | + |
| 171 | + if ($linkedServices.Count -eq 0) { |
| 172 | + continue |
| 173 | + } |
| 174 | + |
| 175 | + foreach ($ls in $linkedServices) { |
| 176 | + $name = $ls.name |
| 177 | + $type = $ls.properties.type |
| 178 | + $version = $ls.properties.version |
| 179 | + $typeProps = $ls.properties.typeProperties | ConvertTo-Json -Depth 10 | ConvertFrom-Json |
| 180 | + |
| 181 | + if ($LegacyV1LSTypes -contains $type) { |
| 182 | + Print-Result -dfName $dataFactoryName -lsName $name -lsType $type -outputFileName $filename |
| 183 | + } |
| 184 | + |
| 185 | + # Find v1 versions. |
| 186 | + if ($LegacyV1VersionLSTypes -contains $type) { |
| 187 | + if ($version -ne "2.0") { # Skip version 2.0, it must be non-legacy |
| 188 | + switch ($type) { # MySql and MariaDB are not following the version design, hence, need some custom logic here |
| 189 | + {($_ -eq "MariaDB") -or ($_ -eq "MySql")} { |
| 190 | + $connectionString = $typeProps.connectionString |
| 191 | + if (-not [string]::IsNullOrEmpty($connectionString)) { |
| 192 | + Print-Result -dfName $dataFactoryName -lsName $name -lsType $type -outputFileName $filename |
| 193 | + } |
| 194 | + break |
| 195 | + } |
| 196 | + default { |
| 197 | + Print-Result -dfName $dataFactoryName -lsName $name -lsType $type -outputFileName $filename |
| 198 | + break |
| 199 | + } |
| 200 | + } |
| 201 | + } |
| 202 | + } |
| 203 | + } |
| 204 | + } catch { |
| 205 | + Write-Host "Failed to fetch linked services for $dataFactoryName" -ForegroundColor Red |
| 206 | + } |
| 207 | +} |
| 208 | + |
| 209 | +# Sometimes, Get-AzDataFactoryV2LinkedService will fail to deserialize the payload due to invalid payload, or out-of-date version, let's use Rest API instead |
| 210 | +# foreach ($df in $dataFactories) { |
| 211 | +# $dataFactoryName = $df.DataFactoryName |
| 212 | +# $resourceGroup = $df.ResourceGroupName |
| 213 | +# Write-Host "Data Factory $dataFactoryName (Resource Group $resourceGroup)" -ForegroundColor Green |
| 214 | + |
| 215 | +# # Get all Linked Services for this Data Factory |
| 216 | +# $linkedServices = Get-AzDataFactoryV2LinkedService -ResourceGroupName $resourceGroup -DataFactoryName $dataFactoryName |
| 217 | + |
| 218 | +# if ($linkedServices.Count -gt 0) { |
| 219 | +# foreach ($ls in $linkedServices) { |
| 220 | +# $type = $ls.Properties.GetType().Name -replace 'LinkedService$', '' |
| 221 | +# # Find all the legacy types |
| 222 | +# if ($LegacyLSTypes -contains $type) { |
| 223 | +# Write-Host "$dataFactoryName, $($ls.Name), $type" |
| 224 | +# } |
| 225 | + |
| 226 | +# # Find v1 versions. |
| 227 | +# if ($LSWithV1Types -contains $type) { |
| 228 | +# $version = $ls.Properties.version |
| 229 | +# if ($version -ne "2.0") { # skip version 2.0 |
| 230 | +# switch ($type) { # We need some custom logic per types |
| 231 | +# "MySql" { |
| 232 | +# $connectionString = $ls.Properties.ConnectionString |
| 233 | +# if (-not [string]::IsNullOrEmpty($connectionString)) { |
| 234 | +# Write-Host "$dataFactoryName, $($ls.Name), $type" |
| 235 | +# } |
| 236 | +# break |
| 237 | +# } |
| 238 | +# default { |
| 239 | +# Write-Host "$dataFactoryName, $($ls.Name), $type" |
| 240 | +# break |
| 241 | +# } |
| 242 | +# } |
| 243 | +# } |
| 244 | +# } |
| 245 | + |
| 246 | +# } |
| 247 | +# } |
| 248 | +# } |
0 commit comments