I've spent a few days on this, and finally found a solution that seems to work. However, it seems a bit brittle or perhaps ill-advised.
I want all non-system referenced assemblies (current project libraries used are NuGet managed) included in a "libs" subfolder of the build output.
The following snippet included in the bottom of my csproj file does this (built from googling and a couple of questions I've found here.)
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. -->
<Target Name="BeforeBuild">
<Message Text="### Removing existing 'lib' folder" Importance="high" />
<RemoveDir Directories="$(TargetDir)libs" />
</Target>
<Target Name="MoveLibrariesOnBuild" AfterTargets="Build">
<ItemGroup>
<Libraries Include="%(Reference.HintPath)" >
<MissingHintPath>$([MSBuild]::ValueOrDefault('%(Reference.HintPath)', '').Equals(''))</MissingHintPath>
</Libraries>
</ItemGroup>
<Message Text="### Moving libraries to 'libs' ###" Importance="high" />
<Copy SourceFiles="@(Libraries)"
DestinationFiles="$(TargetDir)libs\%(Filename).dll"
Condition="%(Libraries.MissingHintPath) == False"
SkipUnchangedFiles="false"
OverwriteReadOnlyFiles="true" />
</Target>
</Project>
I tried using Reference.Identity and Reference.Filename but Filename included the version, culture, etc info as well (so it wouldn't be properly renamed, unless I tried messing around with an inline string replace.)
Your thoughts? Is there an easier way, am I over thinking this?
I build a list based on the References, and use the HintPath (only exists for non-standard assemblies) as a flag as to which I should include. Then, in my MoveLibrariesOnBuild target the MissingHintPath is used as a condition flag.
I've avoided using CopyLocal (which generates a True property for references) as per recommendations I've found. For example, What is the best practice for "Copy Local" and with project references?
I saw other people asking similar questions, but none seemed answered or complete. Perhaps, with some critique from the community, this can become a useful resource.
PS: I also tried using project Build Events using xcopy and robocopy but those proved even less reliable (and difficult to debug.)
Additionally, this relies upon setting the probing path as described here, C#: Custom assembly directory
PPS: If you have "file in use" problems when removing/overwritting the files, you may need to uncheck "Enable the Visual Studio hosting process", as described here