This is not the most elegant or optimized approach but this will get you the result set that you are looking for...
--Parameter
DECLARE @topMonth int=3;
--if a valid month is not selected, return all months
IF @topMonth<=0 OR @topMonth>12 SET @topMonth=12
DECLARE @x varchar(2000), @x2 varchar(1000), @i int=1,
@p1 varchar(40)='SUM(case MONTH(orderdate) when ',
@p2 varchar(50)='',
@months varchar(300)='(';
IF OBJECT_ID('tempdb..##tmp') IS NOT NULL
DROP TABLE ##tmp;
SET @x='SELECT YEAR(OrderDate) as orderyear, '+CHAR(13);
WHILE @i<=@topMonth
BEGIN
SET @x=@x+@p1+CAST(@i AS varchar(2))+' then TotalDue end) as '
+CAST(DATENAME(MONTH,(CAST(@i AS varchar(2))+'/1/2000')) AS varchar(20))
+CASE WHEN @i<>@topMonth THEN ','+CHAR(13) ELSE CHAR(13) END
SET @months=@months+CAST(DATENAME(MONTH,(CAST(@i AS varchar(2))+'/1/2000')) AS varchar(20))+
CASE WHEN @i<>@topMonth THEN '+' ELSE ')' END
SET @i=@i+1
END;
SELECT@x=@x+'INTO ##tmp FROM Sales.SalesOrderHeader GROUP BY YEAR(OrderDate) ORDER BY orderyear',
@x2 = 'SELECT *, '+@months+' AS GrandTotal FROM ##tmp ORDER BY orderyear'
EXEC(@x);
EXEC(@x2);
DROP TABLE ##tmp;
-- Itzik Ben-Gan 2001