function New-ServerlessServiceAccountActiveDirectoryUserPair { <# .SYNOPSIS Create a pair of serverless service accounts in Active Directory. .DESCRIPTION Creates a pair of serverless service accounts in Active Directory and adds the newly created accounts to the SQL access security group for the appropriate environment. .PARAMETER Cred [PSCredential] A credential object for the FH user that has permissions to create new accounts on the domain. .PARAMETER UserDataList [PSCredential[]] An array with exactly two credential objects containing the usernames and passwords to use during account creation. .PARAMETER UserOuPathCommon [string] The OU Path on the domain to create the users within. Formatted as a filesystem path by the calling module to synchronize the AD implementation with the AWS Secrets Manager implementation. .PARAMETER Environment [string] The target environment for the user accounts. .PARAMETER TicketNumber [string] The Jira ticket identifier requesting the new accounts. .EXAMPLE New-ServerlessServiceAccountActiveDirectoryUserPair -Cred (Get-AlkamiCredential) ` -UserDataList @(( Get-AlkamiCredential -UserName 'ExampleA' -Password 'ExampleA!1Pass'), ( Get-AlkamiCredential -UserName 'ExampleB' -Password 'ExampleB!1Pass')) ` -UserOuPathCommon '/ServiceAccounts/Dev' ` -Environment 'Dev' ` -TicketNumber 'SYSENG-1234' #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [PSCredential] $Cred, [Parameter(Mandatory = $true)] [ValidateCount(2, 2)] [PSCredential[]] $UserDataList, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] $UserOuPathCommon, [Parameter(Mandatory = $true)] [ValidateSet('Dev', 'Qa', 'LoadTest', 'Staging', 'Prod', IgnoreCase = $false)] [string] $Environment, [Parameter(Mandatory = $true)] [ValidatePattern("^[a-z]+-\d+$")] [string]$TicketNumber ) $logLead = (Get-LogLeadName) $domainName = "fh.local" $domainNameDn = Get-DomainNameDistinguishedName $domainName $serviceAccountGroupOuPath = "OU=ServiceAccounts,OU=${Environment},OU=SecurityGroups,${domainNameDn}" # Convert the user OU Path into DistinguisedName format $userOuDnParts = $UserOuPathCommon.Split('/', [System.StringSplitOptions]::RemoveEmptyEntries) | ForEach-Object { "OU=$_" } [array]::Reverse($userOuDnParts) $userOuDn = ( "{0},{1}" -f ($userOuDnParts -join ','), $domainNameDn) Write-Verbose "$logLead : Calculated user OU DistinguishedName as '$userOuDn'" # Get the required security group for the user or die trying. $sqlGroupName = "SQL-$Environment-ServerlessApplicationServices" $sqlGroup = Get-ADGroup -filter { GroupCategory -eq "Security" -and Name -eq $sqlGroupName } ` -SearchBase $serviceAccountGroupOuPath ` -Server $domainName ` -Credential $Cred if ( $null -eq $sqlGroup ) { $errorMsg = "$logLead : Unable to find Active Directory group named '$sqlGroupName'; verify AD configuration." Write-Error $errorMsg throw $errorMsg } # Pre-flight that the users do not exist; die early if they do. foreach ( $userAcct in $UserDataList ) { $userName = $userAcct.UserName $userSearchResults = Get-ADUser -Filter { Name -eq $userName } -Credential $Cred -Server $domainName -SearchBase $userOuDn if ( $null -ne $userSearchResults ) { $errorMsg = "$logLead : Found pre-existing user named '$userName' at '$userOuDn'; aborting." Write-Error $errorMsg throw $errorMsg } } Write-Host "$logLead : Creating accounts in security group $sqlGroupName" foreach ($userAcct in $UserDataList) { $userName = $userAcct.UserName try { Write-Verbose "$logLead : Creating User '$userName'" New-ADUser -AccountPassword $userAcct.Password ` -CannotChangePassword $false ` -ChangePasswordAtLogon $false ` -Credential $Cred ` -Description $TicketNumber ` -Enabled $true ` -Name $userName ` -PasswordNeverExpires $false ` -PasswordNotRequired $false ` -Path $userOuDn ` -SamAccountName $userName ` -Server $domainName ` -UserPrincipalName "$userName@$domainName" # Add the new account to the SQL group. Add-ADGroupMember -Identity $sqlGroup -Members $userName # Add the new account to the Disable Interactive Logon group. Add-ADGroupMember -Identity "Disable Interactive Logon" -Members $userName Write-Host "$logLead : Created user '$userName'" } catch { $errorMsg = "$logLead : Creation of user '$userName' failed. Error encountered was: [$PSItem]" Write-Error $errorMsg throw $errorMsg } } }