At the risk of being unpopular, I'll say this: VB.NET does not suck. At all.
No, I won't try to convince you to switch to VB.NET from C# or F#. I won't even tell you that VB.NET is great. But the amount of hate directed towards VB.NET seems unwarranted. Take a look at these recent quotes gathered from a cursory search:
"We identified the presence of VB .NET as our primary source of pain on the development team and committed ourselves to eliminating it."
"C# is far superior for real programmers. VB is far superior for script kitties" (sic)
"To me, Visual Basic seems clumsy, ugly, error-prone, and difficult to read."
It's too bad that few people cite concrete reasons for this hatred. Some mention the verbose syntax as an issue.
Syntax
Well, of course it's better to have a compact syntax to express common ideas, but the thing is, in the great landscape of statically typed programming languages, C# and VB.NET have roughly the same verbosity. Scala and ML languages (including F#) are usually considerably less verbose, and Haskell can be even less verbose.
Whether you like the syntax of a particular language or not is a highly subjective matter. For example, lots of people despise semicolons in C-like syntaxes, the eternal javascript semicolon flamewar is evidence of this. Some other people hate curly braces.
Some particular things I personally find interesting about VB.NET syntax compared to C-like languages:
I mention other languages with similar syntax decisions to emphasize that VB.NET isn't really very different or unique, and not everything about VB.NET's syntax is bad. Sometimes, a bit of verbosity can be a good thing. For example, the Haskell and F# communities generally acknowledge that point-free style, while usually more concise, is not always desirable and can lead to unwanted obfuscation.
Features
No, I'm not going to just list all the features of VB.NET. You can check MSDN for that. Instead, I'll try to describe the features I personally use or find interesting and how I use them.
Functional programming
In 2006, Erik Meijer announced that "Functional programming has reached the masses; it's called Visual Basic". In 2007, with the release of .NET 3.5, VB.NET (and C#) gained some features that help with functional programming: better syntax for anonymous functions, syntax sugar for monads (LINQ), local type inference.
While not strictly only about the language itself, having LINQ as part of the standard library is simply terrific. Even Lisp and OCaml code can be more complex and verbose than VB.NET with LINQ. Take a look at this Stackoverflow question. The VB.NET solution is not much more complex than the F# code:
System.IO.File.ReadLines("ssqHitNum.txt").
SelectMany(Function(s) s.Split(" "c).Skip(1)).
GroupBy(Function(x) x).Select(Function(x) New With {x.Key, x.Count}).
OrderByDescending(Function(x) x.Count).
Take(18)
Related interesting language features include quotations (i.e. System.Linq.Expressions) and language integrated comonads (more widely known as async/await for Tasks).
Some seem to have taken Erik Meijer's announcement as tongue-in-cheek, but for me it has become a reality: thanks to language support and libraries (LINQ and FSharpx), I regularly use persistent data structures, higher-order functions, Option (Maybe) and Choice (Either) monadically, validation applicative functors, in my day job to write code without side-effects. Granted, it will never be as powerful as Haskell or as convenient as F#, but VB.NET has definitely become a usable functional language. Most of what I wrote about functional programming can be easily translated to VB.NET.
XML literals
The most salient and famous feature of VB.NET compared to C# is probably XML literals. I'm using this to model and transform HTML: it's safer and more composable than string-based "template engines" like Razor. You can see some of this in action in three of my open source projects: NHibernate web console, Quartz.NET web console and Boo web console. Underneath these little projects is a tiny web library I designed specifically for embedded ASP.NET modules. I'll probably blog about it in more detail some other day. Anyway, the "view engine" in this web library is just a 300-line file consisting of a bunch of stand-alone functions around System.Xml.Linq.
Type inference
Type inference seems to be slightly more powerful in VB.NET than C#. We can write this in F#:
let f x = x * x
and F# will infer a function int -> int
In C#, if we try to write:
var f = x => x * x;
the compiler complains that it "cannot assign lambda expression to an implicitly-typed local variable". (int x) => x * x doesn't work either. We have to fully declare the parameter and return types:
Func<int, int> f = x => x * x;
In strict, infer mode VB.NET (what I always use), the compiler will infer the return type for you:
Dim f = Function(x As Integer) x * x
Sure it's no big deal when it's an int, but when the return type is something like FSharpChoice<int, NonEmptyList<string>> it's not funny any more. Luckily, you hack around this C# limitation with a simple helper function (FSharpx includes this by the way).
Constants also enjoy better type inference in VB.NET. Const x = 2 is enough for VB.NET to infer that x is an integer. Not so in C#, you have to be explicit about the type: const int x = 2;
In VB.NET, Nothing doubles as default(T) in C#, that is, the type T is inferred by the compiler.
Project-wide imported namespaces
Aren't you tired of having these lines at the top of all your C# files?
using System;
using System.Collections.Generic;
using System.Linq;
You probably have much more than that on any typical project: System.Web, System.IO, your favorite ORM... VB.NET can cut down the number of annoying repeated open namespaces by storing them once in the project properties. Of course, this should not be abused.
Modules and static imports
VB.NET has modules which are similar to F# modules. They compile to sealed classes with static methods. By default, modules are internal, its functions are public, and other values are private.
When doing functional programming in C#, I end up with a lot of static classes and methods representing pure functions that don't close over any values (otherwise I just write a regular class with readonly fields). It gets annoying having to write "static" all the time. VB.NET modules solve that, giving you a programming model closer to F#. The only annoyance is that VB.NET modules are implicitly opened (as in [<AutoOpen>] in F#) when the containing namespace is open.
You can also import any class and get direct access to its static members without an explicit qualified reference to their class, just as when you open a module in F#. For example, I regularly use static functions in FSharpx so for example I just import FSharpx.FSharpOption to avoid having to write FSharpOption.ParseInt all the time.
Conclusion
If you read this far and are thinking "yeah, but these are still minor differences compared to C#", you are absolutely right. There's little difference between C# and VB.NET. If VB.NET sucks, it sucks as much as C#. Next time you start a new .NET project, consider using F# as the default language, and you'll see a real difference compared to C# / VB.NET.
VB.NET is no toy language. Other than the ones I mentioned, it has lots of features (many inherited from .NET, but still) that we now take for granted: garbage collection, parametric polymorphism with co/contravariance (which was considered by many an academics-only feature not long ago), first-class functions, local type inference.
Other features I didn't mention because I don't find them too special: multiple-method interface implementation, exception filters, and many others in this Stackoverflow question.
I don't use it myself, by VB.NET also works quite nicely as a dynamic programming language. As Erik Meijer put it in this Powerpoint presentation (2006): "static typing where possible, dynamic typing where necessary".
So if you're "stuck" with VB.NET for whatever reason (legacy code, corporate policy), your code does not necessarily have to be crap because of the language.
As a last remark: I find it amazing that today's VB.NET evolved quite directly from a language that looked like this in 1979:
10 INPUT "NAME"; A$
20 PRINT "HELLO " A$
(this is Commodore BASIC V2, the original BASIC is older than that)