7
votes

I have written a script that inserts some test data into a document library. I intend to use it as a post-deployment step in Visual Studio 2010, so that the library is not empty after a retract & deploy.

The relevant portions of the script are:

Install.ps1:

$scriptDirectory = Split-Path -Path $script:MyInvocation.MyCommand.Path -Parent
. "$scriptDirectory\Include.ps1"

$webUrl = "http://localhost/the_site_name"
$web = Get-SPWeb($webUrl)
...

Include.ps1:

function global:Get-SPSite($url)
{ 
    return new-Object Microsoft.SharePoint.SPSite($url) 
} 
function global:Get-SPWeb($url,$site) 
{ 
    if($site -ne $null -and $url -ne $null){"Url OR Site can be given"; return} 

    #if SPSite is not given, we have to get it... 
    if($site -eq $null){ 
        $site = Get-SPSite($url); 

    ...
} 

It works fine when run as follows from the command line, even immediately after a Visual Studio re-deploy:

powershell \source\ProjectFiles\TestData\Install.ps1

However, it does not work when I use the exact same command as a post-deployment command line in the SharePoint project's properties in Visual Studio:

Run Post-Deployment Command:
New-Object : Exception calling ".ctor" with "1" argument(s): "The Web applicati
on at http://localhost/the_site_name could not be found. Verify that you have t
yped the URL correctly. If the URL should be serving existing content, the syst
em administrator may need to add a new request URL mapping to the intended appl
ication."
At C:\source\ProjectFiles\TestData\Include.ps1:15 char:18
+ return new-Object <<<<  Microsoft.SharePoint.SPSite($url) 
    + CategoryInfo          : InvalidOperation: (:) [New-Object], MethodInvoca 
   tionException
    + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.Power 
   Shell.Commands.NewObjectCommand

Interestingly, I can reproduce the error on the command line if I run:

c:\windows\Syswow64\WindowsPowerShell\v1.0\powershell \source\ProjectFiles\TestData\Install.ps1

However, the post-deployment command fails even if I explicitly run \windows\System32\WindowsPowerShell\v1.0\powershell and \windows\Syswow64\WindowsPowerShell\v1.0\powershell.

Update: Solution found

I seem to be having a similar problem to the one discussed here:

http://social.technet.microsoft.com/Forums/en-US/sharepoint2010programming/thread/faa25866-330b-4e60-8eee-bd72dc9fa5be

I cannot access a 64-bit SharePoint API using 32-bit clients. Because Visual Studio is 32-bit, the post-deployment action will run in a 32-bit process and will fail. There is, however, a 64-bit MSBuild. If we let it run the PowerShell script, all is fine.

Wrap the script in an MSBuild file such as this:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Install" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="Install">
    <Exec Command="powershell .\Install" />
  </Target>
</Project>

Then, set the post-deployment command line to:

%WinDir%\Microsoft.NET\Framework64\v4.0.30319\MSBuild $(SolutionDir)\ProjectFiles\TestData\Install.msbuild
4

4 Answers

5
votes

Use

%WINDIR%\SysNative\WindowsPowerShell\v1.0\powershell.exe

It’s important that you use the virtual path of %WINDIR%\SysNative and not the actual path of C:\Windows\System32. The reason for this is that Visual Studio 2010 is a 32-bit application that needs to call the 64-bit version of powershell.exe to successfully load the Microsoft.SharePoint.Powershell snap-in.

(c)"Inside Microsoft SharePoint 2010", Microsoft Press, Mar 2011

2
votes

I had same situation, I needed the Post Deployment powershell script to create dummy data for lists on my local instance. I tried several other ways even using the MSBuild with the .msbuild file as suggested above, but i could not all the variables and had to hard code the file with path and url, this is not what i wanted.

I finally figured out a way to explicitly calling the 64-Bit powershell.exe

I know the 64-bit file has to be there on hard dirve. I know that WinSXS folder has all the files. So quick search for powershell.exe in C:\Windows\winsxs folder i got two files so i grabbed the path for one in amd64 folder.

This is what i have as command in post deployment option

C:\Windows\winsxs\amd64_microsoft-windows-powershell-exe_31bf3856ad364e35_6.1.7600.16385_none_c50af05b1be3aa2b\powershell.exe -command "&{$(ProjectDir)PowerShell\dataload.ps1 -xmlPath "$(ProjectDir)PowerShell\dataload.xml" -webUrl "$(SharePointSiteUrl)"}"

I hope this will help someone in future.

1
votes

Visual Studio is a 32-bit application, so in 64-bit Windows it runs in a simulated 32-bit environment.

Strangely, the 32-bit environment is called "WoW64" (when 32-bit Windows did this for 16-bit apps, it was called "WoW16". The "WoW" part means "Windows on Windows".

It's similarly strange that "System32" didn't become "System64" with 64-bit Windows. The "32" is from the 16-bit -> 32-bit transition, to differentiate from "System". Whatever, that's legacy/compatibility for you.

In WoW64, everything looks like a 32-bit Windows.

For example, c:\windows\system32 just points to c:\windows\syswow64. 32-bit applications can't (easily) reach anything 64-bit.

It is possible to use PowerShell Remoting to get a 64-bit PowerShell session from a 32-bit environment.

PS>gci env:PROCESSOR_ARCH*

Name                           Value
----                           -----
PROCESSOR_ARCHITECTURE         x86
PROCESSOR_ARCHITEW6432         AMD64


PS>Invoke-Command -ConfigurationName Microsoft.PowerShell -ComputerName LOCALHOST {  gci env:PROCESSOR_ARCH* }

Name                           Value                                        PSComputerName
----                           -----                                        --------------
PROCESSOR_ARCHITECTURE         AMD64                                        localhost
0
votes

I have success doing this as a post deployment command:

%comspec% /c powershell -File "c:\foo\bar.ps1"