Use \newcommand in \newenvironment - content of environment is argument of \newcommand

The command form is easier:

\documentclass{article}

\newcommand{\LHZZ}[2]{%
  \expandafter\newcommand\csname LH#1\endcsname[1]{#2}}%
}

\begin{document}

\LHZZ{XY}{%
  write stuff here

  refer to #1%
}

\LHXY{parameter}

\end{document}

If you really insist in using an environment, use environ:

\documentclass{article}
\usepackage{environ}

\makeatletter
\NewEnviron{LHZZ}[1]{%
  \edef\maestroglanz@temp{%
    \unexpanded{\expandafter\gdef\csname LH#1\endcsname}####1{\unexpanded\expandafter{\BODY}}%
  }%
  \maestroglanz@temp
}
\makeatother

\begin{document}

\begin{LHZZ}{XY}
write stuff here

refer to #1
\end{LHZZ}

\LHXY{parameter}

\end{document}

enter image description here


An implementation using xparse and expl3; the largest part of the code is the definition of the error messages in case the environment is called twice with the same argument.

\documentclass{article}
\usepackage{environ,xparse}

\ExplSyntaxOn
\NewEnviron{LHZZ}[1]
 {
  \cs_set_protected:cV { LH#1:n } \BODY
  \cs_if_free:cTF { LH#1 }
   {
    \cs_gset_eq:cc { LH#1 }{ LH#1:n }
   }
   {
    \msg_error:nnn { maestroglanz/LH } { already-defined } { #1 }
   }
 }
\cs_generate_variant:Nn \cs_set_protected:Nn { cV }
\msg_new:nnnn { maestroglanz/LH } { already-defined }
 {
  LH#1~already~defined
 }
 {
  You~used~\token_to_str:N \begin{LHZZ}{#1}~before
 }
\ExplSyntaxOff

\begin{document}

\begin{LHZZ}{XY}
write stuff here 

refer to #1
\end{LHZZ}

\LHXY{parameter}

\begin{LHZZ}{XY}a\end{LHZZ}

\end{document}

Without the error check, the code part would look like

\ExplSyntaxOn
\NewEnviron{LHZZ}[1]
 {
  \cs_set_protected:cV { LH#1:n } \BODY
  \cs_gset_eq:cc { LH#1 }{ LH#1:n }
 }
\cs_generate_variant:Nn \cs_set_protected:Nn { cV }
\ExplSyntaxOff

Update

With xparse released 2019-05-03 the code can become

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentEnvironment{LHZZ}{m +b}
 {
  \cs_set_protected:cn { LH#1:n } { #2 }
  \cs_if_free:cTF { LH#1 }
   {
    \cs_gset_eq:cc { LH#1 }{ LH#1:n }
   }
   {
    \msg_error:nnn { maestroglanz/LH } { already-defined } { #1 }
   }
 }{}
\msg_new:nnnn { maestroglanz/LH } { already-defined }
 {
  LH#1~already~defined
 }
 {
  You~used~\token_to_str:N \begin{LHZZ}{#1}~before
 }
\ExplSyntaxOff

\begin{document}

\begin{LHZZ}{XY}
write stuff here 

refer to #1
\end{LHZZ}

\LHXY{parameter}

\begin{LHZZ}{XY}a\end{LHZZ}

\end{document}

Here is your minimal example turned into a working one:

\documentclass[a4paper]{article}
\usepackage[T1]{fontenc}
\usepackage[ascii]{inputenc}
\usepackage{environ}

\makeatletter

\@ifdefinable\@my@temporary{} % check availability of the name
% That's my environment:
\NewEnviron{LHZZ}[1]{%
    \let \newcommand \relax
    \protected@xdef\@my@temporary{%
        \newcommand{\csname LH#1\endcsname}[1]{\BODY}}%
    \aftergroup\@my@temporary
}

\makeatother



\begin{document}

% That's the use of it:  
\begin{LHZZ}{XY}
    write stuff here 

    refer to ##1 % sorry, doubling "#" is necessary here
\end{LHZZ}

\LHXY{parameter} %the command \LHXY has been created indirectly by \begin{LHZZ}

\end{document}

Edit: I think using \newcommand instead of \global\edef (see Christian’s answer; note, however, that \global\edef is exactly the same as \xdef) does have some added value, because one retains, for example, the ability to define a default argument:

\documentclass[a4paper]{article}
\usepackage[T1]{fontenc}
\usepackage[ascii]{inputenc}
\usepackage{environ}

\makeatletter

\@ifdefinable\@my@temporary@x{} % check availability of the names
\@ifdefinable\@my@temporary@y{}
% That's my environment:
\NewEnviron{LHZZ}[1]{%
    \let \newcommand \relax
    \protected@xdef\@my@temporary@x{%
        \newcommand{\csname LH#1\endcsname}[1]{\BODY}
    }%
    % ... but this one works too (the astersik is there only to illustrate 
    % another possibility: define a non-"\long" command):
    \protected@xdef\@my@temporary@y{%
        \newcommand*{\csname MG#1\endcsname}[1][default]{\BODY}
    }%
    \aftergroup\@my@temporary@x
    \aftergroup\@my@temporary@y
}

\makeatother



\begin{document}

% That's the use of it:  
\begin{LHZZ}{XY}
    write stuff here 
    refer to ##1\par % sorry, doubling "#" is necessary here
\end{LHZZ}

Text before.

\LHXY{parameter} %the command \LHXY has been created indirectly by \begin{LHZZ}
\MGXY[parameter]
\MGXY

Text after.

\end{document}

Edit 2: Always double-check that the brain is connected before writing to TeX.SX! (Will it be, now?) Here is a cleaner implementation of the same basic idea:

\documentclass[a4paper]{article}
\usepackage[T1]{fontenc}
\usepackage[ascii]{inputenc}
\usepackage{environ}

\makeatletter

\@ifdefinable\@my@temporary@x{} % check availability of the names
\@ifdefinable\@my@temporary@y{}
% That's my environment:
\NewEnviron{LHZZ}[1]{%
    \xdef\@my@temporary@x{%
        \noexpand\newcommand{\csname LH#1\endcsname}[1]{%
            \unexpanded\expandafter{\BODY}%
        }%
    }%
    % ... but this one works too (the astersik is there only to illustrate 
    % another possibility: define a non-"\long" command):
    \xdef\@my@temporary@y{%
        \noexpand\newcommand*{\csname MG#1\endcsname}[1][default]{%
            \unexpanded\expandafter{\BODY}%
        }%
    }%
    \aftergroup\@my@temporary@x
    \aftergroup\@my@temporary@y
    % Obviously, in a real application you'd choose only one of the two 
    % possibiities.
}

\makeatother



\begin{document}

\begingroup % to show that normal scoping is obeyed

% That's the use of it:  
\begin{LHZZ}{XY}
    write stuff here 
    refer to \texttt{#1}\par % doubling the "#" is no longer necessary
\end{LHZZ}

Now \verb|\LHXY| is
\begin{flushleft}
    \ttfamily \meaning\LHXY
\end{flushleft}

Text before.

\LHXY{parameter} %the command \LHXY has been created indirectly by \begin{LHZZ}
\MGXY[parameter]
\MGXY

Text after.

\endgroup

Here \verb|\LHXY| is \textbf{%
    \ifdefined \LHXY defined\else not defined\fi
}.

\end{document}

But I’d better follow @egreg’s solicitation… (see comments ;-)


I think this is code golfing however...

\expandafter\newcommand\csname ....\endcsname{... won't work outside -- it's a local definition.

\global\expandafter\newcommand...won't work neither due to expansion, but \global\expandafter\def\csname... would work, but since the environment body shall be grabbed, the \BODY macro must be expanded first, otherwise it would be undefined outside of the environment, so either use \expandafter\xdef\csname.... or \global\expandafter\edef\csname...

\documentclass[12pt,a4paper]{article}
\usepackage[utf8]{inputenc}


\usepackage{environ}
\setlength{\parindent}{0pt}


\NewEnviron{LHZZ}[1]{%
  \long\global\expandafter\edef\csname LH#1\endcsname##1{\BODY\ ##1}
}

\begin{LHZZ}{XY}
  write stuff here 

  Other stuff here
\end{LHZZ}


\begin{document}


\LHXY{parameter} %the command \LHXY has been created indirectly by \begin{LHZZ}
\end{document}