Microsoft cloud engineer - SharePoint, Office 365, Azure, DotNet, Angular, JavaScript.
Microsoft cloud engineer - SharePoint, Office 365, Azure, DotNet, Angular, JavaScript.

October 2014

NEW CodePlex project – SPUpgradeHelper

Today I am happy to announce https://spupgradehelper.codeplex.com/ is available for download.   This project aims to smooth the “double hop” upgrade from MOSS 2007 to SP2010 to SP 2013 by reading a CSV of database targets and automating the Cmdlets needed for a consistent, repeatable, high quality, and fast process.   Please leave a comment here or on CodePlex if you found this helpful.  Cheers! 

shades_smile

 

Project Description

Migrating MOSS 2007 to SP 2013? This script takes a CSV of databases and runs upgrade Cmdlets in bulk (DB version/Mount/Dismount/Upgrade-SPSite/Claims auth)

Upgrading MOSS to SP2013 is a tedious process with many Cmdlets, especially if you have many databases. This script aims to help automate that process.

Given a CSV with SQL instance and content database names, this script offers Cmdlets to run upgrade steps across many databases all at once. No more TXT or XLS copy and paste madness. Simply populate the CSV, get familiar with UH* Cmdlets and upgrade with ease.

Key Features

  • Read CSV of databases
  • Load helper functions into memory
  • Enable admin to more easily run Cmdlets in bulk
  • Measure time duration for each step (# minutes)
  • Provide detailed LOG file of actions, result, and duration

Quick Start Guide

  • Extract “SPUpgradeHelper.ZIP” to any SharePoint machine in your farm
  • Run “SPUpgradeHelper.ps1” to load helper functions
  • Type in full path to your CSV file (i.e. “C:\TEMP\COLLAB.CSV”)

Function Names

  • UHCIaims – execute SPWebApplication function to upgrade Classic to Claims auth
  • UHCompatibiIity – execute Get-SPSite for “set” of databases to show GUI version (14/15)
  • UHDBVersion – execute TSQL for “set” of databases to show build number (12.0, 14.0, 15.0)
  • UHDismount – execute DisMount-SPContentDatabase for “set” of databases
  • UHMount – execute Mount-SPContentDatabase for “set” of databases
  • UHReadCSV – load CSV file into memory with upgrade “set”, SQL instance, and database names
  • UHUpgrade – execute Upgrade-SPSite for “set” of databases

NOTE – Upgrade “set” is meant for running parallel workstreams. For example, two servers with SP2010 and two servers with SP2013. That way overall upgrade can be expedited by running database set “A” through the first SP2010 and SP2013 server while database set “B” runs on the second server.

Microsoft Upgrade Process

WebAPI OData – 10 min video introduction (Visual Studio 2013)

I’ve been learning about OData and wanted to record a quick getting started video with how to create a new WebAPI project, add OData Controller, and send HTTP CRUD operations.  Below is an example using Adventure Works Departments with sample code, screenshots, and a 10 minute video introduction.   Please leave a comment if you found this helpful.  Thanks! 

shades_smile

Video Content

  • Create MVC 4 web application
  • SQL Express – Adventure Works Departments
  • Add “AdventureWorks.edmx
    • Wizard driven
    • F4 set namespace
  • Add “DepartmentsController.cs
    • Create from EDMX class
    • Implements ODataController
    • Replace ID with KEY
  • Edit “WebApiConfig.cs
    • Comment out default route
    • Add OData route builder
  • Test with HTTP manually
  • Test with Chrome REST Postman
  • SQL Express – see changed data

Watch Video

WebAPI OData – 10 min video introduction (Visual Studio 2013) from Jeff Jones on Vimeo.

Sample Code

[WebApiConfig.cs]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.Http.OData.Builder;
namespace MvcApplication1
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            //config.Routes.MapHttpRoute(
            //    name: "DefaultApi",
            //    routeTemplate: "api/{controller}/{id}",
            //    defaults: new { id = RouteParameter.Optional }
            //);
            ODataConventionModelBuilder build = new ODataConventionModelBuilder();
            build.EntitySet("Departments");
            config.Routes.MapODataRoute("odata", "odata", build.GetEdmModel());
            config.EnableQuerySupport(new QueryableAttribute()); 
            // Uncomment the following line of code to enable query support for actions with an IQueryable or IQueryable return type.
            // To avoid processing unexpected or malicious queries, use the validation settings on QueryableAttribute to validate incoming queries.
            // For more information, visit http://go.microsoft.com/fwlink/?LinkId=279712.
            //config.EnableQuerySupport();
            // To disable tracing in your application, please comment out or remove the following line of code
            // For more information, refer to: http://www.asp.net/web-api
            config.EnableSystemDiagnosticsTracing();
        }
    }
}

 

[DepartmentsController.cs]

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using System.Web.Http.OData;
namespace MvcApplication1.Controllers
{
    public class DepartmentsController : ODataController
    {
        private AdventureWorks2012Entities db = new AdventureWorks2012Entities();
        // GET api/Default1
        public IEnumerable GetDepartments()
        {
            return db.Departments.AsEnumerable();
        }
        // GET api/Default1/5
        public Department GetDepartment(short key)
        {
            Department department = db.Departments.Find(key);
            if (department == null)
            {
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
            }
            return department;
        }
        // PUT api/Default1/5
        public HttpResponseMessage PutDepartment(short key, Department department)
        {
            if (!ModelState.IsValid)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
            if (key != department.DepartmentID)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }
            db.Entry(department).State = EntityState.Modified;
            try
            {
                db.SaveChanges();
            }
            catch (DbUpdateConcurrencyException ex)
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
            }
            return Request.CreateResponse(HttpStatusCode.OK);
        }
        // POST api/Default1
        public HttpResponseMessage PostDepartment(Department department)
        {
            if (ModelState.IsValid)
            {
                db.Departments.Add(department);
                db.SaveChanges();
                HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, department);
                response.Headers.Location = new Uri(Url.Link("odata", new { key = department.DepartmentID }));
                return response;
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
        }
        // DELETE api/Default1/5
        public HttpResponseMessage DeleteDepartment(short key)
        {
            Department department = db.Departments.Find(key);
            if (department == null)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }
            db.Departments.Remove(department);
            try
            {
                db.SaveChanges();
            }
            catch (DbUpdateConcurrencyException ex)
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
            }
            return Request.CreateResponse(HttpStatusCode.OK, department);
        }
        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    }
}

Downloads

Screenshots

image
image
image
image
image

PowerMap – 6 min video introduction (Excel 2013)

I heard a lot about PowerMap and wanted to record a quick getting started video with how to download, screenshots, and play a sample XLSX workbook.  

Background

The “Power” family of Business Intelligence features is getting a lot of attention at conferences, SharePoint Saturday, Channel 9, and social media.   Personally I hadn’t worked hands-on with the features before.   The idea is simple and practical – everyone uses Excel for data, so why not leverage that as the BI design surface?

Video Content

  • PowerMap screenshots
  • Download PowerMap EXE for Excel 2013
  • Download sample XLS PowerMap workbooks
  • How to play the Chicago sample XLSX

If you found it helpful please leave a comment below.  Enjoy! 

shades_smile

Downloads

 

Watch Video

PowerMap – 6 min video introduction (Excel 2013) from Jeff Jones on Vimeo.

Screenshots

image
image
image
image
image
image
image
image

Colorize PowerShell Transcript with CSS

I use Start-Transcript and Stop-Transcript on nearly all PS1 files I create.   It’s a great way to troubleshoot and easily make detailed log files.   PowerShell gives us Write-Host -ForegroundColor to make console output look snazzy with color.   However, TXT output is flat by comparison without color coding.

Below I have sample code for adding <STYLE> and <DIV> tags to PowerShell Write-Host.  This example uses Get-Process to highlight any process using more than 50MB RAM in yellow and 500MB RAM in red.

After renaming TXT to HTM, we can see with Internet Explorer highlights from Transcript logs after the script runs.  Cool beans!  Please leave a comment if you found this helpful.  

shades_smile

 

Code

# functions
function Get-TranscriptFilePath {
	try {
		$externalHost = $host.gettype().getproperty("ExternalHost",[reflection.bindingflags]"nonpublic,instance").getvalue($host, @())
		$externalhost.gettype().getfield("transcriptFileName", "nonpublic,instance").getvalue($externalhost)
    } catch {
		Write-Warning "This host does not support transcription."
    }
}
# main script
Start-Transcript
$proc = Get-Process |? {$_.WS -gt 10MB}
foreach ($p in $proc) {
	$ws=$p.WS
	$pn=$p.ProcessName
	$c="White"
	if ($ws -gt 50MB) {$c="yellow"}
	if ($ws -gt 500MB) {$c="red"}
	$html="
$ws,$pn
" Write-Host $html -ForegroundColor $c } $tran = Get-TranscriptFilePath Stop-Transcript # format TXT transcript as HTM $filename = $tran.Replace(".txt",".htm") $header = "`n`n`n`n`n" $txt = Get-Content $tran $footer = "`n`n" "$header $txt $footer" | Out-File $filename # launch IE to view HTM start iexplore.exe $filename

 

 

Screenshots

image
color

© Copyright 2016
@ SPJeff

Return to Top ▲Return to Top ▲