C#, 267 bytes
()=>{for(int x=99;x>0;){string e="",s="s",t=x>1?s:e,b=" bottle",o=" of beer",w=$"{o} on the wall",a=x+b+t;System.Console.Write($"{a+w}, {a+o}.\n"+(x-->1?$"Take one down and pass it around, {x+b+(x>1?s:e)+w}.\n\n":$"Go to the store and buy some more, 99{b}s{w}."));}};
C# lambda where the output is stdout and without output. You can try it on .NetFiddle.
Code :
()=>{
for (int x=99;x>0;) {
string e="",s="s",t=x>1?s:e,b=" bottle",o=" of beer",w=$"{o} on the wall",a=x+b+t;
System.Console.Write($"{a+w}, {a+o}.\n"+(x-->1
?$"Take one down and pass it around, {x+b+(x>1?s:e)+w}.\n\n"
:$"Go to the store and buy some more, 99{b}s{w}."));
}};
Kudos to Igby Largeman for his solutionsolution. I think it is better than mine (shorter if it had use a lambda too).