J'ai récemment appris beaucoup de choses à jouer avec les scripts hybrides batch + VBScript et même si c'était un excellent apprentissage et que cela fonctionnait, il est temps d'apprendre plus en profondeur PowerShell. Mais ma partie préférée de la solution Batch / VBScript est que je peux créer un seul fichier script.cmd
à distribuer.
Existe-t-il une sorte de solution avec PowerShell / VBScript? Idéalement, je pense que je préférerais un script .ps1
avec VBScript intégré, mais je voudrais connaître mes options.
Il semble y avoir une certaine confusion concernant l'objectif.
.ps1
ou .vbs
POWERSHELL
et VBScript
dans un seul fichierVoici un exemple théorique:
script.{ps1/vbs}
:
<!-- : 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>
Quelque chose comme ça ->
https://stackoverflow.com/a/9074483/5079799
<!-- : 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>
4 Réponses :
Créez le script VBS comme d'habitude. Enregistrez dans un endroit et convertissez-le en Base64. Le codage d'octets est utilisé pour que cela fonctionne également sur les fichiers binaires et surmonte les problèmes de codage de caractères. Ainsi,
# 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
Ensuite, dans votre script Powershell, incluez la version codée du script VBS. Reconvertissez Base64 en chaîne et écrivez-la dans un fichier. Enfin, appelez cscript
pour exécuter le .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
Une autre option est d'incorporer le VBScript dans une chaîne ici comme ceci,
$Content = Get-Content -Path C:\temp\myScript.vbs -Encoding Byte $Base64 = [System.Convert]::ToBase64String($Content) $Base64 | Out-File c:\temp\myScript.b64
@FreeSoftwareServers Oups, vous avez mal lu la question. Maintenant, il s'agit de PS1 / VBS.
Peut-être voulez-vous dire créer un fichier de script .ps1
et l'exécuter à partir de vbscript?
Si tel est le cas, voici un exemple nommé Compress_Archive_by_Extension.vbs
Remarque: Compress-Archive
n'est disponible qu'avec PS v4
$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 !'
Deuxième exemple: pour télécharger une image depuis le site: Download_File.vbs
$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
EDIT: 21/08/2020 à 20:45
Voici un "pseudo-hybride" car il utilise un fichier temporaire à exécuter: inspiré de la réponse @vonPryz.
Vous pouvez l'enregistrer sous Test.ps1
et l'exécuter à partir de PowerShell ISE
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 '----------------------------------------------------------------------------------------
Un autre exemple simple:
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 '---------------------------------------------------------------------
Je ne suis pas sûr de suivre cela, mais j'ai mis à jour ma question pour être plus clair sur l'objectif.
Cela semble prometteur, mais il se passe beaucoup de choses, pouvez-vous simplement utiliser une MsgBox
VBS et un ECHO
dans PowerShell en disant simplement Hello {VBS/PowerShell}
@FreeSoftwareServers Le dernier code avec seulement MsgBox ne fonctionne pas de votre côté ???
Fonctionne très bien, j'ai adapté / formaté le changement à cscript
ou le vôtre a été exécuté simultanément. Honnêtement, je ne sais pas quelle réponse choisir ...
Voici ma réponse finale, je n'ai pas testé avec quoi que ce soit de super compliqué, donc je ne sais pas comment cela gérerait des choses comme les caractères spéciaux ...
#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
Vous pouvez intégrer du code VB.NET dans du code PowerShell avec 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();
Pas exactement vbscript mais c'est une bonne solution.
Pourquoi tho? Je ne peux pas penser à quoi que ce soit que vous puissiez faire dans VBScript que vous ne pouvez pas faire dans Powershell.
J'apprends cela en cherchant davantage à convertir certains de mes scripts. Une première pensée pourrait être de migrer par programmation des sections de mon code tout en utilisant simultanément l'ancien code VB. @ Nick.McDermaid