As derived from this thread, you cannot echo a multi-line string using immediate (%-)expansion, because everything after the first line-break is ignored.
To make your script working you need to correct two issues:
- before the line endlocal & set data=%out%you must replace every new-line in variableoutby an escaped new-line, that is the sequence^plus new-line plus new-line, which is exactly the same that you are using for defining the variableNL;
- echo %data%truncates the displayed string at the first occurrence of a new-line in the value of variable- data, so you need to use- set datato show the actual content of the variable (or more precisely said, of all variables whose names begin with- data);
Both of these items are commented (rem) in the following code:
@echo off
setlocal EnableDelayedExpansion
set out=
set NL=^
for /F "delims= eol=|" %%i in ('dir /b') do (
    if defined out set "out=!out!!NL!"
    set "out=!out!%%i"
)
echo * Original variable content:
set out
rem // Replace every new-line by an escaped new-line:
set out=!out:^%NL%%NL%=^^^%NL%%NL%^%NL%%NL%!
echo * Modified variable content:
set out
endlocal & set data=%out%
rem // Do not use `echo` to show true content of variable:
echo * Returned variable content:
set data
echo * Mistaken variable content:
echo %data%
exit /B 0
Although the variable value is now correctly passed over the endlocal barrier, this approach is not exactly brilliant, because it does not allow you to use variable %data% (again because everything after the first line-break is ignored as initially mentioned), unless you have got delayed expansion enabled in the hosting cmd instance, which would permit to use !data!.
Another remaining problem is that special characters in the multi-line string (like ^, &, (, ) and ", <, >, |) may cause syntax errors or other unexpected issues. However, this can be avoided by using a for meta-variable rather than a normal environment variable for passing the variable value beyond the endlocal barrier, because the former are expanded after special character recognition, in contrast to the latter, which are expanded before:
@echo off
setlocal EnableDelayedExpansion
set out=
set NL=^
for /F "delims=" %%i in ('dir /b') do (
    if defined out set "out=!out!!NL!"
    set "out=!out!%%i"
)
echo # Original variable content:
set out
rem /* Use a `for` meta-variable rather than a normal environment variable to
rem    pass the variable value beyond the `endlocal` barrier;
rem    a standard `for` loop can be used here, because there are not going to be
rem    wildcards `?` and `*` in the variable value since they have already been
rem    resolved by `dir`; `for /F` cannot be used here due to the new-lines: */
for %%j in ("!out!") do endlocal & set "data=%%~j"
rem // Do not use `echo` to show true content of variable:
echo # Returned variable content:
set data
echo # Mistaken variable content:
echo %data%
exit /B 0
The problem not being able to use variable %data% remains though.
To be able to use variable %data% with immediate expansion you could however simply store escaped new-lines rather than literal ones in the variable, because upon expansion you will have the intended literal new-line:
@echo off
setlocal EnableDelayedExpansion
set out=
set NL=^
for /F "delims=" %%i in ('dir /b') do (
    if defined out set "out=!out!!NL!"
    set "out=!out!%%i"
)
echo # Original variable content:
set out
rem // Replace every new-line by an escaped new-line:
set out=!out:^%NL%%NL%=^^^%NL%%NL%^%NL%%NL%!
echo # Modified variable content:
set out
rem /* Use a `for` meta-variable rather than a normal environment variable to
rem    pass the variable value beyond the `endlocal` barrier;
rem    a standard `for` loop can be used here, because there are not going to be
rem    wildcards `?` and `*` in the variable value since they have already been
rem    resolved by `dir`; `for /F` cannot be used here due to the new-lines: */
for %%j in ("!out!") do endlocal & set "data=%%~j"
rem // Do not use `echo` to show true content of variable:
echo # Actual variable content:
set data
echo # Parsed variable content:
echo %data%
exit /B 0
But regard that this is only going to work when %data% does not appear within quoted ("") strings.