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 .vbsPOWERSHELL 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