Advertisements

Auto-Restarting Forefront for SharePoint when it hangs and times out with PowerShell

Scenario

Every once in a while I would have the Forefront Antivirus for SharePoint engine on 1 of my 3 WFE’s conk out. When this happens, SharePoint is fully functional via that WFE except for file uploads which would cause users to experience an error message. This error would prevent the users from uploading any files via that WFE.

Error Messages

The end users uploading the files may experience the following error message:

“The installed virus scanner is currently unavailable. If the problem persists, contact your administrator.”

The Event Viewer Logs may show:

1719104822: #960013: Antivirus scanner timed out.

The SharePoint service is running but the Forefront VSAPI Library is not registered.

Manual Solution

The manual solution is to perform the procedure as described here by Ingo Karstein.

My Automated Solution

At first, I thought it would be a good idea to leverage my existing Diagnostics Log Monitoring script to check for the error messages. But after testing it out, I realized that the error entries would only be logged after a user had unsuccessfully tried to upload a document. After pondering for a bit, I wanted a way to prevent users from getting their uploads denied in the first place. So I ended up creating another script that auto-uploads a 1KB test document from each WFE and assumes that any upload error would have been caused by a hung Forefront service. The following PowerShell script was placed on each WFE and runs on a 5-minute interval. Upon an upload exception, it will disable the antivirus settings in Central Administration, restart the appropriate Windows Services, and then reinstate the Central Admin settings all with minimal service interruption. In testing, this automated process took between 5-10 seconds to run upon identification of an error. No IIS resets are performed during this process so the end-users wouldn’t even know that anything’s going on unless they happen to be trying to upload something right after Forefront hangs and  before the automated job runs every 5 minutes.

PowerShell Script

############# Start Variables ################
$uploadSite = "https://SharePointSite/"
$documentLibName = "Documents"
$testFile = "D:\Temp\TestUpload.txt"
$emailFrom = fromEmail
$emailTo = @("yourEmail")
$subject = "Forefront Failure; Auto-Kick Start Initiated"
$body = "Server: " + $env:COMPUTERNAME
$smtpserver = "yourSMTPServer"
$foreFrontDirectory = "C:\Program Files\Microsoft Forefront Protection for SharePoint\"
############# End Variables ##################

####### Start create test file if it doesn't exist
if(!(Test-Path -Path $testFile))
{
new-item -Path $testFile -Value "." –itemtype file
}
####### End create test file if it doesn't exist

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
$site = New-Object microsoft.sharepoint.spsite($uploadSite)
$web = $site.openweb()
$library = $web.GetFolder($documentLibName)

$filestream = ([System.IO.FileInfo] (Get-Item $testFile)).openread()
$bytes = new-object byte[] $filestream.length
$filestream.read($bytes, 0, $filestream.length)
$filestream.close()
$folderPath = $library.URL + "/AutomatedTestUpload - $env:COMPUTERNAME.txt"

try
{
$library.files.add($folderPath, $bytes, $true)
}
catch [Exception]
{
$CAService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$CAService.AntivirusSettings.UploadScanEnabled = $false
$CAService.AntivirusSettings.CleaningEnabled = $false
$CAService.Update()

Stop-Service -Displayname "Microsoft Forefront Server Protection Controller"
Stop-Service -DisplayName "Microsoft Forefront Server Protection Controller for SharePoint"
& ($foreFrontDirectory + "fsccontroller.exe") " /disable"
& ($foreFrontDirectory + "fsccontroller.exe") " /enable"

Restart-Service -DisplayName "SharePoint 2010 Administration"
Restart-Service -DisplayName "SharePoint 2010 Timer"

 Start-Service -DisplayName "Microsoft Forefront Server Protection Controller for SharePoint"
Start-Service -Displayname "Microsoft Forefront Server Protection Controller"

$CAService.AntivirusSettings.UploadScanEnabled = $true
$CAService.AntivirusSettings.CleaningEnabled = $true
$CAService.Update()

  Send-MailMessage -To $emailTo -Subject "Forefront Antivirus Auto-Kicked" -Body $body -SmtpServer $smtpserver -From $emailFrom -BodyAsHtml
}

$web.dispose()
$site.dispose()

Helpful Resources

http://ikarstein.wordpress.com/2010/12/07/forefront-protection-2010-for-sharepointerror-the-sharepoint-service-is-running-but-the-forefront-vsapi-library-is-not-registered/

http://ystex.net/2010/12/12/powershell-fun-setting-sharepoint-antivirus-settings/

Advertisements

Security Trimming InfoPath fields with SharePoint 2010 InfoPath Forms Services Based on SharePoint User Groups & Claims-Based Authentication

Yes, I know variations of this topic have been blogged about quite a few times but I couldn’t find one that fit my particular use case and environment variables. Also, it was difficult for me to find a clear and concise guide in setting this up so hopefully this write-up will help you achieve what I’m about to show you in as few steps as necessary. But first of all, I should give props to the following blogs and links for giving me a head start and some food for thought:

http://blog.symprogress.com/2011/05/infopath-list-form-hidedisable-fields-based-on-sharepoint-group-membership/

http://www.projectpoint.at/?p=97

http://gordonduthie.net/2011/01/26/sharepoint-2010-claims-based-security-infopath-data-connections-and-getuserprofilebyname/

http://msdn.microsoft.com/en-us/library/dd946988%28office.12%29.aspx

My Scenario & Environment

Using browser enabled InfoPath 2010 forms, I have a need to hide and/or disable certain fields from users based on their SharePoint group membership. The form is used to track change requests and its status. The only noteworthy thing about my farm is that it is utilizing Claims-Based Authentication throughout.

Step 1 – Design your form

Design your browser based form as desired and then publish it to a SharePoint Form Library. Instructions on how to do that can be found here. Everything render ok? Cool, move on to Step 2.

Step 2 – Add Data Connections

Since we’d like to leverage SharePoint’s out of the box web services to figure out if the current user is in a particular group, we’ll want to add a Data Connection to https://YourSharePointSiteCollection/_vti_bin/usergroup.asmx. The method we’re interested in using is GetGroupCollectionFromUser.

Step 3 – Modify the Schema Files

I’m borrowing this step from Daniel Laksana’s blog post (Steps 3 & 4). To recap:

I. Publish > Export the source files

II. Below

<s:import namespace="http://www.w3.org/2001/XMLSchema"></s:import>

You’ll want to copy paste the following:

<s:complexType name="GetGroupCollectionFromUserType">
    <s:sequence>
      <s:element minOccurs="0" maxOccurs="1" name="userLoginName" type="s:string"/>
      <s:element minOccurs="0" maxOccurs="1" name="Groups">
        <s:complexType>
          <s:sequence>
            <s:element maxOccurs="unbounded" name="Group" >
              <s:complexType>
                <s:attribute name="ID" type="s:unsignedShort"></s:attribute>
                <s:attribute name="Name" type="s:string"></s:attribute>
                <s:attribute name="Description" type="s:string"></s:attribute>
                <s:attribute name="OwnerID" type="s:unsignedByte"></s:attribute>
                <s:attribute name="OwnerIsUser" type="s:string"></s:attribute>
              </s:complexType>
            </s:element>
          </s:sequence>
        </s:complexType>
      </s:element>
    </s:sequence>
  </s:complexType>

III. Find this:

<s:element name="GetGroupCollectionFromUser">
   <s:complexType>
     <s:sequence>
       <s:element minOccurs="0" maxOccurs="1" name="userLoginName" type="s:string">
         </s:element>
    </s:sequence>
  </s:complexType>
</s:element>

and replace it with this:

<s:element name="GetGroupCollectionFromUser" type="tns:GetGroupCollectionFromUserType">
</s:element>

Save your changes.

Step 4 – Getting a list of the SharePoint groups that the current user belongs to

We can do this with a Form Load action. I’ve named this rule “GetUserGroups”.

Let’s now zoom into the actions that this rule will perform:

Action 1: Set the userLoginName query field with the value of the current user’s username.

Action 2: Query for data.

Step 5 – Manage rules for a field that should be disabled for certain users

In my example, we are going to disable the Request Status drop down for users that are not in the “Request Queues Owners” SharePoint group. To do so, we’ll create a rule on that field by left clicking on it and then the related rules will show up in the Rules pane. If the Rules pane is not currently open, then you’ll want to right-click on the form field and then select Rules > Manage Rules… from the drop down.

Since the data connection in our previous step brings back all of the groups that the current user is a member of, we’ll want to configure the rule to tell us if any of those groups match a predefined SharePoint group that would be able to update the field. Otherwise, the field would be disabled/read-only. Let’s configure this rule like so:

Step 6 – Publish to SharePoint & Test

We’re now ready to publish the form back out to the SharePoint Form Library and test the security trimming! If you don’t have two accounts to test with, you should be able to test with a single account by adding and removing yourself into/out of the preconfigured SharePoint group that’s being referenced within the previously configured formatting rule.

That’s all folks! Enjoy 🙂