Search code examples
c#azure-ad-msalclient-certificatesazure-authenticationazure-identity

Get back deleted applications starting with 'dev' client-certificate authentication


We're currently in the process of transitioning to client certificate authentication for our application and got this working code from previous ask on retrieving the deleted application objects from Microsoft Graph Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException: 'The specified network password is not correct.'

using Azure.Identity;
using Microsoft.Graph;
using System.Security.Cryptography.X509Certificates;

var scopes = new[] { "https://graph.microsoft.com/.default" };
var clientId = "appID";
var tenantId = "tenantId";
var certificatePath = "C:/MYPATH";
var certificatePassword = "xxxxxxxx";
var clientCertificate = new X509Certificate2(certificatePath, certificatePassword);
var options = new ClientCertificateCredentialOptions
{
    AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
};

var clientCertCredential = new ClientCertificateCredential(
    tenantId, clientId, clientCertificate, options);

var graphClient = new GraphServiceClient(clientCertCredential, scopes);

var apps= await graphClient.Directory.DeletedItems.GraphApplication.GetAsync((requestConfiguration) =>
{
    requestConfiguration.QueryParameters.Count = true;
    requestConfiguration.QueryParameters.Orderby = new string[] { "deletedDateTime asc" };
    requestConfiguration.QueryParameters.Select = new string[] { "appId", "DisplayName", "deletedDateTime" };
    requestConfiguration.Headers.Add("Consistencylevel", "Eventual");
});

Console.WriteLine($"Total deleted apps: {apps.OdataCount}\n");

foreach (var app in apps.Value)
{
    Console.WriteLine($"App ID: {app.AppId}");
    Console.WriteLine($"Application Name: {app.DisplayName}");
    Console.WriteLine($"Deleted Date and Time: {app.DeletedDateTime}");

    Console.WriteLine();
}

While the code effectively retrieves deleted application objects, we now have a specific requirement to restore only those deleted applications whose names begin with "dev" We've attempted to modify the code to achieve this by including a filter condition, but encountered difficulties in implementation.

Could you please provide guidance on how to integrate a filter condition to selectively restore deleted applications based on their names starting with "dev"? Any assistance or insights would be greatly appreciated.


Solution

  • To restore the deleted application, you need to grant Application.ReadWrite.All permission of Application type:

    enter image description here

    I have 3 deleted applications that starts with 'dev' in my tenant like this:

    enter image description here

    Now, you can make use of below modified code to restore these deleted applications by filtering them starting with 'dev' :

    using Azure.Identity;
    using Microsoft.Graph;
    using System.Security.Cryptography.X509Certificates;
    
    var scopes = new[] { "https://graph.microsoft.com/.default" };
    
    var clientId = "appID";
    var tenantId = "tenantId";
    
    // Load certificate from file
    var certificatePath = "C:/demo/graphcert20.pfx";
    var certificatePassword = "password"; // Provide the password here
    var clientCertificate = new X509Certificate2(certificatePath, certificatePassword);
    
    // using Azure.Identity;
    var options = new ClientCertificateCredentialOptions
    {
        AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
    };
    
    var clientCertCredential = new ClientCertificateCredential(
        tenantId, clientId, clientCertificate, options);
    
    var graphClient = new GraphServiceClient(clientCertCredential, scopes);
    
    var deletedApps = await graphClient.Directory.DeletedItems.GraphApplication.GetAsync((requestConfiguration) =>
    {
        requestConfiguration.QueryParameters.Count = true;
        requestConfiguration.QueryParameters.Filter = "startsWith(displayName, 'dev')";
        requestConfiguration.QueryParameters.Select = new string[] { "displayName", "Id", "deletedDateTime" };
        requestConfiguration.Headers.Add("Consistencylevel", "Eventual");
    });
    
    Console.WriteLine($"Total deleted apps starting with 'dev': {deletedApps.OdataCount}\n");
    
    foreach (var deletedApp in deletedApps.Value)
    {
        var appId = deletedApp.Id;
        Console.WriteLine($"Restoring app with ID: {appId}");
    
        var restoreResponse = await graphClient.Directory.DeletedItems[appId].Restore.PostAsync();
        if (restoreResponse != null)
        {
            Console.WriteLine($"App with display name '{deletedApp.DisplayName}' restored successfully.\n");
        }
        else
        {
            Console.WriteLine($"Failed to restore app with ID {appId}.");
        }
    }
    

    Response:

    enter image description here

    To confirm that, I checked the same in Portal where deleted applications starting with 'dev' restored successfully like this:

    enter image description here