Compare commits
2 Commits
main
...
fresh-main
Author | SHA1 | Date |
---|---|---|
|
f1f5ac4b33 | |
|
2792e86546 |
|
@ -0,0 +1,135 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Case Study: SharePoint & M365 Migrations | Daniel LaForce</title>
|
||||
<meta name="description" content="Enterprise migration case study: Seamless transition from legacy systems to Microsoft 365 with automation, SharePoint, OneDrive, and Teams integration.">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
.portfolio-header {
|
||||
padding: 2rem 0 1rem;
|
||||
}
|
||||
|
||||
.portfolio-section {
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
.project-card {
|
||||
margin-top: 0;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<!-- Header/Nav -->
|
||||
<nav class="navbar">
|
||||
<div class="container">
|
||||
<div class="logo">
|
||||
<a href="index.html">
|
||||
<span class="logo-text-glow">Daniel LaForce</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="nav-menu">
|
||||
<a href="index.html#home" class="nav-link">Home</a>
|
||||
<a href="index.html#portfolio" class="nav-link active">Portfolio</a>
|
||||
<a href="index.html#services" class="nav-link">Services</a>
|
||||
<a href="index.html#lab" class="nav-link">Live Lab</a>
|
||||
<a href="resume.html" class="nav-link">Resume</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Case Study Content -->
|
||||
<section class="portfolio-header">
|
||||
<div class="container">
|
||||
<h1 class="portfolio-title">Case Study: SharePoint & M365 Migrations</h1>
|
||||
<p class="portfolio-subtitle">Modernizing enterprise collaboration and storage through Microsoft 365</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="portfolio-section">
|
||||
<div class="container">
|
||||
<div class="project-card">
|
||||
<div class="project-content">
|
||||
<h3 class="project-title">Client Overview</h3>
|
||||
<p class="project-description">
|
||||
A mid-sized professional services firm relied on Dropbox, Egnyte, Google Workspace, and on-prem file servers to manage daily operations. The IT environment was fragmented, increasing operational complexity and impeding secure collaboration. They needed a scalable solution to unify infrastructure, reduce support load, and enhance productivity.
|
||||
</p>
|
||||
|
||||
<h3 class="project-title">Objectives</h3>
|
||||
<ul>
|
||||
<li>Consolidate file and email services under Microsoft 365</li>
|
||||
<li>Minimize business disruption during migration</li>
|
||||
<li>Strengthen compliance, backup, and access control</li>
|
||||
<li>Enable centralized collaboration with Microsoft Teams</li>
|
||||
</ul>
|
||||
<br>
|
||||
<h3 class="project-title">Solution Strategy</h3>
|
||||
<ul>
|
||||
<li>Provisioned a temporary VM to act as a synchronized landing zone for Egnyte and local file server data</li>
|
||||
<li>Used Egnyte’s API and command-line tools to batch-export permissions and files to the sync VM</li>
|
||||
<li>Ran Microsoft’s SharePoint Migration Tool (SPMT) with JSON-based mapping to import content into SharePoint document libraries</li>
|
||||
<li>Automated pre/post migration checks and permissions auditing via PowerShell and Graph API</li>
|
||||
<li>Staged migration of mail and calendar data using MigrationWiz with coexistence enabled between Google Workspace and Exchange Online</li>
|
||||
<li>Provided Teams onboarding with channel templates and cross-platform training</li>
|
||||
</ul>
|
||||
<br>
|
||||
<h3 class="project-title">Results</h3>
|
||||
<ul>
|
||||
<li>12.4 TB of content migrated across four platforms in under 90 days</li>
|
||||
<li>Zero data loss or permission mismatches confirmed via script-based audits</li>
|
||||
<li>Helpdesk load cut by 40% within the first month post-migration</li>
|
||||
<li>Fully adopted Microsoft Teams structure with defined department-based channels and integrated file repositories</li>
|
||||
<li>End-user training boosted post-migration satisfaction to 97%</li>
|
||||
</ul>
|
||||
|
||||
<div class="project-skills">
|
||||
<span class="skill-tag">SharePoint Online</span>
|
||||
<span class="skill-tag">OneDrive</span>
|
||||
<span class="skill-tag">Teams</span>
|
||||
<span class="skill-tag">Exchange Online</span>
|
||||
<span class="skill-tag">PowerShell</span>
|
||||
<span class="skill-tag">Migration Tools</span>
|
||||
<span class="skill-tag">Egnyte API</span>
|
||||
<span class="skill-tag">SPMT</span>
|
||||
</div>
|
||||
|
||||
<div class="project-links">
|
||||
<a href="/index.html#portfolio" class="project-link"><i class="fas fa-arrow-left"></i> Back to Portfolio</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="footer-content">
|
||||
<div class="footer-logo">
|
||||
<span class="logo-text-glow">Daniel LaForce</span>
|
||||
</div>
|
||||
|
||||
<div class="footer-links">
|
||||
<a href="/index.html#home">Home</a>
|
||||
<a href="/index.html#portfolio">Portfolio</a>
|
||||
<a href="/index.html#services">Services</a>
|
||||
<a href="/index.html#lab">Live Lab</a>
|
||||
<a href="/resume.html">Resume</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-bottom">
|
||||
<p>© All rights reserved. LaForceIT.com</p>
|
||||
<p class="disclaimer">Custom-built with HTML, CSS, and JavaScript.</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -3,6 +3,8 @@
|
|||
import { getCollection } from 'astro:content';
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import MiniGraph from '../../components/MiniGraph.astro';
|
||||
import Header from '../../components/Header.astro'; // Added import
|
||||
import Footer from '../../components/Footer.astro'; // Added import
|
||||
|
||||
// Required getStaticPaths function for dynamic routes
|
||||
export async function getStaticPaths() {
|
||||
|
@ -131,9 +133,37 @@ const combinedRelatedPosts = [
|
|||
|
||||
// Get the Content component for rendering markdown
|
||||
const { Content } = await post.render();
|
||||
|
||||
// Capture rendered content in a string for MiniGraph
|
||||
// Note: This is a simplified approach. A more robust method might be needed
|
||||
// if Content.toString() doesn't reliably produce HTML.
|
||||
let renderedContent = '';
|
||||
try {
|
||||
const contentRender = await post.render();
|
||||
renderedContent = contentRender.Content ? contentRender.Content.toString() : '';
|
||||
} catch (e) {
|
||||
console.error(`Error rendering content for post ${post.slug}:`, e);
|
||||
}
|
||||
|
||||
// Prepare related posts with content (best effort)
|
||||
const relatedPostsWithContent = await Promise.all(
|
||||
combinedRelatedPosts.map(async (relatedPost) => {
|
||||
try {
|
||||
const contentRender = await relatedPost.render();
|
||||
return {
|
||||
...relatedPost,
|
||||
content: contentRender.Content ? contentRender.Content.toString() : ''
|
||||
};
|
||||
} catch (e) {
|
||||
console.error(`Error rendering content for related post ${relatedPost.slug}:`, e);
|
||||
return { ...relatedPost, content: '' }; // Fallback
|
||||
}
|
||||
})
|
||||
);
|
||||
---
|
||||
|
||||
<BaseLayout title={post.data.title} description={post.data.description || ''}>
|
||||
<Header slot="header" /> {/* Added Header */}
|
||||
<article class="container blog-post">
|
||||
<header class="post-header">
|
||||
<h1>{post.data.title}</h1>
|
||||
|
@ -176,7 +206,9 @@ const { Content } = await post.render();
|
|||
tags={post.data.tags || []}
|
||||
category={post.data.category || "Uncategorized"}
|
||||
allPosts={allPosts}
|
||||
content={""} {/* Pass empty string for content */}
|
||||
content={renderedContent} /* Pass rendered HTML */
|
||||
relatedPosts={relatedPostsWithContent} /* Pass related posts with content */
|
||||
width="130%" /* Pass width prop */
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
@ -243,6 +275,7 @@ const { Content } = await post.render();
|
|||
</a>
|
||||
</div>
|
||||
</article>
|
||||
<Footer slot="footer" /> {/* Added Footer */}
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
|
|
Loading…
Reference in New Issue