Month: July 2013

SharePoint Farm Version Matched with Online XML

This script does what Microsoft could have done from the beginning. Provide an online XML file, with the different versions of SharePoint, so it is easier to match the build version number with the release name.

It will look at the farm version and match this with a publicly shared XML containing all SharePoint 2007, 2010 and 2013 releases. This XML will be updated as new updates are released.

Similar scripts will be produced for Exchange and Lync servers.

Note: This script has not been tested on SharePoint 2007 and earlier yet.

#-- Checks google.com for connection, writes status and proceeds with script if google.com is up
if(Test-Connection -computer google.com -count 1 -quiet) 
    {
    cls
    Write-Host -ForegroundColor Green “Connectivity confirmed, proceeding with script...`r`n”
    
    #-- Clears all variables used throughout this script
    $dottedVersion, $buildVersion, $tempFile, $xmldoc, $i = $null
    
    #-- Setting working directory as current directory
    [Environment]::CurrentDirectory = $PWD
    
    #-- Name of xml file to use
    $tempFile = "spversion.xml"

    #-- If temp file already exists, remove it
    if(Test-Path $tempFile){Remove-Item $tempFile}

    #-- Checking if SharePoint Portal Services (SPS) 2001 is installed, based on file presence and getting version number
    if(Test-Path "C:\Program Files\Common Files\Microsoft Shared\MSSearch\Bin\mssrch.dll"){$dottedVersion = (Get-Command "C:\Program Files\Common Files\Microsoft Shared\MSSearch\Bin\mssrch.dll").FileVersionInfo.ProductVersion}
    
    #-- Checking if SharePoint Portal Server (SPS) 2003 is installed, based on file presence and getting version number
    elseif(Test-Path "C:\Program Files\SharePoint Portal Server\Bin\mssrch.dll"){$dottedVersion = (Get-Command "C:\Program Files\SharePoint Portal Server\Bin\mssrch.dll").FileVersionInfo.ProductVersion}
    
    #-- Checking if Windows SharePoint Services (WSS) 2.0 is installed, based on add/remove programs entry and getting version number
    elseif(Get-ChildItem HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall | % {Get-ItemProperty $_.PsPath} | where {$_.Displayname -match "Windows SharePoint Services 2.0"}){$dottedVersion = (Get-ChildItem HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall | % {Get-ItemProperty $_.PsPath} | where {$_.Displayname -match "Windows SharePoint Services"} | select DisplayVersion).DisplayVersion}
    
    #-- Checking if SharePoint 2007 is installed, based on registry entry and getting version number
    elseif(Test-Path "HKLM:software\microsoft\shared tools\web server extensions\12.0"){$dottedVersion = (Get-item "HKLM:software\microsoft\shared tools\web server extensions\12.0").getvalue("version")}
    
    else{
        #-- Adds the PowerShell SharePoint snapin if it is not already added
        if((Get-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue) -eq $null){Write-Host -ForegroundColor Yellow "Adding Microsoft.SharePoint.PowerShell snap-in... " -NoNewline;Add-PSSnapin Microsoft.SharePoint.PowerShell; Write-Host -ForegroundColor Yellow "Done!"; $i = $True}
        
        #-- Gets farm version number objects for SP2010 or SP2013
        $buildVersion = (Get-SPFarm).Buildversion
        
        #-- Builds version string from objects aquired in the preceding line, by concatenating them seperated by a period 
        $dottedVersion = $buildVersion -join "."
        }

    #-- Removes leading zeros from $dottedversion (if any exists)
    $dottedVersion = $dottedVersion -replace '(?<=^|\.)0+(?=[^\.])',''
    
    #-- Downloads the public XML file
    Write-Host -ForegroundColor Yellow "Downloading xml file... " -NoNewline
    (New-Object System.Net.WebClient).DownloadFile("https://docs.google.com/uc?export=download&id=0B3OwYqqW3V0aRUhiUlRJSnJQMTA", $tempFile)  
    Write-Host -ForegroundColor Yellow "Done!`r`n"
    
    #-- Saves the content of the downloaded file as an xml array
    [xml]$xmldoc = Get-Content $tempFile

    #-- Finds the build version in the xml file and gives you the relevant entry
    if(($dottedVersion.Split(".")[0] -eq 10) -or ($dottedVersion.Split(".")[0] -eq 11)){$xmldoc.SPVersions.Legacy.Version | Where-Object {$_.Build -eq $dottedVersion}}
    elseif($dottedVersion.Split(".")[0] -eq 12){$xmldoc.SPVersions.SP2007.Version | Where-Object {$_.Build -eq $dottedVersion}}
    elseif($dottedVersion.Split(".")[0] -eq 14){$xmldoc.SPVersions.SP2010.Version | Where-Object {$_.Build -eq $dottedVersion}}
    elseif($dottedVersion.Split(".")[0] -eq 15){$xmldoc.SPVersions.SP2013.Version | Where-Object {$_.Build -eq $dottedVersion}}
    else{}

    #-- Removes the local xml
    Remove-Item $tempFile

    #-- Removes the PS snapin if added earlier in the script
    if($i){Remove-PSSnapin Microsoft.SharePoint.PowerShell}
    }

#-- Show message and stop script if google.com is down
else{Write-Host -ForegroundColor Red -NoNewline “Connection is down… Please try again when you have internet access."}

Get, Set Time with Powershell

Had some challenges with time on some virtual environments that got reverted to snapshot each day and redeployed. Domain Controller was not connected to the Internet and host time synchronization caused some issues here. Basically we created a script which polled a public NTP pool and changed DC time accordingly, using remote powershell from server connected to DC and the Internet.

#--Find the FQDN of the DC.
$DC=([system.net.dns]::GetHostByAddress(([System.Net.Dns]::GetHostAddresses($(gwmi WIN32_ComputerSystem).Domain)[0].IPAddressToString))).hostname
#-- Creates Session to the DC.
$Session= New-PSSession -computername $DC -authentication Kerberos

#-- Collects time from dk ntp pool.
$Time = w32tm /stripchart /dataonly /computer:dk.pool.ntp.org /samples:1
#-- Gets local time of server
$LocalTime = Get-Date

#-- Synchronizes Local time with NTP pool time, using difference in time.
$SetTime= ($LocalTime.AddSeconds($Time[3].split("")[1].trim("+s")))

#-- Creates scriptblock to be run on DC
$SB= {param($SetTime)Set-Date $SetTime}

#-- Sets time according to dk.ntp.pool.org on Domain Controller
Invoke-Command $Session -ArgumentList $SetTime -Scriptblock $SB

#-- Removes Session to DC
Remove-PSSession $Session

SharePoint 2010 – MySite Preferred Search Center Setting – Powershell

Due to the fact that MySite settings belongs to an internal class in SharePoint 2010 and no powershell cmdlet was able to edit the Preferred Search center setting for MySite, a little creative scripting was needed. Reusing and optimizing the Change Enterprise Key script made it possible.

I changed the visible parameter for IE and stopped the ie process afterwards, making it a cleaner script.

#–Setting Preferred Search center for MySite

#--Get the central admin URL
$CAUrl = (Get-spwebapplication -includecentraladministration | where {$_.IsAdministrationWebApplication}).Url
#-- Get the User Profile Service MySite settings page
$UPSID = ((Get-SPServiceApplication | Where-Object {$_.DisplayName -like "User Profile*"}).Id).Guid
$MySiteSettingsPage = $CAUrl + "_layouts/PersonalSites.aspx?ApplicationID=" + "$UPSID"
#-- Create MySite Preferred Search center value.
$MySiteUrl= (Get-SPWebApplication | Where-Object {$_.DisplayName -like "minside.*"}).Url
$MySiteSearch= $MySiteUrl +"soeg"

$ie = New-Object -ComObject "InternetExplorer.Application"
$ie.Navigate($MySiteSettingsPage)

#wait for central Admin to load
while ($ie.ReadyState -ne 4)
{
sleep -Milliseconds 100
}
$PreferredSearchCenterBox = $ie.Document.getElementById("ctl00_PlaceHolderMain_txtboxSearchCenter")
$PreferredSearchCenterBox.value = $MySiteSearch
$Button = $ie.Document.getElementById("ctl00_PlaceHolderMain_btnOk")
$Button.click()
Sleep -seconds 2
Stop-Process -Name iexplore

SharePoint Web Services – HTTPS – Certificate

​During one of the ongoing projects I am associated with, we had a peculiar problem. In a multiple server farm setup for https, the service application Uri are also created with https URL’s. Accessing a site on https requires a valid certificate trusted by the requester or disabling the certificate check. There was some .Net code that disables this check; however, this affected the entire application pool until next recycle, so we did not want to use that.

We found out that the server address in these end points are created from the value SharePoint has stored for the server. (Get-SPServer).

For the entire solution we had been using a wildcard certificate, as it offers more flexibility and ease of implementation. However as the server was not FQDN, the wildcard certificate would not work. So what options did we have?

1: Use the Rename-SPServer and change the internal server in SharePoint to the FQDN, and thereby use the wildcard certificate. We tried this, but saw quite a few effects from this change. Therefore, we did not choose to proceed with this. This could properly be a valid approach, if the SharePoint internal names were configured initially using FQDN and not NetBIOS name.

2: Create single server certificates for each server in the farm, as well as adding each certificate to each server. This approach was not chosen due to the amount of administration involved initially and if adding servers later.

3: One of my colleagues came up with the brilliant plan to use the SharePoint internal Root certificate, as this is already trusted by all SharePoint servers, there is no need for additional certificates. Another colleague of mine wrote a little script, which pulls out this SharePoint Root certificate from the Certificate Store, adds it to the IIS, and binds it to the SharePoint Web Services site.

Updated: Check for port used as well as binding on static certificate name, rather than array.

# --------------------------------------------------------------------------------------------------------

.SYNOPSIS
Exports the currently used SharePoint Services certificate and uses it to create an SSL binding for SharePoint Web Services
.DESCRIPTION
This script lists all the certificates in the local SharePoint store, selects the one which matches
"SharePoint Services" and then calls certutil to import the certificate and key.
It then gets the current port of the webbinding named "SharePoint Web Services", removes the
webbinding and re-creates it with an sslbinding using the certificate.
.NOTES
File Name : export-spCert-import-in-IIS.ps1
Author : Mads Hjort Larsen - mads.hjort.larsen@gmail.com
.LINK
https://jesperarnecke.wordpress.com
.EXAMPLE
.\export-spCert-import-in-IIS.ps1
Certificate "CN=SharePoint Services, OU=SharePoint, O=Microsoft, C=US" added

CertUtil: -importPFX command completed successfully.

IP Address       Port        Store    Sites
----------             ----           -----      -----
0.0.0.0              32844    My       SharePoint Web Services

#--------------------------------------------------------------------------------

$cert = dir cert:\localmachine\sharepoint | Where-Object {$_.Subject -match "SharePoint Services"}
$type = [System.Security.Cryptography.X509Certificates.X509ContentType]::pfx
$pass = "password"
$certPath = (Split-Path $MyInvocation.MyCommand.Path)+"file.pfx"
$bytes = $cert.export($type, $pass)
[System.IO.File]::WriteAllBytes($certPath, $bytes)

certutil -f -p "$pass" -importpfx "$certPath"

Import-Module WebAdministration
$port = ((Get-WebBinding -Name "SharePoint Web Services" -Protocol https).bindingInformation).Trim("*:")
if((Get-WebBinding -Name "SharePoint Web Services" -IP "*" -Port $port -Protocol https) -ne $null) {Remove-WebBinding -Name "SharePoint Web Services" -IP "*" -Port $port -Protocol https}
New-WebBinding -Name "SharePoint Web Services" -IP "*" -Port $port -Protocol https
$certObj = Get-Item $cert.PSPath
if(Test-Path IIS:\SslBindings.0.0.0!$port){Remove-Item IIS:\SslBindings.0.0.0!$port}
New-Item IIS:\SslBindings.0.0.0!$port -value $certobj
Remove-Module WebAdministration