Union of results of all database query to also include database name
Just add the DBName to your first query:

DECLARE @sql varchar(max);

SELECT @sql = Coalesce(@sql + ' UNION ALL ', '') + 
        'SELECT '''+name+''' AS DBName, count(*) as ''Number of Sections'' FROM ' + QuoteName(name) + '.dbo.section' + CHAR(13)
FROM   sys.databases
where database_id &gt; 4;

--PRINT @sql
EXEC (@sql);


Generally you want to avoid sp_msforeachdb.  It has some well known bugs.


https://sqlblog.org/2010/12/29/a-more-reliable-and-more-flexible-sp_msforeachdb


Edit: If you want to run this on multiple servers you could write a quick SSIS package that loops through an instance table and collects the data to a central location.  I did a walkthrough on the following 3 posts:


Using a fixed list and a for each loop that changes a connection manager with expressions.
Using the package to store data to a central location.
Touching up the package and expanding it to use an instance table to store the list of servers.


Combining all of that into this answer would be a bit long but here are the basics:


Create an instance table on one of your instances.
Create a table to store the data you want to collect (probably the same instance).
In an SSIS package create a SQL Task that queries the instance table and stores the results in an object variable.
Create a for each loop that loops through the variable.
In the for each loop change a variable to be equal to the current instance name from the object variable.
Create a connection manager that uses an expression to change the server name property to the contents of the instance variable.
In the for each loop create a data flow


The data flow source uses the connection manager with the expression.
Put the query that collects your data in the source.
Set the destination to the table you created in step 2.