ฝัง VBScript ในสคริปต์ PowerShell - ไฟล์เดียว

Aug 21 2020

เมื่อเร็ว ๆ นี้ฉันได้เรียนรู้มากมายเกี่ยวกับสคริปต์ไฮบริดแบทช์ + VBScript และแม้ว่าจะเป็นการเรียนรู้และใช้งานได้ดี แต่ก็ถึงเวลาเรียนรู้ PowerShell อย่างละเอียดมากขึ้น แต่ส่วนที่ฉันชอบที่สุดของโซลูชัน Batch / VBScript คือฉันสามารถสร้างscript.cmdไฟล์เดียวเพื่อแจกจ่าย

มีวิธีแก้ปัญหาใด ๆ กับ PowerShell / VBScript หรือไม่? ตามหลักการแล้วฉันคิดว่าฉันต้องการ.ps1สคริปต์ที่มี VBScript ในตัว แต่สนใจที่จะรู้จักตัวเลือกของฉัน

ดูเหมือนจะมีความสับสนเกี่ยวกับเป้าหมาย

  • ไฟล์เดียว (นี่คือส่วนที่สำคัญที่สุด)
  • ส่วนขยาย.ps1หรือ.vbs
  • ทั้งPOWERSHELLและVBScriptภายในไฟล์เดียว
  • โบนัส:
    • ไม่มีการเขียนไปยังไฟล์ภายนอก
    • นำหน้าแต่ละบรรทัด
    • ต้องหนีอักขระพิเศษในรหัส
    • การเข้ารหัสส่วนทั้งหมดของสคริปต์ (การดำเนินการที่เน้น 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>

คำตอบ

2 vonPryz Aug 21 2020 at 13:44

สร้างสคริปต์ 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 
1 Hackoo Aug 21 2020 at 16:27

บางทีคุณอาจหมายถึงสร้าง.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

นี่คือ "pseudo-hybrid" เนื่องจากใช้ไฟล์ชั่วคราวในการดำเนินการ: ได้รับแรงบันดาลใจจากคำตอบของ @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 !'
FreeSoftwareServers Aug 22 2020 at 07:20

นี่คือคำตอบสุดท้ายของฉันฉันไม่ได้ทดสอบกับอะไรที่ซับซ้อนมากดังนั้นไม่แน่ใจว่ามันจะจัดการกับสิ่งต่างๆเช่นอักขระพิเศษอย่างไร ...

#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
npocmaka Nov 13 2020 at 19:27

คุณสามารถฝังโค้ด VB.NET ลงในโค้ด powershell ด้วย TypeDefinition:

$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 แต่เป็นทางออกที่ดี