PowerShell - Get User Profile Service info
# Get_UserProfileServices.ps1
# Dump out any info I can glean from the User Profile Synch for SharePoint.
#
# LukeB
# https://technet.microsoft.com/en-us/library/ee721049.aspx
#
if ((Get-PSSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null)
{
Add-PSSnapin "Microsoft.SharePoint.PowerShell"
}
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
$USERPROFILESERVICEPROXY = "Microsoft.Office.Server.Administration.UserProfileServiceProxy"
$USERPROFILEAPPLICPROXY = "Microsoft.Office.Server.Administration.UserProfileApplicationProxy"
$USERPROFILESERVICE = "Microsoft.Office.Server.Administration.UserProfileServiceInstance"
$SYNCHSERVICE = "Microsoft.Office.Server.Administration.ProfileSynchronizationServiceInstance"
###############################################################################################################
# -- helper function
function Get-SPfarmAdministrators {
$adminwebapp = Get-SPwebapplication -includecentraladministration | where {$_.IsAdministrationWebApplication}
$adminsite = Get-SPweb($adminwebapp.Url)
$AdminGroupName = $adminsite.AssociatedOwnerGroup
$farmAdministratorsGroup = $adminsite.SiteGroups[$AdminGroupName]
return $farmAdministratorsGroup.users
}
# -- helper function
function Check-ADUserPermission( [System.DirectoryServices.DirectoryEntry]$entry, [string]$user, [string]$permission ) {
$dse = [ADSI]"LDAP://Rootdse"
$ext = [ADSI]("LDAP://CN=Extended-Rights," + $dse.ConfigurationNamingContext)
$right = $ext.psbase.Children | ? { $_.DisplayName -eq $permission }
if ($right -ne $null) {
$perms = $entry.psbase.ObjectSecurity.Access | ? { $_.IdentityReference -eq $user } | ? { $_.ObjectType -eq [GUID]$right.RightsGuid.Value }
return ($perms -ne $null)
}
else {
Write-output "Permission '$permission' not found."
return $false
}
}
# -- helper function
# If the NetBIOS name of any domain that you are synchronizing with differs from its
# FQDN, you must enable NetBIOS domain names on the User Profile service application.
# So we should grab their FQDN and the NETBIOS name and compare the NETBIOS name with the first portion of the FQDN.
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public class NetUtil
{
[DllImport("netapi32.dll", CharSet = CharSet.Auto)]
static extern int NetWkstaGetInfo(string server, int level, out IntPtr info);
[DllImport("netapi32.dll")]
static extern int NetApiBufferFree(IntPtr pBuf);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
class WKSTA_INFO_100
{
public int wki100_platform_id;
[MarshalAs(UnmanagedType.LPWStr)]
public string wki100_computername;
[MarshalAs(UnmanagedType.LPWStr)]
public string wki100_langroup;
public int wki100_ver_major;
public int wki100_ver_minor;
}
public static string GetMachineNetBiosDomain()
{
IntPtr pBuffer = IntPtr.Zero;
WKSTA_INFO_100 info;
int retval = NetWkstaGetInfo(null, 100, out pBuffer);
info = (WKSTA_INFO_100)Marshal.PtrToStructure(pBuffer, typeof(WKSTA_INFO_100));
string domainName = info.wki100_langroup;
NetApiBufferFree(pBuffer);
return domainName;
}
}
"@
function Check-NETBIOS {
$fqdn = $(Get-WmiObject Win32_ComputerSystem).Domain
$domainpart= $($fqdn.split('.',2)[0]).ToUpper()
$netbiosdomain = [NetUtil]::GetMachineNetBiosDomain()
return $domainpart.Equals($netbiosDomain)
}
# -- helper function
function Get-DomainMode {
$domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
return $domain.DomainMode
}
# -- helper function
function get-DNSLookup {
param ( $hostname )
try {
$dnsResult = [System.Net.Dns]::GetHostEntry($hostname)
$name = $dnsResult.HostName
if ($name -notlike "*.*") { $name += " (from WINS)" }
$ip =$dnsResult.AddressList
}
catch {
$name="Host Not Resolved"
$ip="Host Not Resolved"
}
$object = New-Object PSObject -Property @{
Name = $name
IP = $ip
}
return $object
}
###############################################################################################################
$ProfileServiceApplicProxy = Get-SPServiceApplicationProxy | where {$_.GetType().ToString() -eq $USERPROFILEAPPLICPROXY}
if ($ProfileServiceApplicProxy) {
$ProfileServiceProxy = $ProfileServiceApplicProxy.Parent
$PSAS=Get-SPProfileServiceApplicationSecurity -ProfileServiceApplicationProxy $ProfileServiceApplicProxy -ErrorAction SilentlyContinue
# $PSAS is the access rights
$UPSP = New-Object PSObject -Property @{
ServiceName = $ProfileServiceApplicProxy.Name
AccessRights = $PSAS
}
write-output "User Profile Service Proxy:"
$UPSP | FL
}
#
# check if the User Profile Service is present and running on this box
#
$UserProfileServiceInstances = Get-SPServiceInstance | where {$_.GetType().ToString() -eq $USERPROFILESERVICE}
if ($UserProfileServiceInstances) {
foreach ($UserProfileServiceInstance in $UserProfileServiceInstances) {
if ($UserProfileServiceInstance -eq $null) { Continue }
$UPSI = New-Object PSObject -Property @{
Status = $UserProfileServiceInstance.Status
Address = $UserProfileServiceInstance.Server.Address
NetBIOSDomainNamesEnabled = $UserProfileServiceInstance.NetBIOSDomainNamesEnabled
NetBIOSDomainNamesEnabledOK = $true
NetBIOSDomainEqualsDomain = $true
JobDefinitions = $UserProfileServiceInstance.Service.JobDefinitions
JobHistoryEntries = $UserProfileServiceInstance.Service.JobHistoryEntries
ProcessAccountName = "<none>"
}
# The UPA property NetBIOSDomainNamesEnabled is used to control whether the CNC partition is included in the AD Connection or not.
# By default it is false (not enabled) and the CNC and associated run steps are not included in the AD Connection configuration.
# If it is enabled, then the CNC partition and run steps are included.
$UPSI.NetBIOSDomainEqualsDomain = Check-NETBIOS
if (!($UPSI.NetBIOSDomainEqualsDomain)) {
if ($UPSI.$NetBIOSDomainNamesEnabled) { $UPSI.NetBIOSDomainNamesEnabledOK = $true }
else { $UPSI.NetBIOSDomainNamesEnabledOK = $false }
}
# Now find the account that is running the User Profile Service.
$UPSWebApps=$UserProfileServiceInstance.Service.Applications
foreach ($WebApp in $UPSWebApps) {
if ($WebApp -eq $null) { Continue }
$AppPool=$WebApp.ApplicationPool
$UPSI.ProcessAccountName = $AppPool.ProcessAccountName
}
write-output "User Profile Service Instance:"
$UPSI
}
}
else { write-output "NO UserProfileServiceInstances!" }
# If the farm contains multiple servers running SP2010, and two or more servers are running the User Profile service,
# the timer job responsible for synchronization might fail. This happens when the server that runs the synchronization
# timer job is not running the synchronization service. To resolve this problem, grant the farm account the Remote Enable
# permission on the server that runs the synchronization service. Doing this enables the timer job to run successfully
# regardless of which server picks up the timer job.
#
# check if the User Profile Synchronization Service (FIM) is present and running
#
$ProfileSynchServiceInstances = Get-SPServiceInstance | where {$_.GetType().ToString() -eq $SYNCHSERVICE}
if ($ProfileSynchServiceInstances) {
$ProfileSynchServiceInstance = $ProfileSynchServiceInstances | where {$_.Status -eq "Online"}
If ($ProfileSynchServiceInstance) {
$context = [Microsoft.Office.Server.ServerContext]::Default
try {
$UPAConfMgr = new-object Microsoft.Office.Server.UserProfiles.UserProfileConfigManager($context)
$UPAConnMgr = $UPAConfMgr.ConnectionManager
$CurrentContext=$UPAConnMgr.getenumerator()
foreach ($connection in $CurrentContext) {
if ($connection -eq $null) { Continue }
$PSSIDisplayName = $connection.DisplayName
$PSSIAccountDomain = $connection.AccountDomain
$PSSIUserName = $connection.AccountUserName
}
$PSSI = New-Object PSObject -Property @{
Status = $ProfileSynchServiceInstance.Status
Server = $ProfileSynchServiceInstance.Server.Name
ServerDNSresolve = $true
Service = $PSSIDisplayName
UserName = $PSSIUserName
AccountDomain = $PSSIAccountDomain.ToUpper()
UserNameIsManagedAccount = $false
UserNameIsFarmAccount = $false
UserNameIsFarmAdmin = $false
UserNameHasReplicatingDirectoryChanges = $false
UserNameHasPreWin2kcompatible = $false
}
$PSSIUserName = $PSSI.AccountDomain + "\" + $PSSI.UserName
# test that the servername resolves.
# we should run some resolver tests on the actual synch-service server.
#
$DNSresult = get-DNSLookup $PSSIserver
if ($DNSresult.Name -eq "Host Not Resolved") {
$PSSI.ServerDNSresolve = $false }
else { $PSSI.ServerDNSresolve = $true }
# 1. You MUST run the UserProfileSynchService Instance as the Farm Account.
# 2. the Farm Account MUST be a local administrator of the machine running the UPS Service Instance >>> during provisioning only <<<.
# now we need to check if that is a Farm Admin account
$FarmAccount = (Get-SPFarm).DefaultServiceAccount
if ( $FarmAccount.Name -eq $PSSIusername ) {
$PSSI.UserNameIsFarmAccount = $true }
else { $PSSI.UserNameIsFarmAccount = $false }
# now we should also check if it is a Farm Administrator
$isFarmAdmin = Get-SPfarmAdministrators | where-object {$_.UserLogin -eq $PSSIUserName}
if ($isFarmAdmin) {
$PSSI.UserNameIsFarmAdmin = $true }
else { $PSSI.UserNameIsFarmAdmin = $false }
# $LocalAdminGroup =[ADSI]"WinNT://$PSSIserver/Administrators"
# $members = @($LocalAdminGroup.psbase.Invoke("Members"))
# $members | foreach {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}
# check if the account has the AD access permissions
$ReplicatingDirectoryChanges = "Replicating Directory Changes"
$dse = [ADSI]"LDAP://Rootdse"
$dNC = [ADSI]("LDAP://" + $dse.defaultNamingContext)
$result = Check-ADUserPermission $dNC $PSSIusername $ReplicatingDirectoryChanges
if ($result) {
$PSSI.UserNameHasReplicatingDirectoryChanges=$true }
Else { $PSSI.UserNameHasReplicatingDirectoryChanges=$false }
# DirSynch will need "Pre-Windows 2000 Compatible Access", so check if they have that.
# Why? Because under the covers we grab the token-groups-global-and-universal (TGGAU) attribute. And the account
# will need the rights to get that. Depending on the domain mode, this will fail. Yes, really. (KB331951)
# So set it and we are safe.
$DomainMode = Get-DomainMode
if ( ($DomainMode -eq "Windows2000MixedDomain") -or
($DomainMode -eq "Windows2000NativeDomain") -or
($DomainMode -eq "Windows2003InterimDomain") -or
($DomainMode -eq "Windows2003Domain") ) {
$PreWin2kcompatible = "Pre-Windows 2000 Compatible Access"
$dse = [ADSI]"LDAP://Rootdse"
$dNC = [ADSI]("LDAP://" + $dse.defaultNamingContext)
$result = Check-ADUserPermission $dNC $PSSIusername $PreWin2kcompatible
if ($result) {
$PSSI.UserNameHasPreWin2kcompatible = $true }
Else { $PSSI.UserNameHasPreWin2kcompatible = $false }
}
$isMgdAccount = Get-SPManagedAccount | where {$_.Username -eq $PSSIusername }
if ($isMgdAccount) {
$PSSI.UserNameIsManagedAccount = $true }
Else { $PSSI.UserNameIsManagedAccount = $false }
write-output "Profile Service Synch Instance:"
$PSSI
}
catch {
write-output "NO UserProfileConfigManager!"
}
}
}
else {
write-output "NO ProfileSynchServiceInstances!"
}