diff --git a/windows/msvc/common.props b/windows/msvc/common.props
index 73103f627a784f93b9577fa66f9eab26a2d0d8ef..cfb6adbc14b68c4485b000d61d2f67f85a57d7bb 100644
--- a/windows/msvc/common.props
+++ b/windows/msvc/common.props
@@ -1,13 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ImportGroup Label="PropertySheets">
-    <Import Project="env.props" />
+    <Import Project="paths.props" Condition="'$(PyPathsIncluded)' != 'True'"/>
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup>
     <OutDir>$(PyOutDir)</OutDir>
-    <IntDir>$(PyBuildDir)$(Configuration)$(Platform)\</IntDir>
-    <PyIncDirs>$(PyBaseDir);$(PyBaseDir)windows;$(PyBaseDir)windows\msvc;$(PyBuildDir)</PyIncDirs>
+    <IntDir>$(PyIntDir)</IntDir>
+    <PyFileCopyCookie>$(PyBuildDir)copycookie$(Configuration)$(Platform)</PyFileCopyCookie>
   </PropertyGroup>
   <ItemDefinitionGroup>
     <ClCompile>
@@ -22,5 +22,24 @@
       <GenerateMapFile>true</GenerateMapFile>
     </Link>
   </ItemDefinitionGroup>
-  <ItemGroup />
+  <ItemGroup>
+    <PyOutputFiles Include="$(TargetPath)">
+      <Destination>$(PyWinDir)%(FileName)%(Extension)</Destination>
+    </PyOutputFiles>
+    <PyCookieFiles Include="$(PyBuildDir)copycookie*" Exclude="$(PyFileCopyCookie)"/>
+  </ItemGroup>
+
+  <!-- Copy PyOutputFiles to their target destination.
+       To force this when switching between platforms/configurations which are already up-to-date (and as such,
+       for which a build wouldn't even start because all outputs are effectively newer than the inputs)
+       an empty file $(PyFileCopyCookie) is created serving as a record to indicate what was last copied,
+       and any previous records are deleted. So when switching between builds which are otherwise up-to-date
+       the tracker will notice a missing file and a build is started anyway (and it will just copy our files). -->
+  <Target Name="CopyFilesToWinDir" AfterTargets="Build"
+          Inputs="$(TargetPath)" Outputs="$(PyFileCopyCookie);@(PyOutputFiles->'%(Destination)')">
+    <Delete Files="@(PyCookieFiles)"/>
+    <Touch Files="$(PyFileCopyCookie)" AlwaysCreate="true"/>
+    <Copy SourceFiles="%(PyOutputFiles.Identity)" DestinationFiles="%(PyOutputFiles.Destination)"/>
+    <WriteLinesToFile File="$(TLogLocation)$(ProjectName).write.u.tlog" Lines="$(PyFileCopyCookie);@(PyOutputFiles->'%(Destination)')" Overwrite="True"/>
+  </Target>
 </Project>
diff --git a/windows/msvc/env.props b/windows/msvc/env.props
deleted file mode 100644
index 824b529e67c64bff3554eaff635227d9ccd3ad36..0000000000000000000000000000000000000000
--- a/windows/msvc/env.props
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <PyBaseDir>$([System.IO.Path]::GetFullPath(`$(MSBuildThisFileDirectory)..\..`))\</PyBaseDir>
-    <PyBuildDir Condition="'$(PyBuildDir)'==''">$(MSBuildThisFileDirectory)build\</PyBuildDir>
-    <PyOutDir Condition="'$(PyOutDir)'==''">$(PyBaseDir)windows\</PyOutDir>
-    <PyEnvIncluded>True</PyEnvIncluded>
-  </PropertyGroup>
-</Project>
diff --git a/windows/msvc/genhdr.targets b/windows/msvc/genhdr.targets
index 93bb74ee9d7a6aab98085ee38279e53bb691f52d..3d9a148bedb0959befa30847d6b050f401bb9d44 100644
--- a/windows/msvc/genhdr.targets
+++ b/windows/msvc/genhdr.targets
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="GenerateHeaders">
 
-  <Import Project="env.props" Condition="$(PyEnvIncluded)!=True"/>
+  <Import Project="paths.props" Condition="'$(PyPathsIncluded)' != 'True'"/>
 
   <!--Generate qstrdefs.h and mpversion.h similar to what is done in py/py.mk-->
   <Target Name="GenerateHeaders" DependsOnTargets="MakeQstrData;MakeVersionHdr">
diff --git a/windows/msvc/paths.props b/windows/msvc/paths.props
new file mode 100644
index 0000000000000000000000000000000000000000..71669824342fd93fff2a512e4c67a1cf048ded41
--- /dev/null
+++ b/windows/msvc/paths.props
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <PyPathsIncluded>True</PyPathsIncluded>
+
+    <!-- The properties below specify the output directory structure.
+         This defaults to, for example for Configuration = Debug and Platform = x64:
+
+         micropython [PyBaseDir]
+          |- ...
+          |- windows [PyWinDir]
+              |- ...
+              |- micropython.exe
+              |- build [PyBuildDir]
+                  |- Debugx64 [PyOutDir]
+                  |   |- ...
+                  |   |- micropython.exe
+                  |   |- micropython.map
+                  |   |- obj [PyIntDir]
+                  |- genhdr
+
+         Note that the micropython executable will be copied from PyOutDir
+         to PyWinDir after each build. -->
+
+    <!-- Start from project root -->
+    <PyBaseDir>$([System.IO.Path]::GetFullPath(`$(MSBuildThisFileDirectory)..\..`))\</PyBaseDir>
+    <PyWinDir>$(PyBaseDir)windows\</PyWinDir>
+    <PyBuildDir Condition="'$(PyBuildDir)' == ''">$(PyWinDir)build\</PyBuildDir>
+
+    <!-- All include directories needed for uPy -->
+    <PyIncDirs>$(PyBaseDir);$(PyWinDir);$(PyBuildDir);$(PyWinDir)msvc</PyIncDirs>
+
+    <!-- Within PyBuildDir different subdirectories are used based on configuration and platform.
+         By default these are chosen based on the Configuration and Platform properties, but
+         this file might be imported by other projects (to figure out where the artifacts go
+         or what the include files are) and those projects might already contain conflicting
+         Configuration/Platform properties, so allow to override these -->
+    <PyPlatform Condition="'$(PyPlatform)' == ''">$(Platform)</PyPlatform>
+    <PyConfiguration Condition="'$(PyConfiguration)' == ''">$(Configuration)</PyConfiguration>
+
+    <!-- The final destination directories -->
+    <PyOutDir>$(PyBuildDir)$(PyConfiguration)$(PyPlatform)\</PyOutDir>
+    <PyIntDir>$(PyOutDir)obj\</PyIntDir>
+  </PropertyGroup>
+</Project>
diff --git a/windows/msvc/sources.props b/windows/msvc/sources.props
index eea28fc46e56cde4f0d078302c1a3163fbfe8e17..b840025006941bf036985e684e1129a40a1fd693 100644
--- a/windows/msvc/sources.props
+++ b/windows/msvc/sources.props
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="env.props" Condition="$(PyEnvIncluded)!=True"/>
+  <Import Project="paths.props" Condition="'$(PyPathsIncluded)' != 'True'"/>
   <ItemGroup>
     <ClCompile Include="$(PyBaseDir)py\*.c" />
     <ClCompile Include="$(PyBaseDir)windows\*.c" />