PowerShell, JSON, oData and CRM 2011 (or SharePoint 2010)

I am working on how to consume data from/to SharePoint 2010 and from/to CRM 2011. I decided to try and see if I can get the data to display in PowerShell, figuring if I can get it there, I should be able to get it anywhere?  Here is the code to loop through all the Contacts in a CRM 2011 deployment.

Took me a while to figure this out. Should work with any oData source?

$url="http://your.crm.server/Instance/XRMServices/2011/OrganizationData.svc/ContactSet"
$assembly = [Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions")
while ($url){
	$webclient = new-object System.Net.WebClient
	$webclient.UseDefaultCredentials = $true
	$webclient.Headers.Add("Accept", "application/json")
	$webclient.Headers.Add("Content-Type", "application/json; charset=utf-8");
	$dataString=$webclient.DownloadString($url)
	$json=new-object System.Web.Script.Serialization.JavaScriptSerializer
	$data=$json.DeserializeObject($dataString)
	foreach ($result in $data.d.results){
		write-host "$($result.FullName) , $($result.EMailAddress1)"
	}
	Write-Host "Press any key to continue ..."
	$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
	if ($data.d.__next){
		$url=$data.d.__next.ToString()
	}
	else {
		$url=$null
	}
}

To loop through the items of a SharePoint 2010 list, you would change $url to:

$url=”http://sharepoint2010.server.com/_vti_bin/listdata.svc/Announcements”

Not sure if this would be valuable to anyone, but here it is!

How to tell if your PowerShell session is remote

I wanted to write a conditional to prevent certain things from runing if in a remote PSSession.

If you are in a standard PowerShell session the following is returned:

[Environment]::GetCommandLineArgs()[0] = C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

If you are in a remote PSSession:

[Environment]::GetCommandLineArgs()[0] = C:\Windows\system32\wsmprovhost.exe 

How to add custom JavaScript code to all SharePoint 2010 pages (CustomAction)

There are plenty or articles on how to do this. This is more of a note for myself, as I have to “re-learn” this every time I need to customize SharePoint. There are 2 ways (that I know of) that you can add code to every page in SharePoint 2010, 1 by the AdditionalPageHead delegate control, or ,2 by Custom Action. This article is about #2 using a Custom Action. This article is about #1 – Delegate Controls

To add JavaScript to every page via CustomAction:

  1. Start Visual Studio, and create a new Empty SharePoint Project (uncheck the Create Directory for Solution because you salways create the destination directory yourself)
  2. Deploy as a Farm Solution (I have not figured what you can and can’t do with sandboxed solutions yet)
  3. RightCLick the Project and select Add Module and name the Module at the bottom (I name the Module the name of the Document Library where I want to put the file)
  4. Delete Sample.txt and add the javascript file you want (I usually have to go to the correct folder, put the file there, right click the ProjectName and select “Show all files”, then I can include the file in the project).
  5. Chop up the elements.xml file. The final should look like this below:
    1. is changed to (Url is the Doc Library where the file will be added)
    2. is changed to (Remove the path from Url and add the “GhostableInLibrary” part)
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="Test" Url="Test">
    <File Path="Test\jquery-1.7.min.js" Url="jquery-1.7.min.js" Type="GhostableInLibrary" />
  </Module>
</Elements>

Now you need to the code to add the file to the top of every page, add the “CustomAction” stuff below

  <CustomAction
    ScriptSrc="~SiteCollection/Test/jquery-1.7.min.js"
    Location="ScriptLink"
    Sequence="11">
  </CustomAction>

Final looks like this:

Right click the project and package it up.

Common PowerShell commands to work with solutions are (you must create the destination Document Library before you try to install this code):

To add/install
Add-SPSolution H:\Path\To\wsp\Test.wsp
Install-SPSolution Test.wsp -GACDeploy
Update-SPSolution -literalpath  H:\Path\To\wsp\Test.wsp -identity Test.wsp -GACDeploy

To remove
Uninstall-SPSolution Test.wsp
Remove-SPSolution Test.wsp

This results in a new Feature in manage features (Active it!)

A new file in the document library, and the following in the source code for the page. Done!:

How to use Visual Studio to package a SharePoint solution if you don’t have SharePoint installed

I re-image my machine often, and when I fire up a Visual Studio 2010 for the first time, I always get an error “To work with this project, either SharePoint Foundation 2010 or SharePoint Server 2010 must be installed on the system” or “A SharePoint server is not installed on this computer. A SharePoint server must be installed to work with SharePoint projects.”

Instead of installing SharePoint on my local machine, I usually just trick Visual Studio into thinking that SharePoint is installed. This link says to export the RegHive from a real SharePoint server and import it. I can never remember this.

To compile your code, you need to copy the “Microsoft.SharePoint.dll” and Microsoft.SharePoint.Security.dll from “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI” to your local drive and “Add Reference” to your project (Right Click References)

Haven’t worked with remote debugging to much, but this article describes it.

How to tell if your PowerShell function was called by name or by alias

I been wanting to write functions that act differently depending on how they were called. I am not sure if this is good practice or not, but I like the idea. Turns out all you need is “$MyInvocation.InvocationName” Look at they following code:

Function Test-Calling {
if ($MyInvocation.InvocationName -eq "cows"){Write-host "This function was called by an alias ($($MyInvocation.InvocationName))"}
if ($MyInvocation.InvocationName -eq $MyInvocation.MyCommand){Write-host "This function was called by name ($($MyInvocation.MyCommand))"}
}
set-alias cows Test-Calling

If you call the function by alias you get : This function was called by an alias (cows)
If you call the function by it’s name you get: This function was called by name (Test-Calling)

I hope that helps someone.


	

PowerShell script to force download and install WindowsUpdates

I have been using the UpdateHF.vbs vbscript for years to patch all my servers. I wrote a simple HTA to wrap it, and it gets executed by psexec. I wanted to take that script, strip it down, and convert it to PowerShell. My intension was to  run it through a PSSession but I get access denied. Maybe I will try launching it with SCCM?

I found these three scripts, that I chopped to together for a script that I wanted:

Function JBMURPHY-Install-WindowsUpdates {
PARAM([switch]$Install,[switch]$reboot)
	if($(Test-Path &quot;HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired&quot;)){
		if (!($reboot)){
    		write-host &quot;There are pending reboots, please pass the reboot command&quot;
    		return
		}
		else{
		restart-computer
		return
		}
	}

	Write-Host -nonewline &quot; + Searching for Updates: &quot;
	$UpdateSession = New-Object -ComObject Microsoft.Update.Session
	$Updates=$updateSession.CreateupdateSearcher().Search(&quot;IsAssigned=1 and IsHidden=0 and IsInstalled=0&quot;).Updates
	Write-Host &quot; Found [$($Updates.count)] Updates to Download and install`n`n&quot;

	$UpdatesCollection = New-Object -ComObject Microsoft.Update.UpdateColl
	$UpdatesDownloader = $UpdateSession.CreateUpdateDownloader()
	foreach ($Update in $Updates){

		# Add Update to Collection
		if ( $Update.EulaAccepted -eq 0 ) { $Update.AcceptEula() }
		$UpdatesCollection.Add($Update) | out-null

		# Download
		Write-Host -NoNewline &quot; + Downloading Update $($Update.Title)&quot;
		$UpdatesDownloader.Updates = $UpdatesCollection
		$DownloadResult = $UpdatesDownloader.Download()
		$DownloadResultResultCode = switch -exact ($DownloadResult.ResultCode)
		{
		  0   {&quot;NotStarted&quot;}
		  1   {&quot;InProgress&quot;}
		  2   {&quot;Succeeded&quot;}
		  3   {&quot;SucceededWithErrors&quot;}
		  4   {&quot;Failed&quot;}
		  5   {&quot;Aborted&quot;}
		}
		$Message = &quot; [{0}] &quot; -f ($DownloadResultResultCode)
		Write-Host -ForegroundColor Green $message
	}
	if (($Install) -and ($($Updates.count) -gt 0)) {
	write-host &quot;`n`nInstalling updates&quot;
	$Installer = $UpdateSession.CreateUpdateInstaller()
	$Installer.Updates = $UpdatesCollection
	$InstallerResult = $Installer.Install()
	$InstallerResultCode = switch -exact ($InstallerResult.ResultCode)
		{
		  0   {&quot;NotStarted&quot;}
		  1   {&quot;InProgress&quot;}
		  2   {&quot;Succeeded&quot;}
		  3   {&quot;SucceededWithErrors&quot;}
		  4   {&quot;Failed&quot;}
		  5   {&quot;Aborted&quot;}
		}
		$Message = &quot; Installation [{0}] &quot; -f ($InstallerResultCode)
		Write-Host $message
		Write-Host
	}
	if (($reboot) -and ($($Updates.count) -gt 0)) {
	if($(Test-Path &quot;HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired&quot;))
		{
    		write-host &quot;Rebooting&quot;
    		restart-computer
		}
	}
}

Thanks to those that put the original scripts together

PowerShell script to “process” scripts/functions

I was not happy with the code I wrote in this post. The goal was to write my functions with a “generic” naming convention, and then “process them” – change the naming convention to match my employer’s company name. For example JBMURPHY-AD-GetCurrentSite would be “processed” to Company-AD-GetCurrentSite. In the previous post, I just looped thought and created an alias for each function that matched a RegEx.

I think figured out a better way. Instead of creating aliases, I read the contents of the script line by line, replacing strings as I go, and then create a new file with the new naming conventions.

First I created a hash table with my search and replace strings:

	$SearchAndReplace = @{
	"JBMURPHY-" = "COMPANY-";
	"server.domain.com" = "realservername.company.com";
	}

Next I loop through the files, get their content line by line, loop through the hash table replacing the matching text and output to a temp file.

      foreach ($file in $(gci $SourcePath)) {
    	$tempFile = [System.IO.Path]::GetTempFileName()
    	get-content $file | %{
    	$OutPut=$_
    	ForEach ($key in $SearchAndReplace.Keys) {
    	  $OutPut=$OutPut -Replace $key,$SearchAndReplace[$key]
    	}
    	$OutPut >> $tempFile
    	}
    	move-item $tempFile $destination -force
    	}

Much cleaner, and I can keep adding search and replace terms to my hash table.

PowerShell script to make a WinPE USB drive

I wanted to take my previous set of scripts to create a WinPE environment  a step further. I wanted a script to create a bootable WinPE USB drive (UFD).

Here is that script (again it is numbered to indicate the order in which to run things). I borrowed the diskpart stuff from here:

Function JBMURPHY-WinPE-7MakeUFD{
        Param($OSArchitecture="x86",$RootDirectory="c:\PE\winpe_$OSArchitecture\ISO")
$UFD=Get-WmiObject -Class Win32_LogicalDisk | Where-Object {($_.DriveType -eq 2) -and ($_.DeviceID -ne "A:")}
If ($UFD.Count -eq 0){
Write-host "Can't find any UFDs"
return
}
"list disk" | diskpart
$DriveToUse=read-host "`nWhat disk do you want to use (just the number)"
If (!($DriveToUse)){exit}

$command= @"
select disk $DriveToUse
clean
create partition primary
select partition 1
format fs=fat32 quick
active
assign LETTER=K
"@

$command|
DiskPart |
Where-Object { $_.Length -gt 0 } |
Foreach-Object { Write-Progress -Activity "Creating New UFD" -Status $_ -Id 1}

copy-item -verbose "$RootDirectory\*" "K:\" -recurse
}

Powered by WordPress. Designed by WooThemes