Consider the situation where you have a multi-domain forest with MOSS/Sharepoint installed in a child domain. You need to be able to pick users from the entire forest and not only from child domain where Sharepoint is installed, but you can't. If you use people picker from Central Administration site then you are able to find users from entire forest.
Check if your people picker for that particular web application is configured correctly by running this command:
STSADM.exe -o getsiteuseraccountdirectorypath -url http://intranet
If you get output like this:
<SiteUserAccountDirectoryPath>DC=childdomain,DC=rootdomain,DC=local</SiteUserAccountDirectoryPath>
Then you need to run the following command to change the people picker search scope to search the entire forest:
STSADM.exe -o setsiteuseraccountdirectorypath -path "" -url http://intranet
The setuseraccountdirectorypath property is actually intended to allow you to limit people picker searches to a sub OU, but in a multi-domain environment it is limited to domain level by default in MOSS 2007. So if you need to search the entire forest, you need to set directory path to "" like it is set for Central Administration web application.
IT Solution Braindumps
IT solutions and frustrations from real life including Exchange, Sharepoint, TMG, virtualization etc.
Wednesday, 7 November 2012
Thursday, 18 October 2012
Setting up Meet URLs in Lync Server 2010 Multitenant
In this article I'm going to explain how I solved the problem of setting up the tenant meet URLs correctly in Lync Server 2010 Multitenant Pack for Parner Hosting.
Microsoft released a special version of Lync Server 2010 intended just for hosting organizations that want to provide Lync services to multiple distinct organizations.
The deployment guide for this scenario can be very confusing in some sections and it takes multiple reading as well as good Lync 2010 background to get it right. But I still believe that some procedures in the document are not correct. The section that gave me the most trouble was about setting up simple URLs for hosted organizations.
In on-premise installation of Lync 2010 there is usually one SIP domain and one set of simple URLs. However, in multitenant installation there are multiple SIP domains, one SIP domain for each tenant.
The deployment guide in one section states that one should use Topology Builder to setup the meet URLs for a tenant. In a dynamic environment like multitenant hosting where you would use custom built provisioning service to set up tenants, you cannot rely on Topology Builder. Furthermore, if you try to run the scripts offered for setting up meet URLs (section 8.11.3), you would get the following error:
There must be an Active URL for Meet for each SIP Domain.
What this actually means is that you cannot set up one Meet URL for one SIP domain and assign it to one tenant organization and do the same for each tenant. That would make sense but it does not work. What you must do is create Meet URLs for all SIP domains and assign them all to a single tenant. And you must do that for each tenant.
This is the script I first wrote following the deployment guide:
#get your tenant GUID
$TenORgID = xxxx-xxxx-xxxx-xxxx-xxxx
#assing a SIP domain to a variable
$SIPDomain1 = "itsolutionbraindumps.com"
#generate a base URL for your Meet URL
$URL1 = "https://meet.hoster.com/" + $SIPDomain1
#generate a Simple URL entry
$urlEntry1 = New-CsSimpleUrlEntry -Url $URL1
#generate a Simple URL for the meet component and assing all the variables
$simpleUrl1 = New-CsSimpleUrl -Component "meet" -Domain $SIPDomain1 -SimpleUrl $urlEntry1 -ActiveUrl $URL1
#assign the Simple URL to your tenant
Set-CsSimpleUrlConfiguration –Tenant $TenORgID -SimpleUrl @{Add=$simpleUrl1} -ErrorAction Stop
If you wrote the same script it means you too followed the deployment guide. The script would work if you have only one SIP domain on the system, but if you have multiple SIP domains you would get the error above.
So, the solution is to modify the script to create Simple URLs for each SIP domain and assign all these Simple URLs to a single tenant. And you must do that for all your tenants. The good thing is that, as you add new tenants and create SIP domain for each tenant, you must create Simple URLs for all SIP domains that exist on your system at that time but you don't have to fix each and every tenant. So, for a single tenant system, you would only create one Simple URL. When you add your second tenant, you would create two Simple URLs and assign them to your second tenant, three Simple URLs for your third tenant and so forth. As you add your tenants, your Simple URLs list would grow for your new tenants but you won't have to go back and correct the previously added tenants.
So, for your second tenant, let's name him Fabrikam, you would have a script like this:
$TenORgID = xxxx-xxxx-xxxx-xxxx-xxxx
$SIPDomain1 = "itsolutionbraindumps.com"
$SIPDomain2 = "fabrikam.com"
$URL1 = "https://meet.hoster.com/" + $SIPDomain1
$URL2 = "https://meet.hoster.com/" + $SIPDomain2
$urlEntry1 = New-CsSimpleUrlEntry -Url $URL1
$urlEntry2 = New-CsSimpleUrlEntry -Url $URL2
$simpleUrl1 = New-CsSimpleUrl -Component "meet" -Domain $SIPDomain1 -SimpleUrl $urlEntry1 -ActiveUrl $URL1
$simpleUrl2 = New-CsSimpleUrl -Component "meet" -Domain $SIPDomain2 -SimpleUrl $urlEntry2 -ActiveUrl $URL2
Set-CsSimpleUrlConfiguration –Tenant $TenORgID -SimpleUrl @{Add=$simpleUrl1,$simpleUrl2} -ErrorAction Stop
But of course, in a dynamic environment you must have more automated way of creating Meet URLs for new tenants. So I wrote the following script:
After the script executes you will get the following warning:
WARNING: Activation (Enable-CsComputer) may need to be re-run on impacted Front End servers.
Execute Enable-CsComputer and you are done.
The previous script fully automates generation of Simple URLs based on all existing SIP domains on a system and assignes them all to a tenant. When adding new tenant to your Lync 2010 hosting environment you can just automatically run this script.
Once you setup your tenant Meet URLs correctly, the tenant users would be able to succesfully schedule Online Meetings from Outlook and the meeting URL for other users to connect would be correctly populated.
There is one more thing to do. Tenant users must be configured with the correct Base URL for their tenant organization. Base URL is configured on the msRTCSIP-BaseSimpleUrl property for each tenant user in Active Directory. Here is how to do that:
Without setting this property your users would get this error when they click on the meet URL:
Error: Meeting URL is not valid.
Lync Server 2010 Logging Tool will also return this error:
Failed to find a domain mapping for this BaseURL
So you need to make sure that msRTCSIP-BaseSimpleUrl is set at the moment you provision tenant users.
There it is, I hope I made it clear enough for you to be able to set Meet URLs for tenant organizations in Lync. If you have troubles getting this to work please let me know. Also, if you have a better way to solve this problem, please share it here. I'm not going to exclude a possibility that I got everyhing wrong, but this is a configuration that works in my environment.
The deployment guide for this scenario can be very confusing in some sections and it takes multiple reading as well as good Lync 2010 background to get it right. But I still believe that some procedures in the document are not correct. The section that gave me the most trouble was about setting up simple URLs for hosted organizations.
In on-premise installation of Lync 2010 there is usually one SIP domain and one set of simple URLs. However, in multitenant installation there are multiple SIP domains, one SIP domain for each tenant.
The deployment guide in one section states that one should use Topology Builder to setup the meet URLs for a tenant. In a dynamic environment like multitenant hosting where you would use custom built provisioning service to set up tenants, you cannot rely on Topology Builder. Furthermore, if you try to run the scripts offered for setting up meet URLs (section 8.11.3), you would get the following error:
There must be an Active URL for Meet for each SIP Domain.
What this actually means is that you cannot set up one Meet URL for one SIP domain and assign it to one tenant organization and do the same for each tenant. That would make sense but it does not work. What you must do is create Meet URLs for all SIP domains and assign them all to a single tenant. And you must do that for each tenant.
This is the script I first wrote following the deployment guide:
#get your tenant GUID
$TenORgID = xxxx-xxxx-xxxx-xxxx-xxxx
#assing a SIP domain to a variable
$SIPDomain1 = "itsolutionbraindumps.com"
#generate a base URL for your Meet URL
$URL1 = "https://meet.hoster.com/" + $SIPDomain1
#generate a Simple URL entry
$urlEntry1 = New-CsSimpleUrlEntry -Url $URL1
#generate a Simple URL for the meet component and assing all the variables
$simpleUrl1 = New-CsSimpleUrl -Component "meet" -Domain $SIPDomain1 -SimpleUrl $urlEntry1 -ActiveUrl $URL1
#assign the Simple URL to your tenant
Set-CsSimpleUrlConfiguration –Tenant $TenORgID -SimpleUrl @{Add=$simpleUrl1} -ErrorAction Stop
If you wrote the same script it means you too followed the deployment guide. The script would work if you have only one SIP domain on the system, but if you have multiple SIP domains you would get the error above.
So, the solution is to modify the script to create Simple URLs for each SIP domain and assign all these Simple URLs to a single tenant. And you must do that for all your tenants. The good thing is that, as you add new tenants and create SIP domain for each tenant, you must create Simple URLs for all SIP domains that exist on your system at that time but you don't have to fix each and every tenant. So, for a single tenant system, you would only create one Simple URL. When you add your second tenant, you would create two Simple URLs and assign them to your second tenant, three Simple URLs for your third tenant and so forth. As you add your tenants, your Simple URLs list would grow for your new tenants but you won't have to go back and correct the previously added tenants.
So, for your second tenant, let's name him Fabrikam, you would have a script like this:
$TenORgID = xxxx-xxxx-xxxx-xxxx-xxxx
$SIPDomain1 = "itsolutionbraindumps.com"
$SIPDomain2 = "fabrikam.com"
$URL1 = "https://meet.hoster.com/" + $SIPDomain1
$URL2 = "https://meet.hoster.com/" + $SIPDomain2
$urlEntry1 = New-CsSimpleUrlEntry -Url $URL1
$urlEntry2 = New-CsSimpleUrlEntry -Url $URL2
$simpleUrl1 = New-CsSimpleUrl -Component "meet" -Domain $SIPDomain1 -SimpleUrl $urlEntry1 -ActiveUrl $URL1
$simpleUrl2 = New-CsSimpleUrl -Component "meet" -Domain $SIPDomain2 -SimpleUrl $urlEntry2 -ActiveUrl $URL2
Set-CsSimpleUrlConfiguration –Tenant $TenORgID -SimpleUrl @{Add=$simpleUrl1,$simpleUrl2} -ErrorAction Stop
But of course, in a dynamic environment you must have more automated way of creating Meet URLs for new tenants. So I wrote the following script:
$OUName = "IT Solution Braindumps" $PathRoot = "OU=OCS Tenants,DC=cloud,DC=local" $TargetOU = "OU="+$OUName+","+$pathRoot $TenantOU = Get-ADOrganizationalUnit -Identity $TargetOU -Properties msRTCSIP-TenantId -Server "ad01.cloud.local" $TenORgID = New-Object -TypeName System.guid -ArgumentList $TenantOU.ObjectGUID $Count = 0 $SIPDomain = @() $URL = @() $URLEntry = @() $SimpleUrl = @() $siparray = Get-CsSipDomain foreach($sip in $siparray) { $SIPDomain += $sip.Identity $URL += "https://meet.hoster.com/" + $SIPDomain[$Count] $URLEntry += New-CSSimpleUrlEntry -Url $URL[$Count] $SimpleUrl += New-CsSimpleUrl -Component "meet" -Domain $SIPDomain[$Count] -SimpleUrl $URLEntry[$Count] -ActiveUrl $URL[$Count] $Count++ } Set-CsSimpleUrlConfiguration -Tenant $TenORgID -SimpleUrl @{Add=$SimpleUrl} -ErrorAction Stop
After the script executes you will get the following warning:
WARNING: Activation (Enable-CsComputer) may need to be re-run on impacted Front End servers.
Execute Enable-CsComputer and you are done.
The previous script fully automates generation of Simple URLs based on all existing SIP domains on a system and assignes them all to a tenant. When adding new tenant to your Lync 2010 hosting environment you can just automatically run this script.
Once you setup your tenant Meet URLs correctly, the tenant users would be able to succesfully schedule Online Meetings from Outlook and the meeting URL for other users to connect would be correctly populated.
$SIPDomain = "itsolutionbraindumps.com" $CompanyName = "IT Solution Braindumps" $BaseURL = "https://meet.hoster.com/"+$SIPDomain $PathRoot = "OU=OCS Tenants,DC=cloud,DC=local" $TargetOU = "OU="+$CompanyName+","+$PathRoot $OUObject = Get-ADOrganizationalunit -Identity $TargetOU Get-ADUser -LDAPFilter "(objectClass=user)" -SearchBase $TargetOU -Properties msRTCSIP-BaseSimpleUrl -Server "AD01.cloud.local" |Set-ADUser -Replace @{'msRTCSIP-BaseSimpleUrl'=$BaseURL}
Without setting this property your users would get this error when they click on the meet URL:
Error: Meeting URL is not valid.
Lync Server 2010 Logging Tool will also return this error:
Failed to find a domain mapping for this BaseURL
So you need to make sure that msRTCSIP-BaseSimpleUrl is set at the moment you provision tenant users.
There it is, I hope I made it clear enough for you to be able to set Meet URLs for tenant organizations in Lync. If you have troubles getting this to work please let me know. Also, if you have a better way to solve this problem, please share it here. I'm not going to exclude a possibility that I got everyhing wrong, but this is a configuration that works in my environment.
Wednesday, 17 October 2012
Trouble installing Exchange 2010 SP2 Rollup 4 v2
If you have trouble with the installation of KB2756485, that is, Rollup 4-v2 for Exchange Server 2010 SP2, you must run the installer from the elevated command prompt like this:
Once the installation starts, be patient because it can take a while.
If you just double click on the .msp file from Windows Explorer, the installation will start but it will very soon rollback and you will see this error in the application log:
Log Name: Application
Source: MsiInstaller
Date: 16.10.2012. 10:30:01
Event ID: 1024
Task Category: None
Level: Error
Keywords: Classic
User: DOMAIN\username
Computer: exchange.contoso.com
Description:
Product: Microsoft Exchange Server - Update 'Update Rollup 4-v2 for Exchange Server 2010 Service Pack 2 (KB2756485) 14.2.318.4' could not be installed. Error code 1603. Windows Installer can create logs to help troubleshoot issues with installing software packages. Use the following link for instructions on turning on logging support: http://go.microsoft.com/ fwlink/?LinkId=23127
You may also ran into some blog posts that say to try setting the execution policy in Powershell from RemoteSigned to Unrestricted, but that did not help in my case.
There, I hope it helps someone.
Once the installation starts, be patient because it can take a while.
If you just double click on the .msp file from Windows Explorer, the installation will start but it will very soon rollback and you will see this error in the application log:
Log Name: Application
Source: MsiInstaller
Date: 16.10.2012. 10:30:01
Event ID: 1024
Task Category: None
Level: Error
Keywords: Classic
User: DOMAIN\username
Computer: exchange.contoso.com
Description:
Product: Microsoft Exchange Server - Update 'Update Rollup 4-v2 for Exchange Server 2010 Service Pack 2 (KB2756485) 14.2.318.4' could not be installed. Error code 1603. Windows Installer can create logs to help troubleshoot issues with installing software packages. Use the following link for instructions on turning on logging support: http://go.microsoft.com/
You may also ran into some blog posts that say to try setting the execution policy in Powershell from RemoteSigned to Unrestricted, but that did not help in my case.
There, I hope it helps someone.
Wednesday, 8 August 2012
Expiring password notifications with Powershell scripting
Let's say that your users have non-domain joined workstation, but use Outlook or Outlook Web Access to access your e-mail infrastructure. These users would never be notified that their domain password is about to expire. Once it does, their only resort would be to contact administrator and ask him to reset his or her password.
Because of this, I wrote a simple Powershell script that is scheduled to run every day and creates a list of user accounts which passwords will expire in less than 7 days and sends them an e-mail notification that they should change their password. Once a user receives this notification, he can use Outlook Web Access to change his password.
Some notes about the script:
Here is the script:
PowerGUI Script Editor
Because of this, I wrote a simple Powershell script that is scheduled to run every day and creates a list of user accounts which passwords will expire in less than 7 days and sends them an e-mail notification that they should change their password. Once a user receives this notification, he can use Outlook Web Access to change his password.
Some notes about the script:
- The script uses System.Globalization.CultureInfo object to format the date returned for Croatian region (hr-HR). If you come from US, you can change hr-HR in the script to en-US
- The $msg.Body property in the script contains HTML formatted text that user receives as an e-mail message body. You can modify this HTML code, for example, to include your company branding
- You can modify the $OU property so that script only scopes your external users, users from a specific department, etc.
- The script does not send e-mail to users whose passwords are already expired or who have "Password never expires" property set
- You can modify how many days are left until password expiry before you start notifying users. Currently, script notifies users whose passwords expire in less than 7 days.
You can modify the following line: $DaysToExpire.Days -lt 7 - The policy works with default domain password policy and with Password Settings Object, a feature of Windows Server 2008 Active Directory
- You must run the script on a domain controller or on a server with Remote Server Administration Tools installed
- You must change the variable $smtpServer to your internal mail server (usually Exchange Hub Transport server) that can send e-mails to your users
Here is the script:
Import-Module ActiveDirectory #System globalization $ci = New-Object System.Globalization.CultureInfo("hr-HR") #SMTP server name $smtpServer = "smtp.domain.local" #Creating SMTP server object $smtp = new-object Net.Mail.SmtpClient($smtpServer) #E-mail structure Function EmailStructure($to,$expiryDate,$upn) { #Creating a Mail object $msg = new-object Net.Mail.MailMessage $msg.IsBodyHtml = $true $msg.From = "administrator@domain.com" $msg.To.Add($to) $msg.Subject = "Password expiration notice" $msg.Body = "<html><body><font face='Arial'>This is an automatically generated message from Service Provider Exchange service.<br><br><b>Please note that the password for your account $upn will expire on $expiryDate.</b><br><br>Please change your password immediately or at least before this date as you will be unable to access the service without contacting your administrator.</font></body></html>" return $msg } #Set the target OU that will be searched for user accounts $OU = "OU=Users,DC=domain,DC=local" $ADAccounts = Get-ADUser -LDAPFilter "(objectClass=user)" -searchbase $OU -properties PasswordExpired, PasswordNeverExpires, PasswordLastSet, Mail, Enabled | Where-object {$_.Enabled -eq $true -and $_.PasswordNeverExpires -eq $false} Foreach ($ADAccount in $ADAccounts) { $accountFGPP = Get-ADUserResultantPasswordPolicy $ADAccount if ($accountFGPP -ne $null) { $maxPasswordAgeTimeSpan = $accountFGPP.MaxPasswordAge } else { $maxPasswordAgeTimeSpan = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge } #Fill in the user variables $samAccountName = $ADAccount.samAccountName $userEmailAddress = $ADAccount.Mail $userPrincipalName = $ADAccount.UserPrincipalName if ($ADAccount.PasswordExpired) { Write-host "The password for account $samAccountName has expired!" } else { $ExpiryDate = $ADAccount.PasswordLastSet + $maxPasswordAgeTimeSpan Write-host "The password for account $samAccountName expires on: $ExpiryDate" $TodaysDate = Get-Date $DaysToExpire = $ExpiryDate - $TodaysDate #Write-Host $DaysToExpire.Days if ($DaysToExpire.Days -lt 7) { $expiryDate = $expiryDate.ToString("d",$ci) #Generate e-mail structure and send message $msg = EmailStructure $userEmailAddress $expiryDate $userPrincipalName $smtp.Send($msg) Write-Host "The expiration notification e-mail was sent to $userEmailAddress" } } }
Subscribe to:
Posts (Atom)