【问题标题】:Embed VBScript in PowerShell Script - One File在 PowerShell 脚本中嵌入 VBScript - 一个文件
【发布时间】:2020-12-10 08:22:11
【问题描述】:

我最近在批处理 + VBScript 混合脚本方面学到了很多东西,虽然它是很好的学习和工作,但现在是时候更彻底地学习 PowerShell。但是,我最喜欢 Batch/VBScript 解决方案的部分是我可以创建一个 script.cmd 文件来分发。

PowerShell/VBScript 有什么解决方案吗?理想情况下,我认为我更喜欢带有嵌入式 VBScript 的 .ps1 脚本,但有兴趣了解我的选择。

关于目标似乎有些混乱。

  • 一个文件(这是最重要的部分)
  • 扩展名.ps1.vbs
  • POWERSHELLVBScript 在单个文件中
  • 奖金:
    • 不写入外部文件
    • 每行开头
    • 必须在代码中转义特殊字符
    • 对整个脚本部分进行编码(开销 CPU 密集型操作)

这是一个理论上的例子:

script.{ps1/vbs}:

<!-- : Begin PS1 script
$strString = "Hello PowerShell"
write-host $strString

cscript //nologo "%~f0?.wsf" //job:HELLOWORLD
exit /b
PAUSE
----- Begin wsf script --->
<package>
  <job id="HELLOWORLD">
    <script language="VBScript">
      MsgBox "Hello World VBS"
    </script>
  </job>
  <job id="VBS">
    <script language="VBScript">
        'Second Script!
    </script>
  </job>
</package>

类似的东西 -->

https://stackoverflow.com/a/9074483/5079799

<!-- : Begin batch script
@ECHO OFF
CLS

cscript //nologo "%~f0?.wsf" //job:HELLOWORLD
exit /b
PAUSE
----- Begin wsf script --->
<package>
  <job id="HELLOWORLD">
    <script language="VBScript">
      MsgBox "Hello World"
    </script>
  </job>
  <job id="VBS">
    <script language="VBScript">
        'Second Script!
    </script>
  </job>
</package>

【问题讨论】:

  • 为什么?我想不出任何你可以在 VBScript 中做而在 Powershell 中做不到的事情。
  • 当我更多地关注转换我的一些脚本时,我了解到这一点。最初的想法可能是在同时使用旧的 VB 代码的同时以编程方式迁移我的代码部分。 @Nick.McDermaid

标签: powershell vbscript


【解决方案1】:

像往常一样创建 VBS 脚本。保存在某个位置,然后将其转换为 Base64。使用字节编码,因此这也适用于二进制文件,并克服了字符编码问题。像这样,

$Content = Get-Content -Path C:\temp\myScript.vbs -Encoding Byte
$Base64 = [System.Convert]::ToBase64String($Content)
$Base64 | Out-File c:\temp\myScript.b64

然后,在您的 Powershell 脚本中,包含 VBS 脚本的编码版本。将 Base64 转换回字符串并将其写入文件。最后调用cscript运行.vbs

$Base64 = "ZgB1AG4AYwB0AGkAbwBuACAAR..."
$Content = [System.Convert]::FromBase64String($Base64)
Set-Content -Path $env:temp\myScript.vbs -Value $Content -Encoding Byte

& cscript /nologo $env:temp\myScript.vbs 

另一种选择是将 VBScript 嵌入到此处的字符串中,就像这样,

# Paste the VBS in a here string
$Content = @'
dim foo
...
'@
Set-Content -Path $env:temp\myScript.vbs -Value $Content
& cscript /nologo $env:temp\myScript.vbs 

【讨论】:

  • @FreeSoftwareServers 哎呀,误读了这个问题。现在是关于 PS1/VBS 的。
【解决方案2】:

也许,您的意思是创建一个 .ps1 脚本文件并从 vbscript 运行它?

如果是这样,这里有一个名为Compress_Archive_by_Extension.vbs的示例

备注: Compress-Archive 仅适用于 PS v4


Option Explicit
Dim Title,ArrExt,Ext
Title = "Compress Archive With Powreshell And Vbscript by Hackoo 2020"
REM We define an array of extensions for archiving !
ArrExt = Array("vbs","vbe","cmd","bat","ps1","js","jse","lnk")

REM Looping thru extensions defined from our array in order to zip and archive them, 
REM so you can add or remove what you want as extension in the array above !
For each Ext in ArrExt
    Call Compress_Archive("%Temp%\*."& Ext,"Temp_Archive_"& Ext)
    Call Compress_Archive("%AppData%\*."& Ext,"AppData_Archive_"& Ext)
    Call Compress_Archive("%LocalAppData%\*."& Ext,"LocalAppData_Archive_"& Ext)
    Call Compress_Archive("%ProgramData%\Microsoft\Windows\Start Menu\Programs\Startup\*."& Ext,"ProgramData_Archive_"& Ext)
    Call Compress_Archive("%UserProfile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\*."& Ext,"UserProfile_Archive_"& Ext)
Next

MsgBox "Archive Script is completed !",vbInformation,Title
'---------------------------------------------------------------------
REM https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.archive/compress-archive?view=powershell-5.1&redirectedfrom=MSDN
Sub Compress_Archive(Source,Destination)
    Const ForWriting = 2
    Dim fs,Ws,ts,Ret,PSFile,ByPassPSFile
    Set fs = CreateObject("Scripting.FileSystemObject")
    Set Ws = WScript.CreateObject("WScript.Shell")
    Source = Ws.ExpandEnvironmentStrings(Source)
    Destination = Ws.ExpandEnvironmentStrings(Destination)
    PSFile = Ws.ExpandEnvironmentStrings("%Temp%") & fs.GetTempName & ".ps1"
    ByPassPSFile = "PowerShell -ExecutionPolicy bypass -noprofile -file "
    Set ts = fs.OpenTextFile(PSFile,ForWriting,True)
    ts.WriteLine "Compress-Archive -Path " & DblQuote(Source) &_
 " -Update -CompressionLevel Optimal -DestinationPath "& DblQuote(Destination)
    ts.Close
    Ret = Ws.run(ByPassPSFile & PSFile,0,True)
    If fs.FileExists(PSFile) Then fs.DeleteFile(PSFile)
End Sub
'---------------------------------------------------------------------
Function DblQuote(Str)
    DblQuote = Chr(34) & Str & Chr(34)
End Function
'---------------------------------------------------------------------

第二个例子: 从网站下载图片:Download_File.vbs

Option Explicit
Dim URL,Ws,ByPassPSFile,PSFile,MyCmd,Result
URL = "https://cdn2.unrealengine.com/Fortnite%2FBoogieDown_GIF-1f2be97208316867da7d3cf5217c2486da3c2fe6.gif"
Set Ws = CreateObject("wscript.Shell")
PSFile = Left(Wscript.ScriptFullName, InstrRev(Wscript.ScriptFullName, ".")) & "ps1"
ByPassPSFile = "cmd /C PowerShell.exe -ExecutionPolicy bypass -noprofile -file "
MyCmd = "$source = " & DblQuote(URL) & VbCrlF
MyCmd = MyCmd & "$Filename = [System.IO.Path]::GetFileName($source)" & VbCrlF
MyCmd = MyCmd & "$dest = " & DblQuote("$env:temp\$Filename") & VbCrlF
MyCmd = MyCmd & "$wc = New-Object System.Net.WebClient" & VbCrlF
MyCmd = MyCmd & "$wc.DownloadFile($source,$dest)" & VbCrlF
MyCmd = MyCmd & "Start-Process $dest"
Call WriteMyPSFile(MyCmd)
Result = Ws.run(ByPassPSFile & PSFile,0,True)
'----------------------------------------------------------------------------------------
Sub WriteMyPSFile(strText)
Dim fs,ts,PSFile
Const ForWriting = 2
    PSFile = Left(Wscript.ScriptFullName, InstrRev(Wscript.ScriptFullName, ".")) & "ps1"
    Set fs = CreateObject("Scripting.FileSystemObject")
    Set ts = fs.OpenTextFile(PSFile,ForWriting,True)
    ts.WriteLine strText
    ts.Close
End Sub
'----------------------------------------------------------------------------------------
Function DblQuote(Str)
    DblQuote = Chr(34) & Str & Chr(34)
End Function
'----------------------------------------------------------------------------------------

编辑:21/08/2020 @ 20:45

这是一个“伪混合”,因为它使用临时文件来执行: 灵感来自@vonPryz 的回答。

您可以将其保存为 Test.ps1 并从 PowerShell ISE 执行


$VBS_Content = @'
Dim http, WAN_IP
Set http = CreateObject( "MSXML2.ServerXmlHttp" )
http.Open "GET", "http://icanhazip.com", False
http.Send
WAN_IP = http.responseText
wscript.echo "WAN_IP : "  & WAN_IP
'@
Set-Content -Path $env:temp\myScript.vbs -Value $VBS_Content
& wscript.exe $env:temp\myScript.vbs

$url = "https://externals.lesechos.fr/medias/2019/04/26/2262811_pourquoi-salto-le-futur-netflix-francais-devra-seuropeaniser-195514-1.jpg" 
#https://stackoverflow.com/questions/35813186/extract-the-filename-from-a-path
$output = $env:temp + "\" + $url.Split("/")[-1]
$start_time = Get-Date
Try {$wb = (New-Object System.Net.WebClient).DownloadFile($url,$output)}
Catch {
    Write-Host "Error from $url ! " -ForegroundColor Red -BackgroundColor Yellow
    Write-Host "Message: [$($_.Exception.Message)"] -ForegroundColor Red -BackgroundColor Yellow
}
Write-Output "Running Script Time taken is : $((Get-Date).Subtract($start_time).Seconds) second(s)"
Start-process $output

另一个简单的例子:

$VBS_Content = @'
MsgBox "This a simple MsgBox from Vbscript"
'@

$TmpVBS="$env:temp\myScript.vbs"
SC $TmpVBS $VBS_Content
wscript.exe $TmpVBS

Echo 'Hello World from Powershell !'

【讨论】:

  • 我不确定我是否遵循这一点,但我更新了我的问题以更清楚地了解目标。
  • 这看起来很有希望,但还有很多事情要做,你能不能简单地在 PowerShell 中使用 VBS MsgBoxECHO 简单地说 Hello {VBS/PowerShell}
  • @FreeSoftwareServers 最后一个只有 MsgBox 的代码对你不起作用???
  • 效果很好,我将更改调整/格式化为 cscript 或您的同时运行。老实说,不确定该选择谁的答案...
【解决方案3】:

这是我的最终答案,我还没有测试过任何超级复杂的东西,所以不确定它会如何处理特殊字符之类的东西......

#https://stackoverflow.com/questions/63514534/embed-vbscript-in-powershell-script-one-file
#######################Begin VBS1#######################
###JOB_A START###
$VBS_Content_Job_A = @'
MsgBox "This a simple MsgBox from Vbscript (Job_A)"
'@
###JOB_A END###
###JOB_B START###
$VBS_Content_Job_B = @'
MsgBox "This a simple MsgBox from Vbscript (Job_B)"
'@
###JOB_B END###
#######################Begin PS1#######################
ECHO 'Hello World from Powershell !'
PAUSE

ECHO "Running VBS Now"
PAUSE

###VBS CALL START###
$VBSJob=$VBS_Content_Job_A
$TmpVBS="$env:temp\myScript.vbs"
Remove-Item $TmpVBS -ErrorAction SilentlyContinue
SC $TmpVBS $VBSJob 
cscript //nologo $TmpVBS
Remove-Item $TmpVBS -ErrorAction SilentlyContinue
###VBS CALL END###

ECHO "Some More PowerShell"
PAUSE

ECHO "I need anoter VBS Script"
PAUSE

###VBS CALL START###
$VBSJob=$VBS_Content_Job_B
$TmpVBS="$env:temp\myScript.vbs"
Remove-Item $TmpVBS -ErrorAction SilentlyContinue
Set-Content -Path $TmpVBS -Value $VBSJob
cscript //nologo $TmpVBS
Remove-Item $TmpVBS -ErrorAction SilentlyContinue
###VBS CALL END###

ECHO "All Done!"
PAUSE

【讨论】:

    【解决方案4】:

    您可以使用 TypeDefinition 将 VB.NET 代码嵌入到 powershell 代码中:

    $code = @"
    Imports System
    
    Namespace MyNameSpace
        Public Class Responder
            Public Shared Sub StaticRespond()
                Console.WriteLine("Static Response")
            End Sub
    
            Public Sub Respond()
                Console.WriteLine("Instance Respond")
            End Sub
        End Class
    End Namespace
    "@
    
    # Check the type has not been previously added within the session, otherwise an exception is raised
    if (-not ([System.Management.Automation.PSTypeName]'MyNameSpace.Responder').Type)
    {
        Add-Type -TypeDefinition $code -Language VisualBasic;
    }
    
    [MyNameSpace.Responder]::StaticRespond();
    
    $instance = New-Object MyNameSpace.Responder;
    $instance.Respond();
    

    不完全是 vbscript,但它是一个很好的解决方案。

    【讨论】:

      猜你喜欢
      • 2016-10-22
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 2015-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多