在使用PowerShell的控制台中使用CMD脚本时是否存在任何基本不兼容问题?

我为自动化套件提供了大量的CMD脚本。

在使用CMD.exe的控制台中,一切工作正常。 安装Windows Creator的更新后,PowerShell将通过资源pipe理器的菜单选项成为新的默认Windows Shell,我的脚本将随机分解。 由于两个主要的原因,我无法提供任何有意义的代码重现:

  1. 没有明显的错误发生; 我的自动化脚本最终只是挂起
  2. 每次停顿甚至不在同一个地方发生

我可以告诉你的是,该套件严重依赖退出代码,使用findstr.exetype

我知道像Windowsmacros这样的东西,例如, %Var%是不兼容的,但我假定,因为我做的唯一的调用是.bat文件, .bat行为将是我唯一需要担心的事情。

如果不是这样的话,我的初始.bat应该触发我的参数直接执行CMD.exe实例? 如果是这样,PowerShell友好的最佳方式是什么?

赤松对这个问题的评论都值得一提。

答案的这一部分为问题标题中的通用问题提供了一个通用答案。 请参阅下一节,了解OP的情况。

一般来说从PowerShell调用批处理文件时 ,只需注意以下几点:

  • 始终在文件名中包含特定的文件扩展名( .bat.cmd ,例如script_name.bat

    • 这确保了没有其他形式的优先级较高的相同命令(在本例中命名为script_name )被意外执行,这可能是:
      • 如果没有路径组件的命令名称:
        • 恰好位于$env:PATH%PATH% )变量中前面列出的目录中的别名,函数,cmdlet或外部可执行文件/ PowerShell脚本( *.ps1 ) 如果同一名称的多个可执行文件在同一个 (最早的)目录中,则下一个要点也适用。
      • 带有路径组件的命令名称的情况下:
        • PowerShell脚本( *.ps1 )或可执行文件具有相同的文件名根目录,其扩展名位于%PATHEXT%环境变量的.bat.cmd 之前
  • 如果批处理文件位于当前目录中,则必须以./为文件名前缀./

    • 通过设计,作为安全措施,PowerShell(与cmd.exe不同)不会调用位于当前目录中的可执行文件 ,因此调用script_name.bat来调用当前目录中的该名称的批处理文件不起作用。 [1]

    • 相反,你必须使用一个路径来定位这样一个可执行文件,以便明确表示执行位于当前目录中的东西的意图,最简单的方法是使用前缀./.\ ,如果只在Windows上运行)。 例如./script_name.bat

  • 将参数传递给批处理文件时

    • 要么:要知道PowerShell的解析规则,在参数传递到批处理文件之前应用 – 请参阅我的答案 。
    • 或者:使用--% ( PSv3 +停止解析符号 )传递剩余的参数,就好像它们是从批处理文件传递的一样 (PowerShell除了扩展%<var>% – 样式的环境变量引用)。

[1] eryksun指出,在Vista +中,通过定义环境变量NoDefaultCurrentDirectoryInExePath (其具体值无关紧要),可以使cmd像PowerShell一样运行。
虽然不明智 ,但您仍然可以强制这两个环境总是通过显式添加找到当前目录中的可执行文件. %PATH% / $env:PATH变量; 如果你预先安排 . ,你会得到默认的cmd行为。


至于你的具体情况

安装Windows Creator的更新之后,PowerShell将通过资源管理器的菜单选项成为新的默认Windows Shell

这适用于以下情况:

  • 按下Win-X (系统范围的键盘快捷键)现在在弹出的快捷菜单中提供PowerShell而不是cmd。

  • 使用文件浏览的File菜单现在显示Open Windows PowerShell来代替Open command promptcmd )。

但是, 从文件资源管理器打开/双击时如何调用批处理文件没有任何变化 :注册表中HKEY_CLASSES_ROOT\batchfileHKEY_CLASSES_ROOT\cmdfile的子项仍将shell\open动词定义为"%1" %* ,它应该像以前一样用cmd /c隐式地调用一个批处理文件。

但是,根据您的意见, 您的批处理文件永远不会直接从文件资源管理器中运行 ,因为它需要参数值 ,并且可以通过两种基本方式进行调用:

  • 在按下Win-R (系统范围键盘快捷方式)后出现的Run对话框中输入cmd后,显式地通过cmd控制台。

    • 在这种情况下,一切都应该像以前一样工作:你从cmd调用你的批处理文件。
  • 使用文件资源管理器的File菜单显式地通过PowerShell

    • 根据您的意见,可能会打开PowerShell控制台:

      • 直接在目标批处理文件所在的目录中。
      • 在一个祖先的目录中,比如批处理文件所在的拇指驱动器的根目录。
    • 在这两种情况下,PowerShell对争论的潜在解释都起到了作用。

    • 另外,在第二种情况下(祖先目录),如果批处理文件不依赖于当前目录或显式设置当前目录(例如使用cd /d "%~dp0"将其设置为自己的位置cd /d "%~dp0" )。

如果遇到问题的具体行为,这是一个没有答案的解决方案。 我已经验证了所有停止脚本停止停止后实施类似垫片的解决方法。

正如erykson所说,似乎没有必要使用垫片的原因。 然后使用PowerShell 在CMD中 明确地启动脚本,这与Jeff timelin在问题评论中的原始建议是一致的。

所以,假设你用自己的script_name.bat在我的鞋子里。

script_name.bat 您的旧脚本,初始化并启动一切。 我们可以确保无论在script_name.bat中,通过执行以下操作,都可以通过CMD而不是PowerShell正确运行:

  1. script_name.bat重命名为script_name_shim.bat
  2. 在同一个目录下创建一个新的script_name.bat
  3. 将其内容设置为:

     @echo off CMD.exe /C "%~dp0script_name_shim.bat" %* exit /b %errorlevel% 

这将启动您的脚本与CMD.exe无论您在PowerShell中启动的事实,它也将使用您的所有命令行参数。

这看起来像一个鸡蛋问题,不知道代码很难说出问题的出在哪里。
即使在win10cu中,也有很多方法可以用cmd.exe启动批处理。

与PowerShell控制台进行交互操作时,别名只是一个问题并且与以前的cmd.exe相同。
别名也取决于加载/导入的模块和配置文件。

  • 这个小的PowerShell脚本将从Help.exe获取所有项目,并使用该项目执行Get-Command
  • 内部命令没有对应的PoSh被ErrorAction SilentlyContinue SilentlyContinue过滤掉。
  • 应用程序(* .exe文件)假定是相同的,并由where子句删除。

 help.exe | Select-String '^[AZ][^ ]+'| ForEach-Object { Get-Command $_.Matches.Value -ErrorAction SilentlyContinue }| Where-Object CommandType -ne 'Application'|Select *| Format-Table -auto CommandType,Name,DisplayName,ResolvedCommand,modulee 

在我的系统上的输出示例中,所有这些项目在PowerShell中可能会有所不同:

 CommandType Name DisplayName ResolvedCommand modulee ----------- ---- ----------- --------------- ------ Alias call call -> Invoke-Method Invoke-Method pscx Alias cd cd -> Set-LocationEx Set-LocationEx Pscx.CD Alias chdir chdir -> Set-Location Set-Location Alias cls cls -> Clear-Host Clear-Host Alias copy copy -> Copy-Item Copy-Item Alias del del -> Remove-Item Remove-Item Alias dir dir -> Get-ChildItem Get-ChildItem Alias echo echo -> Write-Output Write-Output Alias erase erase -> Remove-Item Remove-Item Alias fc fc -> Format-Custom Format-Custom Function help pscx Alias md md -> mkdir mkdir Function mkdir Function more Alias move move -> Move-Item Move-Item Function Pause Alias popd popd -> Pop-Location Pop-Location Function prompt Alias pushd pushd -> Push-Location Push-Location Alias rd rd -> Remove-Item Remove-Item Alias ren ren -> Rename-Item Rename-Item Alias rmdir rmdir -> Remove-Item Remove-Item Alias set set -> Set-Variable Set-Variable Alias sc sc -> Set-Content Set-Content Alias sort sort -> Sort-Object Sort-Object Alias start start -> Start-Process Start-Process Alias type type -> Get-Content Get-Content