1

I adapted some code from a solution here, but it doesn't work for me when executed as a bat script. Executed within a bat script, it gives the error below. Executed on the command line (with the correct line number as calculated by the script in place of %Line%, it works fine.

The key line is

more +%Line% %0 | powershell -c –

The error is

û : The term 'û' is not recognized as the name of a cmdlet, function, script file, or operable program.

The full Bat script is

@echo off
set fn=Archive-Extract
set fnp0=C:\RMT\VCS\GIT\Games\soulfu\build\dependencies2\libogg-1.2.2.zip
set fnp1=C:\RMT\VCS\GIT\Games\soulfu\build\dependencies2
::::::::::::::::::::::::::::::::::::
REM Set %A to the line number of all lines starting with ':', this leaves %A with the line number of the last ':'.
for /f "delims=:" %%a In ('findstr /Bn ":" %0') do set /A Line=%%a
REM Send the content of this script past the last line starting with ':' to powershell.
more +%Line% %0 | powershell -c –
::::::::::::::::::::::::::::::::::::

dir *.bat
pause & exit /b

::::::::::::::::::::::::::::::::::::

function Archive-Extract([string]$zipFilePath, [string]$destinationPath) {
    # This will get added when paths are joined, and path comparison will need it to be absent.
    $destinationPath = $destinationPath.TrimEnd("\");

    [Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem');
    $zipfile = [IO.Compression.ZipFile]::OpenRead($zipFilePath);

    # Determine how many top level entries there are.
    $ziplevel0files = @{};
    $zipfile.Entries | foreach {
        $s = ($_.FullName.TrimEnd("/") -split "/")[0];
        if ($ziplevel0files.ContainsKey($s)) {
            $ziplevel0files[$s] = $ziplevel0files[$s] + 1;
        } else {
            $ziplevel0files[$s] = 0;
        }
    }

    if ($ziplevel0files.count -ne 1) {
        Write-Host "Zip archives are (at this time) expected to contain one top-level directory, and all content within it.";
        return 1; # Failure
    }

    $zipDirPath = Join-Path -Path $destinationPath -ChildPath $ziplevel0files.Keys[0];
    # If the directory does not exist, extract the zip archive into the current folder.
    if (Test-Path -LiteralPath $zipDirPath) {
        Write-Host "Top-level extraction directory already exists.";
        return 2; # Failure
    }

    $zipfile.Entries | foreach {
        $extractFilePath = Join-Path -Path $destinationPath -ChildPath $_.FullName;
        $extractFileDirPath = Split-Path -Parent $extractFilePath;
        # Skip the top-level directory everything comes under.
        if ($extractFileDirPath -ne $destinationPath) {
            if (-not (Test-Path -LiteralPath $extractFileDirPath -PathType Container)) {
                New-Item -Path $extractFileDirPath -Type Directory | Out-Null;
            }

            # Sometimes a directory comes after a file within the directory (the latter causes it to be created implicitly above).
            if (-not $extractFilePath.EndsWith("\")) {
                try {
                    [IO.Compression.ZipFileExtensions]::ExtractToFile($_, $extractFilePath, $true);
                } catch {
                    Write-Host "Failed to extract file:" $extractFilePath;
                    return 3; # Failure
                }
            }
        }
    }
    return 0; # Success
}

# Anything that calls should execute the powershell and set the parameters.

$fn = (Get-ChildItem Env:fn).Value;
$f = (get-item -path function:$fn);
Write-Host "sss1" $fn;
if ($fn -eq "Archive-Extract") {
    Write-Host "sss2";
    $archivepath = (Get-ChildItem Env:fnp0).Value;
    $destinationpath = (Get-ChildItem Env:fnp1).Value;
    $err = & $f.ScriptBlock $archivepath $destinationpath;
    exit $err;
} else {
    Write-Host "sss3";
    Write-Error "Failed to match function: "+ $fn;
    exit 1000;
}

What needs to be added to the BAT script to execute the same as when the code is executed line-by-line on the command-line?

EDIT: Note that when I adapted this script to follow the multi-line powerscript commenting approach recommended by npocmaka, the existing code above based on more but with no skipped line numbers worked. However, I am not entirely convinced that this solves the problem. I believe the above code worked fine at one point, as is, and worked for the person who came up with the original base code to begin with.

  • so you want a batch and powershell code in one file ? – npocmaka Feb 01 '15 at 09:26
  • Yes. Getting this working is the sole purpose of this question. – yourpublicdisplayname Feb 01 '15 at 18:52
  • This is a very old post but I think I might have found the problem. If you look very closely at the "key" line in the listing above you will notice that the - indicating read from standard input seems a bit longer than the - in -c. By appropriate cutting and pasting into Notepad and saving as UTF-8, it turns out that the long - is actually U+2013 EN DASH which is saved by Notepad in Ansi mode as 0x96 which is the OEM character û. So the upshot is that the "key" line was actually "more +%Line% %0 | powershell -c û" – Uber Kluger Jul 07 '20 at 16:02

1 Answers1

0
<# : 
@echo off

echo --START POWERSHELL--
:: $cmdargs variable will contain the command line.
powershell $cmdargs="""%*""";$exp=$(Get-Content '%~f0') -replace """`n""",""";""" ;invoke-expression """$exp"""

echo --START BATCH--
dir *.bat
pause & exit /b
#>

Write-Host "sss";

exit;

Try this.I think it's better way for hybridization and allows something like argument passing to powershell script.Just have in mind that every line should be terminated with ;

npocmaka
  • 55,367
  • 18
  • 148
  • 187
  • This works for simple snippets of powershell. But it doesn't work for the actual code I plan to use. See the updated question, which extracts a zip archive that contains a directory with files within it. – yourpublicdisplayname Feb 01 '15 at 18:52
  • @yourpublicdisplayname - the problem probably is with one line comments.Try with `<#comment#>` .Have on mind that this kind of hybridization cannot be perfect. Powershell is verry strict about extensions.You can try also to make [ps1 file to act as batch scripts](http://stackoverflow.com/questions/23162474/) or try to hybrid it with [ADS] (http://www.dostips.com/forum/viewtopic.php?f=3&t=6185) – npocmaka Feb 01 '15 at 19:04
  • The problem is not one line comments. If the first comment is removed, it errors on the next line of code. I expect the problem is the leading spaces. – yourpublicdisplayname Feb 01 '15 at 20:19