我对PowerShell相当陌生,我正在尝试编写PowerShell脚本以将VBScript中的某些语句转换为Microsoft JScript。这是我的代码:
$vbs = 'C:\infile.vbs'
$js = 'C:\outfile.js'
(Get-Content $vbs | Set-Content $js)
(Get-Content $js) |
Foreach-Object { $_ -match "Sub " } | Foreach-Object { "$_()`n`{" } | Foreach-Object { $_ -replace "Sub", "function" } | Out-File $js
Foreach-Object { $_ -match "End Sub" } | Foreach-Object { $_ -replace "End Sub", "`}" } | Out-File $js
Foreach-Object { $_ -match "Function " } | Foreach-Object { "$_()`n`{" } | Foreach-Object { $_ -replace "Function", "function" } | Out-File $js
Foreach-Object { $_ -match "End Function" } | Foreach-Object { $_ -replace "End Function", "`}" } | Out-File $js
我想要的是PowerShell程序从VBScript输入文件infile.vbs
中获取代码,对其进行转换,然后将其输出到JScript输出文件outfile.js
。这是我想要它做的一个例子:
输入文件:
Sub HelloWorld
(Code Here)
End Sub
输出文件:
function HelloWorld()
{
(Code Here)
}
在功能上会发生类似的事情。从那里,我将手动调整代码以进行转换。当我在PowerShell v5.1中运行程序时,它没有显示任何错误。但是,当我打开outfile.js
时,只能看到一行:
False
实际上,我有两个问题。
1。为什么会这样?
2。如何修复此程序,使其表现出我想要的效果(如上所述)?
谢谢,
Gabe
答案 0 :(得分:1)
您也可以使用switch
语句执行此操作。像这样:
$vbs = 'C:\infile.vbs'
$js = 'C:\outfile.js'
Get-Content $vbs | ForEach-Object {
switch -Regex ($_) {
'Sub '{
'function {0}(){1}{2}' -f $_.Remove($_.IndexOf('Sub '),4).Trim(),[Environment]::NewLine,'{'
}
'End Sub'{
'}'
}
'Function ' {
'function {0}(){1}{2}' -f $_.Remove($_.IndexOf('Function '),9).Trim(),[Environment]::NewLine,'{'
}
'End Function' {
'}'
}
default {
$_
}
}
} | Out-File $js
答案 1 :(得分:0)
好的,此脚本有些错误。 Foreach-Object (也称为%)是要迭代管道中的每个项目。 例子是
@(1..10) | %{ "This is Array Item $_"}
这将放出10行来计数数组项。在当前脚本中,您正在使用此脚本,应该在其中 Where-Object (也称为?)的地方。
@(1..10) | ?{ $_ -gt 5 }
这将输出大于5的所有数字。
例如,您正在尝试追求的目标
function ConvertTo-JS([string]$InputFilePath,[string]$SaveAs){
Get-Content $InputFilePath |
%{$_ -replace "Sub", "function"} |
%{$_ -replace "End Function", "}"} |
%{$_ -replace "Function", "function"} |
%{$_ -replace "End Function", "}" } |
Out-File $SaveAs
}
ConvertTo-JS -InputFilePath "C:\TEST\TEST.vbs" -SaveAs "C:\TEST\TEST.JS"
这不考虑在函数的开头添加{或添加()以太。但是随着所提供的信息有望使您走上正确的轨道。
答案 2 :(得分:0)
关于问题2(如何修复此程序[...]?):
Kirill Pashkov's helpful answer根据switch
语句提供了一种优雅的解决方案。
但是请注意,他的解决方案:
取决于Sub <name>
/ Function <name>
语句部分与匹配的End Sub
/ End Function
部分不在同一行 -虽然通常是 情况,但这不是语法上的要求;例如Sub Foo() WScript.Echo("hi") End Sub
-一行也可以。
根据您自己的解决方案尝试,将()
盲目附加到Sub
/ Function
定义中,这不适用于已经具有参数声明的输入过程/函数(例如Sub Foo (bar, baz)
)。
以下解决方案:
Sub
/ Function
定义Get-Content $vbs | ForEach-Object {
$_ -replace '\b(?:sub|function)\s+(\w+)\s*(\(.*?\))', 'function $1$2 {' `
-replace '\bend\s+(?:sub|function)\b', '}'
} | Out-File $js
以上内容非常依赖regexes (regular expressions)来转换输入;有关如何在-replace
运算符的替换字符串操作数中引用正则表达式匹配结果的详细信息,请参见this answer。
注意事项:您的方法未涵盖VBScript与JScript之间的许多其他语法差异,尤其是VBScript没有return
语句,而是使用<funcName> = ...
从函数返回值。
第一个问题:
但是,当我打开outfile.js时,我只看到一行:
False
[...]
1. 为什么会这样?
除 first ForEach-Object
cmdlet之外的所有cmdlet调用均在单独的语句中运行,因为初始管道结束 first 调用Out-File $js
。
随后的ForEach-Object
调用每个开始一个新管道,并且由于每个管道都以Out-File $js
结尾,因此每个这样的管道都会写入归档$js
-从而覆盖上一个记录的内容。
因此,确定文件$js
最终内容的是 last 管道。
启动的ForEach-Object
管道中的无输入。但是,在这种情况下,其关联的脚本块({...}
)仍会输入一次,其中$_
为$null
[1] :
最后一个管道以Foreach-Object { $_ -match "End Function" }
开头,因此其输出与$null -match "End Function"
等效,其结果为$False
,因为-match
的标量为 LHS(单个输入对象)输出一个 Boolean 值,该值指示是否找到了匹配项。
因此,假设中间管道段(Foreach-Object { $_ -replace "End Function", "}" }
)是有效的 no-op ($False
字符串化为'False'
,因此-replace
运算符找不到要替换的匹配项,并且将未修改的字符串化输入传递出去),Out-File $js
接收字符串'False'
并将其仅写入输出文件{{ 1}}。
即使您将单独的命令转换为最后只有一个$js
段的单个管道,您的命令也无法使用,但是:
假设Out-File $js
通过管道一个传送输入文件的行,类似Get-Content
的东西将再次产生 Boolean 结果-指示当前行($_ -match "Sub "
)是否与字符串$_
相匹配-并传递那个。
通过将LHS设置为 array ,可以将"Sub "
变成 filter -将其封装在数组子表达式运算符-match
中;例如@(...)
-将:
@($_) -match "Sub "
的行作为整体通过 和换句话说:这不能按预期工作,因为:
Sub
中完整反映 ,而不仅仅是匹配部分 。 [1]严格来说,$_
将保留其在当前范围内具有的任何值,但是如果您明确地将一个值分配给了$_
$null
-假设$_
是通常由PowerShell本身控制的 automatic 变量,但是这样做是不明智的-请参见{{3} }。