Wednesday, October 19, 2011

Script to change Site Collection Administrators in SharePoint 2007 with PowerShell

Where I work, we receive several requests for site collection admin change per week, so that's something that always bothered me, since it's not a quick task to be done when you take care of a huge number of sites. That's why I managed to create this script today, it will help me (and my team) to save some time to do other more important (and more interesting) things. Here we go:

First of all, you need to create a ps file named Set-SiteCollectionAdmin.ps1 and paste the code below. You must have another file to put the sites which will have their SCA changed, let's name this one as Site-CollectionAdmin-List.txt.

Here's how the file should be formatted:

 http://mysite1,user1@company.com,user2@company.com  
 http://mysite2,,user3@company.com  
 http://mysite1,user4@company.com,  

Note that on the first line, we are changing both the primary and the secondary SCAs, on the second one we are changing only the secondary SCA and on the third one only the primary.

Below is the source code, commented.

 # Declaring SharePoint assembly so PowerShell can use the SP object model  
 # Read more about Developing a PowerShell Script for SharePoint 2007  
 [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")  
   
 # Getting the info from the file Set-SiteCollectionAdmin-List.txt  
 # Read also about Batch process in PowerShell - Get-Content and Import-CSV cmdlets  
 get-content Set-SiteCollectionAdmin-List.txt | foreach {  
      # Splitting the row by the commas and assigning each part to one variable  
      $row = $_.split(",")  
      # Site URL  
      $url = $row[0].Trim()  
      # Primary SCA email/username  
      $prim = $row[1].Trim()  
      # Secondary SCA email/username  
      $sec = $row[2].Trim()  
        
      Write-Host ""  
   
      # Creating an URI variable to be used on the next method  
      $uri = New-Object Uri($url)  
        
      # Checking whether the mentioned site exists  
      if([Microsoft.SharePoint.SPSite]::Exists($uri))  
      {  
           # Instantiating the site collection  
           $site = New-Object Microsoft.SharePoint.SPSite($url)  
           # Opening the top level web  
           $web = $site.OpenWeb()  
        
           Write-Host $site.URL -foregroundcolor Green  
             
           # Checking whether the primary SCA will be changed  
           if($prim -ne "")  
           {  
                # Checking whether the user already exists in the site.  
                # EnsureUser() will add the user to the site collection if he doesn't exist yet.  
                $primAdm = $web.EnsureUser($prim)  
                # Changing the site owner (primary SCA) to the user.  
                $site.Owner = $primAdm  
                Write-Host "New SCA: $prim"  
           }  
             
           # Same process of the primary SCA  
           if($sec -ne "")  
           {  
                # Checking whether the user already exists in the site.  
                # EnsureUser() will add the user to the site collection if he doesn't exist yet.  
                $secAdm = $web.EnsureUser($sec)  
                # Changing the site secondary contact (secondary SCA) to the user.  
                $site.SecondaryContact = $secAdm  
                Write-Host "New Sec SCA: $sec"  
           }  
      }  
      else # if the site doesn't exist, just jump to the next row  
      {  
           Write-Host "Site $url not found. Jumping to next row." -ForegroundColor Red  
      }  
        
      # Disposing web and site objects from memory  
      $web.Dispose()  
      $site.Dispose()  
 }  

Important: I could only make this work by running powershell as the farm account. Any suggestions of how to do it without needing the would be great.
Ler o texto inteiro ►

Batch process in PowerShell - Get-Content and Import-CSV cmdlets

One of the most important, easy and useful things I see in PowerShell is the possibility to easily process several requests in batch, saving a lot of time. In this article I'm going to explain in this article how to get information from a TXT file and process anything with it using Get-Content cmdlet and also how to get information from a CSV file using the Import-CSV cmdlet.

Get-Content cmdlet:

 PS C:\> Get-Content MyTextFile.txt  
 Line0  
 Line1  
 Line2  
 Line3  
 Line4    

This first example shows us just how to show the file content, however, the most interesting utilization is with a loop, which will allow us to do several tasks in a row for each line of the file as follows (let's say I have 3 computer names on MyTextFile.txt now):

 PS C:\> Get-Content MyTextFile.txt | ForEach { IISRESET $_ }  
 Attempting stop...  
 Internet services successfully stopped  
 Attempting start...  
 Internet services successfully restarted  
 Attempting stop...  
 Internet services successfully stopped  
 Attempting start...  
 Internet services successfully restarted  
 Attempting stop...  
 Internet services successfully stopped  
 Attempting start...  
 Internet services successfully restarted  

You can also limit the number of rows you want to be fetched from the file by using the parameter TotalCount if you want to get the x first records, or using the Select-Object cmdlet with the parameter -Last to have the x last records, as follows:

 PS C:\> Get-Content .\MyTextFile.txt -TotalCount 3  
 Computer0  
 Computer1  
 Computer2  
 PS C:\> Get-Content .\MyTextFile.txt | Select-Object -Last 3  
 Computer7  
 Computer8  
 Computer9  

Import-CSV cmdlet:

Let's say we have a CSV file, an Excel file (which can be easily saved as CSV), or even data exported from any application in comma-separated-values. This can be handled by PowerShell just as easily as the TXT file, plus the possibility to search the records you want to work with by quickly building queries to get information from the file content.

 PS C:\> Import-CSV .\MyCSVFile.csv | Format-Table -AutoSize  
 FullName        Extension CreationTime  LastAccessTime LastWriteTime  
 --------        --------- ------------  -------------- -------------  
 C:\install.res.1028.dll .dll   11/7/2006 9:03 5/6/2011 17:29 11/7/2006 9:03  
 C:\install.res.1031.dll .dll   11/7/2007 9:03 5/6/2011 17:29 11/7/2007 9:03  
 C:\install.res.1033.dll .dll   11/7/2008 9:03 5/6/2011 17:29 11/7/2008 9:03  
 C:\install.res.1036.dll .dll   11/7/2009 9:03 5/6/2011 17:29 11/7/2009 9:03  
 C:\install.res.1040.dll .dll   11/7/2010 9:03 5/6/2011 17:29 11/7/2010 9:03  

First example shows how to just get the file content and using Format-Table cmdlet to have the outcome formatted. Next, let's see how to filter only the ones with date greather than 1/1/2009 by using the Where-Object cmdlet an then again Format-Table for the outcome.

 PS C:\> Import-CSV .\MyCSVFile.csv | Where-Object {[datetime]::Parse($_.CreationTime) -gt '1/1/2009' } | Format-Table -AutoSize  
 FullName        Extension CreationTime  LastAccessTime LastWriteTime  
 --------        --------- ------------  -------------- -------------  
 C:\install.res.1036.dll .dll   11/7/2009 9:03 5/6/2011 17:29 11/7/2009 9:03  
 C:\install.res.1040.dll .dll   11/7/2010 9:03 5/6/2011 17:29 11/7/2010 9:03  

More info:

Get-Content cmdlet
Import-CSV cmdlet
Ler o texto inteiro ►

Tuesday, October 18, 2011

Developing a PowerShell Script for SharePoint 2007

Since I started working with SharePoint infrastructure and administration, I've been thinking on a solution to automatize some daily tasks that ever since I was able only to perform either via Central Administration or STSADM command.

So today, I started studying how to work with PowerShell scripting for SharePoint, and it seems to be pretty easy and cool :)

The first thing you must do so PowerShell can access SharePoint assemblies is to load them using below code line:

[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

Once you have the assemblies loaded, you can invoke all methods of SP object model, just like if you were developing with any .NET programming language. Below example shows how to get both the primary and secondary Site Collection Administrators from a given URL:

$site = New-Object Microsoft.SharePoint.SPSite("http://mysite")
$priSCALogin = $site.Owner.LoginName
$secSCALogin = $site.SecondaryContact.LoginName

write "-Primary SCA: $priSCALogin"
write "-Secondary SCA: $secSCALogin"

I'll keep working and studying about this and obviously, posting.

Ler o texto inteiro ►

Monday, October 10, 2011

OCS Conversation History saved on the wrong mailbox

These days I've been working on an issue related to the OCS Conversation History, and where it was saving its instant messaging records. The user in case has an additional mailbox set in Outlook and Communicator was saving all conversation histories in the additional mailbox, which can cause several problems, since the users conversation were being stored into a shared folder.

After several frustrated attempts of solving the problem, a teammate of mine found out a solution, and here it is:

  1. In Communicator, go to Tools > Options...
  2. In Office Communicator - Options window, uncheck Save my instant message conversations in the Outlook Conversation History folder;
  3. Restart Communicator;
  4. Remove all the additional mailboxes as explained here;
  5. Restart Outlook;
  6. Check again "Save my instant message conversations in the Outlook Conversation History folder" in Communicator > Tools > Options;
  7. Chat with someone and double check whether the conversations are being stored in the correct folder;
  8. Add the secondary mailboxes back, as explained here;
  9. Check again whether the conversations are yet being saved at the correct location.


Ler o texto inteiro ►

How to add/remove additional mailboxes in Outlook


How to add an additional mailbox in Outlook:
  1. In Outlook 2010, Go to File > Account Settings > Account Settings...
    • In Outlook 2007, Tools > Account Settings...
  2. On Account Settings window, Select Default, then click Change...
  3. On Change Account window, click More Settings...
  4. On Microsoft Exchange window, go to Advanced tab and click Add...
  5. On Add Mailbox window, type the mailbox name in Add mailbox field.
  6. Click Ok, Ok, Next, Finish.

How to remove the additional mailbox:
  1. In Outlook 2010, Go to File > Account Settings > Account Settings...
    • In Outlook 2007, Tools > Account Settings...
  2. On Account Settings window, Select Default, then click Change...
  3. On Change Account window, click More Settings...
  4. On Microsoft Exchange window, go to Advanced tab
  5. If the mailbox is listed in Open these additional mailboxes, select it and click Remove
  6. Click OK, Next, Finish
Ler o texto inteiro ►

Tuesday, September 27, 2011

The Delegates settings were not saved correctly. Cannot activate free/busy information

Got this error message today when trying to update some delegates settings:

---------------------------
Microsoft Office Outlook
---------------------------
The Delegates settings were not saved correctly. Cannot activate free/busy information.
---------------------------
OK
---------------------------

To fix the issue I needed to use MFCMAPI tool. Just follow below instructions and all should work fine:

  1. Start the MfcMapi.exe
  2. On MFCMAPI x86 Build window, click OK
  3. Go to Session > Logon and Display Store Table
  4. Choose the user profile (if the computer has more than one)
  5. Double-click the Mailbox - username store
  6. In the navigation pane, click Root Container.
  7. In the details pane, right-click PR_FREEBUSY_ENTRYIDS, click Delete Property, and then click OK.
  8. In the navigation pane, expand Root Container, expand Top of Information Store, and then clickInbox.
  9. In the details pane, right-click PR_FREEBUSY_ENTRYIDS, click Delete Property, and then click OK.
  10. Close MFCMAPI
  11. Click Start, click Run, type outlook.exe /cleanfreebusy, and then press ENTER.
Ler o texto inteiro ►

Microsoft Exchange Server MAPI Editor (MFCMAPI)

MFCMAPI is a powerful tool which allows you to access and fix several problems in MAPI stores through a graphical interface.

MFCMAPI download from CodePlex.
Ler o texto inteiro ►

Tuesday, September 13, 2011

Not able to open restricted permission messages (Rights Management Services - RMS)

Last week I worked on a RMS issue, which I couldn't find a solution. However, a teammate of mine who works with security has sent me some instructions which have solved the problem.
  • Start->Run->compmgmt.msc
  • Expand Services and Applications
  • Click on Services
  • Stop “cryptographic server” service on end user machine (keep this windows open).  Right click on the service and select stop.
  • Rename c:\winnt\system32\catroot2 directory to c:\winnt\system32\catroot2.old
  • Start “cryptographic server” service on end user machine.  Righ click on the service and select start.

Ler o texto inteiro ►

Not able to add/remove delegates - Outlook 2007

Got this error message today, when trying to remove an user from delegates tab.

---------------------------
Microsoft Office Outlook
---------------------------
The Delegates settings were not saved correctly.  Cannot activate send-on-behalf-of list.
You do not have sufficient permission to perform this operation on this object.
---------------------------
OK  
---------------------------

I've found a solution in a Microsoft KB, which solved the problem quite easily. You just need to add a registry key, so with Outlook closed follow below steps

  • Cick Start then Run and next type regedit, press Enter;
  • Browse to HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Outlook\Preferences;
  • Click New on the Edit menu and select DWORD Value;
  • Type IgnoreSOBError, press Enter. Right click the new key and click Modify;
  • In Value Data type 1;
  • Close Registry Editor and Reopen Outlook. You should be able to add/remove delegates from now on.

Ler o texto inteiro ►

Wednesday, August 31, 2011

How to reset user's Unified Messaging VoiceMail PIN via PowerShell

This one is so easy that I won't type too much :)

Set-UMMailboxPIN  -Identity USERNAME

Most used parameters:

  • Pin: use this parameter to manually set a new pin to the user
  • SendEmail: set this parameter to $false if you don't want the user to receive an e-mail with the new pin. The default value is $true, which means the user will receive an e-mail with the new pin and information about phone access numbers
  • NotifyEmail: specifies the email address that the automated email will be sent to
  • PinExpired: specifies whether the new Pin will be treated as expired, which means that the user should change it at the first log on.

More info:
Ler o texto inteiro ►

How to get mailbox permissions

Last article I've posted (How to grant/remove permissions on an Exchange 2007 mailbox) was about how to SET mailbox permissions, but another cool thing we can do with PowerShell is to GET them for that, you must use the cmdlet Get-MailboxPermission.

Get-MailboxPermission -Identity MAILBOX | Format-Table User, AccessRights, IsInherited

Most used parameters:
  • Identity: username or email address associated to the mailbox
  • User: use this parameter to check the rights an user has on the mailbox
  • Owner: use this parameter to check users who have owner rights on the mailbox

More info:
Ler o texto inteiro ►

How to grant/remove permissions on an Exchange 2007 mailbox

These almost-daily tasks are quite easy to perform via EMC, but infinitely easier through PowerShell...

Adds mailbox permissions:
Add-MailboxPermission -Identity MAILBOX -User USER -AccessRights FullAccess -InheritanceType All

Removes mailbox permissions:
Remove-MailboxPermission -Identity MAILBOX -User USER -AccessRight FullAccess -confirm:$false
Most used parameters:
  • Identity: the username or email address associated to the mailbox which you want to set the permissions
  • User: the username or email address associated to the user who will receive the permissions on the mailbox
  • InheritanceType: specify how far down the Active Directory object structure the “read” permissions are inherited (more info here)
  • AccessRights: the rights you want to grant to the user on the mailbox. Valid values are: 
    • FullAccess; 
    • SendAs; 
    • ExternalAccount; 
    • DeleteItem; 
    • ReadPermission; 
    • ChangePermission; 
    • ChangeOwner
  • Confirm: Specifies whether the command will pause and wait for your confirmation when removing an user's permissions. Set it as $True if you want the script to run without requesting confirmation.

UPDATE: See also the post How to get mailbox permissions about getting the permissions on a mailbox

More info:
Ler o texto inteiro ►

Tuesday, August 30, 2011

User mailbox has more than one primary SMTP address

Today I've got this issue, an user who couldn't receive e-mails from anyone. When I checked his mailbox, EMC showed me an error saying that his account had more than one primary SMTP address, opening user's properties. EMC didn't let me remove any of them since you can't remove the primary.

Error message: "There are multiple primary SMTP addresses. Please ensure there is only one primary address for each address type."

So the solution I've found was to remove the extra SMTP addresses from the attribute proxyAddress on user's Active Directory object. Leave only one of the addresses with prefix SMTP.

UPDATE: Use ADSIEdit.msc tool to remove the extra SMTP addresses. More information about ADSIEdit here.

Then EMC will let you add the secondary SMTP addresses back and they won't be marked as primary.
Ler o texto inteiro ►

How to check Exchange databases status via PowerShell

Run the cmdlet Get-MailboxDatabase to get information about the DB status. Use parameter -Identity to check the status of a single DB and -Server for all DBs in a server.


Check the status of a single DB

Get-MailboxDatabase -Identity DBNAME -Status | Format-Table Name, Mounted, BackupInProgress, OnlineMaintenanceInProgress

Check the status of all DBs in a Server
Get-MailboxDatabase -Server SERVERNAME -Status | Format-Table Name, Mounted, BackupInProgress, OnlineMaintenanceInProgress

* The -Status parameter specifies whether the script will get status information from the DB(s) or not. If not provided, the attributes Mounted, BackupInProgress and OnlineMaintenanceInProgress will return empty.


More info:
Get-MailboxDatabase cmdlet
Ler o texto inteiro ►

Monday, August 29, 2011

How to specify PowerShell session scope

As well as Exchange Management Console, Exchange Shell Console allows you to define the operations scope. You can choose for viewing and working either on the entire forest or on a single domain.

Exchange 2007
$AdminSessionADSettings.DefaultScope="domain1.contoso.com"
$AdminSessionADSettings.ViewEntireForest=$true


Exchange 2010
Set-AdServerSettings -RecipientViewRoot "domain2.contoso.com"
Set-AdServerSettings -ViewEntireForest $true

* when set to the entire forest, all settings changed will take longer than usual to replicate
Ler o texto inteiro ►

How to mount/dismount mailbox databases via PowerShell

For several times I had to dismount and re-mount all the mailbox databases from a server, and doing this via Exchange Management Console is way to slow, so I've researched a bit and found some commands to do this with PowerShell.

How to check Exchange databases status via PowerShell

In order to mount/dismount DBs, use Mount-Database and Dismount-Database respectively. Use Get-MailboxDatabase cmdlet with -Server parameter to fetch the DBs from a server and then the mount/dismount cmdlet.

Dismount a single DB
Dismount-Database -Identity DBNAME -Confirm:$False

Dismount all DBs of a server
Get-MailboxDatabase -Server SERVERNAME | Dismount-Database -Confirm:$False

Mount a single DB
Mount-Database -Identity DBNAME -Confirm:$False

Mount all DBs of a server
Get-MailboxDatabase -Server SERVERNAME | Mount-Database -Confirm:$False

Ler o texto inteiro ►
Related Posts Plugin for WordPress, Blogger...