This is the VB.NET code that worked for me:
<Extension()> _
Function FindChildControlById(ByVal controlToStartWith As Control, ByVal controlIdToFind As String) As Control
If controlToStartWith Is Nothing Then Return Nothing
If controlToStartWith.ID = controlIdToFind Then Return controlToStartWith
For Each childControl As Control In controlToStartWith.Controls
Dim resCtrl As Control = FindChildControlById(childControl, controlIdToFind)
If resCtrl IsNot Nothing Then Return resCtrl
Next childControl
Return Nothing
End Function ' Function FindChildControlById(ByVal controlToStartWith As Control, ByVal controlIdToFind As String) As Control
Credit goes to George for the initial VB.NET code. I only modified it a teeny bit, with 2 functional change: mine doesn't error if/when null/Nothing is passed as the input control, and mine is implemented as an Extension. My other 3 minor changes don't affect the functionality, but to me, they were code simplifications. But I know it's very subjective.
So this method can be used with:
Dim c1 As Control = Page.FindChildControlById("aspControlID")
And if you want to convert it into a specific child class of a Control, like this:
Dim c1 As Control = Page.FindChildControlById("aspControlID")
Dim c As HyperLink = TryCast(c1, HyperLink)
Update: My function is now named 'FindChildControlById' (previously was 'FindMiControl'). I liked SpeedNet's suggestion better.