VBScript to PowerShell
Drop a .vbs file and get PowerShell back, plus a count of what still needs a
human. Lines it can’t convert cleanly come back as
# TODO with your original underneath.
What needs you
The PowerShell
What breaks if you convert it by hand
VBScript and PowerShell look close enough that a text swap compiles. Then it runs, finishes without an error, and gives you a different answer. These are the ones that get people:
-
&always concatenates."1" & 2is the string12. Swap it for+and PowerShell hands you3. -
=on strings is case-sensitive in VBScript.-eqisn’t, so a comparison that used to fail starts passing. -
\is integer division, not a path separator.7 \ 2is3. -
Trueis-1. That shows up the moment it hits arithmetic or gets written to a registry value. -
MidandInStrcount from 1..Substringand.IndexOfcount from 0, andInStrreturns 0 for no match where.IndexOfreturns -1. -
ByRefis the default. In PowerShell it isn’t, so aSubthat writes to its argument stops affecting the caller.
The output carries one small helper function per behaviour it has to keep, and only the ones
your script actually uses. You get a single self-contained .ps1 with no module
to install.
What it flags instead of converting
On Error Resume Next. VBScript carries on at the next statement and PowerShell
has nothing that does that. $ErrorActionPreference = "SilentlyContinue" only
quiets non-terminating errors and won’t resume anything, so on a script PDQ or your RMM
grades by exit code, a swallowed error lands in the console as a successful deployment.
ByRef parameters that get written to. Where the write is visible in the script
you get the parameter name and the line number, so you can decide whether it needs a
[ref] or a return value.
Everything else it can’t do cleanly comes back as a # TODO with your
original line underneath. Thirty TODOs means thirty decisions, and it’s better to see
that number before you start than three days in.
Open source
It's MIT-licensed at github.com/deadarcher/vbs-to-powershell. The converter on this page is byte-identical to the one in the repo, and our CI fails the build if they ever drift. The engine is one dependency-free file, so you can batch-convert a folder of scripts from Node, or self-host the page with one line of Docker:
docker run --rm -p 8080:80 ghcr.io/deadarcher/vbs-to-powershell:latest Converted something wrong? Open an issue with the smallest VBScript that shows it and what you expected.
Questions
Is my script uploaded anywhere?
No. It's JavaScript running in your browser. No upload, no storage, no account. Watch the network tab if you want, or kill your network first and drop the file anyway. It still works.
Can I just run the output?
Not without reading it first. Work through the # TODOs and test it somewhere you don't mind breaking. You're getting a head start on the port, not a finished script.
Why not just swap & for + and be done?
In VBScript & always concatenates, so "1" & 2 gives you the string "12". In PowerShell "1" + 2 gives you 3. Nothing errors. You just get a number where you used to get a string, and you find out about it somewhere else in the script. The output uses a helper that keeps the VBScript behaviour.
What happens to On Error Resume Next?
It gets flagged for you to deal with. VBScript carries on at the next statement, and PowerShell has nothing that does that. $ErrorActionPreference = "SilentlyContinue" only quiets non-terminating errors, it won’t resume anything. On a script PDQ or your RMM is grading by exit code, a swallowed error shows up in the console as a successful deployment. What the tool says about it depends on how you told it the script gets deployed.
Why does it ask how the script is deployed?
Same script, different stakes. A logon script can't block, so a MsgBox buried in one is a real problem. An RMM push is judged entirely on its exit code. A scheduled task runs as SYSTEM with no desktop, so anything waiting on input sits there until the task times out. That changes the verdict and what it tells you about error handling.
How accurate is it?
Across 610 real sysadmin scripts pulled off GitHub: 98% of lines convert, and 94% of whole files come out as PowerShell that parses clean. There's also a 168-case suite that runs the VBScript and the generated PowerShell against the same inputs and compares the values, which is what catches output that runs fine and returns the wrong thing. It passes. None of that tells you your script is OK, so test it.
Does it handle Classes, Functions and ByRef?
Classes and Functions yes, including the implicit return through the function name. ByRef gets flagged, not converted. It's the default in VBScript and it isn't in PowerShell, so a Sub that writes to its argument quietly stops affecting the caller. Where that write is visible, you get the parameter name and the line number.
What about encoded .vbe files?
It reads UTF-16 and BOMs, which covers most of the .vbs files you'll actually run into. Encoded .vbe uses Microsoft's script encoder, and that doesn't get decoded here.