Update project property with a powershell script - powershell

I want to create a nuget package which will run a Powershell script on restore in a C# project. The script will change the values of the project properties on the project e.g.:
Set value of
<AssemblyVersion>1.0.0.0</AssemblyVersion>
to
<AssemblyVersion>$(ReleaseApplicationVersion)</AssemblyVersion>
and some other properties.
Thanks in advance!
UPDATE-------------------------------------------
This is what I have
param([string]$projectName = $(throw 'csproj file is required'))
$proj = Resolve-Path $projectName
$propAssemblyName = $proj.Properties.Item("AssemblyName")
$propAssemblyName.Value = '$(ReleasedAssemblyName)'
But I obviously dont know how to make this work as I get bunch of issues. Thanks

function Set-Version {
Write-Header "Updating version in .csproj files"
try {
Push-Location ".\csprojLocation"
$versionProjFile = Resolve-Path "*.csproj"
$xml = [xml](Get-Content $versionProjFile)
$xml.Project.PropertyGroup.AssemblyVersion = ${version}
$xml.Save($versionPropsFile)
}
finally {
Pop-Location
}
}
Set-Version

Related

Open or extract files nupkg with Powershell

could you please help me? How I can open and extract files the "nupkg" package using the PowerShell.
Thanks.
You can use Expand-Archive (you have to rename the file, see Can I use PowerShell `Expand-Archive` upon a zip file with no extension)
Rename-Item "Newtonsoft.Json.12.0.1.nupkg" "Newtonsoft.Json.12.0.1.nupkg.zip"
Expand-Archive "Newtonsoft.Json.12.0.1.nupkg.zip"
I prefer to use nuget cli, because it also intstalls dependencies. All you need is nuget install yourpackage . It's really just a 5MB executable, you can even download it each time you need to get the package:
$nugetUrl = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
Invoke-WebRequest -Uri $nugetUrl -OutFile ".\nuget.exe"
.\nuget.exe install yourpackage
I would not recommend direct use of Expand-Archive. As mentioned by guys at Squirrel and as you can see in NuGet sources file names in archive are escaped using URI escaping.
If you decide to expand raw archive you should afterwards rename all files and directories containing % in their names using Uri.UnescapeDataString.
If you want more optimised approach in terms of file system writes here's the implementation:
function Expand-NugetArchive {
[CmdletBinding()]
param (
# File name of the Package
[Parameter(Mandatory = $true)]
[string]
$FileName,
# Directory
[string]
$ExtractDirectory,
[boolean]
$Overwrite = $false
)
# Reference to the knowledge here https://stackoverflow.com/a/72590215/3299257
$extractPath = [System.IO.Path]::GetFullPath($ExtractDirectory);
# Ensures that the last character on the extraction path
# is the directory separator char.
# Without this, a malicious zip file could try to traverse outside of the expected
# extraction path.
if ( -not $extractPath.EndsWith([System.IO.Path]::DirectorySeparatorChar.ToString(), [StringComparison]::Ordinal)) {
$extractPath += [System.IO.Path]::DirectorySeparatorChar;
}
$archive = [System.IO.Compression.ZipFile]::OpenRead($FileName)
try {
foreach ($entry in $archive.Entries) {
$fullName = $entry.FullName
if ($fullName.Contains('%')) {
$fullName = [Uri]::UnescapeDataString($fullName)
}
# Gets the full path to ensure that relative segments are removed.
$destinationPath = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($extractPath, $fullName))
[System.IO.Directory]::CreateDirectory([System.IO.Path]::GetDirectoryName($destinationPath)) | Out-Null
# Ordinal match is safest, case-sensitive volumes can be mounted within volumes that
# are case-insensitive.
if ($destinationPath.StartsWith($extractPath, [StringComparison]::Ordinal)) {
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $destinationPath, $Overwrite)
}
}
}
catch {
if ($null -ne $archive) { $archive.Dispose() }
throw
}
}

Create TFS work item with PowerShell

I'm working on a TFS build with a pre-build PowerShell script that (in addition to building my app) automatically checks out a file where we maintain version, increments the build number, then checks the file in.
I have been able to do this, except that I get an error from the script which results in a partially successful build (orange). I need to have a fully successful (green) build.
Here's the check-in line (using TFS Power Tools for VS 2013):
New-TfsChangeset -Item $versionFile -Override "Automated" -Notes "Code Reviewer=tfs" -Comment "Automated"
The error I receive is that the changeset is not associated with a work item, but the -Override should handle that. The funny thing is that it checks in anyway.
Running locally on my machine instead of the build server, I get the same thing, except that I also see a line that says The policies have been overridden. This tells me that the override is working, but it still outputs the error.
I've tried adding -ErrorAction SilentlyContinue, but it has no effect.
I need one of three options:
A way to suppress output of the checkin error,
A way to create a work item and associate it to the checkin, or
Some other third option that will result in a green build.
Any ideas?
Credit goes to Eddie - MSFT for leading me the right direction, but I wanted to consolidate everything here.
WARNING This will check in all pending changes in the workspace.
Creating a new work item (source)
I did modify it quite a bit to support automation. It connects to TFS and generates a new work item.
function New-WorkItem()
{
# These *should* be registered in the GAC.
# The version numbers will likely have to change as new versions of Visual Studio are installed on the server.
Add-Type -Assembly "Microsoft.TeamFoundation.Client, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
Add-Type -Assembly "Microsoft.TeamFoundation.WorkItemTracking.Client, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
$server = "http://YOURTFSSERVER:8080/tfs"
$tfs = [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]::GetServer($server)
$type = [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore]
$store = [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore] $tfs.GetService($type)
$workItem = New-Object Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem($store.Projects[0].WorkItemTypes[0])
$workItem.Title = "Automated work item"
$workItem
}
Associating the work item and checking in
Slight modifications to the code from the link given by Eddie, we get the following:
function CheckIn()
{
param([Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem] $workItem)
$col = Get-TfsCollection("http://YOURTFSSERVER:8080/tfs/YOURCOLLECTION")
$vcs = Get-TfsVersionControlServer($col)
$ws = $vcs.GetWorkspace([System.IO.Path]::GetDirectoryName($anyPathInWorkspace))
$pc = $ws.GetPendingChanges()
$wici = Get-TfsWorkItemCheckinInfo($workItem)
$changeset = $ws.CheckIn($pc, "Automated check in", $null, $wici, $null)
}
That post doesn't tell you that Get-TfsCollection, Get-TfsVersionControlServer, and Get-TfsWorkItemCheckinInfo aren't defined. I had to find them.
I found the first two on http://nkdagility.com/powershell-tfs-2013-api-1-get-tfscollection-and-tfs-services/. I didn't have to change anything.
function Get-TfsCollection
{
param([string] $CollectionUrl)
if ($CollectionUrl -ne "")
{
#if collection is passed then use it and select all projects
$tfs = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($CollectionUrl)
}
else
{
#if no collection specified, open project picker to select it via gui
$picker = New-Object Microsoft.TeamFoundation.Client.TeamProjectPicker([Microsoft.TeamFoundation.Client.TeamProjectPickerMode]::NoProject, $false)
$dialogResult = $picker.ShowDialog()
if ($dialogResult -ne "OK")
{
#exit
}
$tfs = $picker.SelectedTeamProjectCollection
}
$tfs
}
function Get-TfsVersionControlServer
{
param([Microsoft.TeamFoundation.Client.TfsTeamProjectCollection] $TfsCollection)
$TfsCollection.GetService("Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer")
}
But I couldn't find Get-TfsWorkItemCheckinInfo. The only Google hit was the kinook link from Eddie (and soon probably this answer). Here's what I came up with:
function Get-TfsWorkItemCheckinInfo
{
param([Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem] $workItem)
$wi = New-Object Microsoft.TeamFoundation.VersionControl.Client.WorkItemCheckinInfo($workItem, [Microsoft.TeamFoundation.VersionControl.Client.WorkItemCheckinAction]::Resolve)
$wi
}
Now we can use it
CheckIn (New-WorkItem)
That's it!
You can create a work item from PowerShell by following this article: http://halanstevens.com/blog/powershell-script-to-create-a-workitem/
Quote the code here for reference:
$key = Get-ItemProperty HKLM:\SOFTWARE\Microsoft\VisualStudio\8.0
$dir = [string] (Get-ItemProperty $key.InstallDir)
$dir += "PrivateAssemblies\"
$lib = $dir + "Microsoft.TeamFoundation.WorkItemTracking.Client.dll"
[Reflection.Assembly]::LoadFrom($lib)
$lib = $dir + "Microsoft.TeamFoundation.Client.dll"
[Reflection.Assembly]::LoadFrom($lib)
"Please enter your Team Foundation Server Name:"
$server = [Console]::ReadLine()
$server = $server.Trim()
"Connecting to " + $server + "..."
$tfs = [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]::GetServer($server)
$type = [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore]
$store = [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore] $tfs.GetService($type)
$workItem = new-object Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem($store.Projects[0].WorkItemTypes[0])
"Created a new work item of type " + $workItem.Type.Name
$workItem.Title = "Created by Windows PowerShell!"
$workItem.Save()
And then refer to this article to associate the work item to changeset: http://www.kinook.com/Forum/showthread.php?t=4502

Wildcard in powershell string for call operator

In a powershell script I need to call a funcion like this
$SpecRunCall = "./packages/SpecRun.Runner.1.2.0/tools/SpecRun.exe"
$MSTestArguments = #('run', 'Default.srprofile', "/baseFolder:.\TestResults", '/log:specrun.log')
if($tag) {
$MSTestArguments += '/filter:#' + $tag
}
& $SpecRunCall $MSTestArguments
But I have to put there the version of the SpecRun Runner, I was thinking of putting a wildcard for that and then find whichever version I have (provided I have only one there) but I'm struggling to find a working solution for it.
Thanks,
Assuming the only version exists, Resolve-Path ...SpecRun.Runner.*... should work:
$SpecRunCall = Resolve-Path ./packages/SpecRun.Runner.*/tools/SpecRun.exe
You could the following assuming that all the SpecRunner version are all in different folders labeled with the version number. And that only one version folder will be on the computer at a time.
$version = "1.1.0","1.2.0","1.3.0"
$SpecRunCall = $null
$version | Foreach {
# Set spec runner version folder
$SpecFolder = "./packages/SpecRun.Runner.$_/"
# Test folder
If(Test-path $SpecFolder){
# Version folder found use it
$SpecRunCall = $SpecFolder+"tools/SpecRun.exe"
}
}
# Check if a version was found
If($SpecRunCall -ne $null){
# ** Your code **
$MSTestArguments = #('run', 'Default.srprofile', "/baseFolder:.\TestResults", '/log:specrun.log')
If($tag) {$MSTestArguments += '/filter:#' + $tag}
& $SpecRunCall $MSTestArguments
}
This code will take a list of version numbers and look for the corresponding SpecRunner folder. If found that version of SpecRunner is selected.

The term 'xWebsite' is not recognized as the name of a cmdlet

I installed xWebAdministration module. For some reason I am still getting this error message
The term 'xWebsite' is not recognized as the name of a cmdlet"
image url: http://i.stack.imgur.com/tTwUe.jpg
here's my code.
Configuration MvcWebTest {
Param(
[String[]]$ComputerName = "tvw-irwebsvc",
$AppName = "MvcWebTest",
$User = "PAOMSvc",
$Password = "Welcome1",
$CodePath = "C:\websites\MvcWebTest"
)
Import-DscResource -Module xWebAdministration
Node $ComputerName {
#Install ASP.NET 4.5
WindowsFeature ASP {
Ensure = “Present”
Name = “Web-Asp-Net45”
}
File WebContent {
Ensure ="Present";
SourcePath ="\\DVW-MORBAM01\Build\Publish\MvcWebTest\Dev";
DestinationPath=$CodePath;
Type = "Directory";
Recurse = $True
}
# Create a new website
xWebsite Website {
Ensure = "Present";
Name = $AppName;
State = "Started";
PhysicalPath = $CodePath;
DependsOn = "[File]WebContent"
}
}
}
The screenshot is showing you the problem: The xWebsite resource isn't installed. Only the xwebApplication and xWebVirtualDirectory resources are installed.
I just downloaded the xWebAdministration 1.3.2.3 zip file from Technet, and it looks like someone made a boo-boo -- it's missing xWebSite! The Q&A section is full of people upset about it, so you're not alone. :)
Oddly enough, the Wave 9 resource kit that supposedly includes all the modules has the same problem!
The easiest way to get past this is to just grab version 1.3.2, which looks like it has everything.
To enact the configuration, run the following command:
Start-DscConfiguration -Wait -Verbose -Path .\MvcWebTest
This cmdlet is part of the DSC system. The Wait parameter is optional and makes the cmdlet run interactively. Without this parameter, the cmdlet will create and return a job.

Using PowerShell to create and add class libraries to a solution

I'm trying to automate some of the tasks I perform on each web project. What I want is a PoSH script that I can run on a new solution that will:
load the solution contained in the scripts current directory.
create new projects for the loaded solution and add them to the solution.
create some classes and add them to each of the projects.
So far I have a simple script (shown below) that finds and opens the local solution file.
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
Set-Location $dir
$solution = Get-ChildItem | Where-Object{($_.Extension -eq ".sln")}
if ($solution.Count -eq 0)
{
"Please place this script in the folder containing you solution file."
break;
}
$dteObj = New-Object -ComObject "VisualStudio.DTE"
$dteObj.Solution.Open($solution.FullName)
How can I now create new projects and add them to the solution?
Check out http://studioshell.codeplex.com/ by Jim Christopher.
To create a project , call GetProjectTemplate, and then pass the returned template paths to AddFromTemplate.
Try this in Package Manager Console.
#Create a Console Project
$csTemplatePath = $dte.Solution.GetProjectTemplate("ConsoleApplication.zip", "CSharp")
$csPrjPath = "C:\\Projects\\SolutionName\\ConsoleApplication1"
$dte.Solution.AddFromTemplate($csTemplatePath, $csPrjPath, "ConsoleApplication1", 'false')
#Create a C# class
$itemPath = $dte.Solution.GetProjectItemTemplate("Class.zip", "CSharp")
$prj = Get-Project
$prjItem = $prj.ProjectItems.AddFromTemplate($itemPath, "Project.cs")