diff --git a/slides/BASS_202508/01_Install-Modules.ps1 b/slides/BASS_202508/01_Install-Modules.ps1 new file mode 100644 index 0000000..c52f861 --- /dev/null +++ b/slides/BASS_202508/01_Install-Modules.ps1 @@ -0,0 +1,14 @@ +# Required +Install-Module Microsoft.Graph.Authentication -Scope CurrentUser ; Import-Module Microsoft.Graph.Authentication + +Install-Module Pester -SkipPublisherCheck -Force -Scope CurrentUser ; Import-Module Pester +Install-Module Maester -Scope CurrentUser ; Import-Module Maester + +# Optional +#Install-Module Microsoft.Graph -Scope CurrentUser #need to long for install in demo +Install-Module Az.Accounts -Scope CurrentUser ; Import-Module Az.Accounts +Install-Module ExchangeOnlineManagement -Scope CurrentUser ; Import-Module ExchangeOnlineManagement +Install-Module MicrosoftTeams -Scope CurrentUser ; Import-Module MicrosoftTeams + + +Get-Module \ No newline at end of file diff --git a/slides/BASS_202508/02_Install-MaesterTests.ps1 b/slides/BASS_202508/02_Install-MaesterTests.ps1 new file mode 100644 index 0000000..868cffb --- /dev/null +++ b/slides/BASS_202508/02_Install-MaesterTests.ps1 @@ -0,0 +1,21 @@ +# Get script path and set it as current location +[string]$ScriptPath = Switch ($host.name){ + 'Visual Studio Code Host' { Split-Path $PsEditor.GetEditorContext().CurrentFile.Path;$TempPathHost = $PsEditor.GetEditorContext().CurrentFile.Path.split("\");[string]$ScriptName=$TempPathHost[($TempPathHost.Length -1)] } + 'Windows PowerShell ISE Host' { Split-Path -Path $psISE.CurrentFile.FullPath;[string]$ScriptName=$psISE.CurrentFile.DisplayName } + 'ConsoleHost' { $PsScriptRoot;[string]$ScriptName=$MyInvocation.MyCommand.Name} +} +Set-Location $ScriptPath + +# Create folder and set location +mkdir maester-tests | Out-Null +Set-Location .\maester-tests + +# Create maester tests +Install-MaesterTests + +# Set location to upper layer +Set-Location .\.. + +# Copy tests for BASS +Copy-Item -Path (Get-ChildItem -Path .\custom_tests) -Destination .\maester-tests\Custom +Write-Output "" \ No newline at end of file diff --git a/slides/BASS_202508/03_Connect-Maester.ps1 b/slides/BASS_202508/03_Connect-Maester.ps1 new file mode 100644 index 0000000..23847fb --- /dev/null +++ b/slides/BASS_202508/03_Connect-Maester.ps1 @@ -0,0 +1,23 @@ +# Relegated permissions +# Connect to all Services and Consent Permissions +Connect-Maester -Service All -Privileged + +# Or + +Connect-Maester -Service Azure,Graph,Teams, SecurityCompliance, ExchangeOnline -Privileged + +# Or (without permission grants) + +Connect-MgGraph + +# Or + +Connect-MgGraph -Scopes DeviceManagementConfiguration.Read.All, DeviceManagementManagedDevices.Read.All, Directory.Read.All, DirectoryRecommendations.Read.All, IdentityRiskEvent.Read.All, Policy.Read.All, Policy.Read.ConditionalAccess, PrivilegedAccess.Read.AzureAD, Reports.Read.All, RoleEligibilitySchedule.Read.Directory, RoleManagement.Read.All, SecurityIdentitiesSensors.Read.All, SecurityIdentitiesHealth.Read.All, RoleEligibilitySchedule.ReadWrite.Directory, DeviceManagementConfiguration.ReadWrite.All + +# Other services +Connect-AzAccount #-> needed permissions in azure + +# Not in demo +Connect-ExchangeOnline #-> needed permissions in exo +Connect-IPPSSession #-> needed permissions in exo +Connect-MicrosoftTeams #-> needed permissions in teams \ No newline at end of file diff --git a/slides/BASS_202508/03_Connect-Maester_Permissions.png b/slides/BASS_202508/03_Connect-Maester_Permissions.png new file mode 100644 index 0000000..85cf39b Binary files /dev/null and b/slides/BASS_202508/03_Connect-Maester_Permissions.png differ diff --git a/slides/BASS_202508/04_Start-Maester.ps1 b/slides/BASS_202508/04_Start-Maester.ps1 new file mode 100644 index 0000000..f2edd8d --- /dev/null +++ b/slides/BASS_202508/04_Start-Maester.ps1 @@ -0,0 +1,12 @@ +# Run maester +Invoke-Maester + +# Start specific test +Invoke-Maester -Tag "CST.1111" + +# Start all custom tests +Invoke-Maester .\maester-tests\Custom\ + + + + diff --git a/slides/BASS_202508/05_Get-Difference.ps1 b/slides/BASS_202508/05_Get-Difference.ps1 new file mode 100644 index 0000000..e0389c0 --- /dev/null +++ b/slides/BASS_202508/05_Get-Difference.ps1 @@ -0,0 +1,21 @@ +# Get script path and set it as current location +[string]$ScriptPath = Switch ($host.name){ + 'Visual Studio Code Host' { Split-Path $PsEditor.GetEditorContext().CurrentFile.Path;$TempPathHost = $PsEditor.GetEditorContext().CurrentFile.Path.split("\");[string]$ScriptName=$TempPathHost[($TempPathHost.Length -1)] } + 'Windows PowerShell ISE Host' { Split-Path -Path $psISE.CurrentFile.FullPath;[string]$ScriptName=$psISE.CurrentFile.DisplayName } + 'ConsoleHost' { $PsScriptRoot;[string]$ScriptName=$MyInvocation.MyCommand.Name} +} +Set-Location $ScriptPath + +# Get test files sorted by creation time (newest first) +$testFiles = Get-ChildItem .\test-results\TestResults-*.json | Sort-Object CreationTime -Descending + +if ($testFiles.Count -lt 2) { + Write-Error "At least 2 test result files are required for comparison" + return +} + +$tests = @{ + NewTest = (Get-Content $testFiles[0].FullName | ConvertFrom-Json) + PriorTest = (Get-Content $testFiles[1].FullName | ConvertFrom-Json) +} +Compare-MtTestResult @tests \ No newline at end of file diff --git a/slides/BASS_202508/99_RemoveRequirements.ps1 b/slides/BASS_202508/99_RemoveRequirements.ps1 new file mode 100644 index 0000000..8643fb3 --- /dev/null +++ b/slides/BASS_202508/99_RemoveRequirements.ps1 @@ -0,0 +1,21 @@ +# Uninstall Mopdules +Uninstall-Module Pester -Force +Uninstall-Module Maester +Uninstall-Module Microsoft.Graph.Authentication +Uninstall-Module Az.Accounts +Uninstall-Module ExchangeOnlineManagement +Uninstall-Module MicrosoftTeams + +# Get script path and set it as current location +[string]$ScriptPath = Switch ($host.name){ + 'Visual Studio Code Host' { Split-Path $PsEditor.GetEditorContext().CurrentFile.Path;$TempPathHost = $PsEditor.GetEditorContext().CurrentFile.Path.split("\");[string]$ScriptName=$TempPathHost[($TempPathHost.Length -1)] } + 'Windows PowerShell ISE Host' { Split-Path -Path $psISE.CurrentFile.FullPath;[string]$ScriptName=$psISE.CurrentFile.DisplayName } + 'ConsoleHost' { $PsScriptRoot;[string]$ScriptName=$MyInvocation.MyCommand.Name} +} +Set-Location $ScriptPath + +# Remove tests +Remove-Item -Path .\maester-tests -Recurse -Force + +# Remove test results +Remove-Item -Path .\test-results -Recurse -Force \ No newline at end of file diff --git a/slides/BASS_202508/Maester_Lukas_BASS_202508_DE.pptx b/slides/BASS_202508/Maester_Lukas_BASS_202508_DE.pptx new file mode 100644 index 0000000..dc35dc0 Binary files /dev/null and b/slides/BASS_202508/Maester_Lukas_BASS_202508_DE.pptx differ diff --git a/slides/BASS_202508/Maester_Lukas_BASS_202508_EN.pptx b/slides/BASS_202508/Maester_Lukas_BASS_202508_EN.pptx new file mode 100644 index 0000000..ebb18b6 Binary files /dev/null and b/slides/BASS_202508/Maester_Lukas_BASS_202508_EN.pptx differ diff --git a/slides/BASS_202508/custom_tests/ContosoConfig.Tests.ps1 b/slides/BASS_202508/custom_tests/ContosoConfig.Tests.ps1 new file mode 100644 index 0000000..5998156 --- /dev/null +++ b/slides/BASS_202508/custom_tests/ContosoConfig.Tests.ps1 @@ -0,0 +1,14 @@ +Describe "ContosoConfig" -Tag "All","Privilege" { + It "CST.1111: Check approved Teams Administrator" -Tag "CST.1111" { + + # Approved list of Teams Administrator + $approvedTeamsAdmin = @("GA-Lukas@MODERNCOMMS474864.onmicrosoft.com") + + # Get all Teams Administrator + $AdminRole = Invoke-MtGraphRequest -RelativeUri "directoryRoles" | Where-Object { $_.displayName -eq "Teams Administrator" } + $roleMembers = (Invoke-MtGraphRequest -RelativeUri "directoryRoles/$($AdminRole.id)/members").userPrincipalName + + # Check if the Teams Administrators are approved + $roleMembers | Should -BeIn $approvedTeamsAdmin + } +} \ No newline at end of file diff --git a/slides/BASS_202508/custom_tests/ContosoConfig2.Tests.ps1 b/slides/BASS_202508/custom_tests/ContosoConfig2.Tests.ps1 new file mode 100644 index 0000000..234630b --- /dev/null +++ b/slides/BASS_202508/custom_tests/ContosoConfig2.Tests.ps1 @@ -0,0 +1,48 @@ +Describe "ContosoConfig2" -Tag "All","Privilege" { + It "CST.2222: Check approved Teams Administrator with Better description" -Tag "CST.2222" { + + # Approved list of Teams Administrator + $approvedTeamsAdmin = @("GA-Lukas@MODERNCOMMS474864.onmicrosoft.com") + + # Get all Teams Administrator + $AdminRole = Invoke-MtGraphRequest -RelativeUri "directoryRoles" | Where-Object { $_.displayName -eq "Teams Administrator" } + $roleMembers = (Invoke-MtGraphRequest -RelativeUri "directoryRoles/$($AdminRole.id)/members").userPrincipalName + + try { + # Create detailed output + $approvedMembers = $roleMembers | Where-Object { $_ -in $approvedTeamsAdmin } + $notApprovedMembers = $roleMembers | Where-Object { $_ -notin $approvedTeamsAdmin } + + $testResultMarkdown = "" + + if ($approvedMembers.Count -gt 0) { + $testResultMarkdown += "**Approved Teams Administrators:**`n" + foreach ($member in $approvedMembers) { + $testResultMarkdown += "✅ $member`n" + } + $testResultMarkdown += "`n" + } + + if ($notApprovedMembers.Count -gt 0) { + $testResultMarkdown += "**Non-approved Teams Administrators:**`n" + foreach ($member in $notApprovedMembers) { + $testResultMarkdown += "❌ $member`n" + } + $testResultMarkdown += "`n" + } + + if ($roleMembers.Count -eq 0) { + $testResultMarkdown += "No Teams Administrators found.`n" + } + + # Add the detailed output first + Add-MtTestResultDetail -Description $testResultMarkdown + } catch { + Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ + } + + # Check if the Teams Administrators are approved + # The test should fail if there are any non-approved members + $notApprovedMembers.Count | Should -Be 0 -Because "Test" + } +} \ No newline at end of file