14 Commits

Author SHA1 Message Date
Doug Rios
c2cc980a91 Merge pull request #111 from CriticalSolutionsNetwork/6.1.2/6.1.3-refactor
6.1.2/6.1.3 refactor
Added
Added Get-MFAStatus function to help with auditing mfa for conditional access controls.
Fixed
Fixed 6.1.2/6.1.3 tests to minimize calls to the Graph API.
Fixed 2.1.1,2.1.4,2.1.5 to suppress error messages and create a standard object when no e5"
2024-06-14 11:06:00 -05:00
DrIOS
4b3e448e48 fix: write-host in public function due to code scanning alert 2024-06-14 11:02:51 -05:00
DrIOS
342d0ac4a9 fix: Module check for Get-MFAStatus 2024-06-14 10:54:58 -05:00
DrIOS
d4252a1839 docs: update help link for get-mfastatus 2024-06-14 10:51:02 -05:00
DrIOS
1fde9947e0 docs: Update CHANGELOG 2024-06-14 10:48:38 -05:00
DrIOS
da856b96e4 update help 2024-06-14 10:47:26 -05:00
DrIOS
8835ddfbfd add: public function to check mfa status 2024-06-14 10:45:17 -05:00
DrIOS
9a7de2f549 fix: error handling for 6.1.2/6.1.3 2024-06-14 10:44:53 -05:00
DrIOS
c9940c2a09 docs: update changelog 2024-06-14 09:24:07 -05:00
DrIOS
83332207b4 docs: test scripts 2024-06-14 09:23:53 -05:00
DrIOS
ccacf76e6c fix: 2.1.1,2.1.4,2.1.5 surpress error messages and create a standard object when no e5 2024-06-14 09:23:03 -05:00
DrIOS
273630839e fix: 2.1.1,2.1.4,2.1.5 surpress error messages and create a standard object when no e5 2024-06-14 08:40:44 -05:00
DrIOS
3ca779650e docs: 6.1.2,6.1.3 refactored 2024-06-13 10:34:37 -05:00
DrIOS
0cde0ae5e2 docs: 6.1.2,6.1.3 refactored 2024-06-13 10:22:38 -05:00
14 changed files with 663 additions and 214 deletions

View File

@@ -6,6 +6,17 @@ The format is based on and uses the types of changes according to [Keep a Change
### Added
- Added Get-MFAStatus function to help with auditing mfa for conditional access controls.
### Fixed
- Fixed 6.1.2/6.1.3 tests to minimize calls to the Graph API.
- Fixed 2.1.1,2.1.4,2.1.5 to suppress error messages and create a standard object when no e5"
## [0.1.10] - 2024-06-12
### Added
- Added condition comments to each test.
### Fixed

BIN
README.md

Binary file not shown.

Binary file not shown.

View File

@@ -4,7 +4,7 @@ Import-Module .\output\module\M365FoundationsCISReport\*\*.psd1
<#
$ver = "v0.1.9"
$ver = "v0.1.10"
git checkout main
git pull origin main
git tag -a $ver -m "Release version $ver refactor Update"

View File

@@ -18,7 +18,7 @@ function Connect-M365Suite {
Write-Host "Successfully connected to Azure Active Directory." -ForegroundColor Green
}
if ($RequiredConnections -contains "Microsoft Graph" -or $RequiredConnections -contains "AzureAD | EXO | Microsoft Graph") {
if ($RequiredConnections -contains "Microsoft Graph" -or $RequiredConnections -contains "EXO | Microsoft Graph") {
Write-Host "Connecting to Microsoft Graph with scopes: Directory.Read.All, Domain.Read.All, Policy.Read.All, Organization.Read.All" -ForegroundColor Cyan
try {
Connect-MgGraph -Scopes "Directory.Read.All", "Domain.Read.All", "Policy.Read.All", "Organization.Read.All" -NoWelcome | Out-Null
@@ -31,7 +31,7 @@ function Connect-M365Suite {
}
}
if ($RequiredConnections -contains "EXO" -or $RequiredConnections -contains "AzureAD | EXO" -or $RequiredConnections -contains "Microsoft Teams | EXO" -or $RequiredConnections -contains "AzureAD | EXO | Microsoft Graph") {
if ($RequiredConnections -contains "EXO" -or $RequiredConnections -contains "AzureAD | EXO" -or $RequiredConnections -contains "Microsoft Teams | EXO" -or $RequiredConnections -contains "EXO | Microsoft Graph") {
Write-Host "Connecting to Exchange Online..." -ForegroundColor Cyan
Connect-ExchangeOnline | Out-Null
Write-Host "Successfully connected to Exchange Online." -ForegroundColor Green

View File

@@ -0,0 +1,103 @@
<#
.SYNOPSIS
Retrieves the MFA (Multi-Factor Authentication) status for Azure Active Directory users.
.DESCRIPTION
The Get-MFAStatus function connects to Microsoft Online Service and retrieves the MFA status for all Azure Active Directory users, excluding guest accounts. Optionally, you can specify a single user by their User Principal Name (UPN) to get their MFA status.
.PARAMETER UserId
The User Principal Name (UPN) of a specific user to retrieve MFA status for. If not provided, the function retrieves MFA status for all users.
.EXAMPLE
Get-MFAStatus
Retrieves the MFA status for all Azure Active Directory users.
.EXAMPLE
Get-MFAStatus -UserId "example@domain.com"
Retrieves the MFA status for the specified user with the UPN "example@domain.com".
.OUTPUTS
System.Object
Returns a sorted list of custom objects containing the following properties:
- UserPrincipalName
- DisplayName
- MFAState
- MFADefaultMethod
- MFAPhoneNumber
- PrimarySMTP
- Aliases
.NOTES
The function requires the MSOL module to be installed and connected to your tenant.
Ensure that you have the necessary permissions to read user and MFA status information.
.LINK
https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Get-MFAStatus
#>
function Get-MFAStatus {
[OutputType([System.Object])]
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$UserId
)
begin {
# Connect to Microsoft Online service
Import-Module MSOnline -ErrorAction SilentlyContinue
}
process {
if (Get-Module MSOnline){
Connect-MsolService
Write-Host -Object "Finding Azure Active Directory Accounts..."
# Get all users, excluding guests
$Users = if ($PSBoundParameters.ContainsKey('UserId')) {
Get-MsolUser -UserPrincipalName $UserId
} else {
Get-MsolUser -All | Where-Object { $_.UserType -ne "Guest" }
}
$Report = [System.Collections.Generic.List[Object]]::new() # Create output list
Write-Host -Object "Processing" $Users.Count "accounts..."
ForEach ($User in $Users) {
$MFADefaultMethod = ($User.StrongAuthenticationMethods | Where-Object { $_.IsDefault -eq "True" }).MethodType
$MFAPhoneNumber = $User.StrongAuthenticationUserDetails.PhoneNumber
$PrimarySMTP = $User.ProxyAddresses | Where-Object { $_ -clike "SMTP*" } | ForEach-Object { $_ -replace "SMTP:", "" }
$Aliases = $User.ProxyAddresses | Where-Object { $_ -clike "smtp*" } | ForEach-Object { $_ -replace "smtp:", "" }
If ($User.StrongAuthenticationRequirements) {
$MFAState = $User.StrongAuthenticationRequirements.State
}
Else {
$MFAState = 'Disabled'
}
If ($MFADefaultMethod) {
Switch ($MFADefaultMethod) {
"OneWaySMS" { $MFADefaultMethod = "Text code authentication phone" }
"TwoWayVoiceMobile" { $MFADefaultMethod = "Call authentication phone" }
"TwoWayVoiceOffice" { $MFADefaultMethod = "Call office phone" }
"PhoneAppOTP" { $MFADefaultMethod = "Authenticator app or hardware token" }
"PhoneAppNotification" { $MFADefaultMethod = "Microsoft authenticator app" }
}
}
Else {
$MFADefaultMethod = "Not enabled"
}
$ReportLine = [PSCustomObject] @{
UserPrincipalName = $User.UserPrincipalName
DisplayName = $User.DisplayName
MFAState = $MFAState
MFADefaultMethod = $MFADefaultMethod
MFAPhoneNumber = $MFAPhoneNumber
PrimarySMTP = ($PrimarySMTP -join ',')
Aliases = ($Aliases -join ',')
}
$Report.Add($ReportLine)
}
Write-Host -Object "Processing complete."
return $Report | Select-Object UserPrincipalName, DisplayName, MFAState, MFADefaultMethod, MFAPhoneNumber, PrimarySMTP, Aliases | Sort-Object UserPrincipalName
}
else {
Write-Host -Object "You must first install MSOL using:`nInstall-Module MSOnline -Scope CurrentUser -Force"
}
}
}

View File

@@ -18,8 +18,8 @@
17,Test-RestrictTenantCreation.ps1,5.1.2.3,Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes',E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Graph
18,Test-PasswordHashSync.ps1,5.1.8.1,Ensure password hash sync is enabled for hybrid deployments,E3,L1,6.7,Centralize Access Control,FALSE,TRUE,TRUE,TRUE,Microsoft Graph
19,Test-AuditDisabledFalse.ps1,6.1.1,Ensure 'AuditDisabled' organizationally is set to 'False',E3,L1,8.2,Collect Audit Logs,TRUE,TRUE,TRUE,TRUE,Microsoft Graph
20,Test-MailboxAuditingE3.ps1,6.1.2,Ensure mailbox auditing for Office E3 users is Enabled,E3,L1,8.2,Collect audit logs.,TRUE,TRUE,TRUE,TRUE,AzureAD | EXO | Microsoft Graph
21,Test-MailboxAuditingE5.ps1,6.1.3,Ensure mailbox auditing for Office E5 users is Enabled,E5,L1,8.2,Collect audit logs.,TRUE,TRUE,TRUE,TRUE,AzureAD | EXO | Microsoft Graph
20,Test-MailboxAuditingE3.ps1,6.1.2,Ensure mailbox auditing for Office E3 users is Enabled,E3,L1,8.2,Collect audit logs.,TRUE,TRUE,TRUE,TRUE,EXO | Microsoft Graph
21,Test-MailboxAuditingE5.ps1,6.1.3,Ensure mailbox auditing for Office E5 users is Enabled,E5,L1,8.2,Collect audit logs.,TRUE,TRUE,TRUE,TRUE,EXO | Microsoft Graph
22,Test-BlockMailForwarding.ps1,6.2.1,Ensure all forms of mail forwarding are blocked and/or disabled,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,EXO
23,Test-NoWhitelistDomains.ps1,6.2.2,Ensure mail transport rules do not whitelist specific domains,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,EXO
24,Test-IdentifyExternalEmail.ps1,6.2.3,Ensure email from external senders is identified,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,EXO
1 Index TestFileName Rec RecDescription ELevel ProfileLevel CISControl CISDescription IG1 IG2 IG3 Automated Connection
18 17 Test-RestrictTenantCreation.ps1 5.1.2.3 Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes' E3 L1 0 Explicitly Not Mapped FALSE FALSE FALSE TRUE Microsoft Graph
19 18 Test-PasswordHashSync.ps1 5.1.8.1 Ensure password hash sync is enabled for hybrid deployments E3 L1 6.7 Centralize Access Control FALSE TRUE TRUE TRUE Microsoft Graph
20 19 Test-AuditDisabledFalse.ps1 6.1.1 Ensure 'AuditDisabled' organizationally is set to 'False' E3 L1 8.2 Collect Audit Logs TRUE TRUE TRUE TRUE Microsoft Graph
21 20 Test-MailboxAuditingE3.ps1 6.1.2 Ensure mailbox auditing for Office E3 users is Enabled E3 L1 8.2 Collect audit logs. TRUE TRUE TRUE TRUE AzureAD | EXO | Microsoft Graph EXO | Microsoft Graph
22 21 Test-MailboxAuditingE5.ps1 6.1.3 Ensure mailbox auditing for Office E5 users is Enabled E5 L1 8.2 Collect audit logs. TRUE TRUE TRUE TRUE AzureAD | EXO | Microsoft Graph EXO | Microsoft Graph
23 22 Test-BlockMailForwarding.ps1 6.2.1 Ensure all forms of mail forwarding are blocked and/or disabled E3 L1 0 Explicitly Not Mapped FALSE FALSE FALSE TRUE EXO
24 23 Test-NoWhitelistDomains.ps1 6.2.2 Ensure mail transport rules do not whitelist specific domains E3 L1 0 Explicitly Not Mapped FALSE FALSE FALSE TRUE EXO
25 24 Test-IdentifyExternalEmail.ps1 6.2.3 Ensure email from external senders is identified E3 L1 0 Explicitly Not Mapped FALSE FALSE FALSE TRUE EXO

View File

@@ -29,32 +29,36 @@ function Test-MailboxAuditingE3 {
# Dot source the class script if necessary
#. .\source\Classes\CISAuditResult.ps1
$e3SkuPartNumbers = @("ENTERPRISEPACK", "OFFICESUBSCRIPTION")
$e3SkuPartNumber = "SPE_E3"
$AdminActions = @("ApplyRecord", "Copy", "Create", "FolderBind", "HardDelete", "Move", "MoveToDeletedItems", "SendAs", "SendOnBehalf", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules")
$DelegateActions = @("ApplyRecord", "Create", "FolderBind", "HardDelete", "Move", "MoveToDeletedItems", "SendAs", "SendOnBehalf", "SoftDelete", "Update", "UpdateFolderPermissions", "UpdateInboxRules")
$OwnerActions = @("ApplyRecord", "Create", "HardDelete", "MailboxLogin", "Move", "MoveToDeletedItems", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules")
$allFailures = @()
$allUsers = Get-AzureADUser -All $true
#$allUsers = Get-AzureADUser -All $true
$founde3Sku = Get-MgSubscribedSku -All | Where-Object {$_.SkuPartNumber -eq $e3SkuPartNumber}
$processedUsers = @{} # Dictionary to track processed users
$recnum = "6.1.2"
}
process {
try {
foreach ($user in $allUsers) {
if ($processedUsers.ContainsKey($user.UserPrincipalName)) {
Write-Verbose "Skipping already processed user: $($user.UserPrincipalName)"
continue
}
if (($founde3Sku.count)-ne 0) {
$allUsers = Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq $($founde3Sku.SkuId) )" -All
$mailboxes = Get-EXOMailbox -PropertySets Audit
try {
foreach ($user in $allUsers) {
if ($processedUsers.ContainsKey($user.UserPrincipalName)) {
Write-Verbose "Skipping already processed user: $($user.UserPrincipalName)"
continue
}
$licenseDetails = Get-MgUserLicenseDetail -UserId $user.UserPrincipalName
$hasOfficeE3 = ($licenseDetails | Where-Object { $_.SkuPartNumber -in $e3SkuPartNumbers }).Count -gt 0
Write-Verbose "Evaluating user $($user.UserPrincipalName) for Office E3 license."
#$licenseDetails = Get-MgUserLicenseDetail -UserId $user.UserPrincipalName
#$hasOfficeE3 = ($licenseDetails | Where-Object { $_.SkuPartNumber -in $e3SkuPartNumbers }).Count -gt 0
#Write-Verbose "Evaluating user $($user.UserPrincipalName) for Office E3 license."
if ($hasOfficeE3) {
$userUPN = $user.UserPrincipalName
$mailbox = Get-EXOMailbox -Identity $userUPN -PropertySets Audit
$mailbox = $mailboxes | Where-Object { $_.UserPrincipalName -eq $user.UserPrincipalName }
$missingActions = @()
if ($mailbox.AuditEnabled) {
@@ -84,39 +88,49 @@ function Test-MailboxAuditingE3 {
# Mark the user as processed
$processedUsers[$user.UserPrincipalName] = $true
}
}
# Prepare failure reasons and details based on compliance
$failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." }
$details = if ($allFailures.Count -eq 0) {
"All Office E3 users have correct mailbox audit settings."
}
else {
"UserPrincipalName|AuditEnabled|AdminActionsMissing|DelegateActionsMissing|OwnerActionsMissing`n" + ($allFailures -join "`n")
}
# Prepare failure reasons and details based on compliance
$failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." }
$details = if ($allFailures.Count -eq 0) {
"All Office E3 users have correct mailbox audit settings."
}
else {
"UserPrincipalName|AuditEnabled|AdminActionsMissing|DelegateActionsMissing|OwnerActionsMissing`n" + ($allFailures -join "`n")
}
# Populate the audit result
# Populate the audit result
$params = @{
Rec = $recnum
Result = $allFailures.Count -eq 0
Status = if ($allFailures.Count -eq 0) { "Pass" } else { "Fail" }
Details = $details
FailureReason = $failureReasons
}
$auditResult = Initialize-CISAuditResult @params
}
catch {
Write-Error "An error occurred during the test: $_"
# Retrieve the description from the test definitions
$testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum }
$description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" }
$script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ })
# Call Initialize-CISAuditResult with error parameters
$auditResult = Initialize-CISAuditResult -Rec $recnum -Failure
}
}
else {
$params = @{
Rec = $recnum
Result = $allFailures.Count -eq 0
Status = if ($allFailures.Count -eq 0) { "Pass" } else { "Fail" }
Details = $details
FailureReason = $failureReasons
Result = $false
Status = "Fail"
Details = "No M365 E3 licenses found."
FailureReason = "The audit is for M365 E3 licenses, but no such licenses were found."
}
$auditResult = Initialize-CISAuditResult @params
}
catch {
Write-Error "An error occurred during the test: $_"
# Retrieve the description from the test definitions
$testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum }
$description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" }
$script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ })
# Call Initialize-CISAuditResult with error parameters
$auditResult = Initialize-CISAuditResult -Rec $recnum -Failure
}
}
end {

View File

@@ -27,32 +27,35 @@ function Test-MailboxAuditingE5 {
# - Condition C: AuditDelegate actions do not include all of the following: ApplyRecord, Create, HardDelete, MailItemsAccessed, MoveToDeletedItems, SendAs, SendOnBehalf, SoftDelete, Update, UpdateFolderPermissions, UpdateInboxRules.
# - Condition D: AuditOwner actions do not include all of the following: ApplyRecord, HardDelete, MailItemsAccessed, MoveToDeletedItems, Send, SoftDelete, Update, UpdateCalendarDelegation, UpdateFolderPermissions, UpdateInboxRules.
$e5SkuPartNumbers = @("SPE_E5", "ENTERPRISEPREMIUM", "OFFICEE5")
$e5SkuPartNumber = "SPE_E5"
$AdminActions = @("ApplyRecord", "Copy", "Create", "FolderBind", "HardDelete", "MailItemsAccessed", "Move", "MoveToDeletedItems", "SendAs", "SendOnBehalf", "Send", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules")
$DelegateActions = @("ApplyRecord", "Create", "FolderBind", "HardDelete", "MailItemsAccessed", "Move", "MoveToDeletedItems", "SendAs", "SendOnBehalf", "SoftDelete", "Update", "UpdateFolderPermissions", "UpdateInboxRules")
$OwnerActions = @("ApplyRecord", "Create", "HardDelete", "MailboxLogin", "Move", "MailItemsAccessed", "MoveToDeletedItems", "Send", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules")
$allFailures = @()
$allUsers = Get-AzureADUser -All $true
#$allUsers = Get-AzureADUser -All $true
$founde5Sku = Get-MgSubscribedSku -All | Where-Object { $_.SkuPartNumber -eq $e5SkuPartNumber }
$processedUsers = @{} # Dictionary to track processed users
$recnum = "6.1.3"
}
process {
try {
foreach ($user in $allUsers) {
if ($processedUsers.ContainsKey($user.UserPrincipalName)) {
Write-Verbose "Skipping already processed user: $($user.UserPrincipalName)"
continue
}
if (($founde5Sku.count) -ne 0) {
$allUsers = Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq $($founde5Sku.SkuId) )" -All
$mailboxes = Get-EXOMailbox -PropertySets Audit
try {
foreach ($user in $allUsers) {
if ($processedUsers.ContainsKey($user.UserPrincipalName)) {
Write-Verbose "Skipping already processed user: $($user.UserPrincipalName)"
continue
}
$licenseDetails = Get-MgUserLicenseDetail -UserId $user.UserPrincipalName
$hasOfficeE5 = ($licenseDetails | Where-Object { $_.SkuPartNumber -in $e5SkuPartNumbers }).Count -gt 0
Write-Verbose "Evaluating user $($user.UserPrincipalName) for Office E5 license."
if ($hasOfficeE5) {
#$licenseDetails = Get-MgUserLicenseDetail -UserId $user.UserPrincipalName
#$hasOfficeE5 = ($licenseDetails | Where-Object { $_.SkuPartNumber -in $e5SkuPartNumbers }).Count -gt 0
#Write-Verbose "Evaluating user $($user.UserPrincipalName) for Office E5 license."
$mailbox = $mailboxes | Where-Object { $_.UserPrincipalName -eq $user.UserPrincipalName }
$userUPN = $user.UserPrincipalName
$mailbox = Get-EXOMailbox -Identity $userUPN -PropertySets Audit
#$mailbox = Get-EXOMailbox -Identity $userUPN -PropertySets Audit
$missingActions = @()
if ($mailbox.AuditEnabled) {
@@ -81,39 +84,49 @@ function Test-MailboxAuditingE5 {
# Mark the user as processed
$processedUsers[$user.UserPrincipalName] = $true
}
}
# Prepare failure reasons and details based on compliance
$failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." }
$details = if ($allFailures.Count -eq 0) {
"All Office E5 users have correct mailbox audit settings." # Condition A for pass
}
else {
"UserPrincipalName|AuditEnabled|AdminActionsMissing|DelegateActionsMissing|OwnerActionsMissing`n" + ($allFailures -join "`n") # Condition A for fail
}
# Prepare failure reasons and details based on compliance
$failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." }
$details = if ($allFailures.Count -eq 0) {
"All Office E5 users have correct mailbox audit settings." # Condition A for pass
}
else {
"UserPrincipalName|AuditEnabled|AdminActionsMissing|DelegateActionsMissing|OwnerActionsMissing`n" + ($allFailures -join "`n") # Condition A for fail
}
# Populate the audit result
# Populate the audit result
$params = @{
Rec = $recnum
Result = $allFailures.Count -eq 0
Status = if ($allFailures.Count -eq 0) { "Pass" } else { "Fail" }
Details = $details
FailureReason = $failureReasons
}
$auditResult = Initialize-CISAuditResult @params
}
catch {
Write-Error "An error occurred during the test: $_"
# Retrieve the description from the test definitions
$testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum }
$description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" }
$script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ })
# Call Initialize-CISAuditResult with error parameters
$auditResult = Initialize-CISAuditResult -Rec $recnum -Failure
}
}
else {
$params = @{
Rec = $recnum
Result = $allFailures.Count -eq 0
Status = if ($allFailures.Count -eq 0) { "Pass" } else { "Fail" }
Details = $details
FailureReason = $failureReasons
Result = $false
Status = "Fail"
Details = "No M365 E5 licenses found."
FailureReason = "The audit is for M365 E5 licenses, but no such licenses were found."
}
$auditResult = Initialize-CISAuditResult @params
}
catch {
Write-Error "An error occurred during the test: $_"
# Retrieve the description from the test definitions
$testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum }
$description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" }
$script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ })
# Call Initialize-CISAuditResult with error parameters
$auditResult = Initialize-CISAuditResult -Rec $recnum -Failure
}
}
end {

View File

@@ -1,10 +1,7 @@
function Test-SafeAttachmentsPolicy {
[CmdletBinding()]
[OutputType([CISAuditResult])]
param (
# Aligned
# Parameters can be added if needed
)
param ()
begin {
# Dot source the class script if necessary
@@ -13,7 +10,7 @@ function Test-SafeAttachmentsPolicy {
# Initialization code, if needed
$recnum = "2.1.4"
<#
<#
Conditions for 2.1.4 (L2) Ensure Safe Attachments policy is enabled
Validate test for a pass:
@@ -31,58 +28,86 @@ function Test-SafeAttachmentsPolicy {
- Condition B: The policy does not cover all recipients within the organization.
- Condition C: The policy action is not set to "Dynamic Delivery" or "Quarantine".
- Condition D: The policy is disabled.
#>
#>
}
process {
try {
# 2.1.4 (L2) Ensure Safe Attachments policy is enabled
if (Get-Command Get-SafeAttachmentPolicy -ErrorAction SilentlyContinue) {
try {
# Retrieve all Safe Attachment policies where Enable is set to True
$safeAttachmentPolicies = Get-SafeAttachmentPolicy -ErrorAction SilentlyContinue | Where-Object { $_.Enable -eq $true }
# Check if any Safe Attachments policy is enabled (Condition A)
$result = $null -ne $safeAttachmentPolicies -and $safeAttachmentPolicies.Count -gt 0
# Retrieve all Safe Attachment policies where Enable is set to True
$safeAttachmentPolicies = Get-SafeAttachmentPolicy | Where-Object { $_.Enable -eq $true }
# Initialize details and failure reasons
$details = @()
$failureReasons = @()
# Condition A: Check if any Safe Attachments policy is enabled
$result = $null -ne $safeAttachmentPolicies -and $safeAttachmentPolicies.Count -gt 0
foreach ($policy in $safeAttachmentPolicies) {
# Initialize policy detail and failed status
$failed = $false
# Condition B, C, D: Additional checks can be added here if more detailed policy attributes are required
# Check if the policy action is set to "Dynamic Delivery" or "Quarantine" (Condition C)
if ($policy.Action -notin @("DynamicDelivery", "Quarantine")) {
$failureReasons += "Policy '$($policy.Name)' action is not set to 'Dynamic Delivery' or 'Quarantine'."
$failed = $true
}
# Determine details and failure reasons based on the presence of enabled policies
$details = if ($result) {
"Enabled Safe Attachments Policies: $($safeAttachmentPolicies.Name -join ', ')"
}
else {
"No Safe Attachments Policies are enabled."
# Check if the policy is not disabled (Condition D)
if (-not $policy.Enable) {
$failureReasons += "Policy '$($policy.Name)' is disabled."
$failed = $true
}
# Add policy details to the details array
$details += [PSCustomObject]@{
Policy = $policy.Name
Enabled = $policy.Enable
Action = $policy.Action
Failed = $failed
}
}
# The result is a pass if there are no failure reasons
$result = $failureReasons.Count -eq 0
# Format details for output
$detailsString = $details | Format-Table -AutoSize | Out-String
$failureReasonsString = ($failureReasons | ForEach-Object { $_ }) -join ' '
# Create and populate the CISAuditResult object
$params = @{
Rec = $recnum
Result = $result
Status = if ($result) { "Pass" } else { "Fail" }
Details = $detailsString
FailureReason = if ($result) { "N/A" } else { $failureReasonsString }
}
$auditResult = Initialize-CISAuditResult @params
}
catch {
Write-Error "An error occurred during the test: $_"
$failureReasons = if ($result) {
"N/A"
}
else {
"Safe Attachments policy is not enabled."
}
# Retrieve the description from the test definitions
$testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum }
$description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" }
# Create and populate the CISAuditResult object
$script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ })
# Call Initialize-CISAuditResult with error parameters
$auditResult = Initialize-CISAuditResult -Rec $recnum -Failure
}
}
else {
$params = @{
Rec = $recnum
Result = $result
Status = if ($result) { "Pass" } else { "Fail" }
Details = $details
FailureReason = $failureReasons
Result = $false
Status = "Fail"
Details = "No M365 E5 licenses found."
FailureReason = "The audit is for M365 E5 licenses and the required EXO commands will not be available otherwise."
}
$auditResult = Initialize-CISAuditResult @params
}
catch {
Write-Error "An error occurred during the test: $_"
# Retrieve the description from the test definitions
$testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum }
$description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" }
$script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ })
# Call Initialize-CISAuditResult with error parameters
$auditResult = Initialize-CISAuditResult -Rec $recnum -Failure
}
}
end {
@@ -90,4 +115,3 @@ function Test-SafeAttachmentsPolicy {
return $auditResult
}
}

View File

@@ -31,61 +31,71 @@ function Test-SafeAttachmentsTeams {
}
process {
try {
# 2.1.5 (L2) Ensure Safe Attachments for SharePoint, OneDrive, and Microsoft Teams is Enabled
if (Get-Command Get-AtpPolicyForO365 -ErrorAction SilentlyContinue) {
try {
# 2.1.5 (L2) Ensure Safe Attachments for SharePoint, OneDrive, and Microsoft Teams is Enabled
# Retrieve the ATP policies for Office 365 and check Safe Attachments settings
$atpPolicies = Get-AtpPolicyForO365
# Check if the required ATP policies are enabled
$atpPolicyResult = $atpPolicies | Where-Object {
$_.EnableATPForSPOTeamsODB -eq $true -and
$_.EnableSafeDocs -eq $true -and
$_.AllowSafeDocsOpen -eq $false
}
# Retrieve the ATP policies for Office 365 and check Safe Attachments settings
$atpPolicies = Get-AtpPolicyForO365
# Condition A: Check Safe Attachments for SharePoint
# Condition B: Check Safe Attachments for OneDrive
# Condition C: Check Safe Attachments for Microsoft Teams
# Check if the required ATP policies are enabled
$atpPolicyResult = $atpPolicies | Where-Object {
$_.EnableATPForSPOTeamsODB -eq $true -and
$_.EnableSafeDocs -eq $true -and
$_.AllowSafeDocsOpen -eq $false
# Determine the result based on the ATP policy settings
$result = $null -ne $atpPolicyResult
$details = if ($result) {
"ATP for SharePoint, OneDrive, and Teams is enabled with correct settings."
}
else {
"ATP for SharePoint, OneDrive, and Teams is not enabled with correct settings."
}
$failureReasons = if ($result) {
"N/A"
}
else {
"ATP policy for SharePoint, OneDrive, and Microsoft Teams is not correctly configured."
}
# Create and populate the CISAuditResult object
$params = @{
Rec = $recnum
Result = $result
Status = if ($result) { "Pass" } else { "Fail" }
Details = $details
FailureReason = $failureReasons
}
$auditResult = Initialize-CISAuditResult @params
}
catch {
Write-Error "An error occurred during the test: $_"
# Condition A: Check Safe Attachments for SharePoint
# Condition B: Check Safe Attachments for OneDrive
# Condition C: Check Safe Attachments for Microsoft Teams
# Retrieve the description from the test definitions
$testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum }
$description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" }
# Determine the result based on the ATP policy settings
$result = $null -ne $atpPolicyResult
$details = if ($result) {
"ATP for SharePoint, OneDrive, and Teams is enabled with correct settings."
}
else {
"ATP for SharePoint, OneDrive, and Teams is not enabled with correct settings."
}
$script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ })
$failureReasons = if ($result) {
"N/A"
# Call Initialize-CISAuditResult with error parameters
$auditResult = Initialize-CISAuditResult -Rec $recnum -Failure
}
else {
"ATP policy for SharePoint, OneDrive, and Microsoft Teams is not correctly configured."
}
# Create and populate the CISAuditResult object
}
else {
$params = @{
Rec = $recnum
Result = $result
Status = if ($result) { "Pass" } else { "Fail" }
Details = $details
FailureReason = $failureReasons
Result = $false
Status = "Fail"
Details = "No M365 E5 licenses found."
FailureReason = "The audit is for M365 E5 licenses and the required EXO commands will not be available otherwise."
}
$auditResult = Initialize-CISAuditResult @params
}
catch {
Write-Error "An error occurred during the test: $_"
# Retrieve the description from the test definitions
$testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum }
$description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" }
$script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ })
# Call Initialize-CISAuditResult with error parameters
$auditResult = Initialize-CISAuditResult -Rec $recnum -Failure
}
}
end {

View File

@@ -40,62 +40,72 @@ function Test-SafeLinksOfficeApps {
}
process {
try {
# 2.1.1 (L2) Ensure Safe Links for Office Applications is Enabled
if (Get-Command Get-SafeLinksPolicy -ErrorAction SilentlyContinue) {
try {
# 2.1.1 (L2) Ensure Safe Links for Office Applications is Enabled
# Retrieve all Safe Links policies
$policies = Get-SafeLinksPolicy
# Initialize the details collection
$misconfiguredDetails = @()
# Retrieve all Safe Links policies
$policies = Get-SafeLinksPolicy
foreach ($policy in $policies) {
# Get the detailed configuration of each policy
$policyDetails = Get-SafeLinksPolicy -Identity $policy.Name
# Initialize the details collection
$misconfiguredDetails = @()
# Check each required property and record failures
# Condition A: Checking policy settings
$failures = @()
if ($policyDetails.EnableSafeLinksForEmail -ne $true) { $failures += "EnableSafeLinksForEmail: False" } # Email: On
if ($policyDetails.EnableSafeLinksForTeams -ne $true) { $failures += "EnableSafeLinksForTeams: False" } # Teams: On
if ($policyDetails.EnableSafeLinksForOffice -ne $true) { $failures += "EnableSafeLinksForOffice: False" } # Office 365 Apps: On
if ($policyDetails.TrackClicks -ne $true) { $failures += "TrackClicks: False" } # Click protection settings: On
if ($policyDetails.AllowClickThrough -ne $false) { $failures += "AllowClickThrough: True" } # Do not track when users click safe links: Off
foreach ($policy in $policies) {
# Get the detailed configuration of each policy
$policyDetails = Get-SafeLinksPolicy -Identity $policy.Name
# Check each required property and record failures
# Condition A: Checking policy settings
$failures = @()
if ($policyDetails.EnableSafeLinksForEmail -ne $true) { $failures += "EnableSafeLinksForEmail: False" } # Email: On
if ($policyDetails.EnableSafeLinksForTeams -ne $true) { $failures += "EnableSafeLinksForTeams: False" } # Teams: On
if ($policyDetails.EnableSafeLinksForOffice -ne $true) { $failures += "EnableSafeLinksForOffice: False" } # Office 365 Apps: On
if ($policyDetails.TrackClicks -ne $true) { $failures += "TrackClicks: False" } # Click protection settings: On
if ($policyDetails.AllowClickThrough -ne $false) { $failures += "AllowClickThrough: True" } # Do not track when users click safe links: Off
# Only add details for policies that have misconfigurations
if ($failures.Count -gt 0) {
$misconfiguredDetails += "Policy: $($policy.Name); Failures: $($failures -join ', ')"
# Only add details for policies that have misconfigurations
if ($failures.Count -gt 0) {
$misconfiguredDetails += "Policy: $($policy.Name); Failures: $($failures -join ', ')"
}
}
# Prepare the final result
# Condition B: Ensuring no misconfigurations
$result = $misconfiguredDetails.Count -eq 0
$details = if ($result) { "All Safe Links policies are correctly configured." } else { $misconfiguredDetails -join ' | ' }
$failureReasons = if ($result) { "N/A" } else { "The following Safe Links policies settings do not meet the recommended configuration: $($misconfiguredDetails -join ' | ')" }
# Create and populate the CISAuditResult object
$params = @{
Rec = $recnum
Result = $result
Status = if ($result) { "Pass" } else { "Fail" }
Details = $details
FailureReason = $failureReasons
}
$auditResult = Initialize-CISAuditResult @params
}
catch {
Write-Error "An error occurred during the test: $_"
# Prepare the final result
# Condition B: Ensuring no misconfigurations
$result = $misconfiguredDetails.Count -eq 0
$details = if ($result) { "All Safe Links policies are correctly configured." } else { $misconfiguredDetails -join ' | ' }
$failureReasons = if ($result) { "N/A" } else { "The following Safe Links policies settings do not meet the recommended configuration: $($misconfiguredDetails -join ' | ')" }
# Retrieve the description from the test definitions
$testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum }
$description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" }
# Create and populate the CISAuditResult object
$script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ })
# Call Initialize-CISAuditResult with error parameters
$auditResult = Initialize-CISAuditResult -Rec $recnum -Failure
}
}
else {
$params = @{
Rec = $recnum
Result = $result
Status = if ($result) { "Pass" } else { "Fail" }
Details = $details
FailureReason = $failureReasons
Result = $false
Status = "Fail"
Details = "No M365 E5 licenses found."
FailureReason = "The audit is for M365 E5 licenses and the required EXO commands will not be available otherwise."
}
$auditResult = Initialize-CISAuditResult @params
}
catch {
Write-Error "An error occurred during the test: $_"
# Retrieve the description from the test definitions
$testDefinition = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $recnum }
$description = if ($testDefinition) { $testDefinition.RecDescription } else { "Description not found" }
$script:FailedTests.Add([PSCustomObject]@{ Rec = $recnum; Description = $description; Error = $_ })
# Call Initialize-CISAuditResult with error parameters
$auditResult = Initialize-CISAuditResult -Rec $recnum -Failure
}
}
end {

View File

@@ -210,3 +210,196 @@ if ($warnings.Count -gt 0) {
Get-GitHubRepository -OwnerName 'CriticalSolutionsNetwork' -RepositoryName 'M365FoundationsCISReport'
#########################################################################################
connect-MgGraph -Scopes "Directory.Read.All", "Domain.Read.All", "Policy.Read.All", "Organization.Read.All" -NoWelcome
# Retrieve the subscribed SKUs
$sub = Get-MgSubscribedSku -All
# Define the product array
$ProductArray = @(
"Microsoft_Cloud_App_Security_App_Governance_Add_On",
"Defender_Threat_Intelligence",
"THREAT_INTELLIGENCE",
"WIN_DEF_ATP",
"Microsoft_Defender_for_Endpoint_F2",
"DEFENDER_ENDPOINT_P1",
"DEFENDER_ENDPOINT_P1_EDU",
"MDATP_XPLAT",
"MDATP_Server",
"ATP_ENTERPRISE_FACULTY",
"ATA",
"ATP_ENTERPRISE_GOV",
"ATP_ENTERPRISE_USGOV_GCCHIGH",
"THREAT_INTELLIGENCE_GOV",
"TVM_Premium_Standalone",
"TVM_Premium_Add_on",
"ATP_ENTERPRISE",
"Azure_Information_Protection_Premium_P1",
"Azure_Information_Protection_Premium_P2",
"Microsoft_Application_Protection_and_Governance",
"Exchange_Online_Protection",
"Microsoft_365_Defender",
"Cloud_App_Security_Discovery"
)
# Define the hashtable
$ProductHashTable = @{
"App governance add-on to Microsoft Defender for Cloud Apps" = "Microsoft_Cloud_App_Security_App_Governance_Add_On"
"Defender Threat Intelligence" = "Defender_Threat_Intelligence"
"Microsoft Defender for Office 365 (Plan 2)" = "THREAT_INTELLIGENCE"
"Microsoft Defender for Endpoint" = "WIN_DEF_ATP"
"Microsoft Defender for Endpoint F2" = "Microsoft_Defender_for_Endpoint_F2"
"Microsoft Defender for Endpoint P1" = "DEFENDER_ENDPOINT_P1"
"Microsoft Defender for Endpoint P1 for EDU" = "DEFENDER_ENDPOINT_P1_EDU"
"Microsoft Defender for Endpoint P2_XPLAT" = "MDATP_XPLAT"
"Microsoft Defender for Endpoint Server" = "MDATP_Server"
"Microsoft Defender for Office 365 (Plan 1) Faculty" = "ATP_ENTERPRISE_FACULTY"
"Microsoft Defender for Identity" = "ATA"
"Microsoft Defender for Office 365 (Plan 1) GCC" = "ATP_ENTERPRISE_GOV"
"Microsoft Defender for Office 365 (Plan 1)_USGOV_GCCHIGH" = "ATP_ENTERPRISE_USGOV_GCCHIGH"
"Microsoft Defender for Office 365 (Plan 2) GCC" = "THREAT_INTELLIGENCE_GOV"
"Microsoft Defender Vulnerability Management" = "TVM_Premium_Standalone"
"Microsoft Defender Vulnerability Management Add-on" = "TVM_Premium_Add_on"
"Microsoft Defender for Office 365 (Plan 1)" = "ATP_ENTERPRISE"
"Azure Information Protection Premium P1" = "Azure_Information_Protection_Premium_P1"
"Azure Information Protection Premium P2" = "Azure_Information_Protection_Premium_P2"
"Microsoft Application Protection and Governance" = "Microsoft_Application_Protection_and_Governance"
"Exchange Online Protection" = "Exchange_Online_Protection"
"Microsoft 365 Defender" = "Microsoft_365_Defender"
"Cloud App Security Discovery" = "Cloud_App_Security_Discovery"
}
# Reverse the hashtable
$ReverseProductHashTable = @{}
foreach ($key in $ProductHashTable.Keys) {
$ReverseProductHashTable[$ProductHashTable[$key]] = $key
}
# Loop through each SKU and get the enabled security features
$securityFeatures = foreach ($sku in $sub) {
if ($sku.SkuPartNumber -eq "MDATP_XPLAT_EDU") {
Write-Host "the SKU is: `n$($sku | gm)"
[PSCustomObject]@{
Skupartnumber = $sku.skupartnumber
AppliesTo = $sku.AppliesTo
ProvisioningStatus = $sku.ProvisioningStatus
ServicePlanId = $sku.ServicePlanId
ServicePlanName = $sku.ServicePlanName
FriendlyName = "Defender P2 for EDU"
}
}
else {
$sku.serviceplans | Where-Object { $_.serviceplanname -in $ProductArray } | ForEach-Object {
$friendlyName = $ReverseProductHashTable[$_.ServicePlanName]
[PSCustomObject]@{
Skupartnumber = $sku.skupartnumber
AppliesTo = $_.AppliesTo
ProvisioningStatus = $_.ProvisioningStatus
ServicePlanId = $_.ServicePlanId
ServicePlanName = $_.ServicePlanName
FriendlyName = $friendlyName
}
}
}
}
# Output the security features
$securityFeatures | Format-Table -AutoSize
##########
# Ensure the ImportExcel module is available
# Ensure the ImportExcel module is available
if (-not (Get-Module -ListAvailable -Name ImportExcel)) {
Install-Module -Name ImportExcel -Force -Scope CurrentUser
}
# Function to wait until the file is available
function Wait-ForFile {
param (
[string]$FilePath
)
while (Test-Path -Path $FilePath -PathType Leaf -and -not (Get-Content $FilePath -ErrorAction SilentlyContinue)) {
Start-Sleep -Seconds 1
}
}
# Path to the Excel file
$excelFilePath = "C:\Users\dougrios\OneDrive - CRITICALSOLUTIONS NET LLC\Documents\_Tools\Benchies\SKUs.xlsx"
# Wait for the file to be available
# Import the Excel file
$excelData = Import-Excel -Path $excelFilePath
# Retrieve the subscribed SKUs
$subscribedSkus = Get-MgSubscribedSku -All
# Define the hashtable with security-related product names
$ProductHashTable = @{
"App governance add-on to Microsoft Defender for Cloud Apps" = "Microsoft_Cloud_App_Security_App_Governance_Add_On"
"Defender Threat Intelligence" = "Defender_Threat_Intelligence"
"Microsoft Defender for Office 365 (Plan 2)" = "THREAT_INTELLIGENCE"
"Microsoft Defender for Endpoint" = "WIN_DEF_ATP"
"Microsoft Defender for Endpoint F2" = "Microsoft_Defender_for_Endpoint_F2"
"Microsoft Defender for Endpoint P1" = "DEFENDER_ENDPOINT_P1"
"Microsoft Defender for Endpoint P1 for EDU" = "DEFENDER_ENDPOINT_P1_EDU"
"Microsoft Defender for Endpoint P2_XPLAT" = "MDATP_XPLAT"
"Microsoft Defender for Endpoint Server" = "MDATP_Server"
"Microsoft Defender for Office 365 (Plan 1) Faculty" = "ATP_ENTERPRISE_FACULTY"
"Microsoft Defender for Identity" = "ATA"
"Microsoft Defender for Office 365 (Plan 1) GCC" = "ATP_ENTERPRISE_GOV"
"Microsoft Defender for Office 365 (Plan 1)_USGOV_GCCHIGH" = "ATP_ENTERPRISE_USGOV_GCCHIGH"
"Microsoft Defender for Office 365 (Plan 2) GCC" = "THREAT_INTELLIGENCE_GOV"
"Microsoft Defender Vulnerability Management" = "TVM_Premium_Standalone"
"Microsoft Defender Vulnerability Management Add-on" = "TVM_Premium_Add_on"
"Microsoft Defender for Office 365 (Plan 1)" = "ATP_ENTERPRISE"
"Azure Information Protection Premium P1" = "Azure_Information_Protection_Premium_P1"
"Azure Information Protection Premium P2" = "Azure_Information_Protection_Premium_P2"
"Microsoft Application Protection and Governance" = "Microsoft_Application_Protection_and_Governance"
"Exchange Online Protection" = "Exchange_Online_Protection"
"Microsoft 365 Defender" = "Microsoft_365_Defender"
"Cloud App Security Discovery" = "Cloud_App_Security_Discovery"
}
# Create a hashtable to store the SKU part numbers and their associated security features
$skuSecurityFeatures = @{}
# Populate the hashtable with data from the Excel file
foreach ($row in $excelData) {
if ($null -ne $row.'String ID' -and $null -ne $row.'Service plans included (friendly names)') {
$skuSecurityFeatures[$row.'String ID'] = $row.'Service plans included (friendly names)'
}
}
# Display the SKU part numbers and their associated security features
foreach ($sku in $subscribedSkus) {
$skuPartNumber = $sku.SkuPartNumber
if ($skuSecurityFeatures.ContainsKey($skuPartNumber)) {
$securityFeatures = $skuSecurityFeatures[$skuPartNumber]
# Check if the security feature is in the hashtable
$isSecurityFeature = $ProductHashTable.ContainsKey($securityFeatures)
if ($isSecurityFeature) {
Write-Output "SKU Part Number: $skuPartNumber"
Write-Output "Security Features: $securityFeatures (Security-related)"
} else {
Write-Output "SKU Part Number: $skuPartNumber"
Write-Output "Security Features: $securityFeatures"
}
Write-Output "----------------------------"
} else {
Write-Output "SKU Part Number: $skuPartNumber"
Write-Output "Security Features: Not Found in Excel"
Write-Output "----------------------------"
}
}

View File

@@ -0,0 +1,71 @@
BeforeAll {
$script:moduleName = '<% $PLASTER_PARAM_ModuleName %>'
# If the module is not found, run the build task 'noop'.
if (-not (Get-Module -Name $script:moduleName -ListAvailable))
{
# Redirect all streams to $null, except the error stream (stream 2)
& "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null
}
# Re-import the module using force to get any code changes between runs.
Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop'
$PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName
$PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName
$PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName
}
AfterAll {
$PSDefaultParameterValues.Remove('Mock:ModuleName')
$PSDefaultParameterValues.Remove('InModuleScope:ModuleName')
$PSDefaultParameterValues.Remove('Should:ModuleName')
Remove-Module -Name $script:moduleName
}
Describe Get-Something {
Context 'Return values' {
BeforeEach {
$return = Get-Something -Data 'value'
}
It 'Returns a single object' {
($return | Measure-Object).Count | Should -Be 1
}
}
Context 'Pipeline' {
It 'Accepts values from the pipeline by value' {
$return = 'value1', 'value2' | Get-Something
$return[0] | Should -Be 'value1'
$return[1] | Should -Be 'value2'
}
It 'Accepts value from the pipeline by property name' {
$return = 'value1', 'value2' | ForEach-Object {
[PSCustomObject]@{
Data = $_
OtherProperty = 'other'
}
} | Get-Something
$return[0] | Should -Be 'value1'
$return[1] | Should -Be 'value2'
}
}
Context 'ShouldProcess' {
It 'Supports WhatIf' {
(Get-Command Get-Something).Parameters.ContainsKey('WhatIf') | Should -Be $true
{ Get-Something -Data 'value' -WhatIf } | Should -Not -Throw
}
}
}