Both OutlookExporter and ScreenCapture applications are now configured to build as standalone single-file executables. This means:
✅ No DLL dependencies required
✅ Includes the .NET 8.0 runtime
✅ Just copy the .exe and run anywhere on Windows x64
✅ No installation or setup needed on target machines
Added a conditional property group to both OutlookExporter.csproj and ScreenCapture.csproj:
<!-- Single-file executable configuration (applied during publish) -->
<PropertyGroup Condition="'$(RuntimeIdentifier)' != ''">
<PublishSingleFile>true</PublishSingleFile>
<SelfContained>true</SelfContained>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
</PropertyGroup>- Condition: Only applies these settings when RuntimeIdentifier is specified (during publish)
- PublishSingleFile: Bundles all application files (assemblies, dependencies, native libraries) into a single executable
- SelfContained: Includes the .NET runtime in the output (no need for .NET to be installed on target machine)
- IncludeNativeLibrariesForSelfExtract: Ensures native DLLs are extracted and loaded correctly
- EnableCompressionInSingleFile: Compresses the bundled files to reduce executable size
Important: RuntimeIdentifier is NOT specified in the project file. It's passed as a command-line parameter during publish. This allows normal
dotnet buildto work whiledotnet publish -r win-x64creates single-file executables.
Changed from dotnet build to dotnet publish:
Before:
dotnet build OutlookExporter.csproj -c ReleaseAfter:
dotnet publish OutlookExporter.csproj -c Release -r win-x64 --self-contained trueBefore:
bin\Release\net8.0-windows\OutlookExporter.exe
bin\Release\net8.0-windows\ScreenCapture.exe
After:
bin\Release\net8.0-windows\win-x64\publish\OutlookExporter.exe
bin\Release\net8.0-windows\win-x64\publish\ScreenCapture.exe
# OutlookExporter
cd exfil\OutlookExporter
build-outlookexporter.bat
# ScreenCapture
cd exfil\ScreenCapture
build-screencapture.batcd exfil
build-all.batSingle-file executables are larger than regular builds because they include the .NET runtime:
- OutlookExporter.exe: ~35 MB (compressed)
- ScreenCapture.exe: ~72 MB (compressed)
The ScreenCapture utility is larger because it includes Windows Forms and additional graphics libraries. These are reasonable sizes for the portability benefit of true standalone executables.
Simply copy the executable from the publish folder to any Windows x64 machine and run it. No installation, no dependencies, no .NET runtime required on the target machine.
# Copy OutlookExporter
copy OutlookExporter\bin\Release\net8.0-windows\win-x64\publish\OutlookExporter.exe C:\Tools\
# Copy ScreenCapture
copy ScreenCapture\bin\Release\net8.0-windows\win-x64\publish\ScreenCapture.exe C:\Tools\
# Run them anywhere
C:\Tools\OutlookExporter.exe --help
C:\Tools\ScreenCapture.exe --helpTo reduce executable size further, you can enable trimming. Add this to the conditional PropertyGroup in the .csproj file:
<PropertyGroup Condition="'$(RuntimeIdentifier)' != ''">
<PublishSingleFile>true</PublishSingleFile>
<SelfContained>true</SelfContained>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
<!-- Add these for trimming -->
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>link</TrimMode>
</PropertyGroup>If you want smaller executables but are okay with requiring .NET 8.0 on target machines, change:
<SelfContained>false</SelfContained>This will produce ~5-10 MB executables but require .NET 8.0 Runtime installed on target systems.
Cause: Missing Visual C++ Redistributable
Solution: Some native dependencies may require Visual C++ Redistributable. Most Windows systems have this installed.
Solution:
- Enable
PublishTrimmed(see Advanced Configuration) - Switch to framework-dependent deployment
- Use compression tools (UPX, etc.) - though this may trigger antivirus
Cause: Self-extracting executables need to extract files to a temp folder on first run
Solution: This is normal behavior. Subsequent runs will be faster.