Wednesday, February 17, 2010 #

Exception setting "ThreadOptions" in SharePoint 2010 Management Shell

Right after you install SP2010 (Foundation or Server), even on a completely updated Windows Server 2008 SP2, when you go to start the SharePoint 2010 Management Shell (the recommended PowerShell interface for working with SharePoint), you get a real ugly looking error:

Exception setting "ThreadOptions": "This property cannot be changed after the Runspace has been opened."
At C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\CONF
IG\POWERSHELL\Registration\SharePoint.ps1:2 char:48
+ if ($ver.Version.Major -gt 1)  {$Host.Runspace. <<<< ThreadOptions = "ReuseTh
read"}
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyAssignmentException

To get around this problem, update the Windows Management Framework Core.  See KB968930, where you can download updates for various versions of Windows.

sp2010mgmtshell

posted @ Wednesday, February 17, 2010 1:56 PM | Feedback (0)

Site Templates in SharePoint 2010

There are still Site Template in SharePoint 2010, but they're no longer .STP files.  Instead, they're packaged in .WSP files just like web parts and features. No longer is there a "Site Template Gallery", instead there is a "Solutions Gallery". 

To create a Site Template, browse to the Site you want to create from.  Go to Site Actions –> Site Settings –> Save site as template (under the Site Actions heading).  Give your template a name, and don't forget to check the "Include Content" box if you want to include library and list content in the template.  This will create a new site template in your Solutions Gallery, which you can then use when creating new sites.  You can also download directly from the Solutions Gallery to a .WSP file.

To upload a Site Template to the Solutions Gallery, go to Site Actions –> Site Settings –> Solutions Gallery (under the Galleries heading).  On the Solutions tab of the ribbon, click "Upload Solution".  Before you close that dialog, you'll need to click "Activate" to activate it if you want your Site Template to appear in the "New Site" dialog later.

To use the Site Template, go to Site Actions –> New Site. You'll find your Site Template in the list of Installed Items, in the All Categories or Blank & Custom filters.

Technorati Tags: ,

posted @ Wednesday, February 17, 2010 1:45 PM | Feedback (0)

Changing Page Layout with SharePoint Designer 2010

Don't like one of your page layouts on your SharePoint Site?  No problem, you can solve this problem quickly and easily using the free SharePoint Designer.  It doesn't take any programming, just a couple minor HTML tweaks. 

Note:  This is different from modifying the master page, which will effect every page on the site.  Instead, we'll be detaching the page from the master page, therefore making it unique on the site.  This obviously has its cons when its comes to long-term site style.

Here's how a site looks, out of the box:

EditSiteLayout0

Notice how the "Right" web part zone is narrow, and the "Left" web part zone takes up the remaining part of the actual page content.  I don't like that…its backwards for me.  Here's how to change it:

  • Inside SharePoint Designer 2010, click "Open Site", type in your URL, and click "Open".

    EditSiteLayout1 EditSiteLayout2
  • Click "Edit site home page".
     EditSiteLayout3
  • Now the default.aspx for the page will appear.  Areas that define the page layout itself will have a highlighted background color.  Those lines cannot be changed unless you enter "Advanced Mode".  So first, click the "Advanced Mode" button found on the Home menu (top right of your screen in the ribbon).  Now, looking at the HTML of the page, the part I want to change is near the bottom, and is the width of the two main WebPartZones on the page (the "Left" and "Right" Web Part Zones)?

    EditSiteLayout4 
  • Finally, just save the site in SharePoint Designer and then close it.  When you save, your changes will be written to the SharePoint Server, so the next time you visit your page, it will appear as desired:

    EditSiteLayout5

 

 

 

 

 

 

 

posted @ Wednesday, February 17, 2010 9:09 AM | Feedback (0)

Wednesday, January 13, 2010 #

10 DIY SharePoint Web Parts #10

This post is the tenth and last in a series of postings, containing examples of SharePoint WebParts that anybody can build all by themselves.  To read all posts in this series, or to get started with the RSSBus WebPart, go here.

#10 - Keep Your SharePoint Calendar Synced with Google

The following is one way you can use to keep your SharePoint Calendar(s) synced up with your Google Calendar.  This particular example only syncs in one direction:  from Google to SharePoint.  It could go the opposite direction, or both, but that's not what I need so that's not what I did.  :)  As usual, this solution requires that you have the RSSBus Web Part installed.  See here for instructions.  You'll also need the GoogleOps Connector, which is automatically included with the RSSBus Web Part.

google.GcalSharePointSync

Step one:  Logon to SharePoint and browse to your calendar.  Under Site Actions, click Edit Page.

Step two:  Now, click on "Add a Web Part", and add the RSSBus Web Part to the page.  I prefer to drag the Calendar up so that it is on top, and this RSSBus Web Part is just below it.  On its edit menu, click Modify Shared Web Part and open the Source Editor.

Step three:  Paste in the following RSSBus Web Part template, and click "Apply".

 
 
 
 
 
<rsb:info title="Google Calendar Sync" description="This template Syncs your SharePoint Calendar events with those in a Google Calendar account.">
  <input name="email" description="The email used to authenticate with Google." required="true"/>
  <input name="password" description="The password used to authenticate with Google." required="true" style="password"/>
  <input name="calendar" description="The SharePoint calendar to sync to." default="Calendar"/>
  <input name="days" description="The number of days to import events for." default="30"/>
</rsb:info>

<rsb:import lib="RSSBus.GoogleOps"/>

<!-- get all the events in the SharePoint calendar -->
<rsb:set attr="list" value="[[calendar]]"/>
<rsb:call op="spListItems" out="myitemout" save="myspitems" >
    <rsb:call op="spGetItem?itemid=[[sp:id]]" >
      <rsb:set attr="myitemout.title" value="[[sp:title]]"/>
      <rsb:set attr="myitemout.location" value="[[sp:location | def('')]]"/>
      <rsb:set attr="myitemout.start_time" value="[[sp:start_time]]"/>
      <rsb:set attr="myitemout.end_time" value="[[sp:end_time]]"/>
      <rsb:set attr="myitemout.description" value="[[sp:description | def('')]]" />
    </rsb:call>
</rsb:call>

<!--get all the events in the Google calendar in the specified range -->
<rsb:set attr="fromdate" value="[[null | date('d')]]"/>
<rsb:set attr="todate" value="[[fromdate | dateadd(day, [[days]]) | todate('d') ]]"/>
<rsb:call op="googleCalSearch" out="mygcalout" save="mygitems">
  <rsb:set attr="mygcalout.title" value="[[ggl:title]]"/>
  <rsb:set attr="mygcalout.location" value="[[ggl:where | def('')]]"/>
  <rsb:set attr="mygcalout.start_time" value="[[ggl:starttime | todate]]"/>
  <rsb:set attr="mygcalout.end_time" value="[[ggl:endtime | todate]]"/>
  <rsb:set attr="mygcalout.description" value="[[ggl:description | def('')]]"/>
</rsb:call>

<!-- now find out what is in google calendar that is not in the sharepoint list, using title and start time as the filter -->
<rsb:set attr="diff.base" value="[[_feeds.myspitems]]"/>
<rsb:set attr="diff.feed" value="[[_feeds.mygitems]]"/>
<rsb:set attr="diff.filter" value="title,start_time"/>
<rsb:set attr="diff.list" value="[[list]]"/>
<rsb:call op="feedDiff" in="diff">
  <!-- for everything not in the sp list, add it!  -->
  <rsb:set attr="name#" value="Title"/>
  <rsb:set attr="name#" value="Location"/>
  <rsb:set attr="name#" value="Start Time"/>
  <rsb:set attr="name#" value="End Time"/>
  <rsb:set attr="name#" value="Description"/>
  <rsb:set attr="value#" value="[[title]]"/>
  <rsb:set attr="value#" value="[[location | def('')]]"/>
  <rsb:set attr="value#" value="[[start_time]]"/>
  <rsb:set attr="value#" value="[[end_time]]"/>
  <rsb:set attr="value#" value="[[description | def('')]]"/>
  <rsb:call op="spAddItem"/>
  <b>[[title]]</b> Successfully imported from Google Calendar.<br>
</rsb:call>
 
 
 

Step four:  After you click Apply, you'll need to specify your Google Calendar email and password, the name of the calendar to sync with (ie, "Calendar"), and the number of days you want it to keep synced at a time.  Optionally, you can embed these inputs into the script if you want, instead of leaving them as web part properties.  To do that, change the rsb:info section of code to this:

<rsb:set attr="email" value="YOUREMAIL" />
<rsb:set attr="password" value="YOURPASSWORD" />
<rsb:set attr="calendar" value="YOURCALENDARNAME" />
<rsb:set attr="days" value="30" />

Now, everytime you view your Calendar page it will automatically be updated with the lastest items from Google Calendar.

See all posts in this series:  10 DIY SharePoint Web Parts.
Browse RSSBus Connectors.
Basic RSSBus Scripting Cheat Sheet.

posted @ Wednesday, January 13, 2010 1:19 PM | Feedback (2)

Tuesday, January 12, 2010 #

PowerShell: Twitter Auto UN-follow

Anybody who uses Twitter has heard of auto-follow services for Twitter.

Below is a PowerShell script I used to auto UNfollow.  The script goes through the people you're following and eliminates "idle" or "spam" friends.  An idle friend is determined by a low friend count or low status count on an account that has been in existance for at least a couple months (configurable).  A spam friend is determined by a high friend count but a low follower count (by default, the script uses a 15-1 ratio as the max).

I would appreciate any good tweaks or improvements you might like to share!  In particular I wasn't sure how to deal with Twitter's rate limiting (150 get requests per hour).  For now I just catch the exception when it occurs and sleep for an hour before resuming.

 
 
 
 
 
#this script goes through the people you're following and eliminates "idle" or "spam" friends.
#an idle friend is determined by low friends or statuses on an account that has been in existance for a while
#a spam friend is determined by high friends but low followers

param([int] $minfriends = 20,
        [int] $minstatuses = 20,
        [int] $minaccountage = 60, #days
        [int] $maxratio = 15,
        [switch] $silent = $false #whether or not to prompt before unfollowing
        )

function unfollow($userid, $userinfo) {
    do {
        Write-Host "Unfollowing User $($userinfo.user.screen_name): $($userinfo.user.friends_count) friends/$($userinfo.user.followers_count) followers/$($userinfo.user.statuses_count) statuses [y/n/l]: " -noNewLine -foregroundColor Yellow
        if ($silent -eq $false) {
            $cmd = Read-Host
        }
        if ($silent -eq $true -or $cmd -eq "y") {
            $wc = new-object net.webclient
            $wc.Credentials = $global:twittercred
            $unfollo = $wc.UploadString("http://www.twitter.com/friendships/destroy/$($userid).xml", "")                
            $unfollow.user.following            
        }
        if ($cmd -eq "l") {
            Start-Process "http://www.twitter.com/$($userinfo.user.screen_name)"
        }
    } while ($silent -eq $false -and $cmd -eq "l")
}

#enter your Twitter credentials for retrieving your friends list
$global:twittercred = Get-Credential

#retrieve the full friends list
$wc = new-object net.webclient
$wc.Credentials = $global:twittercred
$response = [xml]($wc.DownloadString("http://www.twitter.com/friends/ids.xml"))

#now loop through each friend
$response.ids.id | % {
    try
    {
        #get detailed info about this user
        $showuser = [xml]($wc.DownloadString("http://www.twitter.com/users/show.xml?id=$($_)"))
    } catch {
        Write-Host "Twitter rate limit reached (150 gets/hour).  Pausing for one hour..." -foregroundColor Red -noNewLine
        Start-Sleep -Seconds 3600
    }
    #determine if they are worthy of following:
     $datecreated = [DateTime]::ParseExact($showuser.user.created_at, "ddd MMM dd H:mm:ss +0000 yyyy", [System.Globalization.CultureInfo]::InvariantCulture)
     $accountage = ([DateTime]::Now).Subtract($datecreated).Days    
    $statusescount = [int]$showuser.user.statuses_count
    $friendscount = [int]$showuser.user.friends_count
    $followerscount = [int]$showuser.user.followers_count
    if (($accountage -ge $minaccountage) -and ($friendscount -lt $minfriends -or $statusescount -lt $minstatuses)) {
        #unfollow idle friends:
        unfollow $_ $showuser
    }
    elseif (($accountage -ge $minaccountage -and $followerscount -eq 0) -or ($followerscount -gt 0 -and $friendscount / $followerscount -gt $maxratio)) {
        #unfollow spam friends:
        unfollow $_ $showuser
    }    
    else {
        Write-Host "Good friend $($showuser.user.screen_name): $($friendscount)/$($friendscount)/$($statusescount): "
    }
}
 
 
 
Technorati Tags: ,

posted @ Tuesday, January 12, 2010 1:06 PM | Feedback (4)

Tuesday, December 29, 2009 #

Program Files Environment Variable in PowerShell

Today I saw this on Twitter from Julie Blender (@#juneb_get_help): 

Need to reference the "ProgramFiles(x86)" environment variable in #PowerShell? Use ${env:ProgramFiles(x86)}.

I use this in a lot of my scripts, but I want a single variable that contains the right value whether I'm in a 64 bit shell or not.  Here's my solution:

First, I have a function in my testing profile called is64bit, that looks like this:

function is64bit() {
  return ([IntPtr]::Size -eq 8)
}

Next, I have a get-programfilesdir function that I call that checks whether or not I'm in a 64 bit shell or not and returns the appropriate program files environment variable (ie, if I'm running on a 64 bit machine it will return "C:\Program Files (x86)", but if I'm running on a 32 bit machine it will return "C:\Program Files".  If I'm running in a 32 or 64 bit shell on a 64 bit machine, it will always return "C:\Program Files (x86)".

function get-programfilesdir() {
  if (is64bit -eq $true) {
    (Get-Item "Env:ProgramFiles(x86)").Value
  }
  else {
    (Get-Item "Env:ProgramFiles").Value
  }
}

 

Technorati Tags:

posted @ Tuesday, December 29, 2009 7:27 AM | Feedback (1)

GeeksWithBlogs and SubText Bloggers: Input string was not in a correct format

GeeksWithBlogs.net and other SubText Users:

If you are trying to create a new blog post, and you get the following error:

Input string was not in a correct format.    at
System.Text.StringBuilder.FormatError()
   at System.Text.StringBuilder.AppendFormat(IFormatProvider provider,
String format, Object[] args)
   at Subtext.Framework.Util.KeyWords.Scan(String source, String oldValue,
String newValue, Boolean isFormat, Boolean onlyFirstMatch)
   at Subtext.Framework.Util.KeyWords.Format(Entry entry)
   at Subtext.Framework.Data.DatabaseObjectProvider.FormatEntry(Entry e,
Boolean UseKeyWords)
   at Subtext.Framework.Data.DatabaseObjectProvider.Create(Entry entry,
Int32[] categoryIds)
   at Subtext.Framework.Entries.Create(Entry entry)
   at Subtext.Framework.XmlRpc.MetaWeblog.PostContent(String username,
String password, Post& post, Boolean publish, PostType postType)

The problem has been fixed.  It was repoted by Joe Pruitt and fixed by Phil Haack not too long ago.  It was happening for Joe (and me) when attempting to submit a post containing curly braces AND having keywords set up in SubText.  No doubt both Joe and me had this problem due to posting powershell and C# code snippets. 

If you can't get the update yet, you can always just remove your keyword definitions from SubText.  Thats what I did.  :P

posted @ Tuesday, December 29, 2009 4:42 AM | Feedback (1)

10 PowerShell One Liners

Here are a few one-liners that use NetCmdlets. Some of these I've blogged about before, some are new. Let me know if you have questions, which ones you find useful, or how you altered these to suit your own needs.

  1. Send email to a list of recipient addresses:

    import-csv users.csv | % { send-email -to $_.email -from lance@nsoftware.com -subject "Important Email" –message "Hello World!" -server 10.0.1.1 }
  2. Show the access control list for a specific Exchange folder:

    get-imap -server $mymailserver -cred $mycred -folder INBOX.RESUMES –acl
  3. Add look and read permissions on an Exchange folder, for a list of accounts pulled from a CSV file:

    import-csv users.csv | % { set-imap -server -acluser $_.username $mymailserver -cred $mycred -folder INBOX.RESUMES –acl “lr”  }
  4. Sync system time with an Internet time server:

    get-time -server clock.psu.edu –set

    To remotely sync the time on a set of computers:

    import-csv computers.csv | % { Invoke-Command -computerName $_.computer -cred $mycred -scriptblock { get-time -server clock.psu.edu –set } }
  5. Delete all emails from an Exchange folder that match a certain criteria.  For example, delete all emails from alf@email.com:

    get-imap -server $mailserver –cred $mycred | ? {$_.FromEmail -eq alff@email.com} | %{ set-imap -server $mailserver –cred $mycred-message $_.Id -delete }
  6. Update Twitter status from PowerShell:

    get-http –url "http://twitter.com/statuses/update.xml" –cred $mycred -variablename status -variablevalue "Tweeting with NetCmdlets!"
  7. A test-path that works over FTP, FTPS (SSL), and SFTP (SSH) connections:

    get-ftp -server $remoteserver –cred $mycred -path /remote/path/to/checkfor*

    Don't forget the *.  Also, to use SSL or SSH just add an –ssl or –ssh parameter.
  8. List disabled user accounts in Active Directory (or any other LDAP server):

    get-ldap -server $ad -cred $mycred -dn dc=yourdc -searchscope wholesubtree
        -search "(&(objectclass=user)(objectclass=person)(company=*)(userAccountControl:1.2.840.113556.1.4.803:=2))"
  9. List Active Directory groups and their members:

    get-ldap -server testman -cred $mycred -dn dc=NS2 -searchscope wholesubtree -search "(&(objectclass=group)(cn=*admin*))" | select ResultDN, member
  10. Display the last initialization time (e.g. last reboot time) of all discoverable SNMP agents on a network:

    import-csv computers.csv | % { get-snmp -agent $_.computer -oid sysUpTime.0 | %{([datetime]::Now).AddSeconds(-($_.OIDValue/100))} }

Not mentioned here:  data conversion (Yenc, QP, UUencoding, MD5, SHA1, base64, etc), DNS, News Groups (NNTP/UseNet), POP mail, RSS feeds, Amazon S3, Syslog, TFTP, TraceRoute, SNMP Traps, UDP, WebDAV, whois, Rexec/Rshell/Telnet, Zip files, sending IMs (Jabber/GoogleTalk/XMPP), sending text messages and pages, ping, and more.

 

posted @ Tuesday, December 29, 2009 4:36 AM | Feedback (0)

Tuesday, December 08, 2009 #

PowerShell: Smart Parameter Expressions

A while back I posted about how to mark a script parameter as required in PowerShell.  Shortly afterwards, there was some chatter on it that I think makes it worthwhile to add another post on the subject of PowerShell script parameters.

Let’s say you have the question:  “Can I do <X> with a parameter?” 

The answer is probably “Yes”.  :)

Jim and an anonymous emailer both asked:

Is there any way you can specify a parameter based on the value of another parameter?

The answer is yes.  You can put pretty much any expression in the default evaluator of the parameter definition. For example:

 

  param(
    [switch] $switchparam, #an optional "switch parameter" (ie, a flag)
    [string] $user = $(if ($switchparam) { Read-Host -prompt "User"}) #prompt user for value if none provided
  )

In the above example, if –switchparam is specified in the command, the $user parameter default expression will evaluate to true and prompt the user for a user name.

Technorati Tags:

posted @ Tuesday, December 08, 2009 1:49 AM | Feedback (0)

Monday, December 07, 2009 #

Listing SPQuery FieldNameRefs

It took me a while to figure out how to get a list of all the available fields for a particular type of list in SharePoint (for performing custom queries in SPQuery).  I was looking for a published list of these fields, which as far as I know does not exist.  Instead, you just use the GetList method of the Lists SOAP service.  Here’s an example SOAP request:

<?xml version="1.0" encoding="utf-8"?> 
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> 
  <SOAP-ENV:Body> 
    <GetList xmlns="http://schemas.microsoft.com/sharepoint/soap/"> 
      <listName>Private Documents</listName> 
    </GetList> 
  </SOAP-ENV:Body> 
</SOAP-ENV:Envelope>

Just specify the name of the list you want the fields for as the value for the listName input element.

One easy way to work with SharePoint services remotely is by using /n software’s SharePoint Integrator developer toolkit.  Using its SPSite component in Visual Studio I can whip together a few lines of code to consume get the results from the aforementioned service:

spsite1.URL = "http://mysharepoint/mysite/";
spsite1.User = "DOMAIN\lancer";  
spsite1.Password = "password";  
spsite1.DescribeList("Private SharePoint Documents");; 

/n software SharePoint Integrator highlights:

    • Read, Write, and Create SharePoint Lists Items, Documents, and Attachments.
    • Programmatic control of SharePoint Sites, capabilities, and configuration
    • 128-bit strong SSL encryption keeps sensitive transaction information confidential.
    • Small and lightweight components with no dependencies on external libraries.
    • Native development components for all supported platforms and component technologies.
    • Unlimited free Email technical support backed by an experienced & professional staff.
    • Compatible with Microsoft Office SharePoint Server (MOSS), and Windows SharePoint Services v3.0 + (WSS).

 

Technorati Tags: ,

posted @ Monday, December 07, 2009 4:24 AM | Feedback (0)

Copyright © Lance Robinson

Design by Bartosz Brzezinski

Design by Phil Haack Based On A Design By Bartosz Brzezinski