This is a PowerShell function that creates custom security attributes in Azure Active Directory using the Microsoft Graph API. Custom security attributes are useful because they allow you to associate additional information with users or groups in your organization’s directory.
The New-SBCustomSecurityAttribute
function takes two parameters: $AttributeSetName
and $Attributes
. $AttributeSetName
is the name of the attribute set that the custom security attribute should be associated with. $Attributes
is an array of strings, where each string is the name of a custom security attribute.
The Begin
block of the function first imports the necessary PowerShell modules and connects to the Microsoft Graph API. It then checks if an attribute set with the specified name already exists, and if not, creates a new attribute set.
The Process
block of the function loops through each custom security attribute specified in $Attributes
. For each attribute, it sanitizes the name (stripping out any characters that aren’t alphanumeric or whitespace) and creates a unique ID for the attribute. It then checks if a custom security attribute with that ID already exists, and if not, creates a new custom security attribute with the sanitized name and a description based on the original attribute name.
The End
block of the function disconnects from the Microsoft Graph API.
There are also two helper functions defined within this function: New-AttributeSetParams
and New-CustomAttributeParams
. These functions simply define the parameters that are required when creating a new attribute set or a new custom attribute definition.
Overall, this code allows you to easily create and manage custom security attributes in Azure Active Directory, which can help you better organize and manage your organization’s directory.
function New-SBCustomSecurityAttribute {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$AttributeSetName,
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string[]]$Attributes
)
Begin {
Write-Verbose "Importing required PowerShell modules"
Import-Module Microsoft.Graph.Identity.DirectoryManagement -DisableNameChecking
Import-Module Microsoft.Graph.Applications -DisableNameChecking
Connect-MgGraph
$setAttribute = Get-MgDirectoryAttributeSet -AttributeSetId $AttributeSetName -ErrorAction SilentlyContinue
if (!$setAttribute) {
Write-Verbose "Creating new directory attribute set: $AttributeSetName"
$params = New-AttributeSetParams -AttributeSetName $AttributeSetName
$params | New-MgDirectoryAttributeSet -Verbose
}
}
Process {
foreach ($attribute in $Attributes) {
$name = $attribute -replace ('[^a-zA-Z\d\s:]', '')
$customSecurityAttributeID = $AttributeSetName + '_' + $name
$customAttribute = Get-MgDirectoryCustomSecurityAttributeDefinition -CustomSecurityAttributeDefinitionId "$customSecurityAttributeID" -ErrorAction SilentlyContinue
if (!$customAttribute) {
Write-Verbose "Creating new custom security attribute definition: $attribute"
$description = $attribute -replace ('[^a-zA-Z\d\s:]', ' ')
$params = New-CustomAttributeParams -AttributeSetName $AttributeSetName `
-Name $name `
-Description $description
$params | New-MgDirectoryCustomSecurityAttributeDefinition -Verbose
}
else {
Write-Verbose "Custom Security Attribute $customSecurityAttributeID already exists"
}
}
}
End {
if ($null -ne (Get-MgContext -ErrorAction SilentlyContinue)) {
Disconnect-MgGraph | Out-Null
}
}
}
function New-AttributeSetParams {
param($AttributeSetName)
@{
id = $AttributeSetName
description = 'Attributes for IAM Team'
maxAttributesPerSet = 25
}
}
function New-CustomAttributeParams {
param($AttributeSetName, $Name, $Description)
@{
AttributeSet = $AttributeSetName
Description = $Description
IsCollection = $false
IsSearchable = $true
Name = $Name
Status = 'Available'
Type = 'String'
usePreDefinedValuesOnly = $false
}
}
This is a PowerShell test written in Pester, a popular testing framework for PowerShell. The purpose of this test is to validate that the New-SBCustomSecurityAttribute
function behaves correctly.
The first line of the test imports the CreateCustomSecurityAttribute
script file (not shown here), which contains the New-SBCustomSecurityAttribute
function being tested.
The test suite is defined by the Describe
block. Within this block, there is a BeforeAll
block that runs before any tests are executed. This block simply loads the script file containing the function being tested.
Next, there is a Context
block that defines the context for the tests within it. In this case, the context is “When processing attributes”. Within this context, there are two It
blocks that define individual tests.
The first test checks that a new directory attribute set is created when it doesn’t already exist. The test starts by arranging the input variables ($attributeSetName
and $attributes
). It then calls the function being tested with these variables using New-SBCustomSecurityAttribute
. Finally, it asserts that the directory attribute set was actually created by attempting to retrieve it from the Microsoft Graph API and checking that it is not null or empty. If the attribute set couldn’t be found, the test fails.
The second test checks that a new custom security attribute definition is created when it doesn’t already exist. The test starts by arranging the input variables ($attributeSetName
and $attributes
) and generates a unique ID for the custom security attribute definition. It then attempts to retrieve the attribute definition from the Microsoft Graph API, using the generated ID. Finally, it asserts that the attribute definition was actually created by checking that it is not null or empty. If the attribute definition couldn’t be found, the test fails.
Overall, this test validates that the New-SBCustomSecurityAttribute
function behaves correctly under specific test cases. If any of the tests fail, it means that there is a problem with the functionality of the function being tested or the environment in which it is being run.
# Import the CreateCustomSecurityAttribute script file
Describe "New-SBCustomSecurityAttribute" {
BeforeAll {
. $PSCommandPath.Replace('.Tests.ps1','.ps1')
}
# Define a context for the Process block
Context "When processing attributes" {
It "creates a new directory attribute set when it doesn't exist" {
# TODO: Implement test logic here
# Arrange
$attributeSetName = "TestAttributeSet2"
$attributes = @("TestAttribute1", "TestAttribute2")
#Remove-MgDirectoryAttributeSet -AttributeSetId $attributeSetName -ErrorAction SilentlyContinue
# Act
New-SBCustomSecurityAttribute -AttributeSetName $attributeSetName -Attributes $attributes
# Assert
Connect-MgGraph -Scopes 'CustomSecAttributeDefinition.Read.All', 'CustomSecAttributeDefinition.ReadWrite.All'
$result = Get-MgDirectoryAttributeSet -AttributeSetId $attributeSetName
$result | Should -Not -BeNullOrEmpty -ErrorAction Stop
}
It "creates a new custom security attribute definition when it doesn't exist" {
# TODO: Implement test logic here
#Arrange
$attributeSetName = "TestAttributeSet1"
$attributes = @("TestAttribute1", "TestAttribute2")
#Assert
$customSecurityAttributeID = $AttributeSetName + '_' + $attributes[0]
$customAttribute = Get-MgDirectoryCustomSecurityAttributeDefinition -CustomSecurityAttributeDefinitionId "$customSecurityAttributeID" -ErrorAction SilentlyContinue
$customAttribute | Should -Not -BeNullOrEmpty -ErrorAction Stop
}
}
}
Once you run the Pester Test by running Invoke-Pester
you can verify the test result.
<results>
<test-suite type="TestFixture" name="New-SBCustomSecurityAttribute" executed="True" result="Success" success="True" time="5.8525" asserts="0" description="New-SBCustomSecurityAttribute">
<results>
<test-suite type="TestFixture" name="New-SBCustomSecurityAttribute.When processing attributes" executed="True" result="Success" success="True" time="5.796" asserts="0" description="New-SBCustomSecurityAttribute.When processing attributes">
<results>
<test-case description="creates a new directory attribute set when it doesn't exist" name="New-SBCustomSecurityAttribute.When processing attributes.creates a new directory attribute set when it doesn't exist" time="5.5141" asserts="0" success="True" result="Success" executed="True" />
<test-case description="creates a new custom security attribute definition when it doesn't exist" name="New-SBCustomSecurityAttribute.When processing attributes.creates a new custom security attribute definition when it doesn't exist" time="0.2039" asserts="0" success="True" result="Success" executed="True" />
</results>
</test-suite>
</results>
```
You can also verify the changes in Azure Portal.