24

I'm trying to use WebDeploy to publish a website using custom MSDeploy skip rules and a publish profile saved in Visual Studio 2012.

I have the publish profile working from the command line, but the skip rule to skip deleting a folder isn't working.

I have an ErrorLog subfolder in my web app with a web.config file inside it to set the proper folder permissions. Without any skip rules, the ErrorLog folder and web.config file are published normally, but all existing error log files in the folder on the server are deleted on publish.


Error with <SkipAction>Delete</SkipAction>

When I add a custom skip rule to my wpp.targets file, the skip rule is no longer accepting a value for the <SkipAction> element. If I set <SkipAction>Delete</SkipAction>, I get the following error:

C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.targets(4377,5): error : Web deployment task failed. (Unrecognized skip directive 'skipaction'. Must be one of the following: "objectName," "keyAttribute," "absolutePath," "xPath," "attributes.<name>.") [C:\inetpub\wwwroot\My.Website\My.Website\My.Website.csproj]

If I simply omit the <SkipAction> element, the ErrorLog folder is deleted when it would normally be published.

If I set <SkipAction></SkipAction>, again, the ErrorLog folder is deleted on publish.

If I set <KeyAttribute>Delete</KeyAttribute>, then ErrorLog and the web.config file are published normally.

My understanding is that in order to use custom skip rules, you need to call MSBuild from the command line instead of publishing from within VS 2012. I'd still like to use my saved publishing profiles, however, and I understand that's now possible as of VS 2012.


My MSBuild command line:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe My.Website.sln /p:Configuration=Release;DeployOnBuild=true;PublishProfile="Test Server - Web Deploy"

My.Website.wpp.targets:

<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <AfterAddIisSettingAndFileContentsToSourceManifest>AddCustomSkipRules</AfterAddIisSettingAndFileContentsToSourceManifest>
  </PropertyGroup>

  <Target Name="AddCustomSkipRules">
    <Message Text="Adding Custom Skip Rules" />
    <ItemGroup>
      <MsDeploySkipRules Include="SkipErrorLogFolder1">
        <SkipAction></SkipAction>
        <KeyAttribute>Delete</KeyAttribute>
        <ObjectName>dirPath</ObjectName>
        <AbsolutePath>$(_Escaped_WPPAllFilesInSingleFolder)\\ErrorLog$</AbsolutePath>
        <XPath></XPath>
      </MsDeploySkipRules>
    </ItemGroup>
  </Target>
</Project>

My MSBuild output showing the custom skip rule, but still deleting the files:

GenerateMsdeployManifestFiles:
  Generate source manifest file for Web Deploy package/publish ...
AddCustomSkipRules:
  Adding Custom Skip Rules
MSDeployPublish:
  Start Web Deploy Publish the Application/package to http://testserver.domain.com/MSDEPLOYAGENTSERVICE ...
  Starting Web deployment task from source: manifest(C:\inetpub\wwwroot\My.Website\My.Website\obj\Release\Package\My.Website.SourceManifest.xml) to Destination: auto().
  Deleting filePath (MyWeb/ErrorLog\test.txt).
  Updating setAcl (MyWeb/).
  Updating setAcl (MyWeb/).
  Updating filePath (MyWeb/ErrorLog\Web.config).
  Updating filePath (MyWeb/Web.config).
  Updating setAcl (MyWeb/).
  Updating setAcl (MyWeb/).
  Successfully executed Web deployment task.
  Publish is successfully deployed.
nekno
  • 19,177
  • 5
  • 42
  • 47

7 Answers7

23

Edit: It turns out you are right: the skip directive is ignored when executed from Visual Studio.

Fortunately, there's a workaround.

What you want is this:

<!-- Skip the deletion of any file within the ErrorLog directory -->
<MsDeploySkipRules Include="SkipErrorLogFolder1">
  <SkipAction>Delete</SkipAction>
  <ObjectName>filePath</ObjectName>
  <AbsolutePath>ErrorLog</AbsolutePath>
</MsDeploySkipRules>

In addition, you need to prevent VS from using the UI-task (which appears to contain a bug regarding the skip rules). You can do this by declaring the following in your wpp.targets or pubxml:

<PropertyGroup>
  <UseMsDeployExe>true</UseMsDeployExe>
</PropertyGroup>

I've tested this locally and I can confirm that it works as desired: the additional file is updated but no files in the directory are deleted.

Richard Szalay
  • 83,269
  • 19
  • 178
  • 237
  • If I use the skip rule as you show, with no `SkipAction` value and no `KeyAttribute` element, it does skip deleting files in the `ErrorLog` folder --- so that's good --- but it also skips publishing the `ErrorLog\web.config` file --- not good. Why can't I use `Delete`, as all the examples on the web show (including your Technet link)? Btw, I got the impression skip rules work only when building with MSBuild.exe from (A) testing previously in VS 2010, and (B) [this blog post](http://blog.alanta.nl/2011/02/web-deploy-customizing-deployment.html#warning-skip-rules) – nekno Sep 25 '12 at 17:22
  • Specifying a SkipAction is fine. – Richard Szalay Sep 25 '12 at 22:09
  • **No it's not** - You get the error in my opening question if you specify `Delete`. And if you specify `` with an empty element, the `ErrorLog\web.config` **isn't published**. – nekno Sep 25 '12 at 23:35
  • @nekno - I'm not sure about the error, but I've discovered a workaround for the skip rule being ignored. See my updated answer. – Richard Szalay Sep 26 '12 at 02:08
  • Thank you, that works wonderfully - I had tried all sorts of combinations of `UseMsDeployExe` with different `SkipAction`, `ObjectName`, and `AbsolutePath` values, but I wasn't able to land on the exact combo you posted. Despite trying to mimic other rules using regular expressions in Microsoft's own .targets files, it doesn't seem to work with any regex in the `AbsolutePath` value. Only "`ErrorLog`" exactly seems to work. Regardless, it's working for my scenario. – nekno Sep 27 '12 at 19:55
  • @RichardSzalay I'm have a project I continually publish to an Azure Website. In the project I have a folder called "media" with files upload via the content manager. Each time I publish my project this folder gets deleted. I have a rule to skip deletion of this folder using the sintax from your answer. What could I be doing wrong? – amhed Feb 28 '13 at 20:57
  • @amhed Welcome to StackOverflow. We try to avoid asking additional questions from within comments. You should ask in a new question I (ot someone else) will be more able to help. – Richard Szalay Feb 28 '13 at 21:32
  • I think I have the same issue as @amhed, asked here by me http://stackoverflow.com/questions/18226048/msdeployskiprules-in-wpp-targets-not-working-with-publishprofiles Richard can you perhaps show your full example or upload a zip solution file somewhere please? I have tried everything but couldn't get your example to work – David Smit Aug 14 '13 at 08:26
  • This is the answer I was looking for... after 1 hour I managed to find it. Thanks God and @RichardSzalay! :D I even wrote a humble blog post with a simple sample about it here: http://www.leniel.net/2014/05/using-msdeploy-publish-profile-pubxml-to-create-an-empty-folder-structure-on-iis-and-skip-deleting-it-with-msdeployskiprules.html – Leniel Maccaferri May 22 '14 at 16:08
9

For reference, here is my complete .wpp.targets file with working skip rule to skip deleting the ErrorLog folder and custom ACLs to make the ErrorLog folder writable on the server.

As of VS 2012 Update 3, this only works when publishing with MSBuild from the command line with the DeployOnBuild=true;PublishProfile="Test Server - Web Deploy" options passed to MSBuild. This will not work when publishing from within VS.

<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <UseMsdeployExe>true</UseMsdeployExe> <!-- Required for the MSDeploySkipRules to work -->
    <DeployManagedPipelineMode>Integrated</DeployManagedPipelineMode>
  </PropertyGroup>

  <PropertyGroup>
    <AfterAddIisSettingAndFileContentsToSourceManifest>
      $(AfterAddIisSettingAndFileContentsToSourceManifest);
      AddCustomSkipRules;
    </AfterAddIisSettingAndFileContentsToSourceManifest>
  </PropertyGroup>

  <Target Name="AddCustomSkipRules">
    <Message Text="Adding Custom Skip Rules" />
    <ItemGroup>
      <MsDeploySkipRules Include="SkipErrorLogFolder">
        <SkipAction>Delete</SkipAction>
        <ObjectName>filePath</ObjectName>
        <AbsolutePath>ErrorLog</AbsolutePath>
        <XPath></XPath>
      </MsDeploySkipRules>
    </ItemGroup>
  </Target>

  <PropertyGroup>
    <AfterAddIisSettingAndFileContentsToSourceManifest>
      $(AfterAddIisSettingAndFileContentsToSourceManifest);
      SetCustomACLs;
    </AfterAddIisSettingAndFileContentsToSourceManifest>
    <AfterAddDeclareParametersItemsForContentPath>
      $(AfterAddDeclareParametersItemsForContentPath);
      SetCustomAclParameters;
    </AfterAddDeclareParametersItemsForContentPath>
  </PropertyGroup>

  <Target Name="SetCustomACLs">
    <Message Text="Setting Custom ACLs" />
    <ItemGroup>
      <!--Make sure the application pool identity has write permission to the download folder--> 
      <MsDeploySourceManifest Include="setAcl"
        Condition="$(IncludeSetAclProviderOnDestination) And Exists('$(_MSDeployDirPath_FullPath)\ErrorLog')">
        <Path>$(_MSDeployDirPath_FullPath)\ErrorLog</Path>
        <setAclAccess>Write</setAclAccess>
        <setAclResourceType>Directory</setAclResourceType>
        <AdditionalProviderSettings>setAclResourceType;setAclAccess</AdditionalProviderSettings>
      </MsDeploySourceManifest>
    </ItemGroup>
  </Target>

  <Target Name="SetCustomAclParameters">
    <Message Text="Setting Custom ACL Parameters" />
    <EscapeTextForRegularExpressions Text="$(_MSDeployDirPath_FullPath)">
      <Output TaskParameter="Result" PropertyName="_EscapeRegEx_MSDeployDirPath" />
    </EscapeTextForRegularExpressions>
    <ItemGroup>
      <MsDeployDeclareParameters Include="Add write permission to ErrorLog folder"
        Condition="$(IncludeSetAclProviderOnDestination) and Exists('$(_MSDeployDirPath_FullPath)\ErrorLog')">
        <Kind>ProviderPath</Kind>
        <Scope>setAcl</Scope>
        <Match>^$(_EscapeRegEx_MSDeployDirPath)\\ErrorLog$</Match>
        <Description>Add write permission to ErrorLog folder</Description>
        <DefaultValue>Default Web Site/ErrorLog</DefaultValue>
        <Value>$(DeployIisAppPath)/ErrorLog</Value>
        <Tags>Hidden</Tags>
        <Priority>$(VsSetAclPriority)</Priority>
        <ExcludeFromSetParameter>True</ExcludeFromSetParameter>
      </MsDeployDeclareParameters>
    </ItemGroup>
  </Target>
</Project>
nekno
  • 19,177
  • 5
  • 42
  • 47
4

Another approach is to avoid the SkipAction tag, I've successfully used this setup directly from VS 2013:

<Target Name="AddCustomSkipRules"
        AfterTargets="AddIisSettingAndFileContentsToSourceManifest">
    <Message Text="Adding Custom Skip Rules" />
    <ItemGroup>
        <MsDeploySkipRules Include="SkipMedia">
            <objectName>dirPath</objectName>
            <absolutePath>media</absolutePath>
        </MsDeploySkipRules>
        <MsDeploySkipRules Include="SkipUpload">
            <objectName>dirPath</objectName>
            <absolutePath>upload</absolutePath>
        </MsDeploySkipRules>
    </ItemGroup>
</Target>

Only caveat as far as I can tell is that, it will ignore both update, delete and add operations.

Hauge
  • 1,709
  • 15
  • 25
2

After many hours looking through the net. i created this file as {myprojectname}.wpp.targets under the site root folder. it works when publishing with visual studio. the media folder is ignored. i am using VS 2010.

<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <UseMsdeployExe>true</UseMsdeployExe>
        <!-- Required for the MSDeploySkipRules to work -->
        <DeployManagedPipelineMode>Integrated</DeployManagedPipelineMode>
    </PropertyGroup>

    <PropertyGroup>
        <AfterAddIisSettingAndFileContentsToSourceManifest>
            $(AfterAddIisSettingAndFileContentsToSourceManifest);
            AddCustomSkipRules;
        </AfterAddIisSettingAndFileContentsToSourceManifest>
    </PropertyGroup>

    <Target Name="AddCustomSkipRules">
        <Message Text="Adding Custom Skip Rules - WPP Targets 2" />
        <ItemGroup>
            <MsDeploySkipRules Include="SkipErrorLogFolder">
                <SkipAction>Delete</SkipAction>
                <ObjectName>dirPath</ObjectName>
                <AbsolutePath>media</AbsolutePath>
                <XPath></XPath>
                <Apply>Destination</Apply>
            </MsDeploySkipRules>
        </ItemGroup>
    </Target>
</Project>
Sanjay
  • 21
  • 1
0

I think the problem is in incorrect AbsolutePath. It should be a regular expression to match file or folder. so it should be properly escaped. Below is the sample which worked for me (I wanted to skip removal of app_offline.htm to make delivery part of larger deployment)

<PropertyGroup>
    <PackageUsingManifestDependsOn>$(PackageUsingManifestDependsOn);AddCustomSkipRules</PackageUsingManifestDependsOn>
  </PropertyGroup>
  <Target Name="AddCustomSkipRules">
    <ItemGroup>
      <MsDeploySkipRules Include="SkipAppOfflineOnDeploy">
        <SkipAction></SkipAction>
        <ObjectName>filePath</ObjectName>
        <AbsolutePath>app_offline\.htm</AbsolutePath>
        <Apply>Destination</Apply>
        <XPath></XPath>
      </MsDeploySkipRules>
    </ItemGroup>
  </Target>
Koman
  • 31
  • 2
  • No, you'll see from my question that I was using an escaped regex path in `AbsolutePath`: `$(_Escaped_WPPAllFilesInSingleFolder)\\ErrorLog$`, so that's not the issue. You have a different `Apply` value, which may be the key, I don't know without going back to test. – nekno Nov 21 '13 at 18:25
0

Works for me: My Full prepprod.pubxml file in my App_Data/PublishProfiles folder in my web solution. Web Deploy no longer deletes files out of the cachefiles folder on webdeploy from VS 2015. The first PropertyGroup was auto-generated by using the web publishing gui in Visual Studio. I added the second PropertyGroup, and the Target section from previous comments.

<?xml version="1.0" encoding="utf-8"?>
<!--
This file is used by the publish/package process of your Web project. You can customize the behavior of this process
by editing this MSBuild file. In order to learn more about this please visit http://go.microsoft.com/fwlink/?LinkID=208121. 
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>
    <WebPublishMethod>MSDeploy</WebPublishMethod>
    <LastUsedBuildConfiguration>Production</LastUsedBuildConfiguration>
    <LastUsedPlatform>Any CPU</LastUsedPlatform>
    <SiteUrlToLaunchAfterPublish>{masked}</SiteUrlToLaunchAfterPublish>
    <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
    <ExcludeApp_Data>False</ExcludeApp_Data>
    <MSDeployServiceURL>{masked}</MSDeployServiceURL>
    <DeployIisAppPath>{masked}</DeployIisAppPath>
    <RemoteSitePhysicalPath />
    <SkipExtraFilesOnServer>False</SkipExtraFilesOnServer>
    <MSDeployPublishMethod>WMSVC</MSDeployPublishMethod>
    <MSDeployUseChecksum>true</MSDeployUseChecksum>
    <EnableMSDeployBackup>True</EnableMSDeployBackup>
    <UserName>{masked}</UserName>
    <_SavePWD>True</_SavePWD>
    <PublishDatabaseSettings>
      <Objects xmlns="">
      </Objects>
    </PublishDatabaseSettings>
    <ExcludeFilesFromDeployment>packages.config;*.bat;*.sln;*.suo,*.p4ignore</ExcludeFilesFromDeployment>
    <ExcludeFoldersFromDeployment>packages;cachefiles;.ebextensions</ExcludeFoldersFromDeployment>
  </PropertyGroup>

  <PropertyGroup>
    <AfterAddIisSettingAndFileContentsToSourceManifest>
      $(AfterAddIisSettingAndFileContentsToSourceManifest);
      AddCustomSkipRules;
    </AfterAddIisSettingAndFileContentsToSourceManifest>
  </PropertyGroup>

  <Target Name="AddCustomSkipRules">
    <Message Text="Adding Custom Skip Rules" />
    <ItemGroup>
      <MsDeploySkipRules Include="SkipcachefilesFolder">
        <objectName>dirPath</objectName>
        <absolutePath>cachefiles</absolutePath>
      </MsDeploySkipRules>
    </ItemGroup>
  </Target>

</Project>
Avi G
  • 21
  • 3
0

This worked for me in vs 2015, website project type:

<!--Added inside existing <ProjectGroup> tag-->
<AfterAddIisSettingAndFileContentsToSourceManifest>AddCustomSkipRules</AfterAddIisSettingAndFileContentsToSourceManifest>

<!--Added new ProjectGroup tag inside <Project></Project>-->
<PropertyGroup>
   <WebPublishMethod>MSDeploy</WebPublishMethod>
</PropertyGroup>

<!--Added inside existing <Project> tag at the bottom-->
<Target Name="AddCustomSkipRules">
<Message Text="Adding Custom Skip Rules" />
 <ItemGroup>
  <MsDeploySkipRules Include="SkipConfigFolder">
    <SkipAction></SkipAction>
    <!--<KeyAttribute>Delete</KeyAttribute>-->
    <ObjectName>dirPath</ObjectName>
    <AbsolutePath>App_Data\\Composite\\Logfiles</AbsolutePath>
    <XPath>
    </XPath>
  </MsDeploySkipRules>
 </ItemGroup>
</Target>
Sgedda
  • 1,323
  • 1
  • 18
  • 27