diff --git a/src/Internal.AspNetCore.BuildTools.Tasks/FindUnusedReferences.cs b/src/Internal.AspNetCore.BuildTools.Tasks/FindUnusedReferences.cs
new file mode 100644
index 000000000..e027cedc4
--- /dev/null
+++ b/src/Internal.AspNetCore.BuildTools.Tasks/FindUnusedReferences.cs
@@ -0,0 +1,82 @@
+// 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.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection.Metadata;
+using System.Reflection.PortableExecutable;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Microsoft.AspNetCore.BuildTools
+{
+#if SDK
+ public class Sdk_FindUnusedReferences : Task
+#elif BuildTools
+ public class FindUnusedReferences : Task
+#else
+#error This must be built either for an SDK or for BuildTools
+#endif
+ {
+ ///
+ /// IntermediateAssembly from CoreCompile
+ ///
+ [Required]
+ public string Assembly { get; set; }
+
+ ///
+ /// ReferencePath from CoreCompile
+ ///
+ [Required]
+ public ITaskItem[] References { get; set; }
+
+ ///
+ /// FileDefinitions from RunResolvePackageDependencies
+ ///
+ [Required]
+ public ITaskItem[] Packages { get; set; }
+
+ ///
+ /// PackageDependencies from RunResolvePackageDependencies
+ ///
+ [Required]
+ public ITaskItem[] Files { get; set; }
+
+ [Output]
+ public ITaskItem[] UnusedReferences { get; set; }
+
+ public override bool Execute()
+ {
+ var references = new HashSet(References.Select(item => item.ItemSpec), StringComparer.OrdinalIgnoreCase);
+ var referenceFiles = Files.Where(file => references.Contains(file.GetMetadata("ResolvedPath")))
+ .ToDictionary(item => Path.GetFileNameWithoutExtension(item.GetMetadata("ResolvedPath")), StringComparer.OrdinalIgnoreCase);
+
+ var directReferences = new HashSet(
+ Packages.Where(p => string.IsNullOrEmpty(p.GetMetadata("ParentPackage"))).Select(i => i.ItemSpec),
+ StringComparer.OrdinalIgnoreCase);
+
+ using (var fileStream = File.OpenRead(Assembly))
+ using (var reader = new PEReader(fileStream))
+ {
+ var metadataReader = reader.GetMetadataReader();
+ foreach (AssemblyReferenceHandle assemblyReferenceHandle in metadataReader.AssemblyReferences)
+ {
+ var assemblyReference = metadataReader.GetAssemblyReference(assemblyReferenceHandle);
+ var name = metadataReader.GetString(assemblyReference.Name);
+ if (referenceFiles.TryGetValue(name, out var fileItem))
+ {
+ var packageName = fileItem.GetMetadata("PackageName") + "/" + fileItem.GetMetadata("PackageVersion");
+ directReferences.Remove(packageName);
+ referenceFiles.Remove(name);
+ }
+
+ }
+ }
+
+ UnusedReferences = referenceFiles.Values.Where(f => directReferences.Any(r => f.ItemSpec.StartsWith(r))).ToArray();
+ return true;
+ }
+ }
+}
diff --git a/src/Internal.AspNetCore.BuildTools.Tasks/Internal.AspNetCore.BuildTools.Tasks.csproj b/src/Internal.AspNetCore.BuildTools.Tasks/Internal.AspNetCore.BuildTools.Tasks.csproj
index b6e6545ec..d4404dd61 100644
--- a/src/Internal.AspNetCore.BuildTools.Tasks/Internal.AspNetCore.BuildTools.Tasks.csproj
+++ b/src/Internal.AspNetCore.BuildTools.Tasks/Internal.AspNetCore.BuildTools.Tasks.csproj
@@ -34,6 +34,8 @@
+
+
@@ -41,4 +43,17 @@
+
+
+
+ <_PackageFiles Include="bin\$(Configuration)\*\System.Reflection.Metadata.dll;bin\$(Configuration)\*\System.Collections.Immutable.dll">
+ tools\%(RecursiveDir)
+ false
+ Content
+
+
+
diff --git a/src/Internal.AspNetCore.BuildTools.Tasks/build/Tasks.tasks b/src/Internal.AspNetCore.BuildTools.Tasks/build/Tasks.tasks
index 1a3476b87..b92f4df66 100644
--- a/src/Internal.AspNetCore.BuildTools.Tasks/build/Tasks.tasks
+++ b/src/Internal.AspNetCore.BuildTools.Tasks/build/Tasks.tasks
@@ -1,4 +1,4 @@
-
+
<_BuildToolsAssemblyTfm Condition="'$(MSBuildRuntimeType)' == 'Core'">netstandard1.6
@@ -17,6 +17,7 @@
+
diff --git a/src/Internal.AspNetCore.Sdk.Tasks/Internal.AspNetCore.Sdk.Tasks.csproj b/src/Internal.AspNetCore.Sdk.Tasks/Internal.AspNetCore.Sdk.Tasks.csproj
index 43c404363..6ceaf38af 100644
--- a/src/Internal.AspNetCore.Sdk.Tasks/Internal.AspNetCore.Sdk.Tasks.csproj
+++ b/src/Internal.AspNetCore.Sdk.Tasks/Internal.AspNetCore.Sdk.Tasks.csproj
@@ -44,6 +44,9 @@
+
+
+
@@ -51,4 +54,17 @@
+
+
+
+ <_PackageFiles Include="bin\$(Configuration)\*\System.Reflection.Metadata.dll;bin\$(Configuration)\*\System.Collections.Immutable.dll">
+ tools\%(RecursiveDir)
+ false
+ Content
+
+
+
diff --git a/src/Internal.AspNetCore.Sdk/build/FindUnusedReferences.targets b/src/Internal.AspNetCore.Sdk/build/FindUnusedReferences.targets
new file mode 100644
index 000000000..84b95d24a
--- /dev/null
+++ b/src/Internal.AspNetCore.Sdk/build/FindUnusedReferences.targets
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/Internal.AspNetCore.Sdk/build/Internal.AspNetCore.Sdk.targets b/src/Internal.AspNetCore.Sdk/build/Internal.AspNetCore.Sdk.targets
index 30944f3ae..59809fc60 100644
--- a/src/Internal.AspNetCore.Sdk/build/Internal.AspNetCore.Sdk.targets
+++ b/src/Internal.AspNetCore.Sdk/build/Internal.AspNetCore.Sdk.targets
@@ -5,6 +5,7 @@ for use outside of Microsoft.
+