Should That Batch File Move to PowerShell? — Auditing cmd/bat Assets and Making the Migration Call
· Go Komura · PowerShell, Windows, Batch File, cmd, VBScript, Legacy Asset Reuse, Operational Improvement, Script
“We found a mountain of twenty-year-old batch files when we started the server migration. Should we rewrite them all in PowerShell?” — this question is a fixture of legacy asset consultations. Copies and backups, wrappers that launch applications, nightly integration jobs. cmd batch files (bat) still quietly hold up Windows operations in the field today.
To give the answer up front: no, you don’t need to rewrite them all. There is no plan for bat to stop working any time soon, and rewriting something that works is itself a failure risk. At the same time, there are definitely batch files where “leave it as it is” is dangerous: the ones that call VBScript, the ones that swallow errors, the ones that are about to be changed. Without making that distinction, both “keep everything” and “migrate everything” are accidents waiting to happen.
This article is aimed at in-house IT and operations staff at small and mid-sized companies. It lays out criteria for auditing bat assets and deciding on migration, the pitfalls specific to bat, how to have bat and PowerShell coexist during the transition, and a rewrite reference table.
1. The Bottom Line First
- There is no plan to discontinue cmd.exe or bat, but Microsoft states plainly that it recommends PowerShell for Windows automation. The official direction is: if you’re writing something new, write PowerShell.1
- VBScript was formally announced as deprecated in October 2023, with a published staged plan of becoming a Feature on Demand before being removed from the OS. Assets that call VBScript from bat with
cscript/wscriptare the group with the highest migration urgency.23 PowerShell is the officially suggested replacement.4 - The migration decision isn’t “everything”, it’s triage. Running reliably with no changes planned → keep. Changes coming, error handling needed, logging needed → migrate. Depends on VBScript → migrate first. Section 4 has the decision table.
- bat’s structural weaknesses are that it doesn’t stop on errors, the
%ERRORLEVEL%traps, and text encoding.if errorlevel 1is a “1 or greater” test5, and%errorlevel%breaks if an environment variable of the same name is defined.5 - What you gain by migrating to PowerShell is the object pipeline, error handling with try/catch6, dry runs with -WhatIf7, and testing with Pester. “You can notice failures, you can try things safely, you can test automatically” is the essential value of migrating.
- For the mixed period, the realistic answer is calling powershell.exe / pwsh from bat with
-File. The exit code returned by the script’sexitis handed straight to%ERRORLEVEL%on the bat side, so you can replace the internals while keeping existing job management.89 - Don’t rewrite excellent external commands like robocopy — call them from PowerShell as they are. The exit codes run from 0 to 8 and above in an idiosyncratic scheme where 8 and above means failure, so all you need to get right is the
$LASTEXITCODEcheck.1011 - Build the execution policy into your distribution design. The default is Restricted (no script execution) on client OSes with Windows PowerShell 5.1, and RemoteSigned on Windows Server and PowerShell 7. Even under RemoteSigned, unsigned scripts carrying the internet mark are blocked.12
2. Why Think About It Now — cmd Stays, VBScript Goes
Let’s start with the underlying facts. Windows has two command-line shells, cmd (the command shell) and PowerShell, and Microsoft’s official documentation states that “PowerShell is recommended for the most robust and up-to-date Windows automation, rather than Windows commands or Windows Script Host”.1 But a recommendation is only a recommendation: cmd itself doesn’t appear on the list of deprecated Windows features. There is, as of today, no plan for existing batch files to stop working.
VBScript is the opposite case. In October 2023, the deprecation of VBScript was formally announced. A plan has been published under which future Windows releases ship it as a Feature on Demand before it is removed from the OS.2 It is initially supplied preinstalled, so nothing stops tomorrow3, but the direction — removal — is settled. Windows Server 2025 has likewise moved it to a FoD, with migration to PowerShell officially suggested as the replacement.4
The important point here is that VBScript hides inside your bat assets. Calling VBScript from bat with something like cscript //nologo convert.vbs was a standard pattern in the 2000s. A batch file built that way isn’t “safe because it’s bat” — it shares VBScript’s fate. When you audit, always check not just the bat files themselves but what they call (Section 7 includes a script for scanning). A full inspection of VBScript and VBA assets across the company is covered in detail in “Preparing for VBScript Deprecation: An Audit Guide for VBA and Internal Tools”.
3. The Pitfalls of bat, and What You Gain from PowerShell
As input to the migration decision, let’s look concretely at bat’s structural weaknesses. The batch file below is a shape you see all the time for backups.
@echo off
rem Nightly backup (the sort of risky batch file you see everywhere)
xcopy C:\data \\backup01\share\data /E /Y
echo Backup complete >> C:\logs\backup.log
Three easy-to-miss problems are buried in this batch file.
- It doesn’t stop on errors. If xcopy can’t reach the destination share and fails, cmd carries on to the next line by default, and the log records “Backup complete”. To detect failures you have to write an
if errorlevelcheck yourself, every time. %ERRORLEVEL%has traps.if errorlevel 1doesn’t mean “the exit code equals 1” — it means “1 or greater”.5 And the%errorlevel%form is specified as “expands to the current exit code provided no environment variable named ERRORLEVEL is defined”, so the moment somebody writesset ERRORLEVEL=0, every subsequent check is broken.5 Combine that with theexit /b <number>mechanism for returning exit codes13 and getting this right takes a fair amount of knowledge.- Text encoding accidents. cmd in a Japanese-language environment has traditionally lived in a Shift_JIS world, and accidents still happen today: a bat file re-saved as UTF-8 turns to mojibake, or a path containing symbols misbehaves. For the full picture of this problem, see “Windows Text Encodings and Line Endings - The Basics of Mojibake and CRLF/LF”.
Write the same processing in PowerShell and the handling of failure changes structurally.
# Nightly backup (skeleton of the PowerShell version)
$ErrorActionPreference = 'Stop' # tip errors towards "stop"
try {
# Point the source at "the contents of the folder", C:\data\*. Passing 'C:\data' would
# nest it as data\data from the second run onwards, once the destination folder exists
Copy-Item -Path 'C:\data\*' -Destination '\\backup01\share\data' -Recurse -Force
Add-Content -Path 'C:\logs\backup.log' -Value "$(Get-Date -Format o) Backup complete"
exit 0
}
catch {
# What failed and where can be recorded as structured information
Add-Content -Path 'C:\logs\backup.log' -Value "$(Get-Date -Format o) Failed: $($_.Exception.Message)"
exit 1
}
try/catch catches statement-terminating errors, and cleanup can go in finally.6 PowerShell also provides -WhatIf as a common mechanism that displays “what would have happened” without performing the destructive operation7, so you can safely rehearse a rewritten script against production. Add Pester tests on top and you can keep verifying “it should work” automatically (see “Testing PowerShell with Pester — A Practical Approach to Making Operations Scripts Harder to Break”). The design of error handling and retries itself is explored in depth in “PowerShell Error Handling and Retry Design — From the try/catch Trap to Exit Codes and Retry Best Practices”, published alongside this article.
So what you get from migrating isn’t syntactic novelty — it is operational quality: you can notice failures, you can try things safely, and you can protect them with tests. Conversely, that value doesn’t do much for a batch file such as a simple launch wrapper, where a failure is immediately obvious anyway. Which is why triage is necessary.
4. Don’t Migrate Everything — A Triage Decision Table
| Point | Options | How to judge |
|---|---|---|
| Running reliably, no changes planned, simple | Keep as-is / Migrate | An application launch wrapper or a few lines of copying can stay. The rewrite itself is a new risk |
| Calls VBScript (cscript/wscript) | Keep / Migrate first | The deprecated → FoD → removal plan for VBScript has been officially announced. Leaving it alone leads to a discontinuation date2 |
| Specification changes or new features are coming | Rework it in bat / Migrate, then rework | The moment of change is the opportunity to migrate. Do the rework and the test setup at the same time |
| Failure detection, logging or retries are needed | Add checks to the bat / Migrate | Covering everything with if errorlevel is hard to maintain. This is where try/catch and structured logging pay off6 |
| Nightly job (launched by Task Scheduler) | Leave it alone / Consider migrating | Unattended execution is exactly where failure handling matters. Review the run-as account and 0x1 problems at the same time |
| An external command such as robocopy is the star | Reimplement with cmdlets / Keep the external command and call it | Reimplementing a proven command is a losing trade. Move only the invocation and the check into PowerShell10 |
| The author has left and the behaviour is undocumented | Don’t touch it / Record the behaviour, then decide | Document the current inputs, outputs and schedule first. Don’t rewrite what you don’t understand |
There are two principles when in doubt. First, migrate in order of value, not in order of age. Second, if you’re going to touch it, start with reading (auditing and recording).
5. The Realistic Answer for the Mixed Period — Calling PowerShell from bat and Handing Back the Exit Code
After triage, most sites enter a mixed period where “some of it is still bat, some of it is PowerShell”. The useful arrangement here is to keep the bat file as the entry point (the interface with job management) and replace only its internals with PowerShell. Job schedulers and operations manuals keep looking at the bat file’s path, so you can modernise the internals without breaking anything around them.
@echo off
rem Entry-point bat: calls job.ps1 in the same folder and passes the exit code through
rem %~dp0 is the folder this bat file itself lives in (the standard trick, shown in the official docs)
rem If somebody's set ERRORLEVEL=... environment variable is still around, it hides
rem the real exit code from %ERRORLEVEL%, so clear it before the call to restore the dynamic value
rem Don't override the execution policy here. Specifying -ExecutionPolicy applies to the
rem high-precedence Process scope and silently weakens AllSigned and the like that an admin configured
set "ERRORLEVEL="
powershell.exe -NoProfile -File "%~dp0job.ps1"
exit /b %ERRORLEVEL%
Resolving the script’s location with %~dp0 rather than depending on the current directory is exactly what the official documentation shows as an example of calling from a batch file.9 To run it on PowerShell 7, just change powershell.exe to pwsh (5.1 and 7 install separately and can coexist; for choosing between them see “The Differences Between Windows PowerShell 5.1 and PowerShell 7 — A Practical Guide to Migrating In-House Scripts”, published alongside this article).
Handing back the exit code works out as follows.
- If the script finishes with
exit 4, the process exit code becomes 4 and can be received in%ERRORLEVEL%on the bat side. This interaction is documented with a worked example in the official documentation.8 - When invoked with
-File, a script that dies with an unhandled exception exits with code 1, and 0 on normal completion. To avoid “it failed but returned 0”, it is safer for the script to determine success or failure andexitexplicitly.914 - The result of calling an external command from PowerShell lands in the automatic variable
$LASTEXITCODE.11
A batch file built around robocopy is a good example of this shape. robocopy is a proven command with retries (a default of a million attempts, believe it or not, with a 30-second wait), mirroring and logging10, and there is no reason to reimplement it with Copy-Item. Its exit code scheme is idiosyncratic, though: 0 means “nothing to copy”, 1 means “copied successfully”, and 8 or above means failure.10 Apply the general rule “anything other than 0 is a problem” and you will misjudge a perfectly normal copy as a failure.
# Use robocopy as-is, and just get the check right in PowerShell
# /r:2 /w:5 — the default of a million retries is effectively a hang in an unattended job, so always cap it
robocopy 'C:\data' '\\backup01\share\data' /MIR /R:2 /W:5 /NP /LOG+:'C:\logs\robocopy.log'
if ($LASTEXITCODE -ge 8) {
Write-Error "robocopy failed (exit code: $LASTEXITCODE)"
exit 1
}
Write-Host "Sync complete (exit code: $LASTEXITCODE)" # 0-7 are success outcomes
exit 0
6. Rewrite Reference Table — bat Vocabulary in PowerShell
Here is the reference table for the actual rewriting. Use it not as a mechanical substitution list but as a comparison of “how do I express the same intent?”
| bat form | PowerShell standard | Notes |
|---|---|---|
copy / move / del / md |
Copy-Item / Move-Item / Remove-Item / New-Item |
Rehearse destructive operations with -WhatIf first7 |
xcopy / robocopy |
Call robocopy as-is | Don’t reimplement. Treat 8 or above as failure via $LASTEXITCODE1011 |
for %%f in (*.csv) do ... |
Get-ChildItem *.csv \| ForEach-Object { ... } |
Objects flow through, not filename strings |
if errorlevel 1 goto :error |
try/catch + $ErrorActionPreference = 'Stop' |
External commands are still judged by exit code as before6 |
set VAR=value |
$var = 'value' (environment variables are $env:VAR) |
Process environment variables and variables are distinguishable |
call :sub / goto |
function |
You can attach types and validation to the arguments |
findstr |
Select-String |
Matching lines come back as objects you can process downstream |
>> log.txt |
Start-Transcript / Add-Content |
Transcript is the easy way to capture an entire run |
rem |
# |
— |
The basic PowerShell vocabulary — how to find cmdlets, the pipeline, confirmation practices — is collected in “PowerShell Command Basics — The Operations to Learn First and How to Use Them Safely”.
7. A Staged Migration Procedure — Audit → Classify → Pilot → Parallel Running
Finally, here is the process broken into four stages.
(1) Audit. Start with read-only investigation. Mechanically find out where the bat files are and whether they depend on VBScript.
# Auditing bat assets: an inventory of locations plus detection of VBScript calls (safe, read-only investigation)
# Anywhere that couldn't be enumerated becomes a hole in the audit, so record it with -ErrorVariable and disclose it later
$targets = Get-ChildItem -Path 'C:\', 'D:\jobs', '\\fileserver\scripts' -Recurse `
-Include '*.bat', '*.cmd' -File -ErrorAction SilentlyContinue -ErrorVariable enumErrors
$readErrors = @()
$report = foreach ($file in $targets) {
# If there's a cscript/wscript/.vbs call, flag it as "depends on VBScript" for attention
# Pass already-enumerated paths with -LiteralPath (a filename containing square brackets,
# such as [2026]job.bat, would be interpreted as a wildcard by -Path and match a different file)
# Files whose contents couldn't be read, because they were locked or similar, are recorded in $readErrors too
$vbs = Select-String -LiteralPath $file.FullName -Pattern 'cscript|wscript|\.vbs' -Quiet `
-ErrorAction SilentlyContinue -ErrorVariable +readErrors
[pscustomobject]@{
Path = $file.FullName
LastWriteTime = $file.LastWriteTime
UsesVBScript = $vbs
}
}
$report | Sort-Object UsesVBScript -Descending | Export-Csv 'C:\audit\bat-inventory.csv' -NoTypeInformation -Encoding UTF8
# Keep a list of the places you couldn't inspect (if it isn't empty, the audit is incomplete)
# Include both the locations that failed enumeration and the files that were enumerated but couldn't be read
@($enumErrors) + @($readErrors) | ForEach-Object { $_.TargetObject } |
Set-Content -Path 'C:\audit\bat-uninspected.txt'
(2) Risk classification. Apply the audit results to the decision table in Section 4 and sort them into “keep”, “migrate” and “migrate first (VBScript dependency)”. At the same time, record what launches each bat file (Task Scheduler, a job management tool, a human) and the blast radius of a failure. For run-as accounts for nightly jobs and the “ends with 0x1” problem, see “When Task Scheduler Tasks Don’t Run or Exit with 0x1 — Isolating the Cause and Designing for Reliable Operation”.
(3) Pilot. Pick one low-impact script and rewrite it using the entry-point bat approach from Section 5. Build the execution policy into the design at this point. The Windows default is RemoteSigned, so locally created scripts run, but unsigned scripts carrying the internet mark are blocked.12 Isolating the problem when shared-folder distribution trips over this, and the proper design including a signing process, are covered in “PowerShell Execution Policy and Script Signing”, published alongside this article.
(4) Parallel running. Run the old bat and the new script side by side for a period. Separate their output destinations and reconcile the results, run the new one initially with -WhatIf or logging only, and make rollback nothing more than pointing the job back at the bat file — put all of that in place before retiring the old bat and the migration itself will almost never turn into an incident.
8. Summary
- There is no plan to discontinue cmd or bat, but the official recommendation is PowerShell. VBScript, by contrast, has a published deprecated → FoD → removal plan, so VBScript called from bat is the top migration priority.
- Migration is triage, not “everything”. Keep the batch files that run reliably and never change, and migrate the ones that are changing, the ones that need error handling and logging, and the ones that depend on VBScript.
- bat doesn’t stop on errors,
if errorlevel 1is a “1 or greater” test, and%errorlevel%breaks when an environment variable of the same name exists. PowerShell provides “notice, rehearse, protect” through try/catch, -WhatIf and Pester. - For the mixed period, the realistic answer is calling
powershell.exe -File(orpwsh -File) from an entry-point bat and handing the exit code back throughexitand%ERRORLEVEL%. - Don’t rewrite excellent external commands like robocopy — just get the
$LASTEXITCODEcheck right (8 or above means failure). - The procedure is audit (starting with reading) → risk classification → pilot → parallel running. Don’t forget to design the execution policy and distribution as well.
Related Articles
- Preparing for VBScript Deprecation: An Audit Guide for VBA and Internal Tools
- PowerShell Command Basics — The Operations to Learn First and How to Use Them Safely
- When Task Scheduler Tasks Don’t Run or Exit with 0x1 — Isolating the Cause and Designing for Reliable Operation
- Windows Text Encodings and Line Endings - The Basics of Mojibake and CRLF/LF
- PowerShell Execution Policy and Script Signing
- PowerShell Error Handling and Retry Design — From the try/catch Trap to Exit Codes and Retry Best Practices
Related Consulting Areas
KomuraSoft LLC handles auditing legacy assets where bat, VBScript and PowerShell are mixed together and drawing up migration plans, moving nightly jobs to PowerShell along with the operational design that goes with them, and investigating the failures that accompany a migration. Deciphering a batch file whose author is long gone is a perfectly good place to start.
- Legacy Asset Reuse & Migration Support
- Windows Modernization & Maintenance
- Technical Consulting & Design Review
- Bug Investigation & Root Cause Analysis
- Contact
References
-
Microsoft Learn, Windows Commands. On how Windows has two shells, the command shell (cmd) and PowerShell, and the official statement recommending PowerShell rather than Windows commands or Windows Script Host for the most robust and up-to-date Windows automation. ↩ ↩2
-
Microsoft Learn, Deprecated features for Windows client. On how the deprecation of VBScript was announced in October 2023, and the plan for it to be supplied as a Feature on Demand in future Windows releases before being removed from the OS. ↩ ↩2 ↩3
-
Microsoft Learn, Resources for deprecated features. On how the VBScript Feature on Demand is initially preinstalled and can be used without interruption during the retirement preparation period. ↩ ↩2
-
Microsoft Learn, Features removed or no longer developed in Windows Server. On how VBScript is supplied as a FoD in Windows Server 2025 and removed in a later release, and how PowerShell is suggested as the replacement for task automation and scripting. ↩ ↩2
-
Microsoft Learn, if. On how “if errorlevel
" is a greater-than-or-equal test that is true when the preceding program's exit code is number or higher, and how %errorlevel% is an expansion that assumes no environment variable named ERRORLEVEL exists, returning that variable's value if one is defined. ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, about_Try_Catch_Finally. On how try/catch/finally blocks handle statement-terminating and script-terminating errors, how catch can specify an exception type, and how finally runs regardless of whether an error occurred and can be used for cleanup. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, about_CommonParameters. On the risk-mitigation parameters (-WhatIf/-Confirm) offered by cmdlets that change the system or data, and how -WhatIf displays only a description of the impact without running the command. ↩ ↩2 ↩3
-
Microsoft Learn, about_Language_Keywords. On how the exit keyword sets $LASTEXITCODE and corresponds to %ERRORLEVEL% on the cmd.exe side, the worked example where a script run with pwsh -File and ending in exit 4 is observed as 4 in the caller’s %ERRORLEVEL%, and how the absence of an exit statement means 0 on normal completion and 1 on an unhandled exception. ↩ ↩2
-
Microsoft Learn, about_Pwsh. On how to use pwsh’s -File parameter, the official example of using %~dp0 to denote the execution directory when calling from a batch script, how the exit code is 1 when a script-terminating error occurs under -File, and how exiting with the exit command makes that number the exit code. ↩ ↩2 ↩3
-
Microsoft Learn, robocopy. On robocopy’s exit code scheme (0 = nothing to copy, 1 = all files copied successfully, 8 and above = one or more failures), how the retry default is /r:1000000 (a million) with a wait default of /w:30 seconds, and on options such as mirroring and logging. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, about_Automatic_Variables. On how the automatic variable $LASTEXITCODE holds the exit code of a native program or script, and how its value is determined when a script is run with -File (1 on an exception, the value given to exit, or 0 on normal completion). ↩ ↩2 ↩3
-
Microsoft Learn, about_Execution_Policies. On how the default execution policy on Windows is RemoteSigned, how RemoteSigned requires a signature from a trusted publisher for scripts originating on the internet while not requiring one for locally created scripts, and on the meaning of each policy (Restricted, AllSigned, Bypass and so on). ↩ ↩2
-
Microsoft Learn, exit. On how “exit /b
" ends a batch script and sets the specified value in the ERRORLEVEL environment variable, and how it becomes the process exit code when exiting cmd itself. ↩ -
Microsoft Learn, about_PowerShell_exe. On the specification of the -File parameter in Windows PowerShell 5.1’s powershell.exe, the %windir% syntax for passing environment variables from cmd.exe, and how exit codes are handled. ↩
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
Parameter Design and Modularization for PowerShell Scripts — From a Script That Works to a Script You Can Hand Over
A step-by-step procedure for raising a PowerShell script to a quality you can hand to someone else. Covers the param block and [CmdletBin...
The Differences Between Windows PowerShell 5.1 and PowerShell 7 — A Practical Guide to Migrating In-House Scripts
The relationship between Windows PowerShell 5.1 and PowerShell 7 (side-by-side coexistence and pwsh.exe), Microsoft's official position t...
Where to Look When a PowerShell Script Is Slow — Arrays, Pipelines and Matching
The classic causes of slow PowerShell scripts, laid out. Why += on an array is O(n^2), the difference between the pipeline and foreach, t...
Stop Using Write-Host — PowerShell Output Streams and Log Design
How to choose between PowerShell's six output streams, the problems with Write-Host and where it genuinely belongs, why function return v...
Parallel Processing in PowerShell — Choosing Between ForEach-Object -Parallel and Jobs
A practical rundown of the differences between ForEach-Object -Parallel, Start-ThreadJob and Start-Job and when to use each, $using: and ...
Related Topics
These topic pages place the article in a broader service and decision context.
Windows Technical Topics
Topic hub for KomuraSoft LLC's Windows development, investigation, and legacy-asset articles.
Where This Topic Connects
This article connects naturally to the following service pages.
Windows App Development
We support Windows desktop applications that involve resident processing, device integration, operational logging, and maintainable structure.
Frequently Asked Questions
Common questions about the topic of this article.
- Should every batch file in the company be migrated to PowerShell?
- Migrating everything is not recommended. For a batch file that has run reliably for years with no changes planned, the rewrite itself becomes a new source of failure. The high-priority candidates are the ones that are about to be changed, the ones that need error handling and logging, and the ones that call VBScript (cscript/wscript). Sorting them with a decision table and migrating the worthwhile ones in stages is the standard practice in the field.
- Are cmd.exe and batch files being discontinued?
- cmd.exe does not appear on the list of deprecated Windows features, and there has been no announcement of its removal. That said, Microsoft states plainly that it recommends PowerShell rather than Windows commands or WSH for Windows automation. VBScript, by contrast, was formally announced as deprecated in October 2023, and a staged plan has been published under which it becomes a Feature on Demand in future Windows releases before being removed from the OS. bat itself will keep working, but the day will certainly come when the VBScript your bat files call does not.
- How do I call a PowerShell script from a batch file?
- Pass the script to powershell.exe (or pwsh.exe for PowerShell 7) with the -File parameter. For a script in the same folder as the bat file, resolving the location with %~dp0 — as in "powershell.exe -NoProfile -File \"%~dp0job.ps1\"" — is the style shown in the official documentation. Note that specifying -ExecutionPolicy applies to the high-precedence Process scope and weakens the policy an administrator has configured, so leave it out of the bat file and let the environment's execution policy design govern. If the script returns a number with exit, that value is handed straight to %ERRORLEVEL% on the bat side, so you can move the internals to PowerShell while keeping your existing job management intact.
- What traps are there in bat's %ERRORLEVEL%?
- The classic one is that "if errorlevel 1" means "true if the exit code is 1 or greater" — a greater-than-or-equal test, not an equality test. Also, %errorlevel% is a dynamic expansion that assumes no environment variable named ERRORLEVEL is defined, so if you define one yourself with set ERRORLEVEL=0, that value is returned from then on. On top of that, bat proceeds to the next line by default even when a command fails, so any failure whose check you forgot to write is quietly swallowed. The relative absence of traps like these is what motivates migration to PowerShell, which has real error handling.
- How do I rewrite a batch file that uses robocopy in PowerShell?
- The standard answer is: don't rewrite it. robocopy is an excellent external command with proven retry, mirroring and logging features, and you can call it straight from PowerShell. Reimplementing it with Copy-Item is a lot of work for lower reliability. The thing to watch is interpreting the exit code: robocopy returns values from 0 to 8 and above, where 8 and above means failure and 1 means a successful copy. On the PowerShell side, look at $LASTEXITCODE and treat "8 or greater" as a failure.
- I hit the execution policy while distributing a PowerShell script. What should I do?
- The default execution policy (RemoteSigned) requires a signature for scripts marked as coming from the internet. If distribution through a shared folder gets blocked, first confirm the cause; the proper long-term fix is either a signing process or standardising the policy through Group Policy. Adding -ExecutionPolicy Bypass to the call from a batch file is convenient, but use it only after confirming that it is the state your organisation's policy design actually intends.
Author Profile
Profile page for the article author.
Go Komura
Representative of KomuraSoft LLC
Focused on Windows software development, technical consulting, and investigations into failures that are difficult to reproduce.
Public links