Archives

Archives / 2011
  • PowerShell: script to show detailed information on a set of assemblies

    To get some insight in your assemblies you can use the script below. It gets all information out that I required, but you can extend it if you need for example all assemblies an assembly depends on.

    One thing that was new for we was that I needed functions in a script that can be executed in a pipeline. You can define these functions in the begin {} block.

    Save the following code as Get-AssemblyInformation.ps1. Call for example as follows:

    get-childitem -path "D:\MyProject\tools" -filter '*.dll' -recurse | D:\bin\Get-AssemblyInformation.ps1

    Or if all files are in a folder:

    Get-AssemblyInformation.ps1 –Path "D:\MyProject\tools"

    Get-AssemblyInformation.s1
    1. #requires -version 2.0
    2.  
    3. [CmdletBinding(DefaultParameterSetName="Path")]
    4. param(
    5.    [Parameter(Mandatory=$true,
    6.               Position=0,
    7.               ParameterSetName="Path",
    8.               ValueFromPipeline=$true,
    9.               ValueFromPipelineByPropertyName=$true)]
    10.    [ValidateNotNullOrEmpty()]
    11.    [string[]]
    12.    $Path,
    13.    
    14.    [Alias("PSPath")]
    15.    [Parameter(Mandatory=$true,
    16.               Position=0,
    17.               ParameterSetName="LiteralPath",
    18.               ValueFromPipelineByPropertyName=$true)]
    19.    [ValidateNotNullOrEmpty()]
    20.    [string[]]
    21.    $LiteralPath
    22. )
    23.  
    24. Begin
    25. {
    26.    Set-StrictMode -Version 2.0
    27.     
    28.     function Get-AssemblyCustomProperty
    29.     {
    30.         param
    31.         (
    32.             $assembly,
    33.             $TypeNameLike,
    34.             $Property = $null
    35.         )
    36.         
    37.         $value = $null
    38.         foreach ($attribute in $assembly.GetCustomAttributes($false))
    39.         {
    40.             if ($attribute.GetType().ToString() -like "*$TypeNameLike*")
    41.             {
    42.                 if ($Property -ne $null)
    43.                 {
    44.                     # Select-Object -ExpandProperty fails if property value is $null
    45.                     try {
    46.                         $value = $attribute | Select-Object -ExpandProperty $Property
    47.                     }
    48.                     catch {
    49.                         $value = $null
    50.                     }
    51.                 }
    52.                 else
    53.                 {
    54.                     $value = $attribute
    55.                 }
    56.                 break;
    57.             }
    58.         }
    59.         
    60.         $value
    61.     }
    62.  
    63.     function Get-AssemblyInfoAsHashtable
    64.     {
    65.         param
    66.         (
    67.             [System.Reflection.Assembly]$assembly
    68.         )
    69.         $info = @{}
    70.             
    71.         $info.FullName = $assembly.FullName
    72.         $info.Name = $assembly.ManifestModule.Name
    73.         $info.Location = $assembly.Location
    74.         $info.ImageRuntimeVersion = $assembly.ImageRuntimeVersion
    75.         $info.GlobalAssemblyCache = $assembly.GlobalAssemblyCache
    76.         $info.Title = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'Title' -Property 'Title'
    77.         $info.Configuration = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'Configuration' -Property 'Configuration'
    78.         $info.Description = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'Description' -Property 'Description'
    79.         $info.Company = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'Company' -Property 'Company'
    80.         $info.Product = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'Product' -Property 'Product'
    81.         $info.Copyright = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'Copyright' -Property 'Copyright'
    82.         $info.Trademark = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'Trademark' -Property 'Trademark'
    83.         $info.DelaySign = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'DelaySign' -Property 'DelaySign'
    84.         $info.KeyName = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'KeyName' -Property 'KeyName'
    85.         $info.ClsCompliant = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'ClsCompliant' -Property 'IsCompliant'
    86.         $info.ComVisible = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'ComVisible' -Property 'Value'
    87.         $info.IsJITTrackingEnabled = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'System.Diagnostics.DebuggableAttribute' -Property 'IsJITTrackingEnabled'
    88.         $info.IsJITOptimizerDisabled = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'System.Diagnostics.DebuggableAttribute' -Property 'IsJITOptimizerDisabled'
    89.         $info.DebuggingFlags = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'System.Diagnostics.DebuggableAttribute' -Property 'DebuggingFlags'
    90.         $info.CompilationRelaxations = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'CompilationRelaxations' -Property 'CompilationRelaxations'
    91.         $info.WrapNonExceptionThrows = Get-AssemblyCustomProperty -Assembly $assembly -TypeNameLike 'System.Runtime.CompilerServices.RuntimeCompatibilityAttribute' -Property 'WrapNonExceptionThrows'
    92.  
    93.         $info
    94.     }
    95.  
    96.     function Get-AssemblyInformation
    97.     {
    98.         param
    99.         (
    100.             $AssemblyFile
    101.         )
    102.  
    103.         try
    104.         {
    105.             $assembly = [Reflection.Assembly]::LoadFile($AssemblyFile)
    106.             $info = Get-AssemblyInfoAsHashtable -assembly $assembly
    107.             $info.IsValidDotNetAssembly  = $true
    108.         }
    109.         catch { # it is not a valid dotnet assembly
    110.             $info = @{
    111.                 FullName = $AssemblyFile;
    112.                 Name = Split-Path -Path $AssemblyFile -Leaf;
    113.                 IsValidDotNetAssembly = $false
    114.             }
    115.         }
    116.         
    117.         $info
    118.     }
    119. }
    120.  
    121. Process
    122. {
    123.    if ($psCmdlet.ParameterSetName -eq "Path")
    124.    {
    125.        # In the non-literal case we may need to resolve a wildcarded path
    126.         $resolvedPaths = @()
    127.        foreach ($apath in $Path)
    128.        {
    129.            $resolvedPaths += @(Resolve-Path $apath | Foreach { $_.Path })
    130.        }
    131.    }
    132.    else
    133.    {
    134.        $resolvedPaths = $LiteralPath
    135.    }
    136.    
    137.            
    138.    foreach ($rpath in $resolvedPaths)
    139.    {
    140.        $PathIntrinsics = $ExecutionContext.SessionState.Path
    141.        
    142.        if ($PathIntrinsics.IsProviderQualified($rpath))
    143.        {
    144.            $rpath = $PathIntrinsics.GetUnresolvedProviderPathFromPSPath($rpath)
    145.        }
    146.        
    147.         $assemblyInfo = Get-AssemblyInformation -AssemblyFile $rpath
    148.         Write-Host "***************************************************************************************************"
    149.         Write-Host "**************** $($assemblyInfo.Name)"
    150.         Write-Host "***************************************************************************************************"
    151.         $assemblyInfo
    152.         Write-Host ""
    153.     }
    154. }

    Thanks goes to Keith Hill for some of the more advances parameter stuff which is lent from http://rkeithhill.wordpress.com/2009/01/28/tail-content-%E2%80%93-better-performance-for-grabbing-last-lines-from-large-ascii-log-files/.

  • PowerShell: PrimalForms and the TFS source control provider

    I’m using PrimalForms 2011 for designing PowerShell front-ends and editing some PowerShell. Code is under source control (TFS), and PrimalForms has a Source Control tab. Initially the “Providers” section was empty, after installing Team Foundation Server MSSCCI Provider 2010 and restarting PrimalForms I got my provider:

    image

    If you open a file under TFS source control you can now right-click on the file to do our source control operations:

    image

  • Persisting custom properties on a Visual Studio project using object model

    It is possible to persist custom properties in your Visual Studio project. I will show how using some PowerShell code in the NuGet console.

    Note that VariableValue() persist in session, the call to VariablePersists() writes to the project file for persistance over sessions.

    The Global object has the following methods:

    PM> (Get-Project).Globals | gm    TypeName: System.__ComObject#{e68a3e0e-b435-4dde-86b7-f5adefc19df2}
     
    Name             MemberType            Definition                                  ----             ----------            ----------                                  VariableExists   ParameterizedProperty bool VariableExists (string) {get}          VariablePersists ParameterizedProperty bool VariablePersists (string) {get} {set}  VariableValue    ParameterizedProperty Variant VariableValue (string) {get} {set}  DTE              Property              DTE DTE () {get}                            Parent           Property              IDispatch Parent () {get}                   VariableNames    Property              Variant VariableNames () {get}             

    Some sample code:

    PM> (Get-Project –name "MyProject").Globals.VariableValue("FirstProperty") = "Value1"
    PM> (Get-Project –name "MyProject").Globals.VariableValue("SecondProperty") = "Value2"
    PM> (Get-Project –name "MyProject").Globals.VariablePersists("FirstProperty") = $True   PM> (Get-Project –name "MyProject").Globals.VariablePersists("SecondProperty") = $True   PM> (Get-Project –name "MyProject").Globals.VariableValue("FirstProperty")
    Value1
    PM> (Get-Project –name "MyProject").Globals.VariablePersists("SecondProperty")
    True
    PM> (Get-Project –name "MyProject").Globals.VariableNames
    FirstProperty
    SecondProperty
    PM> (Get-Project –name "MyProject").Globals.VariableExists("DoesNotExist")
    False
    PM> (Get-Project –name "MyProject").Globals.VariableExists("FirstProperty")
    True

    And if you look at your .csproj file:

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      :
      <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />   <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\SharePointTools\Microsoft.VisualStudio.SharePoint.targets" />   <ProjectExtensions>     <VisualStudio>       <UserProperties SecondProperty="Value2" FirstProperty="Value1" />
        </VisualStudio>   </ProjectExtensions>
    </Project>
  • Set the properties on your Visual Studio project

    Reminder to self:

    Settings properties on a Visual Studio project,like DefaultNamespace and AssemblyName.

    In NuGet console window:

    (Get-Project).Properties.Item("DefaultNamespace").Value = "HelloWorld"
    Available properties on a simple class library project project:
    PM> (Get-Project).Properties | Select-Object -Property Name,Value

    Name                           Value
    ----                           -----TargetFrameworkMoniker         .NETFramework,Version=v4.0                                     
    ComVisible                     False                                                          
    EnableSecurityDebugging        True                                                           
    OptionCompare                  0                                                              
    StartupObject                                                                                 
    ManifestCertificateThumbprint                                                                 
    Trademark                                                                                     
    Title                          FactoryExtensionsTemplate                                      
    AssemblyOriginatorKeyFileType  1                                                              
    FileName                       FactoryExtensions3.csproj                                      
    WebServer                                                                                     
    AssemblyOriginatorKeyMode      0                                                              
    AssemblyKeyContainerName                                                                      
    ProjectType                    0                                                              
    ReferencePath                                                                                 
    PreBuildEvent                                                                                 
    Copyright                      Copyright © Microsoft 2011                                     
    ApplicationIcon                                                                               
    ExcludedPermissions                                                                           
    RunPostBuildEvent              1                                                              
    DefaultTargetSchema            1                                                              
    RootNamespace                  HelloWorld                                                     
    ManifestTimestampUrl                                                                          
    ManifestKeyFile                                                                               
    DebugSecurityZoneURL                                                                          
    Product                        FactoryExtensionsTemplate                                      
    PostBuildEvent                                                                                
    OptionStrict                   0                                                              
    DefaultHTMLPageLayout          1                                                              
    DelaySign                      False                                                          
    OutputType                     2                                                              
    NeutralResourcesLanguage                                                                      
    OptionExplicit                 1                                                              
    OutputFileName                 FactoryExtensions.dll                                          
    ServerExtensionsVersion                                                                       
    AssemblyGuid                   919e5f68-ec7d-4508-aa24-ee3da14edd84                           
    GenerateManifests              False                                                          
    AssemblyVersion                1.0.0.0                                                        
    Win32ResourceFile                                                                             
    Description                                                                                   
    URL                            file:///d:\temp3\Acme.Portal\FactoryExtensions3\               
    DefaultClientScript            0                                                              
    TargetFramework                262144                                                         
    SignManifests                  False                                                          
    OfflineURL                                                                                    
    WebServerVersion                                                                              
    Publish                        System.__ComObject                                             
    AssemblyType                   0                                                              
    FullPath                       d:\temp3\Acme.Portal\FactoryExtensions3\                       
    WebAccessMethod                                                                               
    AssemblyKeyProviderName                                                                       
    TypeComplianceDiagnostics      False                                                          
    Company                        Microsoft                                                      
    ActiveFileSharePath                                                                           
    AssemblyOriginatorKeyFile                                                                     
    ApplicationManifest            DefaultManifest                                                
    AssemblyFileVersion            1.0.0.0                                                        
    AspnetVersion                                                                                 
    FileSharePath                                                                                 
    AssemblyName                   FactoryExtensions                                              
    LocalPath                      d:\temp3\Acme.Portal\FactoryExtensions3\                       
    DefaultNamespace               HelloWorld                                                     
    LinkRepair                     False                                                          
    TargetZone                                                                                    
    SignAssembly                   False                                                          

  • Nuget 1.3: some observations

    I’m testing out a lot of features from NuGet for extending our software factory. In this testing I made the following observations:

  • Tools\Init.ps1 is only executed if the Content folder contains a file [See: http://nuget.codeplex.com/discussions/257282#post611456]
  • Tools\Install.ps1 is executed AFTER Tools\Init.ps1
  • If you have an empty solution without projects and install a package then the Tools\Init.ps1 is executed, but Tools\Install.ps1 is NOT executed
  • Tools\Install.ps1 is executed when a package is installed for a specific project
  • The $project parameter is always $null in Tools\Init.ps1
  • Don’t use the nuget.config file to configure your packages folder, it is an undocumented experimental feature which results in unexpected behaviour
  • Packages are installed at the solution level in a folder packages next to your solution file (.sln file)
  • Each project that has packages installed writes these installed packages and the installed packages it depends on in a packages.config file that is located in the project folder next to the project file (for example .csproj file)
    <?xml version="1.0" encoding="utf-8"?>
    <packages>   <package id="EntityFramework" version="4.1.10331.0" />   <package id="T4Scaffolding" version="1.0.0" />   <package id="MacawSolutionsFactory-Core" version="1.0.0" />   <package id="MacawSolutionsFactory-Spf2010" version="1.0.0" />
    </packages>
  • The packages folder contains a file repositories.config referencing the packages.config files of all projects in the solution that has packages installed
    <?xml version="1.0" encoding="utf-8"?>
    <repositories>   <repository path="..\srcfactory\Core\packages.config" />   <repository path="..\srcfactory\Spf2010\packages.config" />
    </repositories>
  • The repositories.config and packages.config files are used for “reference counting” packages. If uninstall-package is executed on a package, and there is no more packages.config file containing the package, the package folder is removed from the packages folder
  • The parameter $installPath points to the folder where the package is installed
  • The parameter $rootPath points to the Tools folder in the  folder where the package is installed
  • The parameter $package is a package object describing information about the package. To see the values of the properties add the code $package | format-custom –depth 1 to your Init.ps1/Install.ps1/Uninstall.ps1.
  • The parameter $project is an EnvDTE Project object ($null in Tools\Init.ps1, this script is executed at the solution level)
  • Uninstall-package removes a package, but does not automatically cascade delete the packages that were installed because the package was depending on these packages. Use the parameter –RemoveDependencies to do this
  • Scaffolders (see T4Scaffolding package for more info) are only available in the project where the package containing the scaffolders in installed. To have access to the scaffolders in all projects, add the project at the solution level
  • A package can’t be installed at the solution level using the install-package command, use the command-line NuGet.exe tool to do this
  • A good place for more information on how to create packages, what the parameters mean, etc is http://nuget.codeplex.com/documentation?title=Creating%20a%20Package
  • NuGet is a very active open source project with a lot of great discussions on http://nuget.codeplex.com/discussions

    You can execute the command Install-Package NuGetPSVariables to validate some of the above observations.

    UPDATE 1:

    • Great NuGet documentation on http://docs.nuget.org (uses open source MarkDown based documentation system: http://nugetdocs.codeplex.com) [Thanks Cyriel!]
    • <li><font color="#ff0000">No files required in Content folder for Init.ps1 to run</font> </li>
      
      <li><font color="#ff0000">If a project is removed from a solution (and not deleted from the filesystem) the <strong>packages.config</strong> file in the removed project is still referenced in the <strong>packages\repositories.config</strong> file. It is now not possible to remove a package at solution level that is also referenced by the removed project. Delete the removed project from the filesystem to solve this issue.</font> </li>
      
      <li><font color="#ff0000">Add the <strong>packages.config</strong> files in your project folders to your Visual Studio project (Show hidden files on project, Include in project) and include in source control. Set the build action to none otherwise the file could be included in the project output [Thanks Marino!]</font> </li>
      
      <li><font color="#ff0000">Add the <strong>packages</strong> folder to source control (or at least the <strong>packages\repositories.config</strong> file)</font> </li>
      

    UPDATE 2:

    • When a solution is loaded the script Tools\Init.ps1 of all packages is executed. In execution of the Init.ps1 scripts the package dependencies are respected. So if package A depends on package B, the script B\Tools\Init.ps1 is executed before script A\Tools\Init.ps1.

    UPDATE 3:

    • When a package is installed, the Tools folder is added to the PATH environment variable ($env:PATH) with process scope, so scripts and applications in the tools folder can be directly executed from the NuGet console. Note that if you uninstall the package, the Tools folder of the uninstalled package in NOT removed from the PATH. When the package is installed again, the Tools folder is added to the again, so it appears twice in the PATH.

  • NuGet: refreshing NuGet packages in packages folder during development

    I'm working on NuGet packages in a Visual Studio project. On build I publish a new version of my nuget package to a repository (a directory on my system).

    I don't increment version numbers after each change, i only want to do that on published versions of my packages.

    To test out changes to the package in my solution where I already reference the package I want to pull in a new version of the package that has the same version number.

    install-package does not have a -force option to force uninstall/install of the package with an unchanged version number.

    The script below solves this issue. Save as Update-NuGetPackages.ps1 and put next to NuGet.exe.

    Test out first on a copy of your Packages folder (copy to PackagesTest), so you have all parameters right. The script deletes all existing packages.

    UPDATE: Updated the code so if package is deleted and install fails, an empty folder with the package name is created so after fixing the error the script can be called again to retry the update.

    Update-NuGetPackages.ps1
    1. <#
    2.     .SYNOPSIS
    3.         Update NuGet packages with same version of package.
    4.  
    5.     .DESCRIPTION
    6.         During the development cycle version numbers of packages are often not changed,
    7.         but the contents of the package itself is updates. Update-NuGetPackages.ps1
    8.         refreshes all packages in a given packages directory.
    9.         
    10.         By default don't specify any sources, so NuGet.exe (version 1.3 and later) will use
    11.         the NuGet.config which is stored in the AppData folder and shared between Visual Studio
    12.         and NuGet.exe
    13.  
    14.     .PARAMETER  PackagesPath
    15.         Path to folder containing the packages to refresh.
    16.  
    17.     .PARAMETER  PackagesSource
    18.         Source where packages should be installed from. Post version 1.3 of NuGet.exe
    19.         supports specifying multiple sources separated by ';'.
    20.         Source paths may not contain PSDrives in its path, like product:\mypath.
    21.         
    22.     .PARAMETER  IncludeDefaultSource
    23.         Switch parameter to specify that the default NuGet packages source
    24.         https://go.microsoft.com/fwlink/?LinkID=206669 should be included as a
    25.         packages source. Don't specify this switch and dont use the PackagesSource
    26.         parameter to let NuGet.exe use the sources specified in the NuGet.config.
    27.         This functionality is available after release version 1.3 of NuGet.exe.
    28.         If used together with the PackagesSource parameter a version newer than
    29.         version 1.3 of NuGet.exe is required.
    30.  
    31.     .EXAMPLE
    32.         PS C:\> Update-NuGetPackages.ps1 -PackagesSource c:\MyProduct\Packages
    33.         Deleting package 'EntityFramework' version '4.1.10331.0'
    34.         Deleting package 'MacawSolutionsFactory-Core' version '1.0.0'
    35.         Deleting package 'MacawSolutionsFactory-Spf2010' version '1.0.0'
    36.         Deleting package 'T4Scaffolding' version '1.0.0'
    37.         Reinstalling package 'EntityFramework' version '4.1.10331.0'
    38.         Successfully installed 'EntityFramework 4.1.10331.0'.
    39.         Reinstalling package 'MacawSolutionsFactory-Core' version '1.0.0'
    40.         'T4Scaffolding (= 1.0.0)' not installed. Attempting to retrieve dependency from source...
    41.         Done.
    42.         Dependency 'EntityFramework (= 4.1.10311.0)' already installed.
    43.         Successfully installed 'T4Scaffolding 1.0.0'.
    44.         Successfully installed 'MacawSolutionsFactory-Core 1.0.0'.
    45.         Reinstalling package 'MacawSolutionsFactory-Spf2010' version '1.0.0'
    46.         Dependency 'T4Scaffolding (= 1.0.0)' already installed.
    47.         Dependency 'EntityFramework (= 4.1.10311.0)' already installed.
    48.         Successfully installed 'MacawSolutionsFactory-Spf2010 1.0.0'.
    49.         Reinstalling package 'T4Scaffolding' version '1.0.0'
    50.         Dependency 'EntityFramework (= 4.1.10311.0)' already installed.
    51.         'T4Scaffolding 1.0.0' already installed.
    52.         Done.
    53.  
    54.     .EXAMPLE
    55.         PS C:\> Update-NuGetPackages.ps1 -PackagesSource c:\MyProduct\Packages `
    56.                 -PackagesSource "c:\Dist\Feed1;c:\Dist\Feed2" -IncludeDefaultSource
    57.         :
    58.         
    59.     .INPUTS
    60.         System.String,System.String,System.Boolean
    61.  
    62.     .NOTES
    63.         This script must be located next to NuGet.exe.
    64.         
    65.         This script requires a version later than the release version 1.3 of NuGet.exe
    66.         when specifying multiple sources on the commandline and/or using the IncludeDefaultSource
    67.         parameter.
    68.         
    69.         Version: 1.0
    70.         Author: Serge van den Oever (http://weblogs.asp.net/soever)
    71. #>
    72. [CmdletBinding()]
    73. param
    74. (
    75.     [Parameter(Position=0, Mandatory=$true)][String]$PackagesPath,
    76.     [Parameter(Position=1, Mandatory=$false)][String]$PackagesSource = '',
    77.     [Parameter(Position=2, Mandatory=$false)][Switch]$IncludeDefaultSource = $false
    78. )
    79.  
    80. $nugetDefaultSource= 'https://go.microsoft.com/fwlink/?LinkID=206669'
    81.  
    82. function Get-ScriptDirectory
    83. {
    84. $Invocation = (Get-Variable MyInvocation -Scope 1).Value
    85. Split-Path $Invocation.MyCommand.Path
    86. }
    87.  
    88. $nugetExe = Join-Path -Path (Get-ScriptDirectory) -ChildPath 'nuget.exe'
    89. if (-not (Test-Path -Path $nugetExe)) { throw ("Expected NuGet.exe at path '{0}'" -f $nugetExe) }
    90.  
    91. if (-not (Test-Path -Path $PackagesPath)) { throw ("Specified PackagesPath '{0}' does not exist" -f $PackagesPath) }
    92. $PackagesPath = Convert-Path -Path $PackagesPath
    93.  
    94. # Collect packages
    95. $packageFolders = Get-ChildItem -Path $PackagesPath | Where-Object {$_.psIsContainer -eq $true}
    96.  
    97. $packages = @()
    98. if ($packageFolders -ne $null) {
    99.     $packageFolders | ForEach-Object {
    100.         $packageFolder = Convert-Path -Path $_.FullName # Handle case where PSDrive is specified
    101.         $packageFolderName = Split-Path -Path $packageFolder -Leaf
    102.         $parts = $packageFolderName.split('.')
    103.         $packageName = $parts[0]
    104.         $packageVersion = $parts[1..$($parts.length-1)] -join '.'
    105.         $packages += @{
    106.             Name = $packageName;
    107.             Version = $packageVersion;
    108.             Folder = $packageFolder;
    109.         }
    110.     }
    111. }
    112.  
    113. # Delete all package folders
    114. $packages | ForEach-Object {
    115.     Write-Host ("Deleting package '{0}' version '{1}'" -f $_.Name, $_.Version)
    116.     Remove-Item -Recurse -Force -Path $_.Folder -ErrorAction SilentlyContinue
    117.     if (Test-Path -Path $_.Folder) { Write-Warning ("Can't remove folder '{0}'. Make sure it is not locked." -f $_.Folder) }
    118. }
    119.  
    120. # Reinstall all packages
    121. $packages | ForEach-Object {
    122.     Write-Host ("Reinstalling package '{0}' version '{1}'" -f $_.Name, $_.Version)
    123.     if ($IncludeDefaultSource) {
    124.         $source = $nugetDefaultSource
    125.     } else {
    126.         $source = ''
    127.     }
    128.     if ($PackagesSource -ne '') {
    129.         if ($source -ne '') { $source += ';' }
    130.         $source += (Convert-Path -Path $PackagesSource)
    131.     }
    132.     
    133.     if ($source -ne '') {
    134.         & $nugetExe install $_.Name -Version $_.Version -Source $source -OutputDirectory $PackagesPath
    135.     } else {
    136.         & $nugetExe install $_.Name -Version $_.Version -OutputDirectory $PackagesPath
    137.     }
    138.  
    139.     if (-not (Test-Path -Path $_.Folder)) {
    140.         New-Item -Path $_.Folder -Type Directory -Force
    141.         Write-Warning ("Failed to reinstall package '{0}' version '{1}'. Created dummy directory '$($_.Folder). Fix error and try again." -f $_.Name, $_.Version)
    142.     }
    143. }
    144.  
    145. # Call Init.ps1 on all packages
    146. $packages | ForEach-Object {
    147.     $initScript = Join-Path -Path $_.Folder -ChildPath 'Tools\Init.ps1'
    148.     if (Test-Path -Path $initScript)
    149.     {
    150.         $rootPath = $_.Folder
    151.         $toolsPath = Join-Path -Path $_.Folder -ChildPath 'Tools'
    152.         $package = Get-Package -Filter $_.Name
    153.         $project = $null
    154.         
    155.         & $initScript -rootPath $rootPath -toolsPath $toolsPath -package $package -project $project
    156.     }
    157. }
    158.  
    159. Write-Host 'Done.'

  • NuGet: should you check-in packages into source control?

    Interesting discussion at http://nuget.codeplex.com/discussions/230110 about checking in NuGet packages into source control.

    NuGet packages can contain more than a simple libraries, it can contain tools that grow quite big as well. Good example in the NUnit package that contains the total NUnit toolset.

    Do you want all your binaries into source control, it is already preserved in the NuGet feed. You can always reload the packages from the feed. The required packages in a project are available in the packages.config file that is part of your project and checked into source control.

    But what if a package is removed from the feed by the author? That would be bad… on the other hand: in this case shouldn’t you remove a dependency on that package anyway?

    What about a build server not connected to the internet and not being able to get packages from the NuGet feed?

    After reading the discussion I think I would prefer to not check-in packages into source control…

    Just found the following post: https://msmvps.com/blogs/theproblemsolver/archive/2011/04/12/nuget-and-projects-under-source-control.aspx taking the same approach. It describes how you can install all missing packages using the command-line version of nuget.exe with the following command: NuGet install MyProject\packages.config –OutputDirectory Packages

    From the documentation:

    usage: NuGet install packageId|pathToPackagesConfig [options]

    Install a package from a given source. If no source is specified the default feed is used.

         Specify the id and optionally the version of the package to install. If a path to a 
         packages.config file is used instead of an id, all the packages it contains are installed.

    options:

    Source                     The location to look for packages.
    OutputDirectory            Specifies the directory in which packages will be installed
    Version                    The version of the package to install.
    ExcludeVersion       (x)   If set, the destination folder will contain only the package name, not the version number
    Help                 (?)   help

  • NuGet: test if a package is installed

    With Get-Package you can get the list of currently installed packages. How can you test if a package is installed?

    Get-Package returns list of packages as follows:

    Id                             Version              Description                                                                                                        --                             -------              -----------                                                                                                        EntityFramework                4.1.10331.0          DbContext API and Code First workflow for ADO.NET Entity Framework.                                                MacawSolutionsFactory-Core     1.0.0                Macaw Solutions Factory Base package                                                                               MacawSolutionsFactory-Spf2010  1.0.0                Macaw Solutions Factory core package for Spf2010                                                                   T4Scaffolding                  1.0.0                A fast and customizable way to build parts of your .NET application via templates                                  
    To test if a package is installed do the following:
    (get-package | Select-Object -ExpandProperty ID) -contains 'EntityFramework'
    This will return $true or $false.
  • DualLayout for SharePoint 2010 WCM Quick Start

    DualLayout for SharePoint 2010 WCM is a solution to provide you with complete HTML freedom in your SharePoint Server 2010 publishing pages. In this post I provide a quick start guide to get you up and running quickly so you can try it out for yourself. This quick start creates a simple HTML5 site with a page to show-case the basics and the power of DualLayout. We will create the site in its own web application. Normally there are many things you have to do to create a clean start point for your SharePoint 2010 WCM site. All those steps will be provided in later posts. For now we want to give you the minimal set of steps to take to get DualLayout working on your machine.

    1. Create an authenticated web application with hostheader cms.html5demo.local on port 80 for the cms side of the site.
      imageimage
    2. Click the Create Site Collection link on the Application Created dialog box and create a Site Collection based on the Publishing Portal site template.
      imageimage
    3. Before we can click the site link in the Top-Level Site Successfully Created dialog we need to add the new host header cms.html5demo.local to the hosts file.
      SNAGHTML3954428f
      Add the following line to the hosts file:

      127.0.0.1        cms.html5demo.local

    4. Navigate to the site at http://cms.html5demo.local to see the out-of-the-box example Adventure Works publishing site.
      SNAGHTML3accaba4
    5. Download and add the DualLayout solution package designfactory.duallayout.sps2010.trial.1.2.0.0.wsp to the farm’s solution store:
      1. On the Start menu, click All Programs.
      2. Click Microsoft SharePoint 2010 Products.
      3. Click SharePoint 2010 Management Shell.
      4. At the Windows PowerShell command prompt, type the following command:Add-SPSolution -LiteralPath designfactory.duallayout.sps2010.trial.1.2.0.0.wsp
    6. In SharePoint 2010 Central Administration deploy the solution to the web application http://cms.html5demo.local.
      SNAGHTML3af89a0a
    7. Navigate to the site at http://cms.html5demo.local, and in the Site Settings screen select Site Collection Administration > Site collection features and activate the following feature:
    8. image_thumb3

    9. Open the site http://cms.html5demo.local in SharePoint Designer 2010.
    10. Create a view-mode masterpage html5simple.master with the following code:

      html5simple.master
      1. <%@ Master language="C#" %>
      2. <%@ Register Tagprefix="SharePointWebControls" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
      3. <%@ Register TagPrefix="sdl" Namespace="DesignFactory.DualLayout" Assembly="DesignFactory.DualLayout, Version=1.2.0.0, Culture=neutral, PublicKeyToken=077f92bbf864a536" %>
      4.  
      5. <!DOCTYPE html>
      6. <html class="no-js">
      7.  
      8.     <head>
      9.         <meta charset="utf-8" />
      10.         <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
      11.         <title><SharePointWebControls:FieldValue FieldName="Title" runat="server"/></title>
      12.  
      13.         <script type="text/javascript">
      14.             document.createElement('header');
      15.             document.createElement('nav');
      16.             document.createElement('article');
      17.             document.createElement('hgroup');
      18.             document.createElement('aside');
      19.             document.createElement('section');
      20.             document.createElement('footer');
      21.             document.createElement('figure');
      22.             document.createElement('time');
      23.         </script>
      24.  
      25.         <asp:ContentPlaceHolder id="PlaceHolderAdditionalPageHead" runat="server"/>
      26.     </head>
      27.     
      28.     <body>
      29.         
      30.         <header>
      31.             <div class="logo">Logo</div>
      32.             <h1>SiteTitle</h1>
      33.             <nav>
      34.                 <a href="#">SiteMenu 1</a>
      35.                 <a href="#">SiteMenu 2</a>
      36.                 <a href="#">SiteMenu 3</a>
      37.                 <a href="#">SiteMenu 4</a>
      38.                 <a href="#">SiteMenu 5</a>
      39.                 <sdl:SwitchToWcmModeLinkButton runat="server" Text="…"/>
      40.             </nav>
      41.             <div class="tagline">Tagline</div>
      42.             <form>
      43.                 <label>Zoek</label>
      44.                 <input type="text" placeholder="Voer een zoekterm in...">
      45.                 <button>Zoek</button>                
      46.             </form>
      47.  
      48.         </header>
      49.         
      50.         <div class="content">
      51.             <div class="pageContent">
      52.                 <asp:ContentPlaceHolder id="PlaceHolderMain" runat="server" />
      53.             </div>
      54.         </div>
      55.     
      56.         <footer>
      57.             <nav>
      58.                 <ul>
      59.                     <li><a href="#">FooterMenu 1</a></li>
      60.                     <li><a href="#">FooterMenu 2</a></li>
      61.                     <li><a href="#">FooterMenu 3</a></li>
      62.                     <li><a href="#">FooterMenu 4</a></li>
      63.                     <li><a href="#">FooterMenu 5</a></li>
      64.                 </ul>
      65.             </nav>
      66.             <small>Copyright &copy; 2011 Macaw</small>
      67.         </footer>
      68.     </body>
      69. </html>


      Note that if no specific WCM-mode master page is specified (html5simple-wcm.master), the default v4.master master page will be used in WCM-mode.
    11. Create a WCM-mode page layout html5simplePage-wcm.aspx with the following code:
      html5simplePage-wcm.aspx
      1. <%@ Page language="C#" Inherits="DesignFactory.DualLayout.WcmModeLayoutPage, DesignFactory.DualLayout, Version=1.2.0.0, Culture=neutral, PublicKeyToken=077f92bbf864a536" %>
      2. <%@ Register Tagprefix="SharePointWebControls" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
      3. <%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
      4. <%@ Register Tagprefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
      5. <%@ Register Tagprefix="PublishingNavigation" Namespace="Microsoft.SharePoint.Publishing.Navigation" Assembly="Microsoft.SharePoint.Publishing, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
      6.  
      7. <asp:Content ContentPlaceholderID="PlaceHolderPageTitle" runat="server">
      8.     <SharePointWebControls:FieldValue FieldName="Title" runat="server"/>
      9. </asp:Content>
      10. <asp:Content ContentPlaceholderID="PlaceHolderMain" runat="server">
      11. Title: <SharePointWebControls:TextField FieldName="Title" runat="server"/>
      12. </asp:Content>


      Notice the Inherits at line one. Instead of inheriting from Microsoft.SharePoint.Publishing.PublishingLayoutPage we need to inherit from DesignFactory.DualLayout.WcmModeLayoutPage
    12. Create a view-mode page layout html5simplePage.aspx with the following code:
      SNAGHTML3b358f44

      html5simplePage.aspx
      1. <%@ Page language="C#" Inherits="DesignFactory.DualLayout.ViewModeLayoutPage, DesignFactory.DualLayout, Version=1.2.0.0, Culture=neutral, PublicKeyToken=077f92bbf864a536" %>
      2. <%@ Register Tagprefix="SharePointWebControls" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
      3.  
      4. <asp:Content ContentPlaceholderID="PlaceHolderAdditionalPageHead" runat="server" />
      5. <asp:Content ContentPlaceholderID="PlaceHolderMain" runat="server">
      6.     The title of the page is: <SharePointWebControls:FieldValue FieldName="Title" runat="server"/>
      7. </asp:Content>


      Notice the Inherits at line one. Instead of inheriting from Microsoft.SharePoint.Publishing.PublishingLayoutPage we need to inherit from DesignFactory.DualLayout.ViewModeLayoutPage
    13. Set the html5simple.master master page as the Site Master Page:
      SNAGHTML3b2bb9ee
    14. Set the allowed page layouts to the Html5 Simple Page page layout and set the New Page Default Settings also to Html5 Simple Page so new created pages are also of this page layout.
      image
      Note that the Html5 Simple Page page layout is initially not selectable for New Page Default Settings. Save this configuration page first after selecting the allowed page layouts, then open again and select the default new page.
    15. Under Site Actions select the New Page action. Create a page Home.aspx of the default page layout type Html5 Simple Page.
    16. Set the new created Home.aspx page as Welcome Page.
      SNAGHTML3b50cd15
    17. Navigate to the site http://cms.html5demo.local and see the home page in the WCM display and edit mode.
      imageimage
    18. Select Switch to View Mode under Site Actions to see the resulting page in view-mode. Select the three dots (…) at the right side of the menu to switch back to WCM-mode.
      SNAGHTML3dfe1804
    19. Have a look at the source view of the resulting web page and admire the clean HTML. No SharePoint specific markup or CSS files!
      Clean HTML in page
      1. <!DOCTYPE html>
      2. <html class="no-js">
      3.     <head>
      4.         <meta charset="utf-8" />
      5.         <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
      6.         <title>Home</title>
      7.         <script type="text/javascript">
      8.             document.createElement('header');
      9.             document.createElement('nav');
      10.             document.createElement('article');
      11.             document.createElement('hgroup');
      12.             document.createElement('aside');
      13.             document.createElement('section');
      14.             document.createElement('footer');
      15.             document.createElement('figure');
      16.             document.createElement('time');
      17.         </script>
      18.         
      19.     </head>
      20.     
      21.     <body>
      22.         
      23.         <header>
      24.             <div class="logo">Logo</div>
      25.             <h1>SiteTitle</h1>
      26.             <nav>
      27.                 <a href="#">SiteMenu 1</a>
      28.                 <a href="#">SiteMenu 2</a>
      29.                 <a href="#">SiteMenu 3</a>
      30.                 <a href="#">SiteMenu 4</a>
      31.                 <a href="#">SiteMenu 5</a>
      32.                 <a href="/Pages/Home.aspx?DualLayout_ShowInWcmMode=true">…</a>
      33.             </nav>
      34.             <div class="tagline">Tagline</div>
      35.             <form>
      36.                 <label>Zoek</label>
      37.                 <input type="text" placeholder="Voer een zoekterm in...">
      38.                 <button>Zoek</button>                
      39.             </form>
      40.         </header>
      41.         
      42.         <div class="content">
      43.             <div class="pageContent">
      44.                 
      45.     The title of the page is: Home
      46.             </div>
      47.         </div>
      48.     
      49.         <footer>
      50.             <nav>
      51.                 <ul>
      52.                     <li><a href="#">FooterMenu 1</a></li>
      53.                     <li><a href="#">FooterMenu 2</a></li>
      54.                     <li><a href="#">FooterMenu 3</a></li>
      55.                     <li><a href="#">FooterMenu 4</a></li>
      56.                     <li><a href="#">FooterMenu 5</a></li>
      57.                 </ul>
      58.             </nav>
      59.             <small>Copyright &copy; 2011 Macaw</small>
      60.         </footer>
      61.     </body>
      62. </html>
      63. <!-- Macaw DesignFactory DualLayout for SharePoint 2010 Trial version -->


      Note the link at line 37, this link will only be rendered for authenticated users and is our way to switch back to WCM-mode.

    This concludes our quick start to get DualLayout up an running in a matter of minutes. And what is the result:

    • You can have the full SharePoint 2010 WCM publishing page editing experience to manage the content in your pages.
    • You don’t have to delve into large SharePoint specific master pages and page layouts with a lot of knowledge of the does and don'ts with respect to SharePoint controls, scripts and stylesheets.
    • The end-user gets a clean and light HTML page.

    Get your fully functional, non-timebombed trial copy of DualLayout and start creating!

  • DualLayout OpenSourceFood demo site installation instructions

    We released DualLayout which enables advanced web design with the power of SharePoint. DualLayout and a demo site which shows off the feature of DualLayout can be downloaded from the DualLayout product page.

    This blogpost contains detailed instructions on installing this demo site.

    The DualLayout demo site is based on the site http://opensourcefood.com. The demo site requires internet access because for some menu items it still links to pages and resources of the real site.

    Execute the following steps to install the OpenSourceFoodDemo demo site on your SharePoint Server 2010:

    • Downloaded the OpenSourceFoodDemo.zip file from the DualLayout product page
    • Copy the OpenSourceFoodDemo.zip file to your development computer running SharePoint Server 2010
    • Make sure that the zip file in “unblocked”, otherwise files are marked as “unsecure” because they are downloaded from another computer, and the installation script will not run (right-click on zip file, press “Unblock” button if available, if not available the file is already unblocked)
    • Unzip the OpenSourceFoodDemo.zip file to a folder of your choice (c:\OpenSourceFoodDemo)
    • Open the SharePoint 2010 Management Shell (Start->Microsoft SharePoint 2010 Products->SharePoint 2010 Management Shell)
    • Change directory to the unzip folder (cd c:\OpenSourceFoodDemo)
    • Start the PowerShell installation script: .\InstallDemoSite.ps1
    • Answer the questions, default values are in most cases ok. A little guidance:
      • Question: Give credentials for the account that will be used for the application pool
        Answer: use for example same account as used for the application pool of your SharePoint site (lookup in IIS Manager)
      • Question: Give credentials for the account that will be used for the application pool
        Answer: Use same account you are currently logged in with

    The DualLayout demo site is made available through a SharePoint backup and restore created using stsadm. The SharePoint Server 2010 installation must be patched to a level equal or higher to the update level on the SharePoint Server that we used to create the backup.

    If you get version errors with respect to the restore check http://technet.microsoft.com/en-us/sharepoint/ff800847.aspx for downloading the latest cumulative update. Don’t forget to make a snapshot before installing the cumulative update if you are using a virtual development environment. I updated one of my development machines to the december cummulative update and never got it working again:-(

  • Macaw DualLayout for SharePoint 2010 WCM released!

    A few months ago I wrote a blog post about the DualLayout component we developed for SharePoint Server 2010 WCM. DualLayout enables advanced web design on SharePoint WCM sites. See the blog post DualLayout - Complete HTML freedom in SharePoint Publishing sites! for background information.

    DualLayout if now available for download. Check out DualLayout for SharePoint 2010 WCM and download your fully functional trial copy!

    Enjoy the freedom!