If, as Andrew suggested, playing with GenerateFaceGroups values doesn't work you might try to find the holes' centers computing slices:
- Your source mesh isn't aligned properly to the world planes. Alignig its bounding box to the origin gives that result:
Note the slight lefthand offset.
Think the top surface should be parallel to the grid. So do EDIT align with Source at SurfaceScribble and Destination at WorldOriginYUp. SurfaceScribble allows to draw a loop on a surface. The averaged normal of the included area will be used for alignment. So scribble a loop on the transparent ghost where you consider the object to be planar. (Sorry can't capture the scribble line in a screenshot):

Now after rotating 180° and moving the base to the height of the grid, things look better:

Time to find the holes:
Copy your object for each hole to detect. Keep only one copy visible. Run EDIT/PlaneCut and transform the cutting plane in Y until MM is able to fill the cut (in case of the upper hole):

Go to SELECT and double click on the (green) group done by PlaneCut. Invert the selection hitting I and discard (shortcut X). This leaves a slice only:

Now try the same on a different copy of your source on each hole. In your example this will work for the left and middle hole. At the right hole the scanning depth into the hole isn't deep enough. Fix this by doing a mesh repair using ANALYSIS/Inspector at HoleFillMode = SmoothFill.
Now you can get a cut based on visual reconstruction:

These cuts and discards of the source surface should result in several slices like this:

Now run EDIT/CreatePivot on each slice. Set PlacementMode=SnapToBoundaryCenter and CoordinateFrame=WorldFrame. Double click the inside hole boundary to drop a pivot there. Doing this on each slice object:

Now when we found the centres of the holes: Time to drill the source object.
But wait, it's not watertight dues to the open boundaries inside its holes.
You might trust ANALYSIS/Inspector to close these open boundaries but IMO you'll get better results capping the holes. Draw a closed selection loop around each hole

and discard:

After you did that on each hole select a seed selection on the main surface, hit E to expand to connected, then invert hitting I and discard (X).
This result run in ANALYSIS/Inspector to close all holes in a flat way.
Anyway... having a watertight source object:
Drop a MESHMIX/Primitives cylinder to empty space. Scale its dimensions to be the drill and generate as many holes to drill (the following screenshots are based on an Inspector Autorepair):

EDIT/Align each cylinder to a pivot ( Source=CenterPoint, Destination=Pivot)

You might need to scale the cylinders in Y to give them the needed length:

Now activate all cylinders and combine them to a single object.
Activate the source mesh and the cylinders as a second object (LMB+Shift) and run EDIT/BooleanDifference:
