VS Publish, Web Deploy - create Event Source - powershell

I want to create an new event log Event Source to log my webAPI app to when I Import Application through IIS.
I publish my application to a web deploy folder (zip) file in VS2015 and import from this.
I have found this code to create the event source:
if ([System.Diagnostics.EventLog]::SourceExists("myWeb.API") -eq $false) {
[System.Diagnostics.EventLog]::CreateEventSource("myWeb.API", "Application")
}
and I can put this in a EventSource.ps1 file which does what I want when I run it from a prompt.
How can I execute this during the IIS Import Application process?
I have tried using the .pubxml file but which element to use/override/call-it-via baffles me - I've tried AfterAddIisSettingAndFileContentsToSourceManifest and PipelineDependsOn.
<Target Name="CustomCreateEventSource">
<Message Text="Create Event Source" Importance="high"/>
<PropertyGroup>
<EventSource Condition=" '$(EventSource)'=='' ">
myWeb.API
</EventSource>
</PropertyGroup>
<Exec Command="powershell.exe"
-NonInteractive
-executionpolicy Unrestricted
-file "$(PublishUrl)Publish\EventSource.ps1" "$(EventSource)"" /></Target>
I'd rather it was done via IIS Import Application, as a 1-hit process, and not a:
Import Application
Run the powershell
because it'll be imported by not-necessarily technical users.
Many thanks for taking the time to assist!

You can use the <projectName>.wpp.targets file to kick off a custom command when the application is imported into IIS.
For example, if your project name is MyApp, add a file called MyApp.wpp.targets to the root level of the project.
I tested and verified that this approach works using a targets with the following content:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CustomTask" AfterTargets="AddIisSettingAndFileContentsToSourceManifest">
<ItemGroup>
<MsDeploySourceManifest Include="runCommand">
<!-- specify InputFormat None (see http://stackoverflow.com/questions/4238192/running-powershell-from-msdeploy-runcommand-does-not-exit) -->
<Path>powershell.exe -ExecutionPolicy bypass -NoLogo -inputformat none -NonInteractive -Command .'$(_MSDeployDirPath_FullPath)\Deploy\createEventLog.ps1'</Path>
</MsDeploySourceManifest>
</ItemGroup>
</Target>
</Project>
One important thing to note is that Visual Studio will sometimes cache the .wpp.targets file. The only way I know to release it is to restart Visual Studio. I just experienced this issue which threw me off track for a while, because I was getting an error that I couldn't make go away.
For reference, here is the .pubxml file I used to create the package Zip:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebPublishMethod>Package</WebPublishMethod>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish />
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
<ExcludeApp_Data>False</ExcludeApp_Data>
<DesktopBuildPackageLocation>c:\temp\IISImportTestPkg.zip</DesktopBuildPackageLocation>
<PackageAsSingleFile>true</PackageAsSingleFile>
<DeployIisAppPath>Default Web Site/IISImportTest</DeployIisAppPath>
<PublishDatabaseSettings>
<Objects xmlns="" />
</PublishDatabaseSettings>
</PropertyGroup>
</Project>
Lastly, here are a couple of resources that may help:
This is where I picked the idea of usin .wpp.targets file: http://sedodream.com/2011/11/08/SettingFolderPermissionsOnWebPublish.aspx
List of MsDeploy Providers where I found the runCommand provider: https://technet.microsoft.com/en-us/library/dd569040(v=ws.10).aspx

Related

NuGet Package Restore: Visual Studio Online & POSTSHARP

I installed POSTSHARP as a nuget package and I want Visual Studio Online to automatically restore it.
POSTSHARP must be restored before build though.
I am trying to follow this with no success: link
How can I run scripts / commands in Visual Studio Online BEFORE build?
There are instructions on nuget.org on how to set up a package restore with TFS, including Visual Studio Online: http://docs.nuget.org/docs/reference/package-restore-with-team-build
It mentions that the default Build Process Templates for VSO already implements NuGet Package Restore workflow. So, supposedly, you need to do additional setup only when you customize the templates.
The proposed approach is to create a simple MSBuild project file that will be used to build the solution. You can include all the required targets there (e.g. Build, Rebuild, Clean) that will just invoke MSBuild on your solution file with specifying the corresponding target.
Additionally create a target for package restore - it will invoke NuGet.exe restore MySolution.sln command. The common build targets will depend on this one.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0"
DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<OutDir>$(MSBuildThisFileDirectory)bin</OutDir>
<Configuration>Release</Configuration>
<ProjectProperties>
OutDir=$(OutDir);
Configuration=$(Configuration);
</ProjectProperties>
</PropertyGroup>
<ItemGroup>
<Solution Include="$(MSBuildThisFileDirectory)src\*.sln" />
</ItemGroup>
<Target Name="RestorePackages">
<Exec Command=""$(MSBuildThisFileDirectory)tools\NuGet\NuGet.exe" restore "%(Solution.Identity)"" />
</Target>
<Target Name="Build" DependsOnTargets="RestorePackages">
<MSBuild Targets="Build"
Projects="#(Solution)"
Properties="$(ProjectProperties)" />
</Target>
<!-- other targets... -->
</Project>

Is there a way to create more than one deployment with msbuild on a single build?

I am using msbuild command line multiple times to create a deployment zip file for my dev / test / production websites. I have already configured the parameters and configuration xml for each one. I want to know if i can condense my 3 calls to msbuild down to one, and have it build all three at once?
right now i have to run
msbuild.exe myproject.sln /T:Build /p:DeployOnBuild=True /p:PublishProfile="Dev Server"
msbuild.exe myproject.sln /T:Build /p:DeployOnBuild=True /p:PublishProfile="Prod Server"
etc
The continuous deployment solution i'm using (bamboo) is struggling with this multiple call to msbuild for some reason (i have an open ticket and they are perplexed as well). I'm trying to simplify things.
I have a template for building out all skus of the same solution in parallel.
This is the same concept as Stijn's approach that uses an ItemGroup as a project definition rather than a series of options for a particular property + the msbuild task will build both at the same time, saving you time and bubbling up any configuration issues when building in parallel.
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<SolutionToBuild Include="$(MSBuildThisFileDirectory)\MyProject.sln">
<Properties>DeployOnBuild=True;PublishProfile="Dev Server"</Properties>
</SolutionToBuild>
<SolutionToBuild Include="$(MSBuildThisFileDirectory)\MyProject.sln">
<Properties>DeployOnBuild=True;PublishProfile="Prod Server"</Properties>
</SolutionToBuild>
</ItemGroup>
<Target Name="Build">
<MsBuild BuildInParallel="true" ContinueOnError="true" Projects="#(SolutionToBuild)" />
</Target>
<Target Name="Clean">
<MsBuild BuildInParallel="true" ContinueOnError="true" Projects="#(SolutionToBuild)" Targets="Clean" />
</Target>
</Project>
You can only invoke multiple different targets on the commandline, but you can't supply multiple different values for properties. At least not in a way that I'm aware off. The workaround however is simple, easier to extend than a commandline, and the typical msbuild way of doing things: create a master build file like below and call it from Bamboo instead of the solution.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets=Build>
<Target Name="Build">
<ItemGroup>
<PublishProfiles Include="Dev Server"/>
<PublishProfiles Include="Prod Server"/>
</ItemGroup>
<MsBuild Projects="myproject.sln" Targets="Build"
Properties="DeployOnBuild=True;PublishProfile=%(PublishProfile.Identity)"/>
</Target>
</Project>
(this will invoke MsBuild myproject.sln once for each item in the PublishProfiles list with the properties as shown)

TeamCity MSBuild, remap folders during deployment

We have a solution with a website project which is hosted on a load balanced environment. At the moment no CI is being used, and deployments are manual using zip-files >_< however I'm looking on setting it up, and have run into some difficulties.
The solution requires a App_Config folder containing all the configurations for the site in the root, however these configurations differ from each of the hostingserver, where one is the management server and another is the delivery server.
Each individual server configurations is stored in a separate folder at /Configs/servername/ containing a web.config file and the App_Config folder. These have been manually copied from this folder to the root to overwrite those that already existed.
Also deployment of the /Configs/ folder is not wanted.
Preferably no changes should have to be done to the Visual Studio solution.
Is it possible to automate this before deployment in TeamCity?
regards
You may want to set properties with different values based on the computer name.
That's one trick of the trade.
<Choose>
<When Condition=" '$(Computername)'=='MyManagementServer01' ">
<PropertyGroup>
<MyCustomProperty001>Red</MyCustomProperty001>
<MyCustomProperty002>Yellow</MyCustomProperty002>
</PropertyGroup>
</When>
<When Condition=" '$(Computername)'=='MyDeliveryServer01' ">
<PropertyGroup>
<MyCustomProperty001>Black</MyCustomProperty001>
<MyCustomProperty002>White</MyCustomProperty002>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<MyCustomProperty001>NoMatchMyCustomProperty001</MyCustomProperty001>
<MyCustomProperty002>NoMatchMyCustomProperty002</MyCustomProperty002>
</PropertyGroup>
</Otherwise>
</Choose>
You could setup a property called
<ConfigurationSourceFolder>/Configs/MyManagementServer01/</ConfigurationSourceFolder>
Or setup a "DeploymentType"
<DeploymentType>ManagementServerType</DeploymentType>
You can also put Conditions on "Targets" and even Tasks.
<MakeDir Directories="C:\MyCoolDirectory" Condition="('$(MyCustomProperty001)'!='')"/>
//////Preferably no changes should have to be done to the Visual Studio solution.//////
So here is an "in-general" tip.
Instead of putting alot of custom sometimes-hard-to-follow changes in the csproj files....use a basic .msbuild file.
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="AllTargetsWrapped">
<PropertyGroup>
<!-- Always declare some kind of "base directory" and then work off of that in the majority of cases -->
<WorkingCheckout>.</WorkingCheckout>
</PropertyGroup>
<Target Name="AllTargetsWrapped">
<CallTarget Targets="BuildItUp" />
</Target>
<Target Name="BuildItUp" >
<MSBuild Projects="$(WorkingCheckout)\MySolution.sln" Targets="Build" Properties="Configuration=$(Configuration)">
<Output TaskParameter="TargetOutputs" ItemName="TargetOutputsItemName"/>
</MSBuild>
<Message Text="BuildItUp completed" />
</Target>
</Project>

How can I add an AfterBuild event to a project when installing my NuGet package?

I have a nuget package which adds an executable that I need to run after a project builds each time.
I can manually add this by adding a section to each project file like so:
<Target Name="AfterBuild">
<PropertyGroup>
<PathToOutputExe>..\bin\Executable.exe</PathToOutputExe>
<PathToOutputJs>"$(MSBuildProjectDirectory)\Scripts\Output.js"</PathToOutputJs>
<DirectoryOfAssemblies>"$(MSBuildProjectDirectory)\bin\"</DirectoryOfAssemblies>
</PropertyGroup>
<AspNetCompiler Condition="'$(MvcBuildViews)'=='true'" VirtualPath="temp" PhysicalPath="$(ProjectDir)" />
<Exec Command="$(PathToOutputExe) $(PathToOutputJs) $(DirectoryOfAssemblies)" />
</Target>
How can I add this to a project when I install the nuget package? (i.e. using the DTE $project object in the Install.ps1 file)
I would greatly appreciate any help on this.
Thanks
Richard
As of NuGet 2.5, by convention, if you add a targets file at build\{packageid}.targets (note 'build' is at the same level as content and tools), NuGet will automatically add an Import to the .targets file in the project. Then you don't need handle anything in install.ps1. The Import will be automatically removed on uninstall.
Also, I think the recommended way to do what you want would to create a separate target that is configured to run after the standard "Build" target:
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="NuGetCustomTarget" AfterTargets="Build">
<PropertyGroup>
<PathToOutputExe>..\bin\Executable.exe</PathToOutputExe>
<PathToOutputJs>"$(MSBuildProjectDirectory)\Scripts\Output.js"</PathToOutputJs>
<DirectoryOfAssemblies>"$(MSBuildProjectDirectory)\bin\"</DirectoryOfAssemblies>
</PropertyGroup>
<AspNetCompiler Condition="'$(MvcBuildViews)'=='true'" VirtualPath="temp" PhysicalPath="$(ProjectDir)" />
<Exec Command="$(PathToOutputExe) $(PathToOutputJs) $(DirectoryOfAssemblies)" />
</Target>
</Project>
Here's a script that adds a afterbuild target. It also user the NugetPowerTools mentioned above.
$project = Get-Project
$buildProject = Get-MSBuildProject
$target = $buildProject.Xml.AddTarget("MyCustomTarget")
$target.AfterTargets = "AfterBuild"
$task = $target.AddTask("Exec")
$task.SetParameter("Command", "`"PathToYourEXe`" $(TargetFileName)")
The hard part was getting the quotes right. This is what it looks like in my powertools script.
You can use the MSBuild Api directly, as in this blog post.
Add-Type -AssemblyName 'Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
$msbProject = [Microsoft.Build.Evaluation.ProjectCollection]::GlobalProjectCollection.GetLoadedProjects($project.FullName) | Select-Object -First 1
# use $msbProject to add/change AfterBuild target
Or you could use NugetPowerTools which adds Powershell command Get-MSBuildProject to do much the same thing.
Also, see this forum post for more details on adding the new target.

Publishing my asp.net mvc application via script and not Visual Studio

I dont really know much about this to be honest with you...
I have managed to download mscommunity build and I have managed to use the script below to successfully compile and build my application, however I want to get my asp.net mvc application "published" so I want the same files that you when clicking "publish" inside visual studio. My current build file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Import the MSBuild Tasks -->
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<ClassLibraryOutputDirectory>c:\publish\</ClassLibraryOutputDirectory>
<ProjectDir>..\PetProject\</ProjectDir >
<ProjectTestDir>$(ProjectDir)PetProject.WebUI\</ProjectTestDir >
<ProjectFile>$(ProjectDir)PetProject.sln</ProjectFile >
<TestProjectFile>$(ProjectTestDir)PetProject.WebUI.csproj</TestProjectFile >
</PropertyGroup>
<!-- Build projects by calling the Project files generated by VS -->
<Target Name="Build">
<MSBuild Projects="$(ProjectFile)" />
<MSBuild Projects="$(TestProjectFile)" />
</Target>
</Project>
I call this in command line using:
C:\Windows\Microsoft.NET\Framework\v3.5>msbuild.exe C:\Projects\PetProject\build
\PetProject.build
Help is greatly appreciated...
NOTE: I want to avoid CI, Nant etc. because I dont really know what they are and I ideally want to get the above working as First Base, then move onto other things like CI or whatever else, I dont want to confuse myself too much...
This should give you the same result as publishing from within Visual Studio:
<Project DefaultTargets="BuildAndPublish" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets" />
<PropertyGroup>
<ProjectFile>C:\PetProject\PetProject.csproj</ProjectFile >
<OutDir>C:\PetProject\MyPublish</OutDir>
</PropertyGroup>
<Target Name="BuildAndPublish">
<MSBuild Projects="$(ProjectFile)" Targets="Package" Properties="Configuration=Release;PackageLocation=$(OutDir)\MSDeploy\Package.zip;_PackageTempDir=$(OutDir)\Temp" />
</Target>
</Project>
for your project.
Don't forget to import Microsoft.Web.Publishing.targets which contains the Package target (which I mixed up with Publish in my inital answer).
If you want to build your solution your script should look something like this:
<Project DefaultTargets="BuildAndPublish" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets" />
<PropertyGroup>
<OutDir>C:\PetProject\MyPublish\</OutDir>
</PropertyGroup>
<ItemGroup>
<Solution Include="C:\PetProject\PetProject.sln">
<Properties>
OutDir=$(OutDir);
Platform=Any CPU;
Configuration=Release;
DeployOnBuild=True;
DeployTarget=Package;
PackageLocation=$(OutDir)\MSDeploy\Package.zip;
_PackageTempDir=$(OutDir)\Temp
</Properties>
</Solution>
</ItemGroup>
<Target Name="BuildAndPublish">
<MSBuild Projects="#(Solution)" />
</Target>
</Project>
There's a blog post by Code Inside which describes basically the same approach but didn't work when I tried it in my environment.