Preparing for VBScript Deprecation: An Audit Guide for VBA and Internal Tools
· Go Komura · VBScript, VBA, Excel, PowerShell, Office, Windows, Legacy Asset Reuse
Executive Summary
As of April 2026, Microsoft has published its policy of deprecating VBScript in phases: in Windows 11 version 24H2 it first becomes a Feature on Demand enabled by default, in the next phase it becomes disabled by default, and in the final phase it is planned for removal from a future Windows release. In other words, what you really should do now — before any “full rewrite” — is “make visible where the VBScript dependencies are”.
For VBA and Excel macros, the realistic concerns are two. One is cases that execute external .vbs files; the other is references to VBScript-type libraries such as VBScript.RegExp. For the latter, starting with Office version 2508 (Build 19127.20154) the RegExp class ships in the VBE as standard, so at least some RegExp-dependent code has become easier to migrate. On the other hand, in mixed environments where older Office clients remain, the same VBA can easily work on some machines and fail on others.
What makes migration hard is less VBScript itself than “the surrounding operations”. For example, even if you replace things so that Excel launches powershell.exe, it will not run in production if it trips over the attack surface reduction rules “Block all Office applications from creating child processes” or “Block Win32 API calls from Office macros”, or AppLocker, App Control for Business, PowerShell execution policy, signing operations, or the macro controls for MOTW-tagged files. The migration plan should be designed to include not just code conversion but policy, signing, and log auditing.
The shortest route is inventory → static detection → execution log collection → choosing the replacement → testing → phased rollout. This article organizes things in that order, for practical use.
The code that appears in this article is published on GitHub as a runnable, testable sample set (PowerShell audit scripts, replacement samples, reference VBA and Office Scripts code, and Pester tests).
vbscript-deprecation-vba-excel-macro-internal-tools-audit-guide - komurasoft-blog-samples (GitHub)
Sorting Out What Is Changing
The first thing to grasp is that this is not a story about “VBA being deprecated”. What Microsoft has published is strictly the phased deprecation of VBScript, and the impact on VBA projects concentrates mainly on execution of external .vbs files and references to VBScript-family libraries. The Microsoft 365 Developer Blog likewise identifies .vbs execution from VBA and use of VBScript.RegExp as the representative impact points.
For practical prioritization, this table makes the decisions easier.
| Dependency pattern | What happens | Priority |
|---|---|---|
Direct execution of .vbs from VBA/Excel |
From Phase 2 it fails depending on device configuration; in Phase 3 it stops as a rule | High |
VBScript.RegExp references |
Easily turn into defects in mixed environments where pre-2508 Office remains | High |
External process launches via WScript.Shell / Shell |
Even after replacement, may be stopped by ASR or AppLocker | High |
| GPO logon/startup/shutdown scripts, Scheduled Tasks, Intune-deployed scripts | Prone to mass outages on OS updates or policy switches | High |
| VBScript Custom Actions in MSIs | Install, repair, and uninstall suddenly fail | High |
This prioritization is a practical judgment based on the Windows-side VBScript deprecation plan, the official detection strategy, and the ASR/AppLocker/App Control specifications.
RegExp alone is a slightly different story. From Office version 2508 onward, the VBE includes the RegExp class as standard, so for RegExp use specifically, “part of the VBScript dependency can be resolved by an Office update”. However, this does not resolve automatically in organizations with old Office, slow update channels, mixed environments, or stale device images. Put both “the Office update” and “the Windows phase switch” into your ledger — that is the important part.
How to Run the Inventory
An inventory needs more than file-name searches. At minimum, we recommend keeping the following ten aspects as columns, per project, per tool, per business process.
- (1) Method of detecting VBScript-dependent locations Record file search, code analysis, and log analysis separately.
- (2) Use of
CreateObject/GetObject/Execute/ExecuteGlobaletc. inside VBA The dependency hides inside strings, so static-search misses are common. - (3) External script calls from Excel macros
Track
WScript.Shell, theShellfunction,wscript.exe/cscript.exe, and.vbs/.js/.ps1separately. - (4) Script dependencies of internal batch jobs and tools Include Scheduled Tasks, GPO, Intune, operational scripts on shared folders, and installers.
- (5) Security, permissions, signing, policy AppLocker, App Control for Business, ASR, PowerShell execution policy, digital signatures, whether admin rights are required.
- (6) Replacement technologies and migration cost comparison Compare native VBA, PowerShell, .NET/VSTO, Office Scripts, and Power Automate.
- (7) Test plan Separate unit, integration, user acceptance, and re-testing after policy application.
- (8) Operating procedures and rollback State explicitly what must be reverted to recover, and how far to automate.
- (9) Compatibility and performance Office version differences, 32/64bit, device performance, log-collection load, cloud-flow timeouts.
- (10) A sample migration case study Build one representative example usable for explaining to the field.
Of these ten items, GPO, Scheduled Tasks, Intune-deployed scripts, MSI Custom Actions, and detection via Sysmon/AppLocker/App Control are explicitly highlighted as focus areas in Microsoft’s official guidance.
The overall migration flow stays on track if you think of it like this diagram.
flowchart TD
A[Asset inventory] --> B{Type of dependency}
B -->|External .vbs execution| C[Replace with PowerShell or native VBA]
B -->|VBScript.RegExp| D[Consolidate onto the built-in RegExp of Office 2508+]
B -->|GPO / Tasks / MSI| E[Fix centrally managed settings and deployed artifacts]
B -->|Unknown / buried dependencies| F[Collect execution logs via Sysmon / AppLocker / App Control]
C --> G[Unit testing]
D --> G
E --> H[Integration testing]
F --> H
H --> I[Pilot rollout in audit mode]
I --> J[Phased disabling of the VBScript FOD]
Keep this order and you greatly reduce the classic do-over of “we rewrote it first, and then GPO or ASR knocked it down afterwards”.
Practical Detection and Code Examples
File Search and Enumerating Configuration
Microsoft’s detection guidance recommends recursively searching for .vbs while prioritizing paths with a clear purpose — C:\Users, C:\ProgramData, C:\Scripts, etc. — and checking GPO, Scheduled Tasks, Intune-deployed scripts, and MSI packages on separate tracks. Sysmon’s vbscript.dll monitoring is effective, but Image Load monitoring carries heavy log volume and operational load, so it should be validated in a small pilot first.
# Roughly sweep script dependencies on devices and shared folders
$paths = @("C:\Users", "C:\ProgramData", "C:\Scripts")
$patterns = @(
'wscript\.exe',
'cscript\.exe',
'\.vbs(\s|$)',
'VBScript\.RegExp',
'WScript\.Shell',
'CreateObject\("VBScript\.RegExp"\)',
'ExecuteGlobal'
)
$hits = foreach ($path in $paths) {
if (Test-Path $path) {
Get-ChildItem -Path $path -Recurse -File `
-Include *.vbs,*.ps1,*.bat,*.cmd,*.wsf,*.hta,*.txt `
-ErrorAction SilentlyContinue |
Select-String -Pattern $patterns -AllMatches |
Select-Object Path, LineNumber, Line
}
}
$hits | Export-Csv .\vbscript-dependency-hits.csv -NoTypeInformation -Encoding UTF8
Next, sweep Task Scheduler. With internal tools, more often than in files, wscript.exe / cscript.exe / .vbs is buried inside task definitions.
# Extract VBScript invocations from Scheduled Tasks
Get-ScheduledTask | ForEach-Object {
foreach ($a in $_.Actions) {
if ($a.Execute -match 'wscript|cscript|mshta' -or $a.Arguments -match '\.vbs\b') {
[pscustomobject]@{
TaskName = $_.TaskName
TaskPath = $_.TaskPath
Execute = $a.Execute
Arguments = $a.Arguments
}
}
}
} | Export-Csv .\task-vbscript-dependencies.csv -NoTypeInformation -Encoding UTF8
VBA Code Analysis
On the VBA side, looking only at the references dialog is not enough. CreateObject and GetObject can instantiate COM from a string, so code can be dependent even when nothing shows in the references. Microsoft’s VBA/Office documentation describes CreateObject as the basic means of creating COM objects, and FileSystemObject and Scripting.Dictionary are used in that form too. Also, reading a VBA project programmatically requires “Trust access to the VBA project object model”.
' Prerequisites:
' - Enable "Trust access to the VBA project object model" in the Trust Center
' - Protected projects require separate source export or confirmation with the owner
Sub ScanProjectForVbScriptRisks()
Dim comp As Object
Dim cm As Object
Dim ws As Worksheet
Dim nextRow As Long
Dim patterns As Variant
Dim p As Variant
Dim i As Long
Dim lineText As String
patterns = Array( _
"CreateObject(""VBScript.RegExp"")", _
"VBScript.RegExp", _
"WScript.Shell", _
"Shell(", _
".vbs", _
"wscript.exe", _
"cscript.exe", _
"ExecuteGlobal", _
"Execute(" _
)
Set ws = ThisWorkbook.Worksheets.Add
ws.Range("A1:D1").Value = Array("Module", "Line", "Pattern", "Code")
nextRow = 2
For Each comp In ThisWorkbook.VBProject.VBComponents
Set cm = comp.CodeModule
For i = 1 To cm.CountOfLines
lineText = cm.Lines(i, 1)
For Each p In patterns
If InStr(1, lineText, CStr(p), vbTextCompare) > 0 Then
ws.Cells(nextRow, 1).Value = comp.Name
ws.Cells(nextRow, 2).Value = i
ws.Cells(nextRow, 3).Value = p
ws.Cells(nextRow, 4).Value = lineText
nextRow = nextRow + 1
End If
Next p
Next i
Next comp
ws.Columns.AutoFit
MsgBox "Scan finished: " & (nextRow - 2) & " hits"
End Sub
This scan picks up, at minimum, CreateObject("VBScript.RegExp"), WScript.Shell, Shell(, .vbs, and ExecuteGlobal. String-based execution like Execute / ExecuteGlobal in particular is a hotbed of inventory misses, because the dependency target and the executed code are assembled dynamically.
Log Analysis
At the stage of examining execution logs, the combination of Sysmon + AppLocker/App Control is powerful. Sysmon can track loads of vbscript.dll via Event ID 7, and AppLocker’s allow/audit events for scripts and MSIs are visible in Event Viewer. Run App Control for Business in audit mode, and scripts and MSIs are recorded in the AppLocker\MSI and Script log.
# Sysmon: find processes that loaded vbscript.dll
Get-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" -MaxEvents 2000 |
Where-Object { $_.Id -eq 7 -and $_.Message -match 'vbscript\.dll' } |
Select-Object TimeCreated, MachineName, Message
# AppLocker / App Control: check audit logs for scripts and MSIs
Get-WinEvent -LogName "Microsoft-Windows-AppLocker/MSI and Script" -MaxEvents 2000 |
Where-Object { $_.Id -in 8005, 8006 } |
Select-Object TimeCreated, Id, Message
The important thing here is collecting not just the “it ran” logs but also the “audit says it would have been blocked” logs. AppLocker’s audit events and App Control’s audit mode are well suited to safety checks before blocking in production.
Minimal Replacement Samples
For processing on the level of calling an external .vbs to write out a CSV, the shortest path is replacing it with native VBA first.
Sub ExportCsvNativeVba()
Dim f As Integer
Dim outPath As String
outPath = ThisWorkbook.Path & "\out.csv"
f = FreeFile
Open outPath For Output As #f
Print #f, "Code,Name"
Print #f, "1001,Tokyo"
Print #f, "1002,Osaka"
Close #f
MsgBox "CSV exported: " & outPath
End Sub
If you need to call external processing from Excel — including the OS, shared folders, AD, installers, and log collection — leaning on PowerShell is more realistic. Microsoft recommends PowerShell as the VBScript replacement, and the PowerShell side has official operational mechanisms for execution policy, signing, and Authenticode verification. Note that VBA’s Shell is asynchronous by default, so processing that needs ordering requires separate flow design or wait handling.
Sub RunModernPs()
Dim cmd As String
cmd = "powershell.exe -NoProfile -File """ & ThisWorkbook.Path & "\Normalize.ps1""" & _
" -InputFile """ & ThisWorkbook.Path & "\in.csv""" & _
" -OutputFile """ & ThisWorkbook.Path & "\out.csv"""
Shell cmd, vbNormalFocus
End Sub
param(
[string]$InputFile,
[string]$OutputFile
)
Import-Csv $InputFile |
Sort-Object Code |
Export-Csv $OutputFile -NoTypeInformation -Encoding UTF8
# Apply and verify a signature
$cert = Get-ChildItem -Path Cert:\CurrentUser\My -CodeSigningCert | Select-Object -First 1
Set-AuthenticodeSignature -FilePath .\Normalize.ps1 -Certificate $cert
Get-AuthenticodeSignature -FilePath .\Normalize.ps1
If the Excel processing completes entirely inside the workbook — formatting, aggregation, transformation — Office Scripts is also a strong option. Office Scripts targets Excel and is well suited to cloud-based, cross-platform use and Power Automate integration.
function main(workbook: ExcelScript.Workbook) {
const sheet = workbook.getActiveWorksheet();
const used = sheet.getUsedRange();
used.getFormat().autofitColumns();
const tables = workbook.getTables();
if (tables.length > 0) {
tables[0].getSort().apply([{ key: 0, ascending: true }], true);
}
}
Choosing the Replacement Technology
The replacement should be chosen not by “what can it be written in” but by how much responsibility it will carry. PowerShell leans toward Windows, files, tasks, and installers; native VBA toward the inside of Office; Office Scripts toward Excel workbook processing; VSTO/.NET toward heavy desktop integration; Power Automate toward orchestration. The table below is a practical estimate built on the officially published characteristics of each approach. The effort figures are the author’s rough guide.
| Alternative | Suited processing | Main strengths | Main constraints | Effort | Priority |
|---|---|---|---|---|---|
| Native VBA | Cell manipulation, reports, simple file output, light fixes to existing macros | Easy to leverage existing assets, low user-training cost | Weak governance over OS operations, signing, and distribution; external-process dependencies tend to remain | Low | High |
| PowerShell | File operations, shared folders, AD, tasks, installers, ops automation | Microsoft’s recommended replacement; signing and execution-policy operations available | Requires tuning of execution policy, signing, ASR, AppLocker | Medium | High |
| .NET / VSTO | Complex business logic, long-lived internal add-ins, heavy UI integration | Deep Office integration; can deliver functionality as an application | Windows-only; requires the VSTO runtime and distribution design | High | Medium |
| Office Scripts | Routine formatting inside Excel workbooks, cloud execution, Power Automate integration | Cross-platform, easy to share, tidy if Excel-centric | Excel-only, unsuited to external OS work, limits with huge data | Medium | Medium |
| Power Automate | Scheduled runs, approvals, file-arrival triggers, integrating other services | Whole flow is easy to visualize; can embed PowerShell/.NET | Operations design splits across desktop/cloud; permission design needed | Medium–High | Medium |
Sketching the selection guideline a bit more intuitively:
flowchart TD
A[Discovered VBScript dependency] --> B{Completes inside the Excel workbook?}
B -->|Yes| C[Native VBA]
B -->|Yes, and sharing/cloud matters| D[Office Scripts]
B -->|No| E{Touches the OS, files, tasks, AD?}
E -->|Yes| F[PowerShell]
E -->|No| G{Heavy UI integration or long-lived add-in?}
G -->|Yes| H[.NET / VSTO]
G -->|Flow-triggered or approval-centric| I[Power Automate]
One addition about RegExp specifically: in environments where only Office version 2508 or later exists, consolidating onto Dim re As RegExp / Set re = New RegExp is quite effective. But if even one machine with older Office remains, that code hits the compile-compatibility wall. In mixed environments, decide first whether the migration policy is “new syntax”, “old syntax”, or “a branching wrapper”.
Testing and Operations
Test Plan
A VBScript migration is not covered by unit testing alone. Unless you re-test under production-equivalent conditions with the security policies active, the replacement PowerShell or .NET scripts will stop for entirely different reasons. Microsoft’s materials likewise treat PowerShell execution policy, AppLocker, App Control audit mode, ASR, and the macro controls for MOTW-tagged files as separate rules.
| Level | What to examine | Example pass criteria |
|---|---|---|
| Unit testing | Input/output, exception handling, encodings, regex results | Returns the same results as the old processing |
| Integration testing | Excel⇔PowerShell, shared folders, tasks, AD, report output | The whole batch completes without errors |
| Security testing | Signing, execution policy, AppLocker, App Control, ASR, MOTW | Runs / audits as expected even after policies are applied |
| Acceptance testing | Operating steps, duration, error-time messages | Field procedures are simplified or preserved |
| Compatibility / performance testing | Office version differences, large data, log-collection load | Stable within acceptable performance on mixed devices |
The points most often missed are these:
- A replacement where Excel launches PowerShell may trip over ASR’s “Block all Office applications from creating child processes”.
- Leaving VBA declarations or API calls in place may trip over ASR’s “Block Win32 API calls from Office macros”.
- Test
.xlsm/.ps1files distributed via downloads or mail attachments behave differently depending on MOTW and signature state. - The Office Scripts + Power Automate combination is convenient, but with large CSVs or huge cell counts you must mind timeouts and data-transfer limits.
- Sysmon’s Image Load monitoring is useful, but spread carelessly across the whole company it inflates log volume.
Migration Procedure Checklist
- Statically searched for
.vbs,wscript.exe,cscript.exe,VBScript.RegExp,WScript.Shell,Shell(,ExecuteGlobal - Inventoried GPO, Scheduled Tasks, Intune, shared-folder operations, and MSIs on separate tracks
- Put Office versions and update channels into a ledger and identified remaining pre-2508 installs
- Decided the replacement among “native VBA / PowerShell / .NET / Office Scripts / Power Automate”
- Decided the signing policy and the certificate distribution policy
- Tested the impact of AppLocker / App Control / ASR / execution policy
- Collected audit logs in a pilot department
- Documented the rollback procedure
- Preserved the evidence of “unused” before disabling the VBScript FOD
Risks and Countermeasures
| Risk | Typical symptom | Countermeasure |
|---|---|---|
| Hidden dependencies remain | Month-start processing fails only in some departments | Combine static search with Sysmon/AppLocker/App Control auditing |
| Security policies stop the replacement | Converted to PowerShell, yet it won’t run when launched from Excel | Put ASR, AppLocker, App Control into audit mode in a test environment first |
| Signing gaps cause production-only failures | Works on the developer PC, refused on user PCs | Lock in signing operations with Set-AuthenticodeSignature and Get-AuthenticodeSignature |
| RegExp breaks on mixed Office | Compile errors on some machines | Ledger the pre-2508 remainder; lead with a wrapper or with updates |
| Office Scripts / Flow are slow | Timeouts on large CSVs | Split files, batch the work, design synchronization points |
The countermeasures in this table translate the design constraints in Microsoft’s official materials into internal operations.
Rollback means more than “reverting the code”. At minimum, think of restoring previous versions of deployed artifacts, reverting policies, the headroom to re-enable the optional feature, and continued log collection as a set. While VBScript still exists as a FOD, there is room to re-enable it as an optional feature per the Phase 2 guidance — but once it is removed in Phase 3, that escape hatch is gone.
A Sample Migration Case Study
As a typical example, take the accounting department’s monthly aggregation macro. Today, the Excel macro launches cleanup.vbs via WScript.Shell, validates codes with VBScript.RegExp after CSV formatting, and finally writes the output to a shared folder. This setup takes a direct hit from VBScript deprecation — and even with a naive port to PowerShell, it stalls again on ASR and signing operations.
The right answer in this case is to split it apart. Validation, formatting, and aggregation that complete inside Excel move to native VBA or the built-in RegExp of Office 2508+. File conversion and shared-folder I/O move to PowerShell. If the trigger is “a file arrived” or “daily at a set time”, move that to Power Automate. This untangles the responsibilities that had been stuffed into a single .vbs.
An example post-migration structure:
- Excel macro: input checks, screen interaction, user-facing messages
- PowerShell: CSV normalization, shared-folder I/O, log output
- Signing: Authenticode signatures on the PowerShell scripts
- Security: verify AppLocker/App Control in audit mode first; decide whether ASR exceptions are needed
- Future extension: phase routine in-Excel processing over to Office Scripts
The advantage of this approach is that you cut loose the VBScript runtime dependency early without having to rebuild everything at once. Absorb RegExp via the Office update, move operational scripts to PowerShell, move the business flow to Power Automate — split by responsibility, and the blast radius of any failure shrinks too.
Recommended Tools and Reference Links
- The complete sample code for this article (PowerShell audit scripts and Pester tests) https://github.com/gomurin0428/komurasoft-blog-samples/tree/main/vbscript-deprecation-vba-excel-macro-internal-tools-audit-guide
We recommend reading the official materials in this order.
- VBScript deprecation: Timelines and next steps The starting point for confirming the overall roadmap and what each Phase means.
- VBScript deprecation: Detection strategies for Windows Practical detection guidance covering Sysmon, GPO, Scheduled Tasks, Intune, and MSI Custom Actions.
- Prepare your VBA projects for VBScript deprecation in Windows The most important from the VBA perspective. Covers the built-in RegExp, the handling of Office 2508 and later, and a compatibility table.
- Differences between Office Scripts and VBA macros Helps decide whether Excel-centric processing should move to Office Scripts.
- about_Execution_Policies / about_Signing / Set-AuthenticodeSignature / Get-AuthenticodeSignature The basic set for signing and execution-policy operations during a PowerShell migration.
- Using Event Viewer with AppLocker / Use audit events to create App Control policy rules / Script enforcement with App Control for Business Needed for understanding audit-mode design, event collection, and script enforcement behavior.
- Attack surface reduction rules reference The material for checking the block rules around Office child processes, Win32 APIs, and JS/VBS download execution.
- Macros from the internet are blocked by default in Office Required reading for understanding MOTW issues during test distribution and production rollout.
As supporting tools, these come up often in our practice.
- Sysmon
The basis for monitoring
vbscript.dllloads and collecting process-level events. - Sysmon configuration templates on GitHub
SwiftOnSecurity’s
sysmon-configis a high-quality starting template, and Olaf Hartong’ssysmon-modularis a modular, operations-friendly starting point. - oletools / olevba Suited to extracting VBA source from Office files and assisting detection of suspicious keywords and auto-executing macros.
In conclusion, preparing for VBScript deprecation takes more than “find the VBScript and replace it with PowerShell”. Managing the Office updates, code analysis, operational configuration, signing, ASR/AppLocker/App Control, and UAT in a single ledger is the fastest reliable way forward. Rescue early the areas an Office update can rescue, like RegExp; and detach with priority the areas that break on the Windows-side phase switches — .vbs execution and the GPO/task/MSI dependencies.
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
How to Run PowerShell from C# (CSharp) and Receive the Results as Objects
How to launch PowerShell from C# and receive results as PSObject rather than strings — a practical walkthrough of the PowerShell SDK, Add...
Testing PowerShell with Pester — A Practical Approach to Making Operations Scripts Harder to Break
A practical walkthrough of testing PowerShell scripts with Pester v5 — safely covering date handling, file operations, deletion logic, mo...
Practical PowerShell Command Recipes — Growing the Small Tools You Use Every Day
A practical roundup of PowerShell commands for everyday work, covering where to use Measure-Object, Group-Object, Select-String, Compare-...
Applied PowerShell Scripting — Safely Automating Log Investigation, Archiving, and Reporting
Practical steps for safely automating log investigation, CSV reporting, archiving old logs, keeping audit trails, and Task Scheduler exec...
PowerShell Command Basics — The Operations to Learn First and How to Use Them Safely
So that PowerShell beginners never get lost in real work, this article covers how to find cmdlets, the pipeline, file operations, CSV pro...
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.
Legacy Asset Reuse & Migration Support
Inventorying assets that depend on VBA, Excel macros, and VBScript, and carrying them through a phased migration, overlaps directly with our legacy asset reuse and migration support.
Technical Consulting & Design Review
Selecting replacement technologies (native VBA / PowerShell / Office Scripts / Power Automate) and aligning with signing, AppLocker / App Control, and ASR is easy to handle as a pre-migration design review.
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