From the calendar owner’s perspective, I’m pretty sure Microsoft Office 365 lets you create multiple calendars and view them all together. (Personally I’m a Google Calendar user and it allows this, and I think they’re fairly feature-equivalent services.)
Having the personal and public events managed in separate calendars is kind of the key thing here, because an ICS feed is going to include all of the events in an individual calendar. Office 365 lets you color-code events, but that’s meaningless as far as the feed goes — it doesn’t include that data.
There is one other possibility, if it’s not feasible to separate the calendars, but it will require some custom PHP coding.
ICS Calendar has a handful of actions and filters to allow you to manipulate the parsed calendar data before it gets displayed on the page:
https://icscalendar.com/developer/
If there is something — anything — that consistently distinguishes the private and public data in the calendar (and actually makes it into the ICS feed), then you could use the r34ics_display_calendar_exclude_event filter to remove the private events:
https://icscalendar.com/developer/#r34ics_display_calendar_exclude_event
The example code in the documentation doesn’t include any of the conditional logic you’d need to write, but as an example, if the title (called SUMMARY in the raw ICS feed, and label in the parsed data) contained the word “Private”, then the code would look like this:
add_filter('r34ics_display_calendar_exclude_event', function($exclude, $event, $args) {
if (strpos($event['label'], 'Private') !== false) {
$exclude = true;
}
return $exclude;
}, 10, 3);
This bit of PHP code would need to go into your theme’s functions.php file or someplace similar (in a child theme if necessary), or it could go into a small custom plugin.