diff --git a/.azure/pipelines/site-extensions.yml b/.azure/pipelines/site-extensions.yml
new file mode 100644
index 0000000000..69924ca3c1
--- /dev/null
+++ b/.azure/pipelines/site-extensions.yml
@@ -0,0 +1,38 @@
+trigger:
+ branches:
+ include:
+ - release/2.2
+
+phases:
+- phase: SiteExtensions
+ variables:
+ CI: true
+ DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
+
+ # This variable is required by MicroBuildSigningPlugin to determine permissions for codesigning.
+ TeamName: AspNetCore
+
+ # SignType = { test, real }
+ # This is prefixed underscore because variables automatically become environment variables (and therefore MSBuild properties),
+ # and this one was causing issues in MSBuild projects which use the $(SignType) MSbuild prop.
+ _SignType: real
+
+ steps:
+ - task: MicroBuildSigningPlugin@1
+ displayName: Install MicroBuild plugin
+ condition: and(succeeded(), in(variables['_SignType'], 'test', 'real'))
+ inputs:
+ signType: $(_SignType)
+ zipSources: false
+ - script: src/SiteExtensions/build.cmd -ci
+ displayName: Run src/SiteExtensions/build.cmd
+ - task: PublishBuildArtifacts@1
+ displayName: Upload artifacts
+ condition: eq(variables['system.pullrequest.isfork'], false)
+ inputs:
+ pathtoPublish: ./src/SiteExtensions/artifacts/
+ artifactName: artifacts-Windows-Release
+ artifactType: Container
+ - task: MicroBuildCleanup@1
+ displayName: Cleanup MicroBuild tasks
+ condition: always()
diff --git a/src/SiteExtensions/Directory.Build.props b/src/SiteExtensions/Directory.Build.props
new file mode 100644
index 0000000000..e0780dd926
--- /dev/null
+++ b/src/SiteExtensions/Directory.Build.props
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/SiteExtensions/SiteExtensions.sln b/src/SiteExtensions/SiteExtensions.sln
new file mode 100644
index 0000000000..8fe1d6c64c
--- /dev/null
+++ b/src/SiteExtensions/SiteExtensions.sln
@@ -0,0 +1,54 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26124.0
+MinimumVisualStudioVersion = 15.0.26124.0
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0ED05384-4F64-44BA-A4AA-47519DA26E8C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.AzureAppServices.SiteExtension", "src\Microsoft.AspNetCore.AzureAppServices.SiteExtension\Microsoft.AspNetCore.AzureAppServices.SiteExtension.csproj", "{69E22952-302D-4C56-B2BE-7C086EB05C79}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Web.Xdt.Extensions", "src\Microsoft.Web.Xdt.Extensions\Microsoft.Web.Xdt.Extensions.csproj", "{637E1D65-7F1C-476B-AD0A-30B295DF5414}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {69E22952-302D-4C56-B2BE-7C086EB05C79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {69E22952-302D-4C56-B2BE-7C086EB05C79}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {69E22952-302D-4C56-B2BE-7C086EB05C79}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {69E22952-302D-4C56-B2BE-7C086EB05C79}.Debug|x64.Build.0 = Debug|Any CPU
+ {69E22952-302D-4C56-B2BE-7C086EB05C79}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {69E22952-302D-4C56-B2BE-7C086EB05C79}.Debug|x86.Build.0 = Debug|Any CPU
+ {69E22952-302D-4C56-B2BE-7C086EB05C79}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {69E22952-302D-4C56-B2BE-7C086EB05C79}.Release|Any CPU.Build.0 = Release|Any CPU
+ {69E22952-302D-4C56-B2BE-7C086EB05C79}.Release|x64.ActiveCfg = Release|Any CPU
+ {69E22952-302D-4C56-B2BE-7C086EB05C79}.Release|x64.Build.0 = Release|Any CPU
+ {69E22952-302D-4C56-B2BE-7C086EB05C79}.Release|x86.ActiveCfg = Release|Any CPU
+ {69E22952-302D-4C56-B2BE-7C086EB05C79}.Release|x86.Build.0 = Release|Any CPU
+ {637E1D65-7F1C-476B-AD0A-30B295DF5414}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {637E1D65-7F1C-476B-AD0A-30B295DF5414}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {637E1D65-7F1C-476B-AD0A-30B295DF5414}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {637E1D65-7F1C-476B-AD0A-30B295DF5414}.Debug|x64.Build.0 = Debug|Any CPU
+ {637E1D65-7F1C-476B-AD0A-30B295DF5414}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {637E1D65-7F1C-476B-AD0A-30B295DF5414}.Debug|x86.Build.0 = Debug|Any CPU
+ {637E1D65-7F1C-476B-AD0A-30B295DF5414}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {637E1D65-7F1C-476B-AD0A-30B295DF5414}.Release|Any CPU.Build.0 = Release|Any CPU
+ {637E1D65-7F1C-476B-AD0A-30B295DF5414}.Release|x64.ActiveCfg = Release|Any CPU
+ {637E1D65-7F1C-476B-AD0A-30B295DF5414}.Release|x64.Build.0 = Release|Any CPU
+ {637E1D65-7F1C-476B-AD0A-30B295DF5414}.Release|x86.ActiveCfg = Release|Any CPU
+ {637E1D65-7F1C-476B-AD0A-30B295DF5414}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {69E22952-302D-4C56-B2BE-7C086EB05C79} = {0ED05384-4F64-44BA-A4AA-47519DA26E8C}
+ {637E1D65-7F1C-476B-AD0A-30B295DF5414} = {0ED05384-4F64-44BA-A4AA-47519DA26E8C}
+ EndGlobalSection
+EndGlobal
diff --git a/src/SiteExtensions/build.cmd b/src/SiteExtensions/build.cmd
new file mode 100644
index 0000000000..f4169ea5e4
--- /dev/null
+++ b/src/SiteExtensions/build.cmd
@@ -0,0 +1,3 @@
+@ECHO OFF
+SET RepoRoot="%~dp0..\.."
+%RepoRoot%\build.cmd -LockFile %RepoRoot%\korebuild-lock.txt -Path %~dp0 %*
diff --git a/src/SiteExtensions/build.sh b/src/SiteExtensions/build.sh
new file mode 100644
index 0000000000..d5bb0cf631
--- /dev/null
+++ b/src/SiteExtensions/build.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+repo_root="$DIR/../.."
+"$repo_root/build.sh" --path "$DIR" --lockfile "$repo_root/korebuild-lock.txt" "$@"
diff --git a/src/SiteExtensions/build/dependencies.props b/src/SiteExtensions/build/dependencies.props
new file mode 100644
index 0000000000..4a707b5182
--- /dev/null
+++ b/src/SiteExtensions/build/dependencies.props
@@ -0,0 +1,13 @@
+
+
+ $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
+
+
+
+ 2.2.0-preview2-20181004.6
+ 2.1.1-rtm-31076
+ 2.2.0-rtm-35515
+ 1.4.0
+
+
+
diff --git a/src/SiteExtensions/build/repo.props b/src/SiteExtensions/build/repo.props
new file mode 100644
index 0000000000..25129c9001
--- /dev/null
+++ b/src/SiteExtensions/build/repo.props
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/src/SiteExtensions/build/sources.props b/src/SiteExtensions/build/sources.props
new file mode 100644
index 0000000000..43ce6137a6
--- /dev/null
+++ b/src/SiteExtensions/build/sources.props
@@ -0,0 +1,11 @@
+
+
+
+
+ $(RestoreSources);
+ https://api.nuget.org/v3/index.json;
+ https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;
+
+
+
+
\ No newline at end of file
diff --git a/src/SiteExtensions/global.json b/src/SiteExtensions/global.json
new file mode 100644
index 0000000000..336b8c5dba
--- /dev/null
+++ b/src/SiteExtensions/global.json
@@ -0,0 +1,8 @@
+{
+ "sdk": {
+ "version": "2.2.100-preview2-009404"
+ },
+ "msbuild-sdks": {
+ "Internal.AspNetCore.Sdk": "2.2.0-preview2-20181011.10"
+ }
+}
diff --git a/src/SiteExtensions/src/Directory.Build.props b/src/SiteExtensions/src/Directory.Build.props
new file mode 100644
index 0000000000..4b89a431e7
--- /dev/null
+++ b/src/SiteExtensions/src/Directory.Build.props
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/SiteExtensions/src/Microsoft.AspNetCore.AzureAppServices.SiteExtension/Microsoft.AspNetCore.AzureAppServices.SiteExtension.csproj b/src/SiteExtensions/src/Microsoft.AspNetCore.AzureAppServices.SiteExtension/Microsoft.AspNetCore.AzureAppServices.SiteExtension.csproj
new file mode 100644
index 0000000000..4b8b8f0762
--- /dev/null
+++ b/src/SiteExtensions/src/Microsoft.AspNetCore.AzureAppServices.SiteExtension/Microsoft.AspNetCore.AzureAppServices.SiteExtension.csproj
@@ -0,0 +1,50 @@
+
+
+
+ ASP.NET Core Logging Extensions
+ This extension enables additional functionality for ASP.NET Core on Azure WebSites, such as enabling Azure logging.
+ net461
+ false
+ aspnet;logging;aspnetcore;AzureSiteExtension;keyvault;configuration;dataprotection
+ false
+ AzureSiteExtension
+ true
+ false
+ false
+ false
+ content
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/SiteExtensions/src/Microsoft.AspNetCore.AzureAppServices.SiteExtension/applicationHost.xdt b/src/SiteExtensions/src/Microsoft.AspNetCore.AzureAppServices.SiteExtension/applicationHost.xdt
new file mode 100644
index 0000000000..7078c4f254
--- /dev/null
+++ b/src/SiteExtensions/src/Microsoft.AspNetCore.AzureAppServices.SiteExtension/applicationHost.xdt
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SiteExtensions/src/Microsoft.AspNetCore.AzureAppServices.SiteExtension/scmApplicationHost.xdt b/src/SiteExtensions/src/Microsoft.AspNetCore.AzureAppServices.SiteExtension/scmApplicationHost.xdt
new file mode 100644
index 0000000000..a8dd367f9f
--- /dev/null
+++ b/src/SiteExtensions/src/Microsoft.AspNetCore.AzureAppServices.SiteExtension/scmApplicationHost.xdt
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/SiteExtensions/src/Microsoft.Web.Xdt.Extensions/InsertOrAppendAttribute.cs b/src/SiteExtensions/src/Microsoft.Web.Xdt.Extensions/InsertOrAppendAttribute.cs
new file mode 100644
index 0000000000..c2e711cb93
--- /dev/null
+++ b/src/SiteExtensions/src/Microsoft.Web.Xdt.Extensions/InsertOrAppendAttribute.cs
@@ -0,0 +1,144 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Xml;
+using Microsoft.Web.XmlTransform;
+
+namespace Microsoft.Web.Xdt.Extensions
+{
+ ///
+ /// Insert or append to the given attribute
+ ///
+ public class InsertOrAppendAttribute : Transform
+ {
+ ///
+ ///
+ ///
+ public InsertOrAppendAttribute()
+ : base(TransformFlags.UseParentAsTargetNode, MissingTargetMessage.Error)
+ {
+ }
+
+ private string _attributeName;
+
+ ///
+ ///
+ ///
+ protected string AttributeName
+ {
+ get
+ {
+ if (_attributeName == null)
+ {
+ _attributeName = GetArgumentValue("Attribute");
+ }
+ return _attributeName;
+ }
+ }
+
+ ///
+ /// Extracts a value from the arguments provided
+ ///
+ ///
+ ///
+ protected string GetArgumentValue(string name)
+ {
+ if (string.IsNullOrEmpty(name))
+ {
+ throw new ArgumentNullException(nameof(name));
+ }
+
+ string result = null;
+ if (Arguments != null && Arguments.Count > 0)
+ {
+ foreach (var arg in Arguments)
+ {
+ if (!string.IsNullOrEmpty(arg))
+ {
+ var trimmedArg = arg.Trim();
+ if (trimmedArg.StartsWith(name, StringComparison.OrdinalIgnoreCase))
+ {
+ var start = arg.IndexOf('\'');
+ var last = arg.LastIndexOf('\'');
+ if (start <= 0 || last <= 0 || last <= start)
+ {
+ throw new ArgumentException("Expected two ['] characters");
+ }
+
+ var value = trimmedArg.Substring(start, last - start);
+
+ // remove any leading or trailing '
+ value = value.Trim().TrimStart('\'').TrimStart('\'');
+ result = value;
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ ///
+ ///
+ ///
+ protected override void Apply()
+ {
+ if (TargetChildNodes == null || TargetChildNodes.Count == 0)
+ {
+ TargetNode.AppendChild(TransformNode);
+ }
+ else
+ {
+ XmlAttribute transformAtt = null;
+
+ foreach (XmlAttribute att in TransformNode.Attributes)
+ {
+ if (string.Equals(att.Name, AttributeName, StringComparison.OrdinalIgnoreCase))
+ {
+ transformAtt = att;
+ break;
+ }
+ }
+
+ if (transformAtt == null)
+ {
+ throw new InvalidOperationException("No target attribute to append");
+ }
+
+ foreach (XmlNode targetNode in TargetChildNodes)
+ {
+ var foundAttribute = false;
+ foreach (XmlAttribute att in targetNode.Attributes)
+ {
+ if (string.Equals(att.Name, AttributeName, StringComparison.OrdinalIgnoreCase))
+ {
+ foundAttribute = true;
+ if (string.IsNullOrEmpty(att.Value))
+ {
+ att.Value = transformAtt.Value;
+ }
+ else
+ {
+ // TODO: This doesn't compose well with insertOrAppend being applied on the TargetNode.
+ // The target node is created with the children it has in the transform, which means we would
+ // duplicate the value here.
+ if (att.Value == transformAtt.Value)
+ {
+ return;
+ }
+ att.Value = $"{att.Value};{transformAtt.Value}";
+ }
+ }
+ }
+
+ if (!foundAttribute)
+ {
+ var attribute = targetNode.OwnerDocument.CreateAttribute(AttributeName);
+ attribute.Value = transformAtt.Value;
+ targetNode.Attributes.Append(attribute);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/SiteExtensions/src/Microsoft.Web.Xdt.Extensions/Microsoft.Web.Xdt.Extensions.csproj b/src/SiteExtensions/src/Microsoft.Web.Xdt.Extensions/Microsoft.Web.Xdt.Extensions.csproj
new file mode 100644
index 0000000000..4222ec4e2d
--- /dev/null
+++ b/src/SiteExtensions/src/Microsoft.Web.Xdt.Extensions/Microsoft.Web.Xdt.Extensions.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Additional functionality for Xdt transforms.
+ net461
+ true
+ xdt
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SiteExtensions/src/Microsoft.Web.Xdt.Extensions/baseline.netframework.json b/src/SiteExtensions/src/Microsoft.Web.Xdt.Extensions/baseline.netframework.json
new file mode 100644
index 0000000000..202b401f50
--- /dev/null
+++ b/src/SiteExtensions/src/Microsoft.Web.Xdt.Extensions/baseline.netframework.json
@@ -0,0 +1,53 @@
+{
+ "AssemblyIdentity": "Microsoft.Web.Xdt.Extensions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
+ "Types": [
+ {
+ "Name": "Microsoft.Web.Xdt.Extensions.InsertOrAppendAttribute",
+ "Visibility": "Public",
+ "Kind": "Class",
+ "BaseType": "Microsoft.Web.XmlTransform.Transform",
+ "ImplementedInterfaces": [],
+ "Members": [
+ {
+ "Kind": "Method",
+ "Name": "get_AttributeName",
+ "Parameters": [],
+ "ReturnType": "System.String",
+ "Visibility": "Protected",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "GetArgumentValue",
+ "Parameters": [
+ {
+ "Name": "name",
+ "Type": "System.String"
+ }
+ ],
+ "ReturnType": "System.String",
+ "Visibility": "Protected",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "Apply",
+ "Parameters": [],
+ "ReturnType": "System.Void",
+ "Virtual": true,
+ "Override": true,
+ "Visibility": "Protected",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Constructor",
+ "Name": ".ctor",
+ "Parameters": [],
+ "Visibility": "Public",
+ "GenericParameter": []
+ }
+ ],
+ "GenericParameters": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/SiteExtensions/version.props b/src/SiteExtensions/version.props
new file mode 100644
index 0000000000..4889a26987
--- /dev/null
+++ b/src/SiteExtensions/version.props
@@ -0,0 +1,12 @@
+
+
+ 2.2.0
+ rtm
+ $(VersionPrefix)
+ $(VersionPrefix)-$(VersionSuffix)-final
+ t000
+ a-
+ $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-'))
+ $(VersionSuffix)-$(BuildNumber)
+
+