This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using Azure.Identity; | |
using Azure.Storage.Blobs; | |
using Microsoft.Azure.WebJobs; | |
using Microsoft.Extensions.Logging; | |
using Microsoft.Azure.Management.ResourceGraph; | |
using Microsoft.Rest; | |
using Microsoft.Azure.Management.ResourceGraph.Models; | |
using Microsoft.Azure.Management.Subscription; | |
using Microsoft.Azure.Management.Subscription.Models; | |
using Newtonsoft.Json.Linq; | |
namespace RetrieveAzureVmData_wEntApp | |
{ | |
public static class Function1 | |
{ | |
[FunctionName("Function1")] | |
public static async Task Run([TimerTrigger("0 */15 * * * *")] TimerInfo myTimer, ILogger log) | |
{ | |
log.LogInformation($"Starting function at: {DateTime.Now}"); | |
string strTenant = "TENANT_ID"; | |
string strClientId = "ENTERPRISE_APP_ID"; | |
string strClientSecret = "APP_CLIENT_SECRET"; | |
string accessToken = await ExtractAccessTokenFromCredentials( | |
new ClientSecretCredential(strTenant, strClientId, strClientSecret)); | |
await WriteVmDataToStorageAccount(await GetVMData(accessToken, await GetAllAzureSubscriptions(accessToken, log), log)); | |
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}"); | |
} | |
private static async Task<string> ExtractAccessTokenFromCredentials(Azure.Core.TokenCredential tokenCredential) | |
{ | |
// Extract the access token from the supplied credentials | |
var accessToken = await tokenCredential.GetTokenAsync( | |
new Azure.Core.TokenRequestContext(new string[] { "https://management.core.windows.net/.default" }), | |
new System.Threading.CancellationToken()); | |
return accessToken.Token; | |
} | |
private static async Task<List<string>> GetAllAzureSubscriptions(string accessToken, ILogger log) | |
{ | |
// Pack the credentials in the format required next | |
ServiceClientCredentials serviceClientCreds = new TokenCredentials(accessToken); | |
// Get the subscriptions | |
SubscriptionClient subscriptionClient = new SubscriptionClient(serviceClientCreds); | |
IEnumerable<SubscriptionModel> allSubscriptions = await subscriptionClient.Subscriptions.ListAsync(); | |
log.LogInformation($"{allSubscriptions.Count()} subscriptions retrieved"); | |
// Extract the subscriptions' ids | |
List<string> allSubscriptionIds = new List<string>(); | |
foreach (var subscription in allSubscriptions) | |
{ | |
allSubscriptionIds.Add(subscription.SubscriptionId); | |
} | |
return allSubscriptionIds; | |
} | |
private static async Task<Newtonsoft.Json.Linq.JArray> GetVMData(string accessToken, | |
List<string> listOfAllAzureSubscriptionIds, ILogger log) | |
{ | |
ServiceClientCredentials serviceClientCreds = new TokenCredentials(accessToken); | |
ResourceGraphClient argClient = new ResourceGraphClient(serviceClientCreds); | |
string strQuery = @"Resources | |
| where type =~ 'microsoft.compute/virtualmachines' | |
| project id, vmId = tolower(tostring(id)), vmName = name | |
| join (Resources | |
| where type =~ 'microsoft.network/networkinterfaces' | |
| mv-expand ipconfig=properties.ipConfigurations | |
| project vmId = tolower(tostring(properties.virtualMachine.id)), privateIp = ipconfig.properties.privateIPAddress, publicIpId = tostring(ipconfig.properties.publicIPAddress.id) | |
| join kind=leftouter (Resources | |
| where type =~ 'microsoft.network/publicipaddresses' | |
| project publicIpId = id, publicIp = properties.ipAddress | |
) on publicIpId | |
| project-away publicIpId, publicIpId1 | |
| summarize privateIps = make_list(privateIp), publicIps = make_list(publicIp) by vmId | |
) on vmId | |
| project-away vmId, vmId1 | |
| sort by vmName asc"; | |
QueryRequest request = new QueryRequest(); | |
request.Subscriptions = listOfAllAzureSubscriptionIds; | |
request.Query = strQuery; | |
request.Options = new QueryRequestOptions { ResultFormat = ResultFormat.ObjectArray }; | |
JArray allVmData = new JArray(); | |
QueryResponse response; | |
do | |
{ | |
response = null; | |
try | |
{ | |
response = await argClient.ResourcesAsync(request); | |
request.Options.SkipToken = response.SkipToken; | |
} | |
catch (Exception e) | |
{ | |
log.LogInformation(e.ToString()); | |
} | |
log.LogInformation("No of records in current response page: " + response.Count); | |
allVmData.Merge(response.Data); | |
} while (!string.IsNullOrEmpty(response.SkipToken)); | |
return allVmData; | |
} | |
private static async Task WriteVmDataToStorageAccount(Newtonsoft.Json.Linq.JArray allVmData) | |
{ | |
string blockBlobName = "azureVMs.json"; | |
// Hard-coded connection string below. It would be ideal to read this from Azure Vault | |
var connectionString = "STORAGE_ACCOUNT_CONNECTION_STRING"; | |
// Build the object that will connect to the container within our target storage account | |
BlobContainerClient blobContainerClient = new BlobContainerClient(connectionString, "STORAGE_ACCOUNT_CONTAINER_NAME"); | |
// Write to Azure Blob Storage | |
BlobClient blobClient = blobContainerClient.GetBlobClient(blockBlobName); | |
using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(allVmData.ToString()))) | |
{ | |
await blobClient.UploadAsync(memoryStream, true); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment