Automated Testing Framework Microsoft Identity Manager 2016

Introductie

De afgelopen maanden ben ik druk bezig geweest met het opzetten van ons "Automated  Powershell Test Framework voor Microsoft Identity Manager 2016. Je hoeft niet lang op het internet te zoeken om erachter te komen dat er geen "algemeen test framework" is ontwikkeld voor MIM. Soms kom je wellicht wat kleine voorbeelden tegen maar meestal blijft het bij collega's die ook op zoek zijn naar een al ontwikkelde oplossing.
Dus wat doe je dan? Juist, zelf lekker bouwen :)

Uitdaging

Tijdens een mooie en uitdagende opdracht bij één van onze klanten kreeg ik te maken met de volgende uitdaging: De klant had al een werkende MIM omgeving draaien met vele complexe workflows. Diverse updates aan de omgeving waren nodig en tevens moest er voor worden gezorgd dat bestaande functionaliteit niet omviel. 

De Use Cases die getest moesten worden bestonden al. Fantastisch! Echter bleek dit een behoorlijk document te zijn en waarbij deze use cases telkens handmatig werden getest. Tijdsbesteding? 3 dagen..!

Handmatig....dat moet anno 2018 toch slimmer kunnen. De uitdaging was: Hoe zouden de bestaande Use Cases geautomatiseerd getest kunnen worden m.b.v. Powershell en zonder het gebruik van 3-party modules en frameworks. 

Prerequisites

De meeste Powershell modules die je nodig hebt om scenario's heb je waarschijnlijk al een keer geïmporteerd. (Denk aan de standaard AD Module bijvoorbeeld). Om het framework te kunnen gebruiken is het wel belangrijk om het volgende geïmporteerd en geïnstalleerd te hebben:

- De FIMAutomation Module
- De Microsoft.Exchange.Management.PowerShell.SnapIn
- Volledige MIM Installatie (MIMSync, MIMService, Exchange, etc.)

Scenario's om te testen

De use cases worden elke nacht gedraaid d.m.v. een Scheduled Task in de Task Scheduler. Door het importeren en syncen van fake identities worden de diverse MPR's getriggered in de MIM Portal die ervoor zorgen dat diverse workflows worden uitgevoerd.

In het Framework worden de volgende scenario's / use cases getest:

- User uit dienst
- User in dienst
- User uit dienst en weer in dienst
- Aanmaken van een manager
- User verandert van afdeling en/of functie
- Maak de user een invalid user
- Maak de invalid user weer valid
- Verander de UserName
- Opschonen resultaten tests

Omdat de Use Cases al bestonden en waren ontwikkeld op basis van de bestaande omgeving,  zorgde dit ervoor dat de verwachte resultaten dus al bekend waren. Bij alles heb ik logging ingebouwd. Zodra ik ook maar 1 error terug krijg wordt er automatisch een e-mail gegenereerd.

Opbouw Framework

Het framework is opgezet volgens de Powershell Best Practices en bestaat uit het volgende:

1 module: AutomatedTesting.psm1. Deze module bestaat uit wat ik noem twee "type" functies.
De eerste zijn de losse functies zoals Invoke-DeltaSync, Confirm-AdUser, Confirm-MailSend, etc. Deze losse functies heb ik in "regio's" opgedeeld: MIM sync, MIM Portal, AD, HR om in één opslag te kunnen zijn welke functies waar voor dienen.

De tweede zijn de Use Case Functies. Per Use Case is er een functie zoals Invoke-UCCreateUser, Invoke-UCUserLeave, Invoke-UCUserRejoin.

Vervolgens is er het Run All Use Cases script waarin de fake identity inlaad en alle use cases (en de bijbehorende functies) worden afgetrapt. Het voordeel hiervan is dat functies netjes zijn opgesplitst en ook los gebruikt kunnen worden. Tevens zorgt de heldere structuur ervoor dat deze module stap voor stap gemakkelijk uitgebreid kan worden.

Voorbeeld

In onderstaan voorbeeld is de functie : Voeg PIMGroup toe aan een rol beschreven met bijbehorende resultaten.

• Beschreven Use Case

Blog_UseCase.JPG

• Powershell Functie: Invoke-PimGroupToRole

#region PIMGroup Functions
Function Invoke-PimGroupToRole {
    [CmdletBinding()]param (
        [string]$MIMportalURL = "http://localhost:5725",
        [parameter(mandatory = $true)]
        [string]$GroupID,
        [parameter(mandatory = $true)]
        [string]$RoleID,
        [parameter(mandatory = $True)]
        [string]$RoleOWnerID,
        [parameter(mandatory = $true)]
        [string]$PIMGroupMemberID,
        [parameter(mandatory = $true)]
        [psobject]$RolOwnerCreds,
        [parameter(mandatory = $true)]
        [psobject]$ManagerCreds,         
        [parameter(mandatory = $true)]
        [System.Management.Automation.PSCredential]$AuthorizationTeamUserCredential,
        [parameter(mandatory = $true)]
        [boolean]$TestRun
              
    )



    #Checking if user input.
    if ($GroupID.Length -lt "30") {
        Write-Message -msg "Please Enter a valid PIMGroupID" -type Warning
        Pause
        Exit    
    }
    
    if ($RoleID.Length -lt "30") {
        Write-Message -msg "Please Enter a valid RoleID" -type Warning
        Pause
        Exit
    
    }
    
    If ($TestRun -eq $true) {
        Write-Message -msg "TestRun is Enabled, only performing checks." -type Info
    
    }
    #User "VlistW" exist in the group "Team-HeijkantW" and this team has the Role "PortalRole" assigned. At this moment the role doesn't has any PIMGroups assigned.
    #In this usecase we gonna add the PImGroup: "CA-Safe2-Permission4" to the role. Then we gonna look is user "VlistW" got the role assigned. User Kim is RoleOwner.
    #Getting the role to add the role to
    Try {
           
        $AddGroupToRole = Get-MIMObject -ObjectType PIMRole -AttributeName ObjectID -AttributeValue $RoleID -MIMportalURL $MIMportalURL -AsUserCredential $AuthorizationTeamUserCredential
        $GetUser = Get-MIMObject -ObjectType Person -AttributeName ObjectID -AttributeValue $RoleOWnerID -MIMportalURL $MIMportalURL -AsUserCredential $AuthorizationTeamUserCredential
    
        If ($TestRun -eq $false) {
            Try {
           
                Update-MIMObject -Object $AddGroupToRole -AttributeName PIMGroups -AddValue $GroupID -AsUserCredential $AuthorizationTeamUserCredential -MIMportalURL $MIMportalURL
                Invoke-DeltaSync | Out-Null
                Write-Message -msg "Succesfully!  Added the PIM Group to the role" -type Success
            }
            Catch {
            
                Write-Message -msg "Unable to add the PIM Group to the role"  -type Error
                pause
                exit
            }
        }
    }
    Catch {
        Write-Message -type Error -msg "Unable to get the given PIM Role from the MIM Portal"
        
    }

    Write-Message -msg "Performing checks, please wait." -type Info
    
    
    $CheckRole = Get-MIMObject -ObjectType PIMRole -AttributeName ObjectID -AttributeValue $RoleID -AsUserCredential $AuthorizationTeamUserCredential -MIMportalURL $MIMportalURL
    If ($CheckRole.PIMGroups -contains $GroupID) {
        Write-Message -msg "Succesfully added the PIM Group to the role" -type Success
       
    }
    Else {
        Write-Message -msg "Failed to add the PIM Group to the role" -type Error
          
    }
    
    #Checking if the Authorizationmember can see that the PImGroup is added to he Role
    $GetRole = Get-MIMObject -ObjectType PIMRole -AttributeName ObjectID -AttributeValue $RoleID -AsUserCredential $AuthorizationTeamUserCredential -MIMportalURL $MIMportalURL
    
    If ($GetRole.PIMGroups -contains $GroupID) {
        Write-Message -msg "Succesfully! The AuthorizationTeam can see that the PIMGroup is added to the Role" -type Success
    }
    else {
        Write-Message -msg "Failed! The AuthorizationTeam can't see the PIMgroup added to the Role" -type Error
        
    }
    
            
    $TeamMember = Get-MIMObject -ObjectType Person -AttributeName ObjectID -AttributeValue $PIMGroupMemberID -AsUserCredential $AuthorizationTeamUserCredential -MIMportalURL $MIMportalURL
    $PIMGroupCheckAsAuthorizationMember = Get-MIMObject -ObjectType PIMGroup -AttributeName ObjectID -AttributeValue $GroupID -AsUserCredential $AuthorizationTeamUserCredential -MIMportalURL $MIMportalURL
    
    If ($PIMGroupCheckAsAuthorizationMember.PIMMembers -contains $PIMGroupMemberID ) {
        Write-Message -msg "Succesfully! The AuthorizationTeam can see that user $($TeamMember.AccountName) is added to the PIM Group" -type Success
                
    }
    Else {
        Write-Message -msg "Failed! The AuthorizationTeam can't see that user $($TeamMember.AccountName) is added to the PIM Group" -type Error
        
    }
    
        
    $GetRoleInfo = Get-MIMObject -ObjectType PIMRole -AttributeName ObjectID -AttributeValue $RoleID -AsUserCredential $RolOwnerCreds -MIMportalURL $MIMportalURL
    If ($GetRoleInfo.PIMGroups -contains $GroupID) {
        Write-Message -msg "Succesfully! The Role owner can see the added PIMgroup by the role" -type Success
           
    }
    Else {
        Write-Message -msg "Failed! The Role owner can't see the PIMgroup by the role" -type Error
    }
    
    $PIMGroupCheckAsRoleOwner = Get-MIMObject -ObjectType PIMGroup -AttributeName ObjectID -AttributeValue $GroupID -AsUserCredential $RolOwnerCreds -MIMportalURL $MIMportalURL
    
    If ($PIMGroupCheckAsRoleOwner.PIMMembers -contains $PIMGroupMemberID) {
        Write-Message -msg "Succesfully! The Role Owner can see that the user $($TeamMember.AccountName) is added to the PIM Group" -type Success
       
    }
    Else {
        Write-Message -msg "Failed! The Role Ower can't see that user $($TeamMember.AccountName) is added to the PIM Group" -type Error
          
    }        
    
        
    $PIMGroupCheckAsManager = Get-MIMObject -ObjectType PIMGroup -AttributeName ObjectID -AttributeValue $GroupID -AsUserCredential $ManagerCreds -MIMportalURL $MIMportalURL
    
    If ($PIMGroupCheckAsManager.PIMMembers -contains $PIMGroupMemberID) {
        Write-Message -msg "Succesfully! The Team manager can see that user $($TeamMember.AccountName) is added to the PIM Group" -type Success
        
    }
    Else {
        Write-Message -msg "Failed! The Team manager can't see that user $($TeamMember.AccountName) is added to the PIM Group" -type Error
        
    }
    
    
    
}

• Resultaten

Blog_PortalResult.JPG

Kleine Tip

Valkuilen tijdens het opzetten zijn er niet echt. Maar wat ik jullie wel als advies mee wil geven is: Maak je code generiek. Generieke geschreven code neemt meer tijd in beslag maar zorgt voor een veel hogere kwaliteit van het script/framework.

Hopelijk inspireert en helpt dit jullie bij het maken van jullie eigen Test Framework. Happy scripting :)