The 1999 Ghost in the Machine: How Anthropic’s “Too Dangerous” AI Broke OpenBSD

Imagine a digital lock that has remained unpicked for 27 years. It survived the dot-com bubble, the rise of the smartphone, and the birth of cloud computing. Now, imagine a machine that can look at that lock for three seconds and simply walk through the door.
In April 2026, Claude Mythos Preview, an unreleased model from Anthropic, did exactly that. It autonomously discovered and exploited a vulnerability in OpenBSD that had been hidden in plain sight since 1999. This isn’t just a technical achievement; it is a klaxon call for every IT professional. The era of “security through antiquity” is officially dead.
I. The 27-Year Artifact: A Technical Autopsy
OpenBSD is widely considered the gold standard of secure code. Its developers have a near-fanatical commitment to manual code auditing. Yet, Mythos found a Stack-Based Buffer Overflow in a legacy Network Daemon that had survived human review for nearly three decades.
Breaking Down the “Spilled Cup”
- The Network Daemon: Think of this as a silent receptionist in your server’s lobby. It waits for incoming data requests. Because it has high-level access to the system’s “building,” it is a high-value target.
- The Buffer Overflow: Imagine a cup designed to hold exactly 8 ounces of water. If you pour 12 ounces in, the water spills over the table. In computing, that “spilled data” lands in parts of the memory it shouldn’t touch.
- The Exploit: Mythos didn’t just spill the water; it shaped the spill into a “key” that allowed it to gain Root Privilege Escalation—essentially firing the receptionist and taking over the entire building.
Why humans missed it: For 27 years, auditors saw a code path that looked logically sound under normal conditions. Mythos, however, simulated millions of chaotic, “impossible” data inputs simultaneously until it found the one specific sequence that caused the overflow.
II. Adapting Your Strategy for the Mythos Era
If a 1999 bug can be weaponized today, your legacy systems are no longer “tried and true”—they are liabilities. Here is how professionals are shifting their approach:
From “Patch Tuesday” to “Proactive Hardening”
- AI-Assisted Red Teaming: Don’t wait for a CVE (Common Vulnerabilities and Exposures) report. Use approved AI tools like GitHub Copilot Security to scan your internal scripts. Ask specifically: “Find edge cases where this input could cause a memory leak.”
- The Zero-Trust Mandate: Assume your perimeter has already been breached by an AI-class exploit. Implement Micro-segmentation (using tools like Illumio or Azure NSGs) to ensure that if one server falls, the “fire doors” prevent the attacker from moving sideways through your network.
III. The Global Debate: Who Controls the Shield?
The decision to sequester Mythos within Project Glasswing—a restricted coalition including Google, Microsoft, and AWS—has sparked a fierce ethical debate outside the tech elite.
- The Fortress Argument: Anthropic argues that the “weights” of this model are effectively a cyber-weapon. Releasing it would be like handing out master keys to every bank vault in the world.
- The Democratic Risk: Independent researchers argue that this creates a “Security Monopoly.” If only the giants have the “Mythos Shield,” small businesses and non-profits are left defenseless against nation-state actors who will inevitably build their own version of this technology.
IV. Closing the 27-Year Gap
The discovery of the 1999 OpenBSD bug is a reminder that our digital infrastructure is built on “ancient” foundations. We can no longer rely on the fact that something “hasn’t been hacked yet.”
To survive the next decade, IT leaders must transition from reactive patching to AI-native defense. We are in a race to find the ghosts in our machines before someone else gives them a voice.past before the future arrives.
References
- Anthropic (April 7, 2026): Project Glasswing: Securing critical software for the AI era. anthropic.com/glasswing
- Medium (April 10, 2026): Claude Mythos: The AI That Hacked Every OS and Escaped Its Own Cage. medium.com/mythos-deep-dive
- VentureBeat (April 7, 2026): Anthropic says its most powerful AI cyber model is too dangerous to release publicly. venturebeat.com/mythos-announcement
#AI #CyberSecurity #ProjectGlasswing #ClaudeMythos #Anthropic #InfoSec #TechTrends2026 #ZeroDay #DigitalDefense #FutureOfTech
Azure Alert: Default Outbound Access Ends March 31st 2026 | Lazy Admin Blog

Is your “Internet-less” VM about to lose its connection? Here is the fix.
For years, Azure allowed Virtual Machines without an explicit outbound connection (like a Public IP or NAT Gateway) to “cheat” and access the internet using a default, hidden IP. That ends on March 31st 2026. If you haven’t transitioned your architecture, your updates will fail, your scripts will break, and your apps will go dark.
1. What exactly is changing?
Microsoft is moving toward a “Secure by Default” model. The “Default Outbound Access” (which was essentially a random IP assigned by Azure) is being retired. From now on, you must explicitly define how a VM talks to the outside world.
2. The Three “Lazy Admin” Solutions
You have three ways to fix this before the deadline. Choose the one that fits your budget and security needs:
Option A: The NAT Gateway (Recommended)
This is the most scalable way. You associate a NAT Gateway with your Subnet. All VMs in that subnet will share one (or more) static Public IPs for outbound traffic.
- Pro: Extremely reliable and handles thousands of concurrent sessions.
- Con: There is a small hourly cost + data processing fee.
Option B: Assign a Public IP to the VM
The simplest “Quick Fix.” Give the VM its own Standard Public IP.
- Pro: Immediate fix for a single server.
- Con: It’s a security risk (opens a door into the VM) and gets expensive if you have 50 VMs.
Option C: Use a Load Balancer
If you already use an Azure Load Balancer, you can configure Outbound Rules.
- Pro: Professional, enterprise-grade setup.
- Con: More complex to configure if you’ve never done it before.
3. How to find your “At Risk” VMs
Don’t wait for March 31st 2026 to find out what’s broken. Run this PowerShell snippet to find VMs that might be relying on default outbound access:
# Find VMs without a Public IP in a specific Resource Group$VMs = Get-AzVM -ResourceGroupName "YourRGName"foreach ($vm in $VMs) { $nic = Get-AzNetworkInterface -ResourceId $vm.NetworkProfile.NetworkInterfaces[0].Id if ($null -eq $nic.IpConfigurations.PublicIpAddress) { Write-Host "Warning: $($vm.Name) has no Public IP and may rely on Default Outbound Access!" -ForegroundColor Yellow }}
🛡️ Lazy Admin Verdict:
If you have more than 3 VMs, deploy a NAT Gateway. It’s the “Set and Forget” solution that ensures you won’t get a 2 AM call on April 1st when your servers can’t reach Windows Update.
M365 E7: The “Super SKU” is Here (And it Costs $99) | Lazy Admin Blog

Is the new ‘Frontier Suite’ a lazy admin’s dream or a budget nightmare?
After 11 years of E5 being the king of the mountain, Microsoft has officially announced its successor: Microsoft 365 E7. Launching May 1, 2026, this isn’t just a minor update—it’s a $99/month powerhouse designed for an era where AI agents are treated like actual employees.
1. What’s inside the E7 Box?
If you’ve been “nickel and dimed” by add-on licenses for the last two years, E7 is Microsoft’s way of saying “Fine, here’s everything.”
- Microsoft 365 Copilot (Wave 3): No more $30 add-on. It’s baked in, including the new “Coworker” mode developed with Anthropic.
- Agent 365: This is the big one. A brand-new control plane to manage, secure, and govern AI agents across your tenant.
- Microsoft Entra Suite: You get the full identity stack, including Private Access (ZTNA) and Internet Access (SSE), which were previously separate costs.
- Advanced Security: Enhanced features for Defender, Intune, and Purview specifically tuned for “Agentic AI” (AI that actually performs tasks, not just answers questions).
2. The $99 Math: Is it worth it?
At first glance, $99 per user per month sounds like a typo. But let’s look at the “Lazy Admin” math:
| Component | Standalone Cost (Est.) |
| M365 E5 | $60 (post-July 2026 hike) |
| M365 Copilot | $30 |
| Agent 365 | $15 |
| Entra Suite Add-on | $12 |
| Total Value | $117/month |
By moving to E7, you’re saving about $18 per user and, more importantly, you stop managing four different license renewals. That is the definition of working smarter.
3. The “Agentic” Shift
Why do we need E7? Because in 2026, agents are becoming “Frontier Workers.” Microsoft’s new stance is that AI agents need their own identities. Under E7, your automated agents get their own Entra ID, mailbox, and Teams access so they can attend meetings and file reports just like a human. E7 provides the governance layer to make sure these agents don’t go rogue and start emailing your CEO the company’s secrets.
📊 Microsoft 365 License Comparison: E3 vs. E5 vs. E7
| Feature Category | M365 E3 | M365 E5 | M365 E7 (Frontier) |
| Monthly Cost | ~$36.00 | ~$57.00 | $99.00 |
| Core Productivity | Full Apps + Teams | Full Apps + Teams | Full Apps + Teams |
| Security | Basic (Entra ID P1) | Advanced (Entra ID P2) | Autonomous (P3) |
| Compliance | Core eDiscovery | Inner Risk + Priva | Agentic Governance |
| AI Integration | Add-on Required | Add-on Required | Native Copilot Wave 3 |
| Specialized Tooling | None | Power BI Pro | Agent 365 (Suite) |
| Threat Protection | Defender for Endpoint | Defender XDR Full | Quantum Defender |
| Endpoint Mgmt | Intune (Basic) | Intune (Plan 2) | Autopilot Frontie |
🛡️ Lazy Admin Verdict:
- Upgrade to E7 if: You already have 50%+ Copilot adoption and you’re starting to build custom AI agents in Copilot Studio.
- Stay on E5 if: You’re still fighting with users to turn on MFA and haven’t touched AI yet.
📚 References & Further Reading
- Official Microsoft Announcement: Introducing the First Frontier Suite built on Intelligence + Trust – The primary source for E7 pricing and the “Wave 3” Copilot vision.
- Technical Deep Dive: Secure Agentic AI for your Frontier Transformation – Details on how Agent 365 integrates with Defender and Purview.
- Partner Insights: Leading Frontier Firm Transformation with Microsoft 365 E7 – Great for understanding the licensing shift from an MSP/Partner perspective.
- Analysis: M365 E7 to Launch May 1 for $99 Per User Per Month – Independent analysis of the “Super SKU” value proposition.
Fixed: The VMRC Console has Disconnected (Error 2050470)

It’s a frustrating scenario: you go to check a virtual machine, and instead of a login screen, you get a black box with the message: “The VMRC Console has Disconnected… Trying to reconnect.” To make matters worse, the VM often appears unreachable on the network, leading you to believe the Guest OS has blue-screened or frozen. However, the issue is frequently just a hang-up in the VMware Remote Console (VMRC) process on your local management workstation.
The Quick Fix
You do not need to restart the VM or the ESXi host. Usually, the “stuck” process is living right on your own PC.
- Open Task Manager: Right-click your taskbar and select Task Manager (or press
Ctrl + Shift + Esc). - Find the Process: Go to the Processes or Details tab.
- Kill VMRC: Look for
vmware-vmrc.exe(orvmware-vmrc.exe*32on older systems). - End Task: Right-click the process and select End Task.
- Relaunch: Go back to your vSphere Client and attempt to open the console again.
Why does this happen?
This error usually occurs when the VMRC process loses its handshake with the ESXi host but fails to terminate properly. By killing the process, you force a fresh authentication and network handshake, which typically restores the video feed immediately.
What if the VM is still “Black Screened”?
If killing the local process doesn’t work and the VM is still unreachable via ping/RDP, the issue might be on the host side:
- Check the Hostd Service: Sometimes the management agent on the ESXi host needs a restart.
- Video Memory: Ensure the VM has enough Video RAM allocated in its “Edit Settings” menu to support the resolution you are using.
#VMware #vSphere #VMRC #SysAdmin #ITPro #Virtualization #TechSupport #LazyAdmin #ServerAdmin #WindowsTroubleshooting
Automating Active Directory: Export All AD Groups and Members to CSV

Auditing Active Directory groups is a fundamental part of identity management. Whether you are performing a quarterly security review or preparing for a domain migration, knowing exactly who is in which group—and what the scope of those groups is—is essential.
This PowerShell script does more than just list group names; it iterates through every group in your domain, identifies the members (skipping disabled users to keep your data clean), and exports everything into a dated CSV file.
The PowerShell Script
Save this script as ADGroupsExport.ps1 in C:\Temp\ExportADgroups. Ensure you are running this from a machine with the RSAT (Remote Server Administration Tools) installed and logged in with a domain account that has read permissions.
# Get year and month for the filename$DateTime = Get-Date -f "yyyy-MM"# Set CSV file destination$CSVFile = "C:\Temp\ExportADgroups\AD_Groups_"+$DateTime+".csv"if (!(Test-Path "C:\Temp\ExportADgroups")) { New-Item -ItemType Directory -Path "C:\Temp\ExportADgroups" }$CSVOutput = @()# Fetch all AD groups$ADGroups = Get-ADGroup -Filter *$i = 0$tot = $ADGroups.countforeach ($ADGroup in $ADGroups) { $i++ $status = "{0:N0}" -f ($i / $tot * 100) Write-Progress -Activity "Exporting AD Groups" -status "Processing Group $i of $tot : $status% Completed" -PercentComplete ($i / $tot * 100) $Members = "" # Fetch members and filter for enabled objects $MembersArr = Get-ADGroup $ADGroup.DistinguishedName -Properties Member | Select-Object -ExpandProperty Member if ($MembersArr) { foreach ($Member in $MembersArr) { $ADObj = Get-ADObject -Filter "DistinguishedName -eq '$Member'" -Properties Enabled # Skip disabled users to keep the report relevant if ($ADObj.ObjectClass -eq "user" -and $ADObj.Enabled -eq $false) { continue } $Members = $Members + "," + $ADObj.Name } if ($Members) { $Members = $Members.Substring(1) } } # Create ordered hash table for clean CSV columns $HashTab = [ordered]@{ "Name" = $ADGroup.Name "Category" = $ADGroup.GroupCategory "Scope" = $ADGroup.GroupScope "Members" = $Members } $CSVOutput += New-Object PSObject -Property $HashTab}# Sort by name and export$CSVOutput | Sort-Object Name | Export-Csv $CSVFile -NoTypeInformationWrite-Host "Export Complete: $CSVFile" -ForegroundColor Green
Key Features of this Script
- Progress Bar: Since large domains can take a long time to process, the
Write-Progressbar gives you a real-time percentage of the completion. - Clean Membership Lists: The script concatenates all members into a single “Members” column, separated by commas, making it easy to read in Excel.
- Disabled User Filtering: It intelligently checks the
Enabledstatus of user objects. If a user is disabled, they are omitted from the report to focus on active security risks. - Scope & Category: Clearly identifies if a group is Security vs. Distribution and Global vs. Universal.
#ActiveDirectory #PowerShell #SysAdmin #ITAutomation #WindowsServer #IdentityManagement #LazyAdmin #TechTips #Reporting #CyberSecurity
Deep Audit: Listing Nested Active Directory Group Members via VBScript | Lazy Admin Blog

Have you ever looked at a “Domain Admins” group and thought it looked suspiciously small? The culprit is usually nesting. Standard AD queries often fail to “recurse,” meaning they show you the subgroup but not the people inside it.
This script, ListGroupMembers_IncludingNested.vbs, uses a recursive function to dive into every sub-group and extract the actual users, ensuring your security audits are 100% accurate.
The Script: How it Works
The script utilizes a Dictionary Object to keep track of groups it has already scanned. This is a critical “Lazy Admin” safety feature—it prevents the script from getting stuck in an infinite loop if two groups are members of each other.
Usage Instructions
- Copy the code below into Notepad.
- Edit the
StrGroupNamevariable to match your target group. - Save the file as
ListGroupMembers.vbs. - Run it from the command prompt using
cscript ListGroupMembers.vbs.
' -- Save as ListGroupMembers_IncludingNested.vbsOption ExplicitDim ObjRootDSE, ObjConn, ObjRS, ObjCustomDim StrDomainName, StrGroupName, StrSQL, StrGroupDN, StrEmptySpaceSet ObjRootDSE = GetObject("LDAP://RootDSE")StrDomainName = Trim(ObjRootDSE.Get("DefaultNamingContext"))' -- Edit the line below with your Group NameStrGroupName = "YourGroupNameHere" StrSQL = "Select ADsPath From 'LDAP://" & StrDomainName & "' Where ObjectCategory = 'Group' AND Name = '" & StrGroupName & "'"Set ObjConn = CreateObject("ADODB.Connection")ObjConn.Provider = "ADsDSOObject": ObjConn.Open "Active Directory Provider"Set ObjRS = ObjConn.Execute(StrSQL)If ObjRS.EOF Then WScript.Echo "Group not found: " & StrGroupNameElse StrGroupDN = Trim(ObjRS.Fields("ADsPath").Value) Set ObjCustom = CreateObject("Scripting.Dictionary") GetAllNestedMembers StrGroupDN, " ", ObjCustomEnd If
Why VBScript in 2026?
While PowerShell is the modern standard, many legacy environments and automated scheduled tasks still rely on VBScript because it requires zero execution policy changes and runs natively on every Windows machine since Server 2000. It is the “Old Reliable” of the AD world.
Key Features of this Script
- Recursive Discovery: It doesn’t just stop at the first layer.
- Class Identification: Clearly marks if a member is a
User,Computer, or anotherGroup. - Loop Protection: Uses the
Scripting.Dictionaryto escape circular nesting traps.
#ActiveDirectory #WindowsServer #CyberSecurity #SysAdmin #ITAudit #VBScript #Automation #LazyAdmin #TechArchive
The Ultimate Server Audit: Deep-Dive Inventory to Excel (VBScript) | Lazy Admin Blog

If you are facing a massive compliance audit or a data center migration, “basic” info isn’t enough. You need to know exactly what is under the hood: What roles are active? How much disk space is actually left? What random software was installed three years ago?
This VBScript is a one-stop-shop. It checks network connectivity and then scrapes WMI and the Registry to build a massive, multi-column Excel report.
What this Script Collects:
- Hardware: Manufacturer, Model, CPU Type, and RAM (converted to GB).
- OS Details: Version, Caption, and the exact Installation Date.
- Storage: Total Size vs. Free Space (with a Red-Alert highlight if space is < 20%).
- Network: DHCP status, IP, Subnet, and Gateway.
- Software & Roles: Every Windows Server Role/Feature and every application listed in the Registry’s Uninstall key (including version and install date).
Preparation
- Directory: Create
C:\Tempon your local machine. - Input: Create a file named
ServerList.txtinC:\Tempwith your server names (one per line). - Excel: Ensure Microsoft Excel is installed.
The Script: Server_Inventory.vbs
' Save as Server_Inventory.vbs in C:\Temp' lazyadminblog.com - Ultimate Inventory ScriptOn Error Resume Next dtmDate = DatestrMonth = Month(Date)strDay = Day(Date)strYear = Right(Year(Date),2)strFileName = "C:\Temp\ServerInventory_" & strMonth & "-" & strDay & "-" & strYear & ".xls"Set objExcel = CreateObject("Excel.Application") objExcel.Visible = True objExcel.Workbooks.Add Set fso1 = CreateObject("Scripting.FileSystemObject") Set pcfile = fso1.OpenTextFile("C:\Temp\ServerList.txt",1) Wscript.Echo "Audit in progress... Please wait!"'--- Setup Header Row ---Sub SetupHeader(col, text) objExcel.Cells(1, col).Value = text objExcel.Cells(1, col).Font.Colorindex = 2 objExcel.Cells(1, col).Font.Bold = True objExcel.Cells(1, col).Interior.ColorIndex = 23 objExcel.Cells(1, col).Alignment = -4108 ' CenterEnd SubSetupHeader 1, "Computer Name"SetupHeader 2, "Manufacturer"SetupHeader 3, "Model"SetupHeader 4, "RAM (GB)"SetupHeader 5, "Operating System"SetupHeader 6, "Installed Date"SetupHeader 7, "Processor"SetupHeader 8, "Drive"SetupHeader 9, "Drive Size (GB)"SetupHeader 10, "Free Space (GB)"SetupHeader 11, "Adapter Description"SetupHeader 12, "DHCP Enabled"SetupHeader 13, "IP Address"SetupHeader 14, "Subnet"SetupHeader 15, "Gateway"SetupHeader 16, "Roles & Features"SetupHeader 17, "Installed Software"SetupHeader 18, "Install Date"SetupHeader 19, "Version"SetupHeader 20, "Size"y = 2 Do While Not pcfile.AtEndOfStream computerName = pcfile.ReadLine Err.Clear Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & computerName & "\root\cimv2") If Err.Number = 0 Then ' Fetch Queries Set colSettings = objWMIService.ExecQuery("SELECT * FROM Win32_ComputerSystem") Set colOSSettings = objWMIService.ExecQuery("SELECT * FROM Win32_OperatingSystem") Set colProcSettings = objWMIService.ExecQuery("SELECT * FROM Win32_Processor") Set colDiskSettings = objWMIService.ExecQuery("Select * from Win32_LogicalDisk Where DriveType=3") Set colAdapters = objWMIService.ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True") For Each objComputer In colSettings strManufacturer = objComputer.Manufacturer strModel = objComputer.Model strRAM = FormatNumber((objComputer.TotalPhysicalMemory / (1024^3)), 2) For Each objOS In colOSSettings strOS = objOS.Caption OSinstDate = CDate(Mid(objOS.InstallDate,1,4)+"/"+Mid(objOS.InstallDate,5,2)+"/"+Mid(objOS.InstallDate,7,2)) For Each objProc In colProcSettings strProc = objProc.Name ' Populate Static Info objExcel.Cells(y, 1).Value = computerName objExcel.Cells(y, 2).Value = strManufacturer objExcel.Cells(y, 3).Value = strModel objExcel.Cells(y, 4).Value = strRAM objExcel.Cells(y, 5).Value = strOS objExcel.Cells(y, 6).Value = OSinstDate objExcel.Cells(y, 7).Value = strProc ' Drive Logic a = y For Each objDisk In colDiskSettings objExcel.Cells(a, 8).Value = objDisk.DeviceID sz = objDisk.Size / (1024^3) fr = objDisk.FreeSpace / (1024^3) objExcel.Cells(a, 9).Value = FormatNumber(sz, 2) objExcel.Cells(a, 10).Value = FormatNumber(fr, 2) If fr < (sz * 0.2) Then objExcel.Cells(a, 10).Interior.ColorIndex = 3 ' Low Space Alert a = a + 1 Next ' Network Logic b = y For Each objAdapter In colAdapters objExcel.Cells(b, 11).Value = objAdapter.Description objExcel.Cells(b, 12).Value = objAdapter.DHCPEnabled If Not IsNull(objAdapter.IPAddress) Then objExcel.Cells(b, 13).Value = objAdapter.IPAddress(0) If Not IsNull(objAdapter.IPSubnet) Then objExcel.Cells(b, 14).Value = objAdapter.IPSubnet(0) If Not IsNull(objAdapter.DefaultIPGateway) Then objExcel.Cells(b, 15).Value = objAdapter.DefaultIPGateway(0) b = b + 1 Next ' Roles & Features x = y Set colRoleFeatures = objWMIService.ExecQuery("Select * from Win32_ServerFeature") If colRoleFeatures.Count > 0 Then For Each objRole In colRoleFeatures objExcel.Cells(x, 16).Value = objRole.Name x = x + 1 Next Else objExcel.Cells(x, 16).Value = "None Found" End If ' Software Registry Scan s = y Const HKLM = &H80000002 strKey = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" Set objReg = GetObject("winmgmts://" & computerName & "/root/default:StdRegProv") objReg.EnumKey HKLM, strKey, arrSubkeys For Each strSubkey In arrSubkeys objReg.GetStringValue HKLM, strKey & strSubkey, "DisplayName", strVal1 If strVal1 <> "" Then objExcel.Cells(s, 17).Value = strVal1 objReg.GetStringValue HKLM, strKey & strSubkey, "InstallDate", strVal2 objExcel.Cells(s, 18).Value = strVal2 objReg.GetDWORDValue HKLM, strKey & strSubkey, "VersionMajor", vMaj objReg.GetDWORDValue HKLM, strKey & strSubkey, "VersionMinor", vMin objExcel.Cells(s, 19).Value = vMaj & "." & vMin s = s + 1 End If Next ' Advance Row to next available empty spot y = a If b > y Then y = b If x > y Then y = x If s > y Then y = s y = y + 1 ' Buffer line Next Next Next Else objExcel.Cells(y, 1).Value = computerName objExcel.Cells(y, 2).Value = "OFFLINE" objExcel.Cells(y, 2).Interior.ColorIndex = 3 y = y + 1 End If Loop ' Final FormattingFor col = 1 To 20: objExcel.Columns(col).AutoFit: NextobjExcel.ActiveWorkbook.SaveAs strFileNameWscript.Echo "Complete! Report saved to " & strFileName
Why it’s a Game Changer
- The “Red Flag” Feature: It automatically highlights any disk with less than 20% free space in Red. This instantly tells you which servers need urgent cleanup.
- Software Archeology: Most scripts skip software lists because they are messy. This script pulls directly from the
Uninstallregistry keys, capturing even the apps that don’t show up in standard WMI queries. - Intelligent Row Management: Because software, roles, and disks all have different counts, the script calculates the “max row” used for each server and jumps to the next clear space for the next machine.
Stop Hunting for Web Servers: How to Auto-Discover Every IIS Instance in Your Domain | Lazy Admin Blog

Have you ever been asked for a list of every active web server in your environment, only to realize your documentation is six months out of date? You could check your DNS records manually, or you could let PowerShell do the detective work for you.
This script scans your Active Directory for Windows Servers, checks if the World Wide Web Publishing Service (W3SVC) is actually running, and then pulls a deep-profile of the hardware, OS, and network configuration for every active hit.
The Setup
- Create the workspace: Create a folder at
C:\Temp\ServersRunningIIS. - Prepare the list: The script will automatically generate a list of all Windows Servers from AD, but ensure you have the Active Directory PowerShell module installed.
- Run with Privileges: Since the script uses WMI to query remote system info (RAM, OS Version, etc.), run your PowerShell ISE or Console as a Domain Admin.
The PowerShell Script
# Script: IIS Server Discovery & Profiler# Location: lazyadminblog.com# Purpose: Identify active IIS nodes and collect hardware/OS specsImport-Module ActiveDirectory# 1. Harvest all Windows Servers from ADWrite-Host "Gathering server list from Active Directory..." -ForegroundColor Cyan$servers = Get-ADComputer -Filter {operatingsystem -Like "Windows server*"} | Select-Object -ExpandProperty Name$servers | Out-File "C:\Temp\ServersRunningIIS\serverlist.txt"# 2. Load the list for processing$serversall = Get-Content "C:\Temp\ServersRunningIIS\serverlist.txt" Start-Transcript -Path "C:\Temp\ServersRunningIIS\log_output.txt" -Appendforeach($vm in $serversall) { try { # Check if IIS Service (W3SVC) exists and is running $iis = Get-WmiObject Win32_Service -ComputerName $vm -Filter "name='W3SVC'" -ErrorAction SilentlyContinue if($iis.State -eq "Running") { Write-Host "FOUND: IIS is active on $vm" -BackgroundColor DarkBlue -ForegroundColor DarkYellow # Collect Network Info $ipinfo = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $vm | Where-Object {$_.IPEnabled -eq $true -and $_.IPAddress -like "1*"} | Select-Object -First 1 # Collect Hardware Info $hwinfo = Get-WmiObject Win32_Computersystem -ComputerName $vm # Collect OS Info $osinfo = Get-WmiObject Win32_OperatingSystem -ComputerName $vm # Flattening data for CSV-style output $allinfo = "$($hwinfo.Name);$($hwinfo.Domain);$($ipinfo.IPAddress);$($ipinfo.IPSubnet);$($ipinfo.DefaultIPGateway);$($hwinfo.TotalPhysicalMemory);$($hwinfo.Manufacturer);$($hwinfo.Model);$($osinfo.Caption);$($osinfo.OSArchitecture);$($osinfo.ServicePackMajorVersion);$($osinfo.SystemDrive);$($osinfo.Version)" # Save results to our 'Running' list $allinfo | Out-File "C:\Temp\ServersRunningIIS\RunningWebServers.txt" -Append } } catch { Write-Host "Could not connect to $vm" -ForegroundColor Red }}Stop-TranscriptWrite-Host "Audit Complete! Check C:\Temp\ServersRunningIIS\RunningWebServers.txt" -ForegroundColor Green
What’s inside the report?
The output file (RunningWebServers.txt) uses a semicolon (;) delimiter, making it easy to import into Excel. It captures:
- Network: IP Address, Subnet, and Gateway.
- Hardware: Manufacturer, Model, RAM, and Domain membership.
- Software: OS Version, Architecture (x64/x86), and System Drive.
Lazy Admin Tip
If you want to open the results immediately in Excel, just rename the output file from .txt to .csv and use the “Text to Columns” feature in Excel with the semicolon as the separator!
From Zero to Complete IP Inventory in 5 Seconds: The Multi-Host VBScript | Lazy Admin Blog

Manually documenting IP addresses, MACs, and DNS settings is the definition of “busy work.” This VBScript automates the entire process. It reads a list of servers from a text file, queries each one via WMI, and builds a professional Excel report in real-time.
How to Use This Script
- Prepare the Input: Create a text file (e.g.,
servers.txt) and list your hostnames or IP addresses, one per line. - Save the Script: Save the code below as
IPAddressInventory.vbs. - Run: Double-click the
.vbsfile. When prompted, provide the full path to your text file (e.g.,C:\Scripts\servers.txt). - Requirement: You must have Microsoft Excel installed on the machine where you run the script.
The VBScript Code
VBScript
' Save as IPAddressInventory.vbs' Input: Text file with Hostnames/IPs' Output: Excel Spreadsheet (IP_Addresses.xlsx)On Error Resume NextConst FOR_READING = 1'--- File Input ---strSrvListFile = InputBox ("Please enter the server list file path OR UNC file path" & vbCrLf & "Eg: C:\Scripts\server.txt" & vbCrLf & "Eg: \\servername\scripts\server.txt","File Input location")Set objFSO = CreateObject ("Scripting.FileSystemObject")Set objReadFile = objFSO.OpenTextFile (strSrvListFile, FOR_READING)'--- File Output ---strOutput = objfso.GetParentFolderName(strSrvListFile) &"\"'--- Error Handling ---If Err.Number <> 0 Then WScript.Echo "Please Enter a Valid file Name" Err.Clear WScript.QuitEnd If'--- Excel Object Creation ---Set objExcel = CreateObject ("Excel.application")objExcel.Visible = TrueSet objWorkbook = objExcel.Workbooks.Add()Set objWorksheet = objWorkbook.Worksheets("Sheet1")x = 1y = 1'--- Define Headers ---objWorksheet.Cells (x, y).value = "S.No"objWorksheet.Cells (x, y+1).value = "Server Name"objWorksheet.Cells (x, y+2).value = "Description"objWorksheet.Cells (x, y+3).value = "IP_Address"objWorksheet.Cells (x, y+4).value = "Subnet"objWorksheet.Cells (x, y+5).value = "MACAddress"objWorksheet.Cells (x, y+6).value = "Gateway" objWorksheet.Cells (x, y+7).value = "Preffered DNS"objWorksheet.Cells (x, y+8).value = "Primary DNS"objWorksheet.Cells (x, y+9).value = "Secondary DNS"objWorksheet.Cells (x, y+10).value = "Additional DNS 1"objWorksheet.Cells (x, y+11).value = "Additional DNS 2"objWorksheet.Cells (x, y+12).value = "WINS Primary"objWorksheet.Cells (x, y+13).value = "WINS Secondary"objWorksheet.Cells (x, y+14).value = "DNS Suffix"objWorksheet.Cells (x, y+15).value = "DNS Suffix Order"objWorksheet.Cells (x, y+16).value = "Remarks"s = 1Do Until objReadFile.AtEndOfStream k = 0 arrComputer = objReadFile.ReadLine strServer = Split (arrComputer, ",") objWorksheet.Cells (x+1, y).value = s objWorksheet.Cells (x+1, y+1).value = strServer(k) Set objWMIService = GetObject ("winmgmts:" & "!\\" & strServer(k) & "\root\cimv2") '--- Query Network Information --- If Err.Number = 0 Then WScript.Echo strServer(k) &": Inventoring" Set colAdapters = objWMIService.ExecQuery("Select * from Win32_NetworkAdapterConfiguration Where IPEnabled = True") For Each objAdapter in colAdapters objWorksheet.Cells(x+1, y+2).Value = objAdapter.Description ' IP Address Logic If Not IsNull(objAdapter.IPAddress) Then For i = LBound(objAdapter.IPAddress) To UBound(objAdapter.IPAddress) If Not InStr(objAdapter.IPAddress(i),":") > "0" Then objWorksheet.Cells(x+1, y+3).Value = objAdapter.IPAddress(i) End If Next End If ' Subnet Logic If Not IsNull(objAdapter.IPSubnet) Then For i = LBound(objAdapter.IPSubnet) To UBound(objAdapter.IPSubnet) If objAdapter.IPSubnet(i)<> "64" Then objWorksheet.Cells(x+1, y+4).Value = objAdapter.IPSubnet(i) End If Next End If objWorksheet.Cells(x+1, y+5).Value = objAdapter.MACAddress ' Gateway Logic If IsNull(objAdapter.DefaultIPGateway) Then objWorksheet.Cells(x+1, y+6).Value = "Gateway Not Set" Else For i = LBound(objAdapter.DefaultIPGateway) To UBound(objAdapter.DefaultIPGateway) objWorksheet.Cells(x+1, y+6).Value = objAdapter.DefaultIPGateway(i) Next End If ' DNS Logic If IsNull(objAdapter.DNSServerSearchOrder) Then objworksheet.Cells(x+1, y+7).Value = "DNS Not Set" Else For i = LBound(objAdapter.DNSServerSearchOrder) To UBound(objAdapter.DNSServerSearchOrder) objWorksheet.Cells(x+1, y+7).Value = objAdapter.DNSServerSearchOrder(i) y = y + 1 Next End If y = 1 objWorksheet.Cells(x+1, y+12).Value = objAdapter.WINSPrimaryServer objWorksheet.Cells(x+1, y+13).Value = objAdapter.WINSSecondaryServer objWorksheet.Cells(x+1, y+14).Value = objAdapter.DNSDomain ' Suffix Logic If IsNull(objAdapter.DNSDomainSuffixSearchOrder) Then objworksheet.Cells(x+1, y+14).Value = "Suffix Order NA" Else For i = LBound(objAdapter.DNSDomainSuffixSearchOrder) To UBound(objAdapter.DNSDomainSuffixSearchOrder) objWorksheet.Cells(x+1, y+15).Value = objAdapter.DNSDomainSuffixSearchOrder(i) x = x + 1 Next x = x - 1 End If x = x + 1 WScript.Echo strServer(k) &": Completed" Next Else ' Error Handling for Offline Servers objWorksheet.Cells(x+1, y+16).Value = Err.Number & "_" & Err.Description WScript.Echo strServer(k) &": "& Err.Description Err.Clear x = x + 1 End If s = s + 1Loop'--- Formatting and Saving ---Set objRange = objWorksheet.UsedRangeobjRange.EntireColumn.Autofit()objExcel.ActiveWorkbook.Saveas strOutput & "IP_Addresses.xlsx"MsgBox "Operation Completed Successfully " ,,"IP Address"
Key Features of the Script
- Automatic Excel Formatting: It uses
UsedRange.Autofit()to ensure the data is readable as soon as the file opens. - WMI Integration: It queries the
Win32_NetworkAdapterConfigurationclass directly from the remote machine. - Multi-Adapter Support: If a server has multiple enabled NICs, the script loops through each to capture all configurations.
- Remark Logging: If a machine is unreachable, the error code and description are written directly into the Excel “Remarks” column so you know which servers to check manually.

Automation: Bulk Create and Delete VM Snapshots Across Linked vCenters | Lazy Admin Blog

In a large environment, taking snapshots before a major patch or application update is a standard safety net. But if you have servers spread across multiple vCenters in Linked Mode (e.g., Datacenter1 and Datacenter2), clicking through the vSphere Client is a waste of time.
Today, I’m sharing a “Lazy Admin” script that allows you to bulk create, check, and remove snapshots using a simple CSV list.
Prerequisites
- VMware PowerCLI: Ensure the PowerCLI module is installed on the machine running the script.
- CSV Setup: Create a file named
snapshot_servers.csvinC:\Temp\VMSnapshots\.
The CSV should look like this: | Host | Location | | :— | :— | | Server01 | Datacenter1 | | Server02 | Datacenter2 |
Part 1: Creating Snapshots
- Open PowerShell ISE with vCenter Administrator credentials.
- Load the functions by running the full script (provided below).
- Run the following command:
Create-VMSnapshots -SS_CSV "C:\Temp\VMSnapshots\snapshot_servers.csv" -SS_Name "Pre-Patching" -SS_Description "Requested by App Team"
The script will iterate through your CSV and create snapshots sequentially. You can monitor the progress in the vSphere Tasks console.
Part 2: Deleting Snapshots
Once your changes are verified, don’t let those snapshots linger and bloat your datastores! To remove them:
- Use the same
snapshot_servers.csvlist. - Run the following command:
Remove-VMSnapshots -SS_CSV "C:\Temp\VMSnapshots\snapshot_servers.csv"
Note: This is a sequential script; it will wait for one snapshot removal to finish before moving to the next to avoid pinning your storage I/O.
The Script: VMSnapshots.ps1
Save this code to C:\Temp\VMSnapshots\VMSnapshots.ps1.
function Create-VMSnapshots { param ( [string]$SS_CSV = $(Read-Host "Enter path to CSV"), [string]$SS_Name = $(Read-Host "Enter name for snapshots"), [string]$SS_Description = $(Read-Host "Enter description for snapshots") ) # Import VMware PowerCLI Module If ( !(Get-Module -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue) ) { import-module VMware.VimAutomation.Core } $Servers = Import-CSV $SS_CSV $WLM_vCenter = Connect-VIServer vCenter1 -WarningAction SilentlyContinue $EDN_vCenter = Connect-VIServer vCenter2 -WarningAction SilentlyContinue ForEach($Server in $Servers){ If($Server.Location -eq 'Datacenter1'){ New-Snapshot -VM $Server.Host -Name $SS_Name -Description $SS_Description -Quiesce -Server $WLM_vCenter -WarningAction SilentlyContinue } ElseIf($Server.Location -eq 'Datacenter2'){ New-Snapshot -VM $Server.Host -Name $SS_Name -Description $SS_Description -Quiesce -Server $EDN_vCenter -WarningAction SilentlyContinue } } }function Check-VMSnapshots { param ( [string]$SS_CSV = $(Read-Host "Enter path to CSV"), [string]$SS_Name = $(Read-Host "Enter snapshot name") ) # Import VMware PowerCLI Module If ( !(Get-Module -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue) ) { import-module VMware.VimAutomation.Core } $Servers = Import-CSV $SS_CSV $WLM_vCenter = Connect-VIServer vCenter1 -WarningAction SilentlyContinue $EDN_vCenter = Connect-VIServer vCenter2 -WarningAction SilentlyContinue ForEach($Server in $Servers){ If($Server.Location -eq 'Datacenter1'){ Get-Snapshot -VM $Server.Host -Name $SS_Name -Server $WLM_vCenter | Select VM, Name, @{ n="SpaceUsedGB"; e={[math]::round( $_.SizeGB )}} -WarningAction SilentlyContinue } ElseIf($Server.Location -eq 'Datacenter2'){ Get-Snapshot -VM $Server.Host -Name $SS_Name -Server $EDN_vCenter | Select VM, Name, @{ n="SpaceUsedGB"; e={[math]::round( $_.SizeGB )}} -WarningAction SilentlyContinue } } } function Remove-VMSnapshots { param ( [string]$SS_CSV = $(Read-Host "Enter path to CSV") ) # Import VMware PowerCLI Module If ( !(Get-Module -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue) ) { import-module VMware.VimAutomation.Core } $Servers = Import-CSV $SS_CSV $WLM_vCenter = Connect-VIServer vCenter1 -WarningAction SilentlyContinue $EDN_vCenter = Connect-VIServer vCenter2 -WarningAction SilentlyContinue ForEach($Server in $Servers){ If($Server.Location -eq 'Datacenter1'){ Get-Snapshot $Server.Host -Server $WLM_vCenter | Remove-Snapshot -Confirm:$false -WarningAction SilentlyContinue } ElseIf($Server.Location -eq 'Datacenter2'){ Get-Snapshot $Server.Host -Server $EDN_vCenter | Remove-Snapshot -Confirm:$false -WarningAction SilentlyContinue } } }



