Sample PowerShell Script for Creating Home Directory in AD

Problem

Enablement of Home Directory Creation post MS AD account creation of the user through SailPoint ISC as it’s not happening just by inserting the required attributes of “homeDrive” and “homeDirectory” into Create Account Profile of AD.

Diagnosis

The troubleshooting steps are as follows.

1. We Integrated the ISC with MS AD through OOTB connector.

2. In the OOTB connector, we had 2 attributes namely “homeDrive” and “homeDirectory” which is supported.

3. Hence, we added the above attributes in account schema and create account profile

4. The mentioned 2 attribute values were getting aggregated into ISC and getting provisioned and populated inside the AD profile of user.

5. But the physical drive creation does not happen.

6. This needs to be done separately using powershell scripts.

Solution

1. We create the AD After Create Connector Rule in ISC.

2. Through this After Create AD connector rule, we are calling another PowerShell script to maintain the recommendations of SailPoint of “Asynchronous approach” in connector rule.

3. The details of the AD After Create Connector rule are as follows.

Add-Type -Path "C:\SailPoint\IQService\Utils.dll";
$logDate = Get-Date -UFormat "%Y%m%d"
$logFile = "C:\Test\ConnectorAfterCreate_$logDate.log"
$enableDebug = $true
function LogToFile([String] $info) {
if($enableDebug){
    $info | Out-File $logFile -Append -Force
  }
}
LogToFile("Entering SailPoint TestOrg - ActiveDirectory-ConnectorAfterCreate Rule")
$createdOnServer = "";
$sReader = New-Object System.IO.StringReader([System.String]$env:Request);
$sResult = New-Object System.IO.StringReader([System.String]$env:Result);
$xmlReader = [System.xml.XmlTextReader]([sailpoint.utils.xml.XmlUtil]::getReader($sReader));
LogToFile($xmlReader)
$xmlReader_Result = [System.xml.XmlTextReader]([sailpoint.utils.xml.XmlUtil]::getReader($sResult));
LogToFile($xmlReader_Result)
$requestObject = New-Object Sailpoint.Utils.objects.AccountRequest($xmlReader);
LogToFile($requestObject)
$resultObject = New-Object Sailpoint.Utils.objects.ServiceResult($xmlReader_Result);
LogToFile($resultObject)
$requestAsString = $requestObject.nativeIdentity;
$sAMAccountName = $null
$flagToCreateHomeDirectoryScript = $false;
$flagToCreateHomeDirectoryPathScript = $false;
$flagToEnableMailBoxScript = $false;
$homeDrive = $null
$homeDirectory = $null
$Environment = $null
LogToFile("The Native Identity Details are  ==> $requestAsString")
LogToFile("Operation ==> $requestObject.operation")
LogToFile("Entering SailPoint TestOrg - ActiveDirectory-ConnectorAfterCreate Rule")

foreach ($attrib in $requestObject.AttributeRequests) {

if (($attrib.Name -eq "sAMAccountName") -and ($attrib.Value -ne $null) ) {
	LogToFile("TestOrg ==> sAMAccountName is not EMPTY for the User. Hence, set the Flag to true")
      $sAMAccountName = $attrib.Value;
      $flagToCreateHomeDirectoryScript = $true;
      LogToFile("The value of sAMAccountName is : $sAMAccountName")
	  LogToFile("AccountRequest Operation: $requestObject.operation")
    }
	
if (($attrib.Name -eq "homeDirectory") -and ($attrib.Value -ne $null) ) {
	LogToFile("TestOrg ==> homeDirectory is not EMPTY for the User. Hence, set the Flag to true")
      $homeDirectory = $attrib.Value;
      $flagToCreateHomeDirectoryPathScript = $true;
      LogToFile("The value of homeDirectory is : $homeDirectory")
	  LogToFile("AccountRequest Operation: $requestObject.operation")
    }
	
	
	if (($attrib.Name -eq "Environment") -and ($attrib.Value -ne $null) ) {
	LogToFile("TestOrg ==> Environment is not EMPTY for the User. Hence, set the Flag to true")
      $Environment = $attrib.Value;
      $flagToEnableMailBoxScript = $true;
      LogToFile("The value of Environment is : $Environment")
	  LogToFile("AccountRequest Operation: $requestObject.operation")
    }

}
    
if($resultObject.Errors.count -eq 0) {
	LogToFile("Entering into Joiner  after Script")
	foreach ($resultEntry in $resultObject.Attributes.GetEnumerator()){
		if($resultEntry.Name -eq "createdOnServer"){
			$createdOnServer = $resultEntry.Value
		}
	}
	
	
	if($flagToCreateHomeDirectoryScript -and $flagToCreateHomeDirectoryPathScript){
		LogToFile($requestObject.toxml())
		LogToFile("createdOnServer: $createdOnServer")
		LogToFile("Triggering the PowerShell script to trigger script after user account has been created for Create Home Directory for the User")
		$homeDrive = "W:";
		$command = "C:\SailPoint\PSScripts\CreateHomeDir_v6.ps1"
		
		LogToFile("The SamAccountName is :: $SamAccountName and homeDirectory Path is :: $homeDirectory")
		$command = -join ($command, " -SamAccountName '$sAMAccountName' -HomeRootPath '$homeDirectory'")
		
		LogToFile("Invoking the Command as :: $command")
		Start-Sleep -Seconds 20
		LogToFile("Sleep of 20 seconds is COMPLETED!")
		Invoke-Expression $command
		LogToFile("The Command is Invoked. Hence, sleep of 30 seconds is initiated")
		Start-Sleep -Seconds 30
		LogToFile("The Command is Invoked. Hence, sleep of 30 seconds is Completed")
		LogToFile("Invoking the Command as :: $command is SUCCESSFUL!")
		LogToFile("Request as XML object is: $requestAsString")
	}else{
		LogToFile("The Flag of flagToCreateHomeDirectoryScript is FALSE..!!")
	}
}else{
LogToFile("Error while create account request")
LogToFile($resultObject.toxml())
}
LogToFile("resultObject.toxml")
LogToFile($resultObject.toxml())
LogToFile("Exiting SailPoint TestOrg - ActiveDirectory-ConnectorAfterCreate Rule")

  1.    The actual powershell script which creates the home directory is as follows.
    
param(
    # samAccountName of the user being created in AD
    [Parameter(Mandatory = $true)]
    [string]$SamAccountName,

    # Root path where all home folders will be created
    [Parameter(Mandatory = $true)]
    [string]$HomeRootPath,

    # Home Drive Letter
    [string]$HomeDriveLetter = "W:",

    # Log folder path (optional, default as requested)
    [Parameter(Mandatory = $false)]
    [string]$LogPath = "C:\SailPoint\PSLogs\HomeDirectoryCreate"
)

# Stop on errors
$ErrorActionPreference = "Stop"

function Initialize-Logging {
    # Ensure log directory exists
    if (-not (Test-Path $LogPath)) {
        New-Item -ItemType Directory -Path $LogPath -Force | Out-Null
    }

    # Correlation ID for this run
    $script:CorrelationId = Get-Date -Format "yyyyMMddHHmmssfff"

    # Sanitize SamAccountName for filename safety
    if ($SamAccountName) {
        $safeSam = $SamAccountName -replace '[^a-zA-Z0-9]', '_'
    }
    else {
        $safeSam = 'UnknownUser'
    }

    # Unique log file per user + process
    $timestamp = Get-Date -Format 'yyyyMMdd_HHmmssfff'
    $script:LogFile = Join-Path $LogPath ("CreateHomeDir_{0}_{1}_{2}.log" -f $safeSam, $PID, $timestamp)
}

function Write-Log {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Message,
        
        [Parameter(Mandatory = $false)]
        [ValidateSet('Information', 'Warning', 'Error', 'Debug')]
        [string]$Level = 'Information'
    )
    
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "[$timestamp] [$Level] $script:CorrelationId - $Message"
    
    if ($script:LogFile) {
        Add-Content -Path $script:LogFile -Value $logMessage
    }

    switch ($Level) {
        'Warning' { Write-Warning $Message }
        'Error'   { Write-Error   $Message }
        'Debug'   { Write-Debug   $Message }
        default   { Write-Verbose $Message }
    }
}

# Initialize logging as early as possible
Initialize-Logging
Write-Log "Starting HomeDir for SamAccountName: $SamAccountName" -Level Information
Write-Log "Parameters -> HomeRootPath: $HomeRootPath, HomeDriveLetter: $HomeDriveLetter, LogPath: $LogPath" -Level Debug

# Import AD module
try {
    Import-Module ActiveDirectory -ErrorAction Stop
    Write-Log "Successfully imported ActiveDirectory module" -Level Debug
}
catch {
    Write-Log "Failed to import ActiveDirectory module for the user :: $SamAccountName. Error: $($_.Exception.Message)" -Level Error
    exit 1
}

try {
    # 1) Get the AD user (SID needed for ACL)
    Write-Log "Attempting to get AD user: $SamAccountName" -Level Debug
    $user = Get-ADUser -Identity $SamAccountName -ErrorAction Stop
    Write-Log "Successfully retrieved AD user $SamAccountName (SID: $($user.SID))" -Level Debug

    # 2) Build full home directory path
	# Ensure HomeRootPath does NOT already contain SamAccountName
		if ($HomeRootPath.TrimEnd('\') -like "*\$SamAccountName") {
			$HomeRootPath = Split-Path $HomeRootPath -Parent
		}

    $homePath = Join-Path -Path $HomeRootPath -ChildPath $SamAccountName
    Write-Log "Resolved home directory path as: $homePath" -Level Debug

    # 3) Create folder if missing
    if (-not (Test-Path -Path $homePath)) {
        Write-Log "Home directory does not exist. Creating: $homePath" -Level Information
        New-Item -Path $homePath -ItemType Directory -Force | Out-Null
    }
    else {
        Write-Log "Home directory already exists: $homePath" -Level Debug
    }

	$sam = $user.SamAccountName
	Write-Log "The SamAccountName Extracted from AD is :: $sam" -Level Information
	
	$str = ":(OI)(CI)M"
	Write-Log "The Details of permissions are :: $str" -Level Information
	
	$accessrule = $sam + $str
	Write-Log "The Details of Access Rules are :: $accessrule" -Level Information
	
	Write-Log "Calling the new approach of ICACLS command" -Level Information
	icacls $homepath /inheritance:r /grant:r "Administrators:(OI)(CI)F" $accessrule
	Write-Log "Call to ICACLS Command is a SUCCESS!!" -Level Information


    Write-Log "Successfully applied MODIFY ACL for $SamAccountName on $homePath" -Level Information
	

    # 5) Set AD attributes homeDirectory + homeDrive
    Write-Log "Updating AD user $SamAccountName with HomeDirectory: $homePath and HomeDrive: $HomeDriveLetter" -Level Information
    Set-ADUser -Identity $SamAccountName `
        -HomeDirectory $homePath `
        -HomeDrive $HomeDriveLetter

    Write-Log "Successfully updated AD attributes for $SamAccountName" -Level Information

	Write-Log "SUCCESS|$SamAccountName|$homePath" -Level Information
    Write-Log "HomeDir completed successfully for $SamAccountName" -Level Information
    exit 0
}
catch {
    Write-Log ("Error while creating home directory or updating AD for {0}: {1}" -f $SamAccountName, $_.Exception.Message) -Level Error
    exit 1
}

2 Likes