Archives

Archives / 2007 / October
  • Powershell: Is a SharePoint solution installed or deployed?

    I was having some fun with PowerShell to talks against the SharePoint object model. I needed to know if a SharePoint solution was installed and if it was deployed. I got to the code below. Might be handy for someone to see how easy it is to get info out of SharePoint.

    And the purpose I need it for? In our Macaw Solutions Factory we have a development build and a package build. Development build for SharePoint deploys everything to the bin folder of one or more web applications. Package build creates a solution package (.wsp file) that does install assemblies to the GAC. If this solutions package is deployed on the development machine, we want to detect that, because you will not see any changes after compile in a development build. The GAC assemblies have precedence over the assemblies in the web application bin folder.

    So here is the code, have fun with it.

    [void][reflection.assembly]::LoadWithPartialName("Microsoft.SharePoint")
    

    function global:Test-SharePointSolution { param ( $solutionName = $(throw 'Missing: solutionName'), [switch]$installed, [switch]$deployed )

    </span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)"> (</span><span style="color: rgb(0,0,0)">!</span><span style="color: rgb(0,0,0)">(</span><span style="color: rgb(0,0,255)">$solutionName</span><span style="color: rgb(0,0,0)">.EndsWith(</span><span style="color: rgb(0,0,128)">'</span><span style="color: rgb(0,0,128)">.cab</span><span style="color: rgb(0,0,128)">'</span><span style="color: rgb(0,0,0)">) </span><span style="color: rgb(0,0,0)">-</span><span style="color: rgb(0,128,128)">or</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">$solutionName</span><span style="color: rgb(0,0,0)">.EndsWith(</span><span style="color: rgb(0,0,128)">'</span><span style="color: rgb(0,0,128)">.wsp</span><span style="color: rgb(0,0,128)">'</span><span style="color: rgb(0,0,0)">) </span><span style="color: rgb(0,0,0)">-</span><span style="color: rgb(0,128,128)">or</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">$solutionName</span><span style="color: rgb(0,0,0)">.EndsWith(</span><span style="color: rgb(0,0,128)">'</span><span style="color: rgb(0,0,128)">.wpp</span><span style="color: rgb(0,0,128)">'</span><span style="color: rgb(0,0,0)">)))
    {
        throw </span><span style="color: rgb(0,0,128)">"</span><span style="color: rgb(0,0,128)">solution name '$solutionName' should end with .cab, .wsp or .wpp</span><span style="color: rgb(0,0,128)">"</span><span style="color: rgb(0,0,0)">
    }
    
    </span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)"> (</span><span style="color: rgb(0,0,255)">$installed</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,0)">-</span><span style="color: rgb(0,128,128)">and</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">$deployed</span><span style="color: rgb(0,0,0)">)
    {
        throw </span><span style="color: rgb(0,0,128)">"</span><span style="color: rgb(0,0,128)">Select either the '-installed' switch parameter or the '-deployed' switch parameter, not both at the same time</span><span style="color: rgb(0,0,128)">"</span><span style="color: rgb(0,0,0)">
    }
    
    </span><span style="color: rgb(0,0,255)">$farm</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)"> [Microsoft.SharePoint.Administration.SPFarm]::get_Local()
    </span><span style="color: rgb(0,0,255)">$solutions</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">$farm</span><span style="color: rgb(0,0,0)">.get_Solutions()
    </span><span style="color: rgb(0,0,255)">$solutioncheck</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">$false</span><span style="color: rgb(0,0,0)">
    </span><span style="color: rgb(0,0,255)">foreach</span><span style="color: rgb(0,0,0)"> (</span><span style="color: rgb(0,0,255)">$solution</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">in</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">$solutions</span><span style="color: rgb(0,0,0)">)
    {
        </span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)"> (</span><span style="color: rgb(0,0,255)">$solution</span><span style="color: rgb(0,0,0)">.Name </span><span style="color: rgb(0,0,255)">-ieq</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">$solutionName</span><span style="color: rgb(0,0,0)">)
        {
            </span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)"> (</span><span style="color: rgb(0,0,255)">$deployed</span><span style="color: rgb(0,0,0)">)
            {
                </span><span style="color: rgb(0,0,255)">$solutioncheck</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">$solution</span><span style="color: rgb(0,0,0)">.Deployed
            }
            </span><span style="color: rgb(0,0,255)">else</span><span style="color: rgb(0,0,0)">
            {
                </span><span style="color: rgb(0,128,0)">#</span><span style="color: rgb(0,128,0)"> installed, is always true if we get here</span><span style="color: rgb(0,128,0)">
    

    $solutioncheck = $true } break } } return $solutioncheck }

    Test-SharePointSolution -solutionName wikidiscussionsolution.wsp -installed Test-SharePointSolution -solutionName wikidiscussionsolution.wsp -deployed

  • PowerShell: Creating a SharePoint solution package (WSP file) with CAS

    I need to add some code access security information to a SharePoint solution package manifest file. Given the assembly file we can retrieve the required assembly info, and with some xml magic in PowerShell create some result xml. It is not actually the exact code I use in my solution, but it shows the job...

    # function: GetAssemblyInfo
    #
    Arguments: $assemblyFile - path to assembly file to determine information from
    #
    Returns: Hashtable with the following keys: PublicKeyBlob, Name, Version
    function global:GetAssemblyInfo
    {
        param
        (
           
    $assemblyFile = $(Throw'Missing: assemblyFile')
        )
       
       
    if (!(Test-Path -Path $assemblyFile))
        {
            Throw
    "Assembly file '$assemblyFile' does not exist"
        }
       
       
    # Secutil returns:
       #Line 0: Microsoft (R) .NET Framework SecUtil 2.0.50727.42
       #Line 1: Copyright (c) Microsoft Corporation.  All rights reserved.
       #Line 2:
       #Line 3: Public Key =
       #Line 4: 0x00240000048000009400000006020000002400005253413100040000010001003BBC200DC39F9419851471C4AF65A91540C5904D72694CDE6DF63427FAD8D180630538338E557D90BA4F18A2EF6F44F3A53A5C7CFE625F4954D53B4FF9CF700226FDF13F04731EDED323B1821BA38C5F310231007E7AF862F497174A127BD42C0FA4FAFF1154910B48E177E090888A7745145ED4F4F7BB75D28D6616961A71E3
       #Line 5: Name =
       #Line 6: Macaw.Mast.Wss3.Templates.Presentation.WebAppUI
       #Line 7: Version =
       #Line 8: 1.0.0.0
       #Line 9: Success
       $secutilExe = 'C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\SecUtil.exe'

       
    $resultLines = (& $secutilExe -hex -s $assemblyFile)
       
    if ($resultLines[9]-ne 'Success')
        {
            Throw
    "secutil.exe can't determine assembly information from assembly file '$assemblyFile', secutil.exe command failed"
        }
        @{
    'PublicKeyBlob' = $resultLines[4];'Name' = $resultLines[6];'Version' = $resultLines[8] }
    }

    $assemblyFile = 'C:\Inetpub\wwwroot\wss\VirtualDirectories\1000\bin\Macaw.Mast.Wss3.Templates.Presentation.WebAppUI.dll'
    $result = GetAssemblyInfo -assemblyFile $assemblyFile
    $result

    This will result in the following output:

    We can now create out code access security information (in this case in a SharePoint solution package manifest.xml file with code similar to the following code:

    $assemblyInfo = GetAssemblyInfo -assemblyFile $assemblyFile
    $policyItem = @"
    <PolicyItem>
        <PermissionSet class="NamedPermissionSet" version="1" Description="Macaw Solution Factory generated permissionSet" Name="$($assemblyInfo.Name)-PermissionSet">
            <IPermission class="WebPermission" version="1">
                <ConnectAccess>
                    <URI uri="`$OriginHost`$" />
                </ConnectAccess>
            </IPermission>
            <IPermission class="SmtpPermission" version="1" Access="Connect" />
            <IPermission class="SharePointPermission" version="1" ObjectModel="True" />
            <IPermission class="PrintingPermission" version="1" Level="DefaultPrinting" />
            <IPermission class="FileIOPermission" version="1" Read="`$AppDir`$" Write="`$AppDir`$" Append="`$AppDir`$" PathDiscovery="`$AppDir`$" />
            <IPermission class="EnvironmentPermission" version="1" Read="TEMP;TMP;USERNAME;OS;COMPUTERNAME" />
            <IPermission class="SqlClientPermission" version="1" Unrestricted="true" />
            <IPermission class="SecurityPermission" version="1" Flags="Assertion, Execution, ControlThread, ControlPrincipal, RemotingConfiguration" />
            <IPermission class="DnsPermission" version="1" Unrestricted="true" />
            <IPermission class="WebPartPermission" version="1" Connections="True" />
            <IPermission class="AspNetHostingPermission" version="1" Level="Medium" />
            <IPermission class="IsolatedStorageFilePermission" version="1" Allowed="AssemblyIsolationByUser" UserQuota="9223372036854775807" />
        </PermissionSet>
    <Assemblies>
    	<Assembly Name="$($assemblyInfo.Name)" Version="$($assemblyInfo.Version)" PublicKeyBlob="$($assemblyInfo.PublicKeyBlob)" />
    </Assemblies>
    </PolicyItem>
    "@
    
    $xmltext = @"
    <?xml version="1.0" encoding="utf-8"?>
    <Solution DeploymentServerType="WebFrontEnd" SolutionId="2244989E-9DA9-4a5d-9767-0D8F387181B7" ResetWebServer="true">
        <CodeAccessSecurity>
        </CodeAccessSecurity>
    </Solution>
    "@
    
    [xml]$xmlDoc = $xmltext
    $xmlDoc.SelectSingleNode('/Solution/CodeAccessSecurity').set_InnerXml($policyItem)
    $xmlDoc.get_InnerXml()
    

     

    This will results in the following output:

    In the production of a real SharePoint solution package a lot more is happening, but this showcases some of the PowerShell power you can use to get the job done.