Thursday, October 2, 2014

Lists.asmx GetListCollections and GetListItems example

I recently had to get all items of a list as well as all lists in a SPWeb. This involved calling Lists.asmx. For the service description of Lists.asmx just go to /_vti_bin/lists.asmx

Get all lists for some SPWeb

$webUrl = 'some-web-url'

$credential = Get-Credential -Message "Enter your login for $($webUrl)"

$uri = [uri]"$($webUrl)/_vti_bin/lists.asmx"

$contentType = 'text/xml'
$bodyString = @"
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<GetListCollection xmlns="http://schemas.microsoft.com/sharepoint/soap/" />
</soap12:Body>
</soap12:Envelope>
"@

$result = Invoke-WebRequest -Credential $credential -Method Post -Uri $uri -Body $bodyString -ContentType $contentType
$xml = [xml]$result.Content
$xml.Envelope.Body.GetListCollectionResponse.GetListCollectionResult.Lists.List

Get all list items for some list

$webUrl = 'some-web-url'
$listName = 'some-list-name'

$credential = Get-Credential -Message "Enter your login for $($webUrl)"

$uri = [uri]"$($webUrl)/_vti_bin/lists.asmx"

$contentType = 'text/xml'
$bodyString = @"
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<GetListItems xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<listName>$($listName)</listName>
<viewName></viewName>
<rowLimit>5000</rowLimit>
<query>
<Query xmlns="">
<OrderBy> <FieldRef Name="ContentType" /> </OrderBy>
</Query>
</query>
<viewFields><ViewFields xmlns="" /></viewFields>
<queryOptions>
<QueryOptions xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>
<IncludeAttachmentUrls>TRUE</IncludeAttachmentUrls>
<ViewAttributes Scope='RecursiveAll' IncludeRootFolder='True' />
<DateInUtc>TRUE</DateInUtc>
</QueryOptions>
</queryOptions>
</GetListItems>
</soap12:Body>
</soap12:Envelope>
"@

$result = Invoke-WebRequest -Credential $credential -Method Post -Uri $uri -Body $bodyString -ContentType $contentType
$xml = [xml]$result.Content
$xml.Envelope.Body.GetListItemsResponse.GetListItemsResult.listitems.data.ItemCount
$xml.Envelope.Body.GetListItemsResponse.GetListItemsResult.listitems.data.row | Format-Table ows_LinkFilename, ows_Author, ows_Created, ows_Modified -AutoSize

I could probably use New-WebServiceProxy and skip all the SOAP envelope stuff. However, this better mimics the code that I was trying to troubleshoot.


Monday, May 26, 2014

The solution cannot be deployed. The feature 'some-feature-id' uses the directory "some-directory" in the solution

I recently came across this error when trying to deploy a WSP:
The solution cannot be deployed.  The feature 'some-feature-id' uses the directory "some-directory" in the solution. However, it is currently installed in the farm to the directory "some-other-directory". Uninstall the existing feature before you install a new version of the solution.

Simple enough, I tried to do an Uninstall-SPFeature as well as Uninstall-SPFeature -Force both of which did not help. Finally someone tried stsadm -o uninstallfeature and then the subsequent WSP deploy worked. I guess Powershell and stsadm are not quite equivalent


Calling private member using reflection in Powershell

Often I have to put together some Powershell scripts for troubleshooting. These scripts are based on some c# code. Recently, I had to mimic the behaviour of a call to a private member overload of GetTags in the Microsoft.Office.Server.SocialData.SocialTagManager class.

$site = Get-SPSite my-site-url
$context = Get-SPServiceContext($site)
$socialTagManager = New-Object -TypeName Microsoft.Office.server.SocialData.SocialTagManager -ArgumentList $context

# Get the type definition
$type = [type]'Microsoft.Office.Server.SocialData.SocialTagManager'

# List the GetTags members
($socialTagManager | Get-Member GetTags).Definition.Replace("), ", ")`n")

This results in (just the public members):
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(Microsoft.Office.Server.UserProfiles.UserProfile user)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(Microsoft.Office.Server.UserProfiles.UserProfile user, int maximumItemsToReturn)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(Microsoft.Office.Server.UserProfiles.UserProfile user, int maximumItemsToReturn, int startIndex)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(System.Uri url)


Now use Reflection

# Which methods to list
$bindingFlags = [Reflection.BindingFlags] "Default,NonPublic,Instance"

# List the methods
$type.GetMethods($bindingFlags) | Where-Object {$_.Name -eq 'GetTags'} | ForEach-Object {$_.GetParameters() | Select-Object Member -First 1}

This results in (both public and private members);
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(System.DateTime, System.DateTime)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(System.DateTime, System.DateTime, Int32)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(System.DateTime, System.DateTime, Int32, Int32)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(System.Uri, Microsoft.Office.Server.UserProfiles.UserProfile, System.Nullable`1[System.DateTime], System.Nullable`1[System.DateTime])
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(System.Uri, Int32)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(System.Uri, Int32, Microsoft.Office.Server.SocialData.SocialItemPrivacy)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(Microsoft.SharePoint.Taxonomy.Term[], Int32, Microsoft.Office.Server.SocialData.SocialItemPrivacy)
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(Microsoft.Office.Server.UserProfiles.UserProfile, Int32, Int32, Boolean, System.Nullable`1[System.DateTime], System.Nullable`1[System.DateTime])
Microsoft.Office.Server.SocialData.SocialTag[] GetTags(Microsoft.Office.Server.UserProfiles.UserProfile, Int32, Int32, Boolean, System.Nullable`1[System.DateTime], System.Nullable`1[System.DateTime], System.Nullable`1[System.Guid])


Now to call a private member. Let's call: Microsoft.Office.Server.SocialData.SocialTag[] GetTags(System.DateTime, System.DateTime, Int32, Int32)


$startTime = [DateTime]'2014-05-01 00:00:00'
$endTime = [DateTime]'2014-05-31 00:00:00'
$maximumItemsToReturn = 1000
$startIndex = 0
$typeList = @([type]'DateTime', [type]'DateTime', [type]'Int32', [type]'Int32')
$method = $socialTagManager.GetType().GetMethod('GetTags', $bindingFlags, $null, $typeList, $null)
$terms = $method.Invoke($socialTagManager, [Object[]] @($startTime, $endTime, $maximumItemsToReturn, $startIndex))
$terms | Format-Table @{l='Term';e={$_.Term.Name}}, Title -AutoSize




Sunday, May 25, 2014

Get all features that define Site Settings links

Recently, I needed to find out where a particular link listed under Site Settings. Doing a bit of research on how to add links to a Site Settings page involves defining a CustomAction in the Elements.xml file with a Location of Microsoft.SharePoint.SiteSettings. Reversing this logic, we can find all Elements.xml files that contains a line Location="Microsoft.SharePoint.SiteSettings" and from there work backwards to get the SharePoint feature.

Here is a Powershell that does this:
Get-ChildItem -Recurse -Filter *.xml | Select-String -Pattern 'Microsoft.SharePoint.SiteSettings' | Group-Object path | ForEach-Object {$x = $_.Name; Get-SPFeature | Where-Object {$x -like "$($_.RootDirectory)*"}} | Format-Table Id, Scope, @{l='Title';e={$_.GetTitle(1033)}} -AutoSize

This script can easily be modified to find other menu items by changing the Select-String -Pattern to something else such as Microsoft.SharePoint.StandardMenu.

Tuesday, April 1, 2014

SharePoint Timezone Settings

I recently had to troubleshoot some SharePoint Timezone issues. There are a bewildering number of places where this may be a factor:

These are nicely summarized at http://www.techgrowingpains.com/2012/05/sharepoint-time-zone-confusion-2/

  • Web Application Level
    • Central Administration->Manage Web Applications
    • Select your web application
    • Select General Settings
    • Default Time Zone: Select time zone
  • Site Collection Level
    • Go to your site collection
    • Site Actions->Site Settings->Regional Settings
    • Select time zone
  • User Level
    • Welcome menu (aka Personal menu, aka the menu with your name on it)->My Settings->My Regional Settings
    • Uncheck Always follow web settings (if checked)
    • Select time zone


There is also
  • Server time zone (across all farm servers)
  • Desktop time zone

Wednesday, October 2, 2013

The server is unavailable and could not be accessed. The server is probably disconnected from the network

All of a sudden my FAST search crawler is returning the following error on every item:
The server is unavailable and could not be accessed. The server is probably disconnected from the network

I already had DisableLoopbackCheck enabled so that wasn't it.
In any case, I removed the DisableLoopbackCheck and decided to try BackConnectionHostNames instead (ie: the safer method). This also didn't help
I tried adding in DisableStrictNameChecking. This also didn't help.
Hours of searching, I was about to give up, then I thought I'd check the hosts file. At that point, I remembered that I added an entry there when I had previously done some maintenance on that server. After I removed that errant entry, my crawler now works.

Tuesday, June 18, 2013

%systemdrive% in Powershell

I was just trying to write a script to manage IIS logs. I was able to get the log directory, but it comes back as  %SystemDrive%\inetpub\logs\LogFiles

Reading between the lines from a couple of posts, I found that I can use $env:SystemDrive in place of %SystemDrive%

So I can do something like this:
Import-Module WebAdministration
$website = Get-Website | Where-Object {$_.name -eq 'SharePoint - 443'}
$logfileDirectory = $website.logFile.directory -replace '%SystemDrive%', $env:SystemDrive
...