Skip to content

Commit

Permalink
Merge pull request #3676 from NikCharlebois/M365DSCExternalScopeEvalu…
Browse files Browse the repository at this point in the history
…ation

M365DSCRuleEvaluation
  • Loading branch information
NikCharlebois authored Sep 12, 2023
2 parents 93e5346 + d34842f commit 1b4c768
Show file tree
Hide file tree
Showing 9 changed files with 442 additions and 5 deletions.
1 change: 1 addition & 0 deletions .github/workflows/Unit Tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
shell: pwsh
run: |
Install-Module ReverseDSC -Force -Scope AllUsers
Install-Module DSCParser -Force -Scope AllUsers
Install-Module PSDesiredStateConfiguration -Force -Scope AllUsers
Install-Module Pester -Force -SkipPublisherCheck -Scope AllUsers
[System.Environment]::SetEnvironmentVariable('M365DSCTelemetryEnabled', $false, [System.EnvironmentVariableTarget]::Machine);
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
* IntuneAppProtectionPolicyAndroid
* Added support for 'RequireClass3Biometrics' parameter
* Added support for 'RequirePinAfterBiometricChange' parameter
* M365DSCRuleEvaluation
* Initial Release.
* O365OrgSettings
* Fixes an issue where the wrong Graph URLs were being called for sovereign
clouds.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
function Get-TargetResource
{
[CmdletBinding()]
[OutputType([System.Collections.Hashtable])]
param
(
[Parameter(Mandatory = $true)]
[System.String]
$ResourceName,

[Parameter(Mandatory = $true)]
[System.String]
$RuleDefinition,

[Parameter()]
[System.String]
$AfterRuleCountQuery,

[Parameter()]
[System.Management.Automation.PSCredential]
$Credential,

[Parameter()]
[System.String]
$ApplicationId,

[Parameter()]
[System.String]
$TenantId,

[Parameter()]
[System.Management.Automation.PSCredential]
$ApplicationSecret,

[Parameter()]
[System.String]
$CertificateThumbprint,

[Parameter()]
[Switch]
$ManagedIdentity
)
return $null
}

function Set-TargetResource
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[System.String]
$ResourceName,

[Parameter(Mandatory = $true)]
[System.String]
$RuleDefinition,

[Parameter()]
[System.String]
$AfterRuleCountQuery,

[Parameter()]
[System.Management.Automation.PSCredential]
$Credential,

[Parameter()]
[System.String]
$ApplicationId,

[Parameter()]
[System.String]
$TenantId,

[Parameter()]
[System.Management.Automation.PSCredential]
$ApplicationSecret,

[Parameter()]
[System.String]
$CertificateThumbprint,

[Parameter()]
[Switch]
$ManagedIdentity
)
# Not Implemented
}

function Test-TargetResource
{
[CmdletBinding()]
[OutputType([System.Boolean])]
param
(
[Parameter(Mandatory = $true)]
[System.String]
$ResourceName,

[Parameter(Mandatory = $true)]
[System.String]
$RuleDefinition,

[Parameter()]
[System.String]
$AfterRuleCountQuery,

[Parameter()]
[System.Management.Automation.PSCredential]
$Credential,

[Parameter()]
[System.String]
$ApplicationId,

[Parameter()]
[System.String]
$TenantId,

[Parameter()]
[System.Management.Automation.PSCredential]
$ApplicationSecret,

[Parameter()]
[System.String]
$CertificateThumbprint,

[Parameter()]
[Switch]
$ManagedIdentity
)
#region Telemetry
$CurrentResourceName = $MyInvocation.MyCommand.ModuleName -replace 'MSFT_', ''
$CommandName = $MyInvocation.MyCommand
$data = Format-M365DSCTelemetryParameters -ResourceName $CurrentResourceName `
-CommandName $CommandName `
-Parameters $PSBoundParameters
Add-M365DSCTelemetryEvent -Data $data
#endregion

Write-Verbose -Message 'Testing configuration of AzureAD Tenant Details'

$Global:PartialExportFileName = "$((New-Guid).ToString()).partial"
$module = Get-DSCResource -Module 'Microsoft365DSC' -Name $ResourceName
if ($null -ne $module)
{
$params = @{
Credential = $PSBoundParameters.Credential
ApplicationId = $PSBoundParameters.ApplicationId
TenantId = $PSBoundParameters.TenantId
CertificateThumbprint = $PSBoundParameters.CertificateThumbprint
ManagedIdentity = $PSBoundParameters.ManagedIdentity
}

if ($null -ne $PSBoundParameters.ApplicationSecret)
{
$params.Add("ApplicationSecret", $PSBoundParameters.ApplicationSecret)
}

Write-Verbose -Message "Importing module from Path {$($module.Path)}"
Import-Module $module.Path -Force -Function 'Export-TargetResource' | Out-Null
$cmdName = "MSFT_$ResourceName\Export-TargetResource"

Write-Verbose -Message "Retrieving Instances"
$instances = &$cmdName @params
Write-Verbose -Message "Retrieved {$($instances.Length)} Instances"

$DSCStringContent = @"
# Generated with Microsoft365DSC version 1.23.906.1
# For additional information on how to use Microsoft365DSC, please visit https://aka.ms/M365DSC
param (
)
Configuration M365TenantConfig
{
param (
)
$OrganizationName = $ConfigurationData.NonNodeData.OrganizationName
Import-DscResource -ModuleName 'Microsoft365DSC' -ModuleVersion '1.23.906.1'
Node localhost
{
$instances
}
}
M365TenantConfig -ConfigurationData .\ConfigurationData.psd1
"@
Write-Verbose -Message "Converting the retrieved instances into DSC Objects"
$DSCConvertedInstances = ConvertTo-DSCObject -Content $DSCStringContent
Write-Verbose -Message "Successfully converted {$($DSCConvertedInstances.Length)} DSC Objects."

Write-Verbose -Message "Querying DSC Objects for invalid instances based on the specified Rule Definition."
$queryBlock = [Scriptblock]::Create($RuleDefinition)
[Array]$invalidInstances = $DSCConvertedInstances | Where-Object -FilterScript $queryBlock
Write-Verbose -Message "Identified {$($invalidInstances.Length)} invalid instances."

$result = $InvalidInstances.Length -eq 0

if (-not [System.String]::IsNullOrEmpty($AfterRuleCountQuery))
{
Write-Verbose -Message "Checking the After Rule Count"
$afterRuleCountQueryString = "`$invalidInstances.Length $AfterRuleCountQuery"
$afterRuleCountQueryBlock = [Scriptblock]::Create($afterRuleCountQueryString)
$result = [Boolean](Invoke-Command -ScriptBlock $afterRuleCountQueryBlock)
Write-Verbose -Message "Output of rule count: $($result | Out-String)"
}

if (-not $result)
{
# Log drifts for each invalid instances found.
$invalidInstancesLogNames = ''
foreach ($invalidInstance in $invalidInstances)
{
$invalidInstancesLogNames += "[$ResourceName]$($invalidInstance.ResourceInstanceName)`r`n"
}

if (-not $result)
{
$message = [System.Text.StringBuilder]::New()
[void]$message.AppendLine("The following resource instance(s) failed a rule validation:`r`n$invalidInstancesLogNames")
[void]$message.AppendLine("`r`nRuleDefinition:`r`n$RuleDefinition")
if (-not [System.String]::IsNullOrEmpty($AfterRuleCountQuery))
{
[void]$message.AppendLine("`r`AfterRuleCountQuery:`r`n$AfterRuleCountQuery")
}
Add-M365DSCEvent -Message $message.ToString() `
-EventType 'RuleEvaluation' `
-EntryType 'Warning' `
-EventID 1 -Source $CurrentResourceName
}
}
return $result
}
}

function Export-TargetResource
{
[CmdletBinding()]
[OutputType([System.String])]
param
(
[Parameter()]
[System.Management.Automation.PSCredential]
$Credential,

[Parameter()]
[System.String]
$ApplicationId,

[Parameter()]
[System.String]
$TenantId,

[Parameter()]
[System.Management.Automation.PSCredential]
$ApplicationSecret,

[Parameter()]
[System.String]
$CertificateThumbprint,

[Parameter()]
[Switch]
$ManagedIdentity
)
return $null
}


Export-ModuleMember -Function *-TargetResource
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[ClassVersion("1.0.0.0"), FriendlyName("M365DSCRuleEvaluation")]
class MSFT_M365DSCRuleEvaluation : OMI_BaseResource
{
[Key, Description("")] String ResourceName;
[Required, Description("")] String RuleDefinition;
[Write, Description("")] String AfterRuleCountQuery;
[Write, Description("Credentials of the Azure Active Directory Admin"), EmbeddedInstance("MSFT_Credential")] string Credential;
[Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId;
[Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId;
[Write, Description("Secret of the Azure Active Directory application to authenticate with."), EmbeddedInstance("MSFT_Credential")] String ApplicationSecret;
[Write, Description("Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication.")] String CertificateThumbprint;
[Write, Description("Managed ID being used for authentication.")] Boolean ManagedIdentity;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# AAD Tenant Details

## Description

This resource configures the Azure AD Tenant Details
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"resourceName": "AADTenantDetails",
"description": "This resource configures the Azure AD Tenant Details.",
"roles": {
"read": [],
"update": [
"Billing Administrator"
]
},
"permissions": {
"graph": {
"delegated": {
"read": [
{
"name": "Organization.Read.All"
}
],
"update": [
{
"name": "Organization.Read.All"
},
{
"name": "Organization.ReadWrite.All"
}
]
},
"application": {
"read": [
{
"name": "Organization.Read.All"
}
],
"update": [
{
"name": "Organization.Read.All"
},
{
"name": "Organization.ReadWrite.All"
}
]
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<#
This example is used to test new resources and showcase the usage of new resources being worked on.
It is not meant to use as a production baseline.
#>

Configuration Example
{
param(
[Parameter(Mandatory = $true)]
[PSCredential]
$CredsCredential
)
Import-DscResource -ModuleName Microsoft365DSC

node localhost
{
M365DSCRuleEvaluation 'AllowAnonymousUsersToJoinMeetingAllPolicies'
{
ResourceName = 'TeamsMeetingPolicy'
RuleDefinition = "`$_.AllowAnonymousUsersToJoinMeeting -eq `$true"
Credential = $CredsCredential
}
}
}
Loading

0 comments on commit 1b4c768

Please sign in to comment.