This is not possible without using a loop/cursor of some form. A CTE is a convenient way to walk a static hierarchy, but your problem requires a dynamic hierarchy.
In a static hierarchy there is a deterministic number of steps for each entry point, regardless of how many objects pass through that point. For example, there are two reports between myself and the CEO. If I want to calculate the length of walk for several other employees the length of my walk through the hierarchy will always be two.
In your example, the length of walk changes based on the other folders you want to copy and the order that you process them. If you want to copy 'Folder' and 'Folder (3)', then either 'Folder' or 'Folder (3)' will have a different length of walk depending on which walks the hierarchy first. After the first folder processed has walked the hierarchy then the hierarchy is changed making the hierarchy dynamic.
The below code walks the existing hierarchy for each folder, but doesn't produce the desired answer because the both 'Folder' and 'Folder (3)' end up with the same name
 declare @existing table (folderid uniqueidentifier, displayname varchar(20));
declare @folderstocopy table (folderid uniqueidentifier, displayname varchar(20));
insert @existing
values
    (newid(), 'Folder')
  , (newid(), 'Folder (2)')
  , (newid(), 'Folder (4)');
insert @folderstocopy
values
    (newid(), 'Folder')
  , (newid(), 'Folder (2)')
  , (newid(), 'Folder (3)');
--TODO some logic to deal with name clashes and insert from @folderstocopy into @existing
with cte1 as
    (
        -- anchor
        select
            a.folderid
          , a.displayname
          , b.displayname as existingmatch
          , 1 as lvl
        from
            @folderstocopy as a
        left join
            @existing as b
            on
            a.displayname = b.displayname
        -- recursive
        union all
        select
            a.folderid
          , a.displayname
          , b.displayname as existingmatch
          , a.lvl + 1
        from
            cte1 as a
        inner join
            @existing as b
            on
            a.displayname + ' (' + cast(lvl + 1 as varchar(255)) + ')' = b.displayname
    )
select
    a.folderid
  , a.displayname as originaldisplayname
  , case
        when a.MaxLvl = 1
            then
            a.displayname
        else
            a.displayname + ' (' + cast(a.MaxLvl as varchar(255)) + ')' end as newdisplayname
from
    (
        select
             cte1.folderid
           , cte1.displayname
           , max(case when existingmatch is not null then lvl + 1 else lvl end) as MaxLvl
        from cte1
        group by
             cte1.folderid
           , cte1.displayname
    ) as a;
One possible solution would be to use the a CTE inside a loop as shown below. At each iteration of the loop you could resolve conflicts by adding the lowest folder id to the hierarchy.
declare @existing table (folderid uniqueidentifier, displayname varchar(20));
declare @folderstocopy table (folderid uniqueidentifier, displayname varchar(20));
insert @existing
values
    (newid(), 'Folder')
  , (newid(), 'Folder (2)')
  , (newid(), 'Folder (4)');
insert @folderstocopy
values
    (newid(), 'Folder')
  , (newid(), 'Folder (2)')
  , (newid(), 'Folder (3)');
--TODO some logic to deal with name clashes and insert from @folderstocopy into @existing
while exists (select * from @folderstocopy)
begin;
    with cte1 as
        (
            -- anchor
            select
                a.folderid
              , a.displayname
              , b.displayname as existingmatch
              , 1 as lvl
            from
                @folderstocopy as a
            left join
                @existing as b
                on
                a.displayname = b.displayname
            -- recursive
            union all
            select
                a.folderid
              , a.displayname
              , b.displayname as existingmatch
              , a.lvl + 1
            from
                cte1 as a
            inner join
                @existing as b
                on
                a.displayname + ' (' + cast(lvl + 1 as varchar(255)) + ')' = b.displayname
        )
       , cte2 as
        (
            select
                a.folderid
              , a.displayname as originaldisplayname
              , case
                    when a.MaxLvl = 1
                        then
                        a.displayname
                    else
                        a.displayname + ' (' + cast(a.MaxLvl as varchar(255)) + ')' end as newdisplayname
            from
                (
                    select
                         cte1.folderid
                       , cte1.displayname
                       , max(case when existingmatch is not null then lvl + 1 else lvl end) as MaxLvl
                    from cte1
                    group by
                         cte1.folderid
                       , cte1.displayname
                ) as a
        )
    insert into @existing (folderid, displayname)
    select
         min(folderid) as folderid
       , a.newdisplayname
    from cte2 as a
    group by
         a.newdisplayname;
    delete from @folderstocopy where folderid in (select folderid from @existing);
end;
select * from @existing;