Microsoft
First published on MSDN on Nov 10, 2015
Updated 23 September 2016 MIMPrepScript.zip
For the past few weeks my colleague and I who co author this blog have been working on a script to assist in the preparation and prerequisites to install FIM or MIM on your network. The goal is to complete as much of the labor intensive steps as possible that are often forgotten, the following is a list of task that are currently completed with this script.

  1. Create Organization Units if Needed

  2. Creating Service Accounts for

    1. Standard Synchronization and with the Portal

    2. Privileged Access Management



  3. Sets Permission on Organization Units

  4. Sets Permissions at Root of Domain

  5. Sets SPN's

  6. Creates DNS Records

  7. Creates Admin Groups


As the Script is updated additional task will be added as well as existing tasks will be tweaked and updated. Please keep in mind this is a work in progress and we are looking forward to your comments about this Script. Every effort has been made to ensure that this script does everything as advertised but considering every environment is different there may be complications. Please Respond with any questions, concerns or ideas that you would like to be added in this script. Most importantly use this script in a Lab Environment
Additionally this script is designed to work with the SharePoint Foundations 2013 Configuration Script that has already been posted.

  1. Download the Package

  2. Update the MIMPrepScript_Base.csv file with the information requested.

  3. Run the MIMPrepScript.ps1 Script

  4. Save MIMPrepScript_Base.csv file and use it with the SharePoint Foundations 2013 Configuration Script


I have Just completed testing on this script and I have had consistent results, please let me know if you have errors.
Before you use this script:

  • Script is tested in a Dev or Test Environment

  • Script must be run with credentials of an account with permissions to make the necessary changes in Active Directory

  • The feeder file is completed with as much information as possible I have highlighted the required fields, keep in mind that is if all options are selected during the install.

    • Review feeder file and fill in as much as possible



  • Get updated files MIMPrepScript.zip


Note:
Occasionally when coping and pasting a script text is changed, I have noticed that the spn portions sometimes have issues coping over.
Script
#### Load Modules
### Load Active Directory Module
##########################################################################
if (@( get-module | where-object { $_ . Name -eq "ActiveDirectory" } ) . count -eq 0 ) { import-module ActiveDirectory }
#### Import Feeder File
##########################################################################
[ Reflection.Assembly ]:: LoadWithPartialName( "System.Windows.Forms" ) | Out-Null
$dialog = New-Object -TypeName System.Windows.Forms.OpenFileDialog
$dialog . AddExtension = $true
$dialog . Filter = 'CSV file (*.csv)|*.csv|All Files|*.*'
$dialog . Multiselect = $false
$dialog . FilterIndex = 0
$dialog . InitialDirectory = " $HOME \Documents"
$dialog . RestoreDirectory = $true
$dialog . ShowReadOnly = $true
$dialog . ReadOnlyChecked = $false
$dialog . Title = 'Select Pre Req CSV file'
$result = $dialog . ShowDialog()
if ( $result -ne 'OK' )
{
return
}
$accts = Import-Csv $dialog . FileName
##Functions Prompt for input
function Prompt-ForInput
{
Param ( $message )
$success = "n"
#while($success -ne "" -and $success.ToUpper() -ne "YES")
while ( $success -ne “” -and $success . ToLower() -ne “1” )
{
$val = Read-Host $message
##$success = Read-Host "You entered: $val. Is this correct? Enter Yes or No"
$success = Read-Host “You entered: $val . Is this correct? Enter the #1 for Yes or the # 2 for No”
}
return $val
}
#### Questios that define configuration
### Questions
##########################################################################
$OrganizationalUnits = Prompt-ForInput "Do You need OU's Created Type 'Yes' or 'No'"
$SecurityGroups = Prompt-ForInput "Do you need the Synchronization Service Security Groups Installed Type 'Yes' or 'No'"
$ServiceAccounts = Prompt-ForInput "Do you need Service Accounts Created Type 'Yes' or 'No'"
if ( $ServiceAccounts . ToUpper() -eq "YES" )
{
$SSPRConfiguration = Prompt-ForInput "Will you be Installing SSPR Features Type 'Yes' or 'No'"
$PAMConfiguration = Prompt-ForInput "Will be be installing the PAM Features Type 'Yes' or 'No'"
}
If ( $PAMConfiguration . ToUpper() -eq "YES" )
{
$SetRegistry = Prompt-ForInput "Do You set Registry for SID History Migration Type 'Yes' or 'No'"
}
if ( $OrganizationalUnits . ToUpper() -eq "NO" -and $ServiceAccounts . ToUpper() -eq "NO" -and $SecurityGroups . ToUpper() -eq "NO" )
{
Exit
}
### Variables
##########################################################################
## DOMAINVAR Gets reference to Domain Object to be referenced when needed as opposed to looking up each time.
$DomainVAR = Get-ADDomain
$Domain = $DomainVAR . NetBIOSName
$DomainDN = $DomainVAR . DistinguishedName
$DomainDNSR = $DomainVAR . DNSRoot
##Set Variables based on accts CSV
foreach ( $acct in $accts )
{
if ( $acct . variable -eq "MIMService" )
{
$MIMService = $acct . SamAccountName
}
elseif ( $acct . variable -eq "MIMSPPool" )
{
$MIMSPPool = $acct . SamAccountName
}
elseif ( $acct . variable -eq "ADMA" )
{
$ADMA = $acct . SamAccountName
}
elseif ( $acct . variable -eq "MIMSync" )
{
$MIMSSync = $acct . SamAccountName
}
elseif ( $acct . variable -eq "MIMPWDRST" )
{
$MIMPWDRST = $acct . SamAccountName
}
elseif ( $acct . variable -eq "MIMPWDREG" )
{
$MIMPWDREG = $acct . SamAccountName
}
elseif ( $acct . variable -eq "MIMAdmin" )
{
$MIMAdmin = $acct . SamAccountName
}
elseif ( $acct . variable -eq "MIMMA" )
{
$MIMMA = $acct . SamAccountName
}
elseif ( $acct . variable -eq "MIMSQL" )
{
$MIMSQLSVC = $acct . SamAccountName
}
elseif ( $acct . variable -eq "MIMServiceSVR" )
{
$MIMServiceSVR = $acct . Value
}
elseif ( $acct . variable -eq "MIMPortalSVR" )
{
$MIMPortalSVR = $acct . Value
}
elseif ( $acct . variable -eq "PWDRegSVR" )
{
$PWDREGSite = $acct . DisplayName
$PWDRegSVR = $acct . Value
$PWDRegIP = $acct . IP
}
elseif ( $acct . variable -eq "PWDResetSVR" )
{
$PWDResetSite = $acct . DisplayName
$PWDResetSVR = $acct . Value
$PWDResetIP = $acct . IP
}
elseif ( $acct . variable -eq "MIMSyncSVR" )
{
$SyncSVR = $acct . Value
}
elseif ( $acct . value -eq "BaseMIMDN" )
{
$BASEMIMOU = $acct . DisplayName
$BaseMIMDN = "OU=" + $BASEMIMOU + "," + $DomainDN
}
elseif ( $acct . value -eq "BaseServiceDN" )
{
$BaseServiceOU = $acct . DisplayName
$BaseServiceDN = "OU=" + $BaseServiceOU + "," + $DomainDN
}
elseif ( $acct . variable -eq "BaseUserDN" )
{
$MIMUsersOU = $acct . DisplayName
$MIMUsersDN = "OU=" + $MIMUsersOU + "," + $BaseMIMDN
}
elseif ( $acct . variable -eq "BaseGroupDN" )
{
$MIMGroupsOU = $acct . DisplayName
$MIMGroupsDN = "OU=" + $MIMGroupsOU + "," + $BaseMIMDN
}
elseif ( $acct . variable -eq "MIMSQLSVR" )
{
$SQLSVR = $acct . DisplayName
}
elseif ( $acct . value -eq "CORP" )
{
$CorpDCIP = $acct . ip
$CorpDC = $acct . DisplayName
}
elseif ( $acct . value -eq "PRIV" )
{
$PrivDCIP = $acct . ip
$PrivDC = $acct . DisplayName
}

}

#### Build Functions
##########################################################################
function Create-OUs
{
New-ADOrganizationalUnit -Name $BASEMIMOU -Path $DomainDN
New-ADOrganizationalUnit -Name $BaseServiceOU -Path $DomainDN
New-ADOrganizationalUnit -Name $MIMUserSOU -Path $BASEMIMDN
New-ADOrganizationalUnit -Name $MIMGroupsOU -Path $BASEMIMDN

}

function Create-ServiceAccountsBasic
{
foreach ( $acct in $accts )
{
if ( $acct . Type -eq "Service Account Basic" )
{
$sam = $acct . SamAccountName
$existingUser = Get-ADuser -Filter { SamAccountName -eq $sam }
if ( $existingUser -ne $null )
{
Write-Host " $( $acct . SamAccountName) Already exists. Skipping account creation"
continue
}
$UserPrincipalName = $acct . SamAccountName + "@" + $domain
New-ADUser -SamAccountName $acct . SamAccountName -UserPrincipalName $UserPrincipalName -Name $acct . DisplayName -DisplayName $acct . DisplayName -Path $BaseServiceDN -AccountPassword ( ConvertTo-SecureString "Password@123" -AsPlainText -force ) -Enabled $True -ChangePasswordAtLogon $True -PassThru | Out-Null
}
}
}
function Create-ServiceAccountsSSPR
{
foreach ( $acct in $accts )
{
if ( $acct . Type -eq "Service Account SSPR" )
{
$sam = $acct . SamAccountName
$existingUser = Get-ADuser -Filter { SamAccountName -eq $sam }
if ( $existingUser -ne $null )
{
Write-Host " $( $acct . SamAccountName) Already exists. Skipping account creation"
continue
}
$UserPrincipalName = $acct . SamAccountName + "@" + $domain
New-ADUser -SamAccountName $acct . SamAccountName -UserPrincipalName $UserPrincipalName -Name $acct . DisplayName -DisplayName $acct . DisplayName -Path $BaseServiceDN -AccountPassword ( ConvertTo-SecureString "Password@123" -AsPlainText -force ) -Enabled $True -ChangePasswordAtLogon $True -PassThru | Out-Null
}
}
}
function Create-ServiceAccountsPAM
{
foreach ( $acct in $accts )
{
if ( $acct . Type -eq "Service Account PAM" )
{
$sam = $acct . SamAccountName
$existingUser = Get-ADuser -Filter { SamAccountName -eq $sam }
if ( $existingUser -ne $null )
{
Write-Host " $( $acct . SamAccountName) Already exists. Skipping account creation"
continue
}
$UserPrincipalName = $acct . SamAccountName + "@" + $domain
New-ADUser -SamAccountName $acct . SamAccountName -UserPrincipalName $UserPrincipalName -Name $acct . DisplayName -DisplayName $acct . DisplayName -Path $BaseServiceDN -AccountPassword ( ConvertTo-SecureString "Password@123" -AsPlainText -force ) -Enabled $True -ChangePasswordAtLogon $True -PassThru | Out-Null
}
}
}
function Create-SecurityGroups
{
#Param($CSGacct)
foreach ( $acct in $accts )
{
if ( $acct . Type -eq "Security Group" )
{
$sam = $acct . SamAccountName
# $existingUser = Get-ADGroup -Filter {SamAccountName -eq $sam}
# if($existingUser -ne $null)
# {
# Write-Host "$($acct.SamAccountName) Already exists. Skipping account creation"
# continue
# }
##New-ADGroup -SamAccountName $acct.SamAccountName -UserPrincipalName $UserPrincipalName -Name $acct.DisplayName -DisplayName $acct.DisplayName -Path $BaseServiceDN -GroupScope Global -GroupCategory Security
New-ADGroup -Path $BaseServiceDN -Name $acct . DisplayName -GroupScope Global -GroupCategory Security
}
}
}
function Create-DNS-Records
{
foreach ( $acct in $accts )
{
if ( $acct . Type -eq "DNSRecord" )
{
$DomainVAR = Get-ADDomain
$Domain = $DomainVAR . Name
$DomainDN = $DomainVAR . DistinguishedName
$DomainDNSR = $DomainVAR . DNSRoot
$DNSName = $acct . DisplayName
$DNSServer = $PrivDC
$Zone = $DomainDNSR
$DNSRecord =
$DNStype = "A"
$DNSRecordIP = $acct . IP
$Class = 1
$ttl = 3600
Add-DnsServerResourceRecordA -Name $DNSName -ZoneName $Zone -AllowUpdateAny -IPv4Address $DNSRecordIP -TimeToLive 01:00:00
}
}
}
function Set-Registry
{
New-ItemProperty –Path HKLM:SYSTEM\CurrentControlSet\Control\Lsa –Name TcpipClientSupport –PropertyType DWORD –Value 1
}
function Set-Permissionsbasic
{
### Delegate Permissions at the Root of the Domain
# Delegate Replicating Directory Changes
dsacls " $DomainDN " /G " $Domain \ $( $ADMA ) :CA;Replicating Directory Changes" ;
# Delegate access to the MIM Web Service in order to execute PowerShell scripts against AD directly
# Delegate Read/Write for userAccountControl
dsacls " $DomainDN " /G " $Domain \ $( $MIMService ) :RPWP;userAccountControl;user" /I:S
dsacls " $DomainDN " /G " $Domain \ $( $MIMService ) :RPWP;member;group" /I:S
### Delegate Permissions fot OU's that will contain MIM Managed Objects
##Delegat Permissions to the MIM Managed Users OU
# Delegate Create/Delete Users to the container that will manage Users
dsacls " $MIMUsersDN " /G " $Domain \ $( $ADMA ) :CCDC;user"
# Delegate Read/Write All Properties
dsacls " $MIMUsersDN " /G " $Domain \ $( $ADMA ) :RPWP;"
dsacls " $MIMUsersDN " /G " $Domain \ $( $ADMA ) :RPWP;userAccountControl;user" /I:S
##Delegate Permissions to the MIM Managed Groups OU
# Delegate Create, Delete, and Manage Groups to the Container to allow the ADMA Service Account that will manage Groups
dsacls " $MIMGroupsDN " /G " $Domain \ $( $ADMA ) :CCDC;group"
# Delegate Modify Memberships of Groups to the Container to allow the ADMA Service Account that will manage Groups
dsacls " $MIMGroupsDN " /i:s /g " $Domain \ $( $ADMA ) :rpwp;member;group"
###Set Kerberos Delegations###
##corp\ServiceAccounts Variables
$DomainMIMSVC = " $Domain \ $MIMService "
$DomainMIMSPPool = " $Domain \ $MIMSPPool "
##MIMService/(Server MIM Service is installed on) Variables
$MIMServiceSPN = " $MIMService / $MIMServiceSVR "
$MIMServiceSPNFQDN = " $MIMServiceSPN . $DomainDNSR "
## HTTP//(Server MIM Service is installed on)
$SPserviceSPN = "HTTP/ $MIMServiceSVR "
$SPserviceSPNFQDN = " $SPserviceSPN . $DomainDNSR "
## Password Registration Variables
$PasswordRegDNS = " $PWDREGSite . $DomainDNSR "
$PasswordRegDNSSPN = "HTTP/ $PasswordRegDNS "
$PWDRegSVRSPN = $PWDRegSVR + "$"
$PRDRegSVRDOM = " $Domain \ $PWDRegSVRSPN "
## Password Reset Variables
$PasswordResetDNS = " $PWDResetSite . $DomainDNSR "
$PasswordResetDNSSPN = "HTTP/ $PasswordResetDNS "
$PWDResetSVRSPN = $PWDResetSVR + "$"
$PRDResetSVRDOM = " $Domain \ $PWDResetSVRSPN "
## SQL Server Variables

#### Set SPN's
#### https://technet.microsoft.com/en-us/library/jj134299(v=ws.10).aspx
### Set the SPNs for CORP\SPService
##Setspn.exe –S HTTP/fim1 CORP\SPService
Setspn.exe -S $SPserviceSPN $DomainMIMSPPool
##Setspn.exe –S HTTP/fim1.corp.contoso.com corp\SPService
##Setspn –S HTTP/FIM1.corp.contoso.com corp\SPService
Setspn.exe -S $SPserviceSPNFQDN $DomainMIMSPPool
### Set the SPNs for CORP\FIMService
##Setspn.exe –S FIMService/fim1 CORP\FIMService
setspn.exe -S $MIMServiceSPN $DomainMIMSVC
##Setspn.exe –S FIMService/fim1.corp.contoso.com CORP\FIMService
setspn.exe -S $MIMServiceSPNFQDN $DomainMIMSVC
### Set the SPNs for CORP\SQLDatabase
## Get with your SQL ADMIN to verify this has been completed
##Setspn –S MSSQLsvc/app1.corp.contoso.com:1433 corp\sqldatabase
##Setspn –S MSSQLsvc/app1:1433 corp\sqldatabase
### Set the SPNs for CORP\FIM2$
#$Setspn.exe –S HTTP/Passwordreset.corp.contoso.com CORP\FIM2$
setspn.exe -S $PasswordRegDNSSPN $PRDRegSVRDOM
#$Setspn.exe –S HTTP/Passwordregistration.corp.contoso.com CORP\FIM2$
setspn.exe -S $PasswordResetDNSSPN $PRDResetSVRDOM
}
#### Scripts
##########################################################################
## Create Organizational Units
if ( $OrganizationalUnits . ToUpper() -eq "YES" )
{
Create-OUs
}
## Create Service Accounts
if ( $ServiceAccounts . ToUpper() -eq "YES" )
{
if ( $acct . Type -eq "Service Account Basic" )
{
Create-ServiceAccountsBasic
}
if ( $SSPRConfiguration -eq "YES" )
{
Create-ServiceAccountsSSPR
}
if ( $PAMConfiguration -eq "YES" )
{
Create-ServiceAccountsPAM
}
}
## Create Security Groups
if ( $SecurityGroups . ToUpper() -eq "YES" )
{
Create-SecurityGroups
}
## Set up PAM
if ( $PAMConfiguration . ToUpper() -eq "YES" )
{
If ( $SetRegistry -eq "YES" )
{
Set-Registry
}
}
## Set Permissions for Service Accounts
if ( $ServiceAccounts . ToUpper() -eq "YES" )
{
Set-Permissionsbasic
if ( $SSPRConfiguration . ToUpper() -eq "YES" )
{
Create-DNS-Records
}
}