Wednesday, August 25, 2021

SDK Project attributes

The newer SDK-style project files (*.csproj) do not support all of the Assembly attributes that could be used in older project files. A simple example is the AssemblyTrademarkAttribute. There is no <Trademark> element defined in the new projects. Arbitrary attributes can however be added like this sample:

<ItemGroup>
    <AssemblyAttribute Include="System.Reflection.AssemblyTrademarkAttribute">
      <_Parameter1>My Trademark</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

It's a bit ugly and I can't find formal documentation of the elements, but it works fine. Some people are using this technique to add InternalsVisibleTo attributes to their assemblies without the need to manually add an AssemblyInfo.cs file to their project.

An interesting trick is create your own Attribute with a string property and constructor parameter, then use it like this:

<ItemGroup>
    <AssemblyAttribute Include="MyCompany.AssemblyBuildTimeAttribute">
      <_Parameter1>$([System.DateTime]::UtcNow.ToString("yyyy-MM-dd HH:mm:ss"))</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

A couple of weeks later I realised that only attributes with string constructor arguments can be used this way. If you try to add CLSCompliant for example, you'll find there's no way to pass a bool value to it. Searches hint that this behaviour is expected and suggest you put extra assembly attributes in a separate cs file in the traditional way.

October 2023 Update

You can now create non-string attributes. I found this GitHub issue: https://github.com/dotnet/msbuild/issues/2281. I also read last week in the msbuild documentation that the fix has been released, but I can't find it... It's something to do with _Parameter1_IsLiteral. To be continued...


Wednesday, August 4, 2021

Delete Azure Tenant

 Some time over the previous few years ago I was playing with the Azure B2C feature and I accidentally created two extra Tenants under my Azure Subscription. When I signed-in to my Visual Studio subscription I could see 3 tenants listed in various menus and lists. I made occasional passing attempts to delete the irritating extra Tenants, but the delete page always told me there were active users and applications that had to be removed first, although those lists were empty.

Today I was so fed-up with the Tenant delete failures that I did more research and experiments and I finally succeeded in deleting the two extra useless Tenants.

In the Azure portal go to Azure Active Directory > Manage Tenants > click a useless Tenant in the list to open the details blade on the right and copy the Tenant ID.

Run PowerShell ISE as Administrator. Connect to the useless Tenant.

Connect-AzureAD –TenantID <TenantID>

List objects in the Tenant.

Get-AzureADServicePrincipal

There will be an unpredictably long list of objects. Try to remove as many as possible using this loop.

Get-AzureADServicePrincipal |
    Select-Object -ExpandProperty ObjectId |
    ForEach-Object { Remove-AzureADServicePrincipal -ObjectId $_}

This removed everything from one of my Tenants and I could then delete it in the portal.

The other Tenant had about half of the objects removed and I still couldn't delete it because the portal said I had apps registered, although the app list was empty. I went to various pages and stumbled around, signed out and in again, and after a few minutes returned to the app list page. NOW there was an unfamiliar app listed and it said I couldn't delete it. I went ahead and deleted it anyway, and it worked. Now I could delete the final Tenant.

So overall, the process of deleting Azure AD Tenants is an unpredictable and frustrating process. You get misleading or missing information from the portal pages. Luckily, some web searches told me to use PowerShell to find and remove the objects that were blocking deletion, and even that process seemed nondeterministic.

It took me about two hours of concentrated effort to delete my two useless Tenants.