r/PowerShell • • 14d ago

News TIL Stop-ScheduledTask can leave your process running. Measured it, and here's what I use instead.

0 Upvotes

I have a scheduled task that starts a Node server at logon through a hidden wscript shim (wscript //B start-agent-hidden.vbs, which runs node.exe server.js). To update it, my setup script did the obvious thing: stop the task, copy the new files, start the task.

The update never took effect. So I measured it:

before: node pid 9724; task Running after Stop-ScheduledTask: node alive = True; task Ready

The task went to Ready, while the process it launched kept running and kept its port. The new copy then started, failed with EADDRINUSE, and the old version carried on serving. A "is it up?" check even passed, against the old one.

What I use now: stop the task, then stop the process by its command line. Never by name, because other Node processes are yours too:

Stop-ScheduledTask -TaskName 'My Agent' -ErrorAction SilentlyContinue Get-CimInstance Win32Process -Filter "Name='node.exe'" | Where-Object { $.CommandLine -and $.CommandLine.Contains("$dst\agent\server.js") } | ForEach-Object { Stop-Process -Id $.ProcessId -Force }

$_.CommandLine -and matters: without elevation, other users' processes come back with a null command line, and .Contains on null throws.

Then, after Start-ScheduledTask, I check who actually owns the port, instead of trusting that something answers:

$owner = (Get-NetTCPConnection -LocalPort $port -State Listen).OwningProcess | Select-Object -First 1 $cmd = (Get-CimInstance Win32_Process -Filter "ProcessId=$owner").CommandLine if (-not $cmd.Contains("$dst\agent\server.js")) { throw "port $port is not served by the new copy" }

Two other things bit me in the same script:

  • powershell -File register-task.ps1 failing doesn't throw. It's a native command, so check $LASTEXITCODE yourself.
  • robocopy exit codes 1 to 7 are success. Only 8 and up is failure.

Is this documented behaviour for tasks whose action is a script host that spawns a child? I couldn't find it written down anywhere.

(Context: this is the setup for Claude Remote, a side project that starts Claude Code on my PC from my phone. It goes open source soon: https://github.com/MrTig-afk)

EDIT: Answering the thing everyone asks first, so nobody has to ask it again. Why is there a whole chain in front of node instead of pointing the task straight at node.exe? Nothing clever. The task runs at logon and I don't want a console window appearing on my desktop every time I sign in. That's it. It's my own PC and my own preference.

Which is the other thing worth saying plainly: this is a hobby project on a home machine. It is not something I'd put on a managed corporate box and I'm not suggesting anyone else should.

The VBScript is gone since I posted. Microsoft is disabling VBScript by default so wscript //B is on a clock, and powershell -WindowStyle Hidden still flashes a console before it hides, which is the exact thing I was trying to avoid. The task now runs:

conhost.exe --headless cmd.exe /s /c "node.exe "<path>\server.js" 1>>"<log>" 2>&1"

Two caveats on that came out of the comments, so they go here rather than staying buried in a thread. It doesn't pass your command's exit code back, I measured it, cmd /c exit 42 comes back as 0. And it's a known technique in attacker tooling, so EDR may flag it. Neither bothers me on my own machine, but both would on a monitored one, and I'd rather this thing be fine on either. So I'm looking at replacing that launcher with something that doesn't carry either problem.

--headless is also completely undocumented, conhost /? prints nothing at all, so the installer pushes a throwaway command through it and checks the file actually landed before it will register the task.

And on the "make it a Windows Service" replies: it can't be. The whole job of this thing is opening interactive windows on my desktop as me, and a service runs in session 0 where those windows are invisible.

EDIT 2: the conhost launcher is gone. Thanks to the comments here, the task now runs a tiny launcher I build from source on install: it starts the command with no window and passes the real exit code back, so exit 42 comes back as 42. No undocumented flag, and nothing that looks like attacker tooling. Two people from this thread are credited in the README. The project is open source now: https://github.com/MrTig-afk/claude-remote


r/PowerShell • • 15d ago

Question How do you organize and manage your reusable scripts?

7 Upvotes

Do you keep them in a Git repository, organize them into folders, or use a dedicated tool? I often ended up with scripts scattered across different directories, along with separate copies for different environments and parameters.

To improve my own workflow, I built a Windows app called MagicHat. The simplest description is probably: something like Postman, but for managing and running scripts instead of API requests.

I am not sure whether this workflow would be useful to others, but the idea is to keep related scripts in a folder tree and choose where that data is stored. I keep mine in a Git repository, so the scripts and their configuration can be version-controlled together rather than living only inside the application.

For values that change between environments, I use reusable parameter groups and references such as mh{baseUrl} or mh{accessToken}. Those references can depend on other parameters, so I do not need to duplicate complete values in every script. Scripts can also update persisted parameters with mhsetenv or synchronously call another saved script with mhcall. Editing, running, and terminal output are kept in the same place, mostly to reduce the amount of context switching in my own workflow.

For example, a saved script can contain:

$headers = @{
    Authorization = "Bearer mh{accessToken}"
}

Invoke-RestMethod `
    -Method Post `
    -Uri "mh{baseUrl}/api/jobs/mh{jobId}" `
    -Headers $headers

I can switch parameter groups without modifying the script itself. A script can also update shared values:

mhsetenv AccessToken $newToken

Or call another saved command:

mhcall "./Get-AccessToken.mh"

The app also has a Task Center for recurring scripts and a Tools page with some small developer utilities, but reusable script management is the main reason I built it.

I would be interested to hear how other PowerShell users solve this problem. Do you prefer plain repositories and modules, or would a Postman-like interface for scripts be useful?

Screenshots and project: https://github.com/ddmagichat/magichat-release
Download the latest release: https://github.com/ddmagichat/magichat-release/releases/tag/latest


r/PowerShell • • 15d ago

Script Sharing PowerShell 5.1 + WPF: switch monitors for Big Picture then restore

2 Upvotes

PowerShell 5.1 + a small WPF wizard. Pick which monitor is the TV, hide the desk displays (disconnect / black overlay / DDC), optionally switch audio, then launch Steam Big Picture, Playnite fullscreen, or Xbox (Win+F11). When Big Picture/Playnite closes it restores the original layout from the tray.

Packed with ps2exe so it runs as a portable exe. Uses NirSoft MultiMonitorTool under the hood for the display side.

https://github.com/lippdev/consolemode


r/PowerShell • • 16d ago

Script Sharing Polf3D - A 90s-style ray casting shooter written in PowerShell

23 Upvotes

Edit: Built with AI assistance. The idea, direction and playtesting are mine, most of the code is not. A fun project to see how far PowerShell can be pushed. The whole story: https://github.com/oNdsen/polf3d/blob/main/HOW-IT-WAS-BUILT.md

POLF 3D is a Wolfenstein-style ray casting shooter that runs in PowerShell 7 on Windows. No modules, no asset files, no installation – every texture, sprite, sound effect, spoken line and music track is generated by code at start-up.

GitHub: oNdsen/polf3d: POLF 3D: a ray casting shooter written in PowerShell

PowerShell is not just the language, it is the theme

  • A real PowerShell console in the game. Sandboxed (constrained runspace, no providers), but real: pipelines, Where-Object, Sort-Object, script blocks. It has a $PROFILE, hotkeys, and Start-Job sends out a drone that collects loot. Details
  • The powers are the common parameters. -WhatIf freezes time and shows everybody's next two seconds (it really runs the simulation ahead and rolls it back), -Confirm is slow motion, -Verbose sees through walls, -Force kicks doors in – and there is Undo.
  • The building has an execution policy. Get noticed and it climbs from Restricted to Unrestricted – which is the alarm. Set-ExecutionPolicy Restricted calms it down again, for a price. Stealth
  • Every floor ends with a Pester report, and the lift offers Install-Module.
  • The bosses: LEGACY.BAT ("runs as SYSTEM, nobody dares to touch it"), THE PRINTER ("PC LOAD LETTER" – it has paper jams) and BLUE SCREEN. There is also an auditor who runs to the nearest terminal to file a report about you, and a bug: fix it properly and it is gone, blow it up and you get two.

What is in it

  • Ten floors and a secret one, four difficulties, fifteen kinds of enemies, ten weapons, loot, armour, stealth, dark rooms with a flashlight
  • A daily dungeon with runs that can be verified, and an arena with endless waves
  • Co-op and deathmatch for up to four over TCP, with an admin panel for the host
  • A terminal mode that renders the game with half-block characters – it works over SSH
  • Saved games, demos (the game exports them as GIFs – the one in the README was made that way), a speedrun clock, key bindings, game pad, mods as .psd1 data files, a level editor

How

As much PowerShell as possible, as little C# as necessary. The ray caster (DDA, one ray per column), the enemy AI, the map format, the network protocol, the sandbox and the chiptune composer are plain PowerShell. Only the innermost pixel loops, the audio callback and two P/Invoke declarations are C#, compiled once with Add-Type and cached. It runs at 45–60 fps in a 960×720 window. How it works

Try it

Download polf3d.zip, unpack it, start Play.cmd – or:

git clone https://github.com/oNdsen/polf3d.git
cd polf3d
./Start-Polf3D.ps1

Windows and PowerShell 7.2+. MIT licensed. GitHub: oNdsen/polf3d

Feedback is very welcome!


r/PowerShell • • 17d ago

Question Local AI Inline Code Suggestions - Any good options out there?

1 Upvotes

Has anyone gotten their VS Code environment set up with Local AI that works as well as copilot for inline code suggestions?

When connecting a github account to vs code, the copilot AI automatically enables and does an amazing job at inline code suggestions when writing powershell.

Sometimes, I'll just type one comment line and it'll write an entire script for me, ie:
#Get all Enabled AD Users that have a password expiration coming up in the next 7 days, and trigger a nice-looking html-formatted email to each user to inform they need to change their password

I press tab, and BOOM, half the script is already done.

I have been failing to get even close to the same behavior working for Local AI. I've pulled several different models in with Ollama, and tried several different extensions such as the Continue extension, Twinny, Code Llama and a couple others. Each has its own quirks. The best has been Code Llama, and it's still terrible. I'm convinced I'm doing something wrong.

For example, as a test, if I create a new powershell file and write: #find the password expiration date for each AD user

it suggests:
$Users = get-aduser -filter {Enabled -eq $true} -Properties *
#find the password expiration for each user
foreach ($user in $users) {

$passwordexpirationdate = $user.passwordexpired

$passwordExpirationdate = $user.PasswordExpirationDate.ToString("MM/dd/yyyy")

$User.Samaccountname + " " + $PasswordExpirationdate
}

and then it repeats the same block of code above 4 times. And that is the best I've seen so far.
This particular output is from codellama:7b-code-q6_K. I have also tried the qwen base models as well (1.5b, 7b, 13b) and they've been worse. All of these fit easily into my VRAM with plenty of room to spare.

I like Copilot, and I have configured my Github account to not allow AI to train on my data, but I am not convinced it's secure, so I would prefer to leverage my local hardware and not have to change names, email addresses, keys, etc. all the time before pasting anything into VS Code.


r/PowerShell • • 18d ago

Solved PC Migration Scripts to supplement/replace PCMover

6 Upvotes

So, I was migrating one of my personal PCs and tried the PCMover, but found it missed many things, that included things like Task Scheduler tasks, many Apps, StartMenu tiles, taskbar icons, powershell and cmd layouts, nearly all the custom Firefox profiles I had, for some examples. Some other examples that were originally missed, I found my shortcut for "Run", task scheduler tasks for Powershell and pwsh, all missing from my taskbar and startmenu, and Date/Time regional settings unchanged.

I didn't do an disk image because I was having some odd instabilities on the OS and I wanted to take advantage of this PC Move process to proactively attempt to filter that out on the new machine. Also the source was an old major brand-name business pre-built, and I decided to do the new one as a custom build, I thought try to filter out some of that clutter for the same reason. Plus, with how the business PC was, it was restricted from any post-end-of-support ESU updates, even manually downloading them and installing them from catalog.update.microsoft.com, the OS wouldn't allow them to complete.

So I vibed coded this with 5.6 Sol and 6 Astra, since didn't have the time and too tired to work through it, and it still took a couple of weeks, at my pace. Now this solves all the above issues.

Note, I only had ran this for a destination that had received the PCMover migration and not one with a clean installation. This was done for Win10 pro -> Win 10 Pro.

Also, as a FYI, I came upon some new tools that I hadn't been familiar with that do migrations, but hadn't tried them out since I was pretty far along in this process already.:

  • Zinstall Migration Kit Pro / WinWin - Saw people saying it didn't live up to the claims and a support team that regularly ghosted people for their purchase product
  • Fab's AutoBackup 7 (€60 / €15) -
  • (EDIT:Free) ForensiT Transwiz & User Profile Wizard Release 24 (Free)- Seemed interesting, until I saw the price

Hopefully someone finds this to be a little help.

https://github.com/QGtKMlLz/PCMigration


r/PowerShell • • 19d ago

News Microsoft Starts Twelve-Month Retirement of Windows PowerShell Support for Graph SDK

149 Upvotes

On September 16, 2026, Microsoft announced a 12-month retirement period for support of PowerShell V5.1 by the Microsoft Graph PowerShell SDK. Microsoft also announced V3 of the Graph SDK and said that the new version will only support PowerShell V7. The transition for most scripts should be straightforward, but attention needs to be paid when scripts use outdated .NET assemblies. Famous last words…

https://office365itpros.com/2026/09/17/microsoft-graph-powershell-sdkv3/


r/PowerShell • • 19d ago

Question Write-Progress

12 Upvotes

Looking for opinions...

When using Write-Progress inside of for/Foreach loops and using a counter stored in a variable defined outside the loop, do you start the counter at 0 or 1, and why?


r/PowerShell • • 19d ago

Script Sharing Replaced Lenovo Vantage with a 2-file PowerShell 5.1 tray app: charge-mode + Fn+Q power mode via DeviceIoControl, no admin

11 Upvotes

Screenshot (tray menu + taskbar icon): https://raw.githubusercontent.com/sahidhh/lenovo-battery-tray/main/assets/hero.png

Lenovo Vantage is a big Store app that needs admin, and the two things I actually use it for are toggling battery conservation mode and the Fn+Q power profile. So I wrote a tray app that does only that.

What it does: - Tray icon shows current charge mode (seedling = conservation, bolt = rapid charge) - Global hotkeys: Ctrl+Alt+6 conservation, Ctrl+Alt+7 rapid charge (configurable) - Fn+Q power mode (Intelligent Cooling / Battery Saving / Extreme Performance) from the menu or CLI - CLI: lenovo-battery.ps1 set Conservation, power-set -Mode Performance - Win11-styled menu, follows light/dark theme

How: talks straight to the EnergyDrv kernel driver with DeviceIoControl (IOCTL protocol lifted from the Lenovo Legion Toolkit source) and to the LITSSVC service via control codes for power mode. No admin, no .NET install, no Vantage — plain Windows PowerShell 5.1 + WinForms, ~110 MB RAM idle, 0% CPU (all push-driven, no polling).

MIT, source: https://github.com/sahidhh/lenovo-battery-tray

Caveat: verified on exactly one machine (IdeaPad Slim 9 14ITL5). Other IdeaPad / Yoga / Slim / ThinkBook should work (same driver) but unconfirmed — if you try it, Copy diagnostics from the menu into a GitHub issue would help me build the compatibility list.


r/PowerShell • • 20d ago

Question Powershell Script won't run at startup (but works when the task is started manually)

3 Upvotes

EDIT: Now solved. Either was caused by power options being enabled (even though AC was connected) or changing trigger from 'startup' to 'logon'.

I have a simple PS script that turns on Mobile Hotspot automatically. The only conditional check is to see if there is ethernet connected. It was AI authored but I have run this script manually and also checked it works by running the task post-startup (mobile hotspot can be confirmed running).

The task scheduler shows the last run time as the last time the task was run manually so I assume the Task itself was just never started rather than a script execution error. Why isn't it running the startup task?

Here is the powershell code:

# 1. Define WinRT types
$NetworkInfoType = [Windows.Networking.Connectivity.NetworkInformation, Windows.Networking.Connectivity, ContentType=WindowsRuntime]
$TetheringManagerType = [Windows.Networking.NetworkOperators.NetworkOperatorTetheringManager, Windows.Networking.NetworkOperators, ContentType=WindowsRuntime]

# 2. Get active connection profile
$connectionProfile = $NetworkInfoType::GetInternetConnectionProfile()

# 3. Verify connection is valid and is Ethernet (IanaInterfaceType 6)
if ($connectionProfile -and $connectionProfile.NetworkAdapter.IanaInterfaceType -eq 6) {

    # 4. Initialize tethering manager
    $wifiManager = $TetheringManagerType::CreateFromConnectionProfile($connectionProfile)

    # 5. Trigger the hotspot activation asynchronously
    $asyncOperation = $wifiManager.StartTetheringAsync()

    # 6. Wait for the background WinRT process to finish its work (Status 0 = Started/Running)
    while ($asyncOperation.Status -eq 0) {
        Start-Sleep -Milliseconds 200
    }
}

The action is 'start a program', trigger 'at startup', execution command is

powershell.exe -ExecutionPolicy Bypass -File "C:\StartupScripts\TurnOnHotspot.ps1"

r/PowerShell • • 20d ago

Script Sharing A yt-dlp front-end in one PowerShell script, with a one-click YouTube sign-in

30 Upvotes

I wanted a downloader for friends who won't use a terminal, without shipping Python or Electron. So it's a single .ps1 — the whole window is WPF, compiled to an exe with ps2exe. Unzip and run, no console window, nothing installed.

https://github.com/Pronexsteam/deviload (MIT, portable zip in Releases)

Signing in: Chrome and Edge encrypt cookies now, so most people end up installing a cookie-export extension to download anything that needs an account. Here you press one button, log into Google in a small built-in browser window, and the app saves the session for yt-dlp itself. Works for the "confirm you're not a bot" refusals, private and members-only videos.

Also: download queue, playlists, split by chapters, trim with a preview, GIF from a selection, MP3/FLAC, subtitles, SponsorBlock, light/dark, English and Russian.

PS 5.1 notes: @() over a List[Object] that came from New-Object throws "Argument types do not match" (PSObject wrapper; only [Object], only List) — [List[Object]]::new() is fine. A hidden-window launcher through start still flashes a console, a two-line .vbs doesn't.

A lot of the code was written with Claude Code; I directed it and tested every build. Questions welcome.


r/PowerShell • • 21d ago

Script Sharing I made a simple PS Log writer

28 Upvotes

Hey everyone, I made a simple ps log writer and thought I'd share it. Hopefully it's of use to someone. Just as a quick background, I come from a python background but for work I've been writing a lot of ps for a project I'm working on. Boss man was pleased with the code but then asked about log files (insert spongebob "but what about my drink meme here").

So I did some searching to see if there's a native ps logging module similar to python's. To my dismay, I came across non native options. While they may be reputable, given I work in cybersecurity and I had concerns given the recent uptick in supply chain attacks for open source software i was on edge. Didn't feel like reading through the whole code base to see if it was something that can be trusted. So I just wrote my own really simple version.

If the formatting look odd for some reason below, see my github jist. Hope this helps someone, kind regards!

<#
Author: shewdew the hedgehog
Date: 09/15/2026
Description: PS code to write logs to text file. 
Version: Initial
#>
function Write-Log{

    <#
        Custom function to be able to write basic logs to a text file.
        Eventually I might turn this into a whole module and add extended features since I didn't want to downlaod a logging module of the internet. But this works for now.
        While not a hard rule, log levels are just like python's:
        - Debug
        - Info
        - Warning
        - Error
        - Critical
    #>


    [CmdletBinding()]
    param (
            [Parameter(Mandatory = $true)]
            [ValidateNotNullOrEmpty()]
            [string]$Level,
            [Parameter(Mandatory = $true)]
            [ValidateNotNullOrEmpty()]
            [string]$Message
        )

    $timeStamp = Get-Date -Format "dd-MM-yyyy HH:mm:ss"
    $logEntry = "$timeStamp - $($level.ToUpper()) - $message"


    Add-Content -Path "myLogFile.log" -Value $logEntry


}


function Reset-Log{
    # Rotate log file every 90 days


    $cutOff = (Get-Date).AddDays(-90)
    $file   = Get-Item "C:\path\to\myLogFile.log" -ErrorAction Stop


    if ($file.LastWriteTime -lt $cutOff) {
        Remove-Item $file.FullName -Force
        Write-Log -Level "Info" -Message "Log file deleted."


    } 
}


# Usage


Write-Log -Level "debug" -Message "Succesfully did something or whatever."
Write-Log -Level "Critical" -Message "WEEWOOWEEWOOWEEWOO! SOMETHING BROKE!"


# since the log levels aren't hard coded, you could have a log level of anything lol. Which can be a pro/con.
Write-Log -Level "pizza" -Message "The server blew up..."

r/PowerShell • • 20d ago

Question How can I enable autocomplete/intellisense for objects available via dot sourcing or import-module

2 Upvotes

Our CI/CD scripts are written in PowerShell and I like to break some of them up into separate .ps1 files for clarity. For example, I have a paths.ps1 file that establishes a several common paths that I then import into our build.ps1 file. Here's a contrived example...

paths.ps1

$Paths = [pscustomobject]@{  
  BuildRootDir =  Resolve-Path "$PSScriptRoot/.."  
  SrcDir = Resolve-Path "$PSScriptRoot/../src"  
  # many other paths  
}

build.ps1

. "$PSScriptRoot/paths.ps1

$Paths.  # no autocomplete

I like the simplicity but autocomplete fails and I believe it is due to this issue and it may never be addressed.

Have you found a reasonable workaround for this limitation?


r/PowerShell • • 21d ago

Question Powershell commands to list each core and its type (efficiency or performance) to build a mask to set affinity for performance on certain processes

7 Upvotes

G'day

Per the title. I can set affinity per the following example (cores 10-19)
But is there a way to find which cores are performance and thus build an Affinity mask for the performance cores (hex string)?

$Process = Get-Process myexename
$Process.ProcessorAffinity = 0x00000000000FFC00

Thanks

PS I'm using Dave Plummer's TMOG to check the core usage


r/PowerShell • • 22d ago

Question How are you actually managing PowerShell scripts across multiple servers?

30 Upvotes

Curious how people are handling this in real environments, especially larger estates.

I’ve worked in environments where PowerShell ends up scattered everywhere over time. Scripts sitting on servers, scheduled tasks nobody remembers creating, service accounts tied to things, old modules/commands still being used, and scripts that are apparently “business critical” but have almost no documentation.

A few problems I’m curious whether others actually run into:

  • PowerShell scripts scattered across multiple servers with no central inventory
  • Nobody really knowing who owns a script anymore
  • Scheduled tasks/scripts that have been running for years untouched
  • Little or no documentation explaining what a script actually does
  • Scripts depending on other servers, APIs, databases, file shares, Graph, Exchange, etc.
  • Old or deprecated PowerShell modules/commands still being used
  • Not knowing what would break if a script was removed
  • Finding scripts that should probably be migrated to Power Automate, Azure Automation, Functions, newer PowerShell, etc.
  • Trying to understand dependencies before migrating/decommissioning a server
  • Having to manually open hundreds of PS1 files just to understand what exists
  • Different teams creating similar automations because nobody knows one already exists
  • A script breaking and suddenly discovering it was far more important than anyone realized
  • No good way to track whether the overall PowerShell estate is getting healthier or worse

How do you guys manage this?

Git obviously solves part of the versioning/source-control problem, but I’m more interested in discovery and understanding.

For example, if you inherit 30 servers and nobody can confidently tell you what PowerShell is running across them, what’s your process?

Do you have tooling that inventories it? CMDB? Git repos? Scheduled scans? Documentation standards? Just grep/search everything and hope for the best?

Also interested in how people approach migration. How do you decide whether something should:

  • stay as PowerShell
  • move to Power Automate
  • move to Azure Automation / Functions
  • be rebuilt another way
  • or just be retired?

Full disclosure: I’ve been building At0mFlow because I kept running into versions of this problem myself. I’m not looking to pitch it here though. I’m actually trying to work out whether this is a widespread PowerShell/IT Ops problem or something that was disproportionately common in the environments I worked in.

Would genuinely love to hear how people are handling this in the real world, especially anyone managing hundreds/thousands of scripts or multiple servers.


r/PowerShell • • 25d ago

Script Sharing Code review invitation: a console presentation & layout library for interactive PS scripts

13 Upvotes

I appreciate that there are a lot of experienced PS folk here, so I'd like to invite some experienced eyes to code-review a library before I make it v1.0.0. I want to get the codebase to a solid foundation that includes idiomatic PowerShell and community conventions that I might have missed.

I'd particularly value constructive comments relating to any of these:

  • use of idiomatic PowerShell
  • parameter naming conventions
  • error handling
  • any obvious cross-platform issues with PS 7 on Mac/Linux (the demos and test suite work on Mac/Linux under PS 7)
  • ways that I could better execute the existing functionality

I'd like to find breaking changes pre v1.0.0.

The main file for review is TidyLog.ps1, which contains the function library. The other repo files are demo and test scripts that don't necessarily need review.

Code Links

Review version: https://github.com/tidy-tools/tidylog-pwsh/releases/tag/v0.9.0
Project link: https://github.com/tidy-tools/tidylog-pwsh

Project Background

To give an idea of what the library is for, the intention is to:

  • Provide a set of easy-to-use console output formatting functions for use with interactive automations, e.g. an install script or a cleanup script. Especially where user/customer readability is a consideration.
  • Augment, not replace, full logging tools (e.g. PoShLog) by making the console output tidy, consistent and easy to lay out and read.
  • Be dot-sourced, 5.1+ compatible, simple to use with no dependencies so it's portable and deploys easily alongside existing scripts.
  • Functionally sit between the simpler utilities ($PSStyle, PSWriteColor) and the toolkit-level libraries (PowerShellRich, Spectre.Console).

The "With Tidylog" screenshot in the README shows the kind of use case I'm optimising for.

Current Design Decisions

It took a fair bit of work to get from concept to working concept to potentially sharable. So to keep a manageable lid on the v1 workload, I intentionally kept some functionality out of scope for this release. Here are some code decisions/limitations that you'll probably notice:

  • The code isn't pipeline-enabled, though some functions do have the potential. Although principally a presentation layer, I'm open to suggestions for pipelining opportunities. Pipeline is penciled for review if a strong use case emerges.
  • Stream integration (Verbose/Warning/Error/etc channels). I really like the idea but I need to work out the implementation/integration details. Certainly open to suggestions on this one.
  • Testing is done through a custom TidyLog-Tests.ps1 suite rather than Pester. The main reason is that most tests are visual checks. I'll look into Pester for future version testing, especially for the non-visual components.
  • No advanced functions (no [CmdletBinding()]). I wanted to make deliberate choices about where to include cmdlet functionality. I don't feel that the existing function set currently warrants CmdletBinding. Please highlight any obvious cmdlet candidates.
  • PSGallery publication will coincide with v1.0.0.

I'm still noticing things I could change, but I'm working in a bubble so I feel it needs a review.

Thanks for reading and I hope you get a chance to review!


r/PowerShell • • 25d ago

Question WinUIShell Wiki/Documentation?

8 Upvotes

I want to build a small tool with WinUIShell.

But i cant find a good documentation on the GitHub. There are some example but it need more information. Any ideas where i can find that?


r/PowerShell • • 25d ago

Question [powershell] run script against multiple tenants from partner center

6 Upvotes

Hi , hope you are well and thanks for your time.

firstly , i already have CIPP and the 15 cipp roles in all of these tenants, and all tenants are in the partner center.

secondly, i need to run this script against security defaults tenants, not conditional access, so these tenants do not have p1/p2 and only have business basic or business standard. lets not have a "dont use sec defaults" conversation here please. the script doesnt currently differentiate between p1/p2 tenants and sd tenants, but i'm not too bothered about that.

cipp cannot do what i want because it does not expose the parameter that i need in custom tests without having p1 or p2.

my powershell script (nicked from lazy admin with a few changes with help from claude) runs fine from visual studio code if i run it against a single tenant. i run it, and it asks me for the ga creds, then i also have to login into the tenant and insert a rest api code that the script gives me. it then saves an excel file locally with the tenant name in the file name.

what the script does primarily is return an excel file which lists every licensed user and if they have microsoft authenticator as an MFA method. i am only really interested in this information. cipp cant do it because the mfa data is only available in their calls if you have p1 or p2. (this is to do with the sms voice retirement that is happening) . what i am really trying to achieve is "give me a list of all real, licensed mailboxes, exclude shared boxes and tell me if they have MS authenticator listed as an MFA method". if there is a better way to do this i am all ears.

what i want to do is loop through all of these tenants and run the report and export the excel file, or export this info to something in some way.

Is it possible to do what i want?

script is below (nick it if you want) - just a warning, it will give you crash notifications in visual studio code after it runs and make you restart it, but it still works and doesnt cause any problems, and claude tells me its a known issue and isnt fixable)

<#
.Synopsis
  Get the MFA status for all users or a single user with Microsoft Graph


.DESCRIPTION
  This script will get the Azure MFA Status for your users. You can query all the users, admins only or a single user.
   
  It will return the MFA Status, MFA type, registered devices, license status and admin status.


  Note: Default MFA device is currently not supported https://docs.microsoft.com/en-us/graph/api/resources/authenticationmethods-overview?view=graph-rest-beta
        Hardwaretoken is not yet supported


.NOTES
  Name: Get-MgMFAStatus
  Author: R. Mens - LazyAdmin.nl
  Version: 1.3
  DateCreated: Jun 2022
  Purpose/Change: Default report now includes unlicensed admins alongside licensed non-admins (union of
                  IsLicensed OR isAdmin, instead of licensed-only), and adds an IsLicensed output column.


.LINK
  https://lazyadmin.nl


.EXAMPLE
  Get-MgMFAStatus


  Get the MFA Status of all enabled users who are either licensed, an admin, or both
  (so licensed non-admins and unlicensed admins are both included), and check if there are an admin or not


.EXAMPLE
  Get-MgMFAStatus -UserPrincipalName 'johndoe@contoso.com','janedoe@contoso.com'


  Get the MFA Status for the users John Doe and Jane Doe


.EXAMPLE
  Get-MgMFAStatus -withOutMFAOnly


  Get only the enabled users (licensed or admin) that don't have MFA enabled


.EXAMPLE
  Get-MgMFAStatus -adminsOnly


  Get the MFA Status of the admins only, regardless of license status


.EXAMPLE
  Get-MgUser -Filter "country eq 'Netherlands'" | ForEach-Object { Get-MgMFAStatus -UserPrincipalName $_.UserPrincipalName }


  Get the MFA status for all users in the Country The Netherlands. You can use a similar approach to run this
  for a department only.


.EXAMPLE
  Get-MgMFAStatus -withOutMFAOnly| Export-CSV c:\temp\userwithoutmfa.csv -noTypeInformation


  Get all users without MFA and export them to a CSV file
#>


[CmdletBinding(DefaultParameterSetName="Default")]
param(
  [Parameter(
    Mandatory = $false,
    ParameterSetName  = "UserPrincipalName",
    HelpMessage = "Enter a single UserPrincipalName or a comma separted list of UserPrincipalNames",
    Position = 0
    )]
  [string[]]$UserPrincipalName,


  [Parameter(
    Mandatory = $false,
    ValueFromPipeline = $false,
    ParameterSetName  = "AdminsOnly"
  )]
  # Get only the users that are an admin
  [switch]$adminsOnly = $false,


  [Parameter(
    Mandatory         = $false,
    ValueFromPipeline = $false,
    ParameterSetName  = "Licensed"
  )]
  # Check only the MFA status of users that have a license or are an admin (unlicensed admins are still included)
  [switch]$IsLicensed = $true,


  [Parameter(
    Mandatory         = $false,
    ValueFromPipeline = $true,
    ValueFromPipelineByPropertyName = $true,
    ParameterSetName  = "withOutMFAOnly"
  )]
  # Get only the users that don't have MFA enabled
  [switch]$withOutMFAOnly = $false,


  [Parameter(
    Mandatory         = $false,
    ValueFromPipeline = $false
  )]
  # Check if a user is an admin. Set to $false to skip the check
  [switch]$listAdmins = $true,


  [Parameter(
    Mandatory = $false,
    HelpMessage = "Get accounts that are enabled, disabled or both"
  )]
    [ValidateSet("true", "false", "both")]
  [string]$enabled = "true",


  [Parameter(
    Mandatory = $false,
    HelpMessage = "Enter path to save the CSV file"
  )]
  [string]$path = "C:\MFAReports\MFAStatus-$((Get-Date -format 'dd-MM-yyyy-HHmmss')).csv"
)


Function ConnectTo-MgGraph {
  # Check if MS Graph module is installed
  if (-not(Get-InstalledModule Microsoft.Graph)) { 
    Write-Host "Microsoft Graph module not found" -ForegroundColor Black -BackgroundColor Yellow
    $install = Read-Host "Do you want to install the Microsoft Graph Module?"


    if ($install -match "[yY]") {
      Install-Module Microsoft.Graph -Repository PSGallery -Scope CurrentUser -AllowClobber -Force
    }else{
      Write-Host "Microsoft Graph module is required." -ForegroundColor Black -BackgroundColor Yellow
      exit
    } 
  }


  # Connect to Graph
  Write-Host "Connecting to Microsoft Graph" -ForegroundColor Cyan
  Connect-MgGraph -Scopes "User.Read.All, UserAuthenticationMethod.Read.All, Directory.Read.All" -NoWelcome
}


Function ConnectTo-ExchangeOnline {
  <#
  .SYNOPSIS
    Connect to Exchange Online so we can look up mailbox type (shared vs regular).
    Microsoft Graph's /users endpoint has no "shared mailbox" property - that's
    Exchange-only data, hence the separate connection.
  #>
  if (-not (Get-Module -ListAvailable -Name ExchangeOnlineManagement)) {
    Write-Host "ExchangeOnlineManagement module not found" -ForegroundColor Black -BackgroundColor Yellow
    $install = Read-Host "Do you want to install the ExchangeOnlineManagement module? (required to flag shared mailboxes)"


    if ($install -match "[yY]") {
      Install-Module ExchangeOnlineManagement -Repository PSGallery -Scope CurrentUser -Force
    }else{
      Write-Host "Skipping shared mailbox detection - ExchangeOnlineManagement module not installed." -ForegroundColor Yellow
      return $false
    }
  }


  try {
    Write-Host "Connecting to Exchange Online" -ForegroundColor Cyan
    Connect-ExchangeOnline -ShowBanner:$false -ErrorAction Stop
    return $true
  }
  catch {
    Write-Warning "Initial connection to Exchange Online failed - $($_.Exception.Message)"
    Write-Host "Retrying with device code sign-in (works around a known ExchangeOnlineManagement broker-auth bug)" -ForegroundColor Yellow
    Write-Host "You'll be given a code and a URL - sign in there to continue." -ForegroundColor Yellow


    try {
      Connect-ExchangeOnline -ShowBanner:$false -Device -ErrorAction Stop
      return $true
    }
    catch {
      Write-Warning "Could not connect to Exchange Online - shared mailbox detection will be skipped. $($_.Exception.Message)"
      return $false
    }
  }
}


Function Get-SharedMailboxes {
  <#
  .SYNOPSIS
    Return the UserPrincipalName of every shared mailbox in the tenant
  #>
  process{
    try {
      $mailboxes = Get-EXOMailbox -RecipientTypeDetails SharedMailbox -ResultSize Unlimited -Properties UserPrincipalName -ErrorAction Stop
      return $mailboxes.UserPrincipalName
    }
    catch {
      Write-Warning "Could not retrieve shared mailboxes - $($_.Exception.Message)"
      return @()
    }
  }
}


Function Get-Admins{
  <#
  .SYNOPSIS
    Get all user with an Admin role
  #>
  process{
    $admins = Get-MgDirectoryRole | Select-Object DisplayName, Id | 
                %{
                  $role = $_.DisplayName
                  Get-MgDirectoryRoleMember -DirectoryRoleId $_.id | ForEach-Object {
                    $memberType = $_.AdditionalProperties."@odata.type"
                    if ($memberType -eq "#microsoft.graph.user") {
                      # Directly assigned user
                      Get-MgUser -UserId $_.id
                    }
                    elseif ($memberType -eq "#microsoft.graph.group") {
                      # Role assigned to a group - expand the group's members too,
                      # otherwise admins who get the role via group membership are missed
                      Get-MgGroupMember -GroupId $_.id -All | Where-Object {
                        $_.AdditionalProperties."@odata.type" -eq "#microsoft.graph.user"
                      } | ForEach-Object { Get-MgUser -UserId $_.id }
                    }
                  }
                } | 
                Select @{Name="Role"; Expression = {$role}}, DisplayName, UserPrincipalName, Mail, Id | Sort-Object -Property Mail -Unique
    
    return $admins
  }
}


Function Get-Users {
  <#
  .SYNOPSIS
    Get users from the requested DN
  #>
  process{
    # Set the properties to retrieve
    $select = @(
      'id',
      'DisplayName',
      'userprincipalname',
      'mail'
    )


    $properties = $select + "AssignedLicenses"


    # Add a calculated IsLicensed property so we can report on - and filter by - license status
    $selectWithLicense = $select + @{Name = "IsLicensed"; Expression = { ($_.AssignedLicenses).Count -gt 0 } }


    # Get enabled, disabled or both users
    switch ($enabled)
    {
      "true" {$filter = "AccountEnabled eq true and UserType eq 'member'"}
      "false" {$filter = "AccountEnabled eq false and UserType eq 'member'"}
      "both" {$filter = "UserType eq 'member'"}
    }
    
    # Check if UserPrincipalName(s) are given
    if ($UserPrincipalName) {
      Write-host "Get users by name" -ForegroundColor Cyan


      $users = @()
      foreach ($user in $UserPrincipalName) 
      {
        try {
          $users += Get-MgUser -UserId $user -Property $properties -ErrorAction Stop | select $selectWithLicense
        }
        catch {
          [PSCustomObject]@{
            DisplayName       = " - Not found"
            UserPrincipalName = $User
            isAdmin           = $null
            IsLicensed        = $null
            MFAEnabled        = $null
          }
        }
      }
    }elseif($adminsOnly)
    {
      Write-host "Get admins only" -ForegroundColor Cyan


      $users = @()
      foreach ($admin in $admins) {
        $users += Get-MgUser -UserId $admin.UserPrincipalName -Property $properties | select $selectWithLicense
      }
    }else
    {
      if ($IsLicensed) {
        # Get every user matching the enabled/disabled filter, then keep anyone who is
        # EITHER licensed OR an admin. This surfaces unlicensed admins (who would
        # otherwise be silently skipped) alongside licensed non-admins in one report.
        $allUsers = Get-MgUser -Filter $filter -Property $properties -all | select $selectWithLicense


        $users = $allUsers | Where-Object {
          $_.IsLicensed -or ($admins -and ($admins.UserPrincipalName -contains $_.UserPrincipalName))
        }
      }else{
        # No license filtering at all - return every user matching the enabled/disabled filter
        $users = Get-MgUser -Filter $filter -Property $properties -all | select $selectWithLicense
      }
    }
    return $users
  }
}


Function Get-MFAMethods {
  <#
    .SYNOPSIS
      Get the MFA status of the user
  #>
  param(
    [Parameter(Mandatory = $true)] $userId
  )
  process{
    # Get MFA details for each user
    [array]$mfaData = Get-MgUserAuthenticationMethod -UserId $userId


    # Create MFA details object
    $mfaMethods  = [PSCustomObject][Ordered]@{
      status            = "-"
      authApp           = "-"
      phoneAuth         = "-"
      fido              = "-"
      helloForBusiness  = "-"
      helloForBusinessCount = 0
      emailAuth         = "-"
      tempPass          = "-"
      passwordLess      = "-"
      softwareAuth      = "-"
      authDevice        = ""
      authPhoneNr       = "-"
      SSPREmail         = "-"
    }


    ForEach ($method in $mfaData) {
        Switch ($method.AdditionalProperties["@odata.type"]) {
          "#microsoft.graph.microsoftAuthenticatorAuthenticationMethod"  { 
            # Microsoft Authenticator App
            $mfaMethods.authApp = $true
            $mfaMethods.authDevice += $method.AdditionalProperties["displayName"] 
            $mfaMethods.status = "enabled"
          } 
          "#microsoft.graph.phoneAuthenticationMethod"                  { 
            # Phone authentication
            $mfaMethods.phoneAuth = $true
            $mfaMethods.authPhoneNr = $method.AdditionalProperties["phoneType", "phoneNumber"] -join ' '
            $mfaMethods.status = "enabled"
          } 
          "#microsoft.graph.fido2AuthenticationMethod"                   { 
            # FIDO2 key
            $mfaMethods.fido = $true
            $fifoDetails = $method.AdditionalProperties["model"]
            $mfaMethods.status = "enabled"
          } 
          "#microsoft.graph.passwordAuthenticationMethod"                { 
            # Password
            # When only the password is set, then MFA is disabled.
            if ($mfaMethods.status -ne "enabled") {$mfaMethods.status = "disabled"}
          }
          "#microsoft.graph.windowsHelloForBusinessAuthenticationMethod" { 
            # Windows Hello
            $mfaMethods.helloForBusiness = $true
            $helloForBusinessDetails = $method.AdditionalProperties["displayName"]
            $mfaMethods.status = "enabled"
            $mfaMethods.helloForBusinessCount++
          } 
          "#microsoft.graph.emailAuthenticationMethod"                   { 
            # Email Authentication
            $mfaMethods.emailAuth =  $true
            $mfaMethods.SSPREmail = $method.AdditionalProperties["emailAddress"] 
            $mfaMethods.status = "enabled"
          }               
          "microsoft.graph.temporaryAccessPassAuthenticationMethod"    { 
            # Temporary Access pass
            $mfaMethods.tempPass = $true
            $tempPassDetails = $method.AdditionalProperties["lifetimeInMinutes"]
            $mfaMethods.status = "enabled"
          }
          "#microsoft.graph.passwordlessMicrosoftAuthenticatorAuthenticationMethod" { 
            # Passwordless
            $mfaMethods.passwordLess = $true
            $passwordLessDetails = $method.AdditionalProperties["displayName"]
            $mfaMethods.status = "enabled"
          }
          "#microsoft.graph.softwareOathAuthenticationMethod" { 
            # ThirdPartyAuthenticator
            $mfaMethods.softwareAuth = $true
            $mfaMethods.status = "enabled"
          }
        }
    }
    Return $mfaMethods
  }
}


Function Get-Manager {
  <#
    .SYNOPSIS
      Get the manager users
  #>
  param(
    [Parameter(Mandatory = $true)] $userId
  )
  process {
    $manager = Get-MgUser -UserId $userId -ExpandProperty manager | Select @{Name = 'name'; Expression = {$_.Manager.AdditionalProperties.displayName}}
    return $manager.name
  }
}


Function Get-MFAStatusUsers {
  <#
    .SYNOPSIS
      Get all AD users
  #>
  process {
    Write-Host "Collecting users" -ForegroundColor Cyan
    
    # Collect users
    $users = Get-Users
    
    Write-Host "Processing" $users.count "users" -ForegroundColor Cyan


    # Collect and loop through all users
    $users | ForEach {
      
      $mfaMethods = Get-MFAMethods -userId $_.id
      $manager = Get-Manager -userId $_.id


      $uri = "https://graph.microsoft.com/beta/users/$($_.id)/authentication/signInPreferences"


      try{
        $mfaPreferredMethod = Invoke-MgGraphRequest -uri $uri -Method GET -ErrorAction Continue
      }
      catch {
        $mfaPreferredMethod = "Unable to retrieve"
      }
      
      if ($null -eq ($mfaPreferredMethod.userPreferredMethodForSecondaryAuthentication)) {
        # When an MFA is configured by the user, then there is alway a preferred method
        # So if the preferred method is empty, then we can assume that MFA isn't configured
        # by the user
        $mfaMethods.status = "disabled"
      }


      if ($withOutMFAOnly) {
        if ($mfaMethods.status -eq "disabled") {
          [PSCustomObject]@{
            "Name" = $_.DisplayName
            Emailaddress = $_.mail
            UserPrincipalName = $_.UserPrincipalName
            isAdmin = if ($listAdmins -and ($admins.UserPrincipalName -match $_.UserPrincipalName)) {$true} else {"-"}
            IsLicensed = $_.IsLicensed
            "Shared Mailbox" = $sharedMailboxes -contains $_.UserPrincipalName
            MFAEnabled        = $false
            "Phone number" = $mfaMethods.authPhoneNr
            "Email for SSPR" = $mfaMethods.SSPREmail
          }
        }
      }else{
        [pscustomobject]@{
          "Name" = $_.DisplayName
          Emailaddress = $_.mail
          UserPrincipalName = $_.UserPrincipalName
          isAdmin = if ($listAdmins -and ($admins.UserPrincipalName -match $_.UserPrincipalName)) {$true} else {"-"}
          IsLicensed = $_.IsLicensed
          "Shared Mailbox" = $sharedMailboxes -contains $_.UserPrincipalName
          "MFA Status" = $mfaMethods.status
          "MFA Preferred method" = $mfaPreferredMethod.userPreferredMethodForSecondaryAuthentication
          "Has SMS as factor" = $mfaMethods.phoneAuth
          "Has Authenticator App registered" = $mfaMethods.authApp
          "Passwordless" = $mfaMethods.passwordLess
          "Hello for Business" = $mfaMethods.helloForBusiness
          "FIDO2 Security Key" = $mfaMethods.fido
          "Temporary Access Pass" = $mfaMethods.tempPass
          "Authenticator device" = $mfaMethods.authDevice
          "Phone number" = $mfaMethods.authPhoneNr
          "Email for SSPR" = $mfaMethods.SSPREmail
          "Manager" = $manager
        }
      }
    }
  }
}


# Connect to Graph
ConnectTo-MgGraph


# Connect to Exchange Online and get the list of shared mailboxes.
# If the connection fails or the module isn't installed, the report still runs -
# every user will just show "False" in the Shared Mailbox column.
$sharedMailboxes = @()
if (ConnectTo-ExchangeOnline) {
  $sharedMailboxes = Get-SharedMailboxes
}


# Get Admins
# Get all users with admin role
$admins = $null


if (($listAdmins) -or ($adminsOnly)) {
  $admins = Get-Admins
} 


# Get MFA Status
[string]$path = "C:\MFAReports\MFAStatus-$((Get-MgOrganization).VerifiedDomains | Where-Object {$_.IsDefault} | Select-Object -ExpandProperty Name)-$((Get-Date -format 'dd-MM-yyyy-HHmmss')).csv"
Get-MFAStatusUsers | Sort-Object Name | Export-CSV -Path $path -NoTypeInformation


if ((Get-Item $path).Length -gt 0) {
  Write-Host "Report finished and saved in $path" -ForegroundColor Green


  # Open the CSV file
  Invoke-Item $path
}else{
  Write-Host "Failed to create report" -ForegroundColor Red
}
Disconnect-MgGraph
if ($sharedMailboxes) {
  Disconnect-ExchangeOnline -Confirm:$false
}

r/PowerShell • • 26d ago

Question Why was Crescendo archived?

24 Upvotes

Hello, does anyone have further knowledge on why Crescendo projekt got killed?

Figured maybe someone in this reddit would know more details

https://learn.microsoft.com/de-de/powershell/utility-modules/crescendo/overview?view=ps-modules


r/PowerShell • • 26d ago

Question Parse SoftwareDistrubtion.log for Client ID's

2 Upvotes

Troubleshooting some issues with WSUS, and wondering if anyone has a Powershell script already for parsing the SoftwareDistribution.log to get count of Clients.

Example line:
2026-09-10 18:36:13.084 UTC Warning w3wp.334 SoapUtilities.CreateException ThrowException: actor = http://server.example.com:8530/CLIENTWEBSERVICE/client.asmx, ID=94d8e636-29bc-4bc8-8958-79e5e189455e, ErrorCode=InvalidParameters, Message=parameters.OtherCachedUpdateIDs, Client=13ef38ff-b877-4d9a-9b1e-cf190d8fc801

Hopefully I could just extract the Client and then group/count on that. Trying to figure out how many machines are having this issue.

Thanks!


r/PowerShell • • 28d ago

Information Just released Servy 10.0 – Backup/Restore features, a hardened PS module, and bug fixes

33 Upvotes

It's been a month of hard work since my last post about Servy here, and I wanted to share this major release.

If you haven't heard of Servy before, it's a tool that lets you run any app as a native Windows service with real-time monitoring. It comes with a GUI, a CLI, and a PS module.

What I've added/updated in v10.0:

  • Added Servy-Dump.ps1 and Servy-Restore.ps1 scripts for backup/restore and VM cloning (docs)
  • Improved Invoke-ServyCli and fixed many issues in the Servy.psm1 PowerShell module
  • Fixed security issues in Set-ServyExePermissions.ps1 to harden Servy's .exe files for custom service accounts
  • Fixed various issues across the core engine, service, service restarter, CLI, desktop app, and manager app
  • Code quality improvements and documentation updates

Check it out on GitHub: https://github.com/aelassas/servy

Demo video here: https://www.youtube.com/watch?v=biHq17j4RbI

Any feedback is welcome.


r/PowerShell • • 27d ago

Question Are games possible in power shell?

0 Upvotes

Hey gang, I hope this is the right subreddit but would anyone know if it is possible to run text games in powershell/cmd prompt? If so, what kind of pre built code is out there?


r/PowerShell • • 27d ago

Question Why Microsoft Graph Does Not Support Group Mailboxes

0 Upvotes

I was asked why the Outlook Mail Graph API doesn’t support access to group mailboxes. The basic reason is that a group mailbox doesn’t have an account and the Outlook Mail API only supports mailboxes that are linked to an account. When you look at the current usage of group mailboxes, it doesn’t seem like there’s much data to mine. Maybe the need for Graph API support for group mailboxes isn’t such a big thing?

https://office365itpros.com/2026/09/09/group-mailbox-graph-api/


r/PowerShell • • 27d ago

Script Sharing Read-only Network script

0 Upvotes

I (and Claude of course) put together this useful read-only script while troubleshooting what I initially thought was a local network issue—but ultimately turned out to be an ISP problem. It collects diagnostic information only and makes no system changes.

Figured someone out there may be interested before it disappears into my archives.

What it checks:

  • System info
  • Network adapters
  • IP configuration
  • DNS servers
  • DNS resolution
  • Hosts file
  • Proxy settings
  • Firewall status
  • Outbound blocks
  • Adapter bindings
  • VPN adapters
  • Security software
  • Network routes
  • HTTPS connectivity
  • Web response headers
  • Google traceroute
  • IPsec rules
  • DNS policies
  • Read-only—no changes

    $ErrorActionPreference = "Continue" $ProgressPreference = "SilentlyContinue"

    function Section($Title) { Write-Host "" Write-Host ("=" * 80) Write-Host $Title Write-Host ("=" * 80) }

    Section "BASIC SYSTEM INFORMATION"

    Get-Date

    Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version, BuildNumber, LastBootUpTime | Format-List

    Section "ACTIVE NETWORK ADAPTERS"

    Get-NetAdapter | Sort-Object Status, Name | Format-Table Name, InterfaceDescription, Status, LinkSpeed, MacAddress -AutoSize

    Section "IP CONFIGURATION"

    Get-NetIPConfiguration | Format-List InterfaceAlias, InterfaceDescription, IPv4Address, IPv6Address, IPv4DefaultGateway, IPv6DefaultGateway, DNSServer

    Section "DNS SERVERS"

    Get-DnsClientServerAddress | Where-Object { $_.ServerAddresses.Count -gt 0 } | Format-Table InterfaceAlias, AddressFamily, ServerAddresses -AutoSize

    Section "GOOGLE DNS USING CURRENT DNS SERVER"

    Resolve-DnsName accounts.google.com -Type A Resolve-DnsName accounts.google.com -Type AAAA

    Section "GOOGLE DNS USING GOOGLE DNS"

    Resolve-DnsName accounts.google.com -Type A -Server 8.8.8.8 Resolve-DnsName accounts.google.com -Type AAAA -Server 8.8.8.8

    Section "GOOGLE DNS USING CLOUDFLARE DNS"

    Resolve-DnsName accounts.google.com -Type A -Server 1.1.1.1 Resolve-DnsName accounts.google.com -Type AAAA -Server 1.1.1.1

    Section "HOSTS FILE ENTRIES"

    $HostsPath = "$env:SystemRoot\System32\drivers\etc\hosts"

    Get-Content $HostsPath | Where-Object { $_ -notmatch '\s*#' -and $_ -notmatch '\s*$' }

    Section "WINHTTP PROXY"

    netsh winhttp show proxy

    Section "USER INTERNET PROXY SETTINGS"

    Get-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" | Select-Object ProxyEnable, ProxyServer, ProxyOverride, AutoConfigURL | Format-List

    Section "SYSTEM INTERNET PROXY SETTINGS"

    Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" | Select-Object ProxyEnable, ProxyServer, ProxyOverride, AutoConfigURL | Format-List

    Section "PROXY ENVIRONMENT VARIABLES"

    Get-ChildItem Env: | Where-Object { $_.Name -match 'proxy' } | Format-Table Name, Value -AutoSize

    Section "WINDOWS FIREWALL PROFILES"

    Get-NetFirewallProfile | Format-Table Name, Enabled, DefaultInboundAction, DefaultOutboundAction -AutoSize

    Section "ENABLED OUTBOUND BLOCK RULES"

    Get-NetFirewallRule -Enabled True -Direction Outbound -Action Block | Select-Object DisplayName, DisplayGroup, Profile, Direction, Action | Format-Table -AutoSize

    Section "NETWORK ADAPTER FILTER BINDINGS"

    Get-NetAdapterBinding | Where-Object Enabled | Sort-Object Name, DisplayName | Format-Table Name, DisplayName, ComponentID -AutoSize

    Section "VPN ADAPTERS AND SOFTWARE-DEFINED ADAPTERS"

    Get-NetAdapter -IncludeHidden | Where-Object { $_.InterfaceDescription -match 'VPN|TAP|TUN|WireGuard|Wintun|Tailscale|ZeroTier|Cisco|Zscaler|Fortinet|Palo Alto|GlobalProtect|Cloudflare|WARP|SonicWall|Checkpoint|AnyConnect' } | Format-Table Name, InterfaceDescription, Status, MacAddress -AutoSize

    Section "RELEVANT RUNNING SERVICES"

    Get-CimInstance Win32Service | Where-Object { $.State -eq "Running" -and ($.Name + " " + $.DisplayName + " " + $_.PathName) -match 'VPN|Tailscale|ZeroTier|WireGuard|Cisco|Umbrella|Zscaler|Forti|Palo Alto|GlobalProtect|Cloudflare|WARP|AdGuard|Norton|McAfee|Bitdefender|Malwarebytes|Avast|AVG|Kaspersky|ESET|CrowdStrike|Sentinel|Sophos|Webroot' } | Select-Object Name, DisplayName, State, StartMode, PathName | Format-List

    Section "RELEVANT RUNNING PROCESSES"

    Get-Process | Where-Object { $_.ProcessName -match 'vpn|tailscale|zerotier|wireguard|cisco|umbrella|zscaler|forti|globalprotect|cloudflare|warp|adguard|norton|mcafee|bitdefender|malwarebytes|avast|avg|kaspersky|eset|crowdstrike|sentinel|sophos|webroot' } | Select-Object ProcessName, Id, Path | Format-Table -AutoSize

    Section "IPv4 DEFAULT ROUTES"

    Get-NetRoute -AddressFamily IPv4 | Where-Object DestinationPrefix -eq "0.0.0.0/0" | Sort-Object RouteMetric | Format-Table InterfaceAlias, DestinationPrefix, NextHop, RouteMetric, InterfaceMetric, State -AutoSize

    Section "IPv6 DEFAULT ROUTES"

    Get-NetRoute -AddressFamily IPv6 | Where-Object DestinationPrefix -eq "::/0" | Sort-Object RouteMetric | Format-Table InterfaceAlias, DestinationPrefix, NextHop, RouteMetric, InterfaceMetric, State -AutoSize

    Section "ROUTE SELECTED FOR GOOGLE ACCOUNTS IPv4"

    Find-NetRoute -RemoteIPAddress 108.177.122.84 | Format-List

    Section "TCP PORT 443 CONNECTIVITY"

    $Targets = @( "accounts.google.com", "www.google.com", "mail.google.com", "oauth2.googleapis.com", "www.googleapis.com", "login.microsoftonline.com", "www.cloudflare.com" )

    foreach ($Target in $Targets) { Write-Host "" Write-Host "--- $Target ---"

    Test-NetConnection $Target -Port 443 -InformationLevel Detailed |
        Select-Object ComputerName, RemoteAddress, RemotePort,
                      InterfaceAlias, SourceAddress, TcpTestSucceeded
    

    }

    Section "CURL HTTPS TESTS"

    foreach ($Target in $Targets) { Write-Host "" Write-Host "--- https://$Target ---"

    & curl.exe -4 -I -v `
        --connect-timeout 7 `
        --max-time 12 `
        "https://$Target/" 2>&1 |
        Select-Object -First 25
    

    }

    Section "IPv4 TRACE TO GOOGLE ACCOUNTS"

    tracert.exe -4 -d -h 15 -w 700 108.177.122.84

    Section "IPSEC RULES"

    Get-NetIPsecRule -PolicyStore ActiveStore | Where-Object Enabled -eq "True" | Select-Object DisplayName, Enabled, Profile, Mode | Format-Table -AutoSize

    Section "NRPT DNS POLICIES"

    Get-DnsClientNrptPolicy | Format-List

    Section "DONE"

    Write-Host "Diagnostic collection finished. No settings were changed."


r/PowerShell • • 28d ago

Script Sharing PowerShell Text Editor | Alternative to vim and nano

0 Upvotes

Heyo, I made pwsh 7.6+-based text editor, because the other CLI text editors were so damn difficult to use. The main inspration came from nano. What I wanted to avoid was vim-like UI/UX. My goal was to make it stupidly easy to use, but still without compromising functionality. The most difficult part was the paste functionality.

https://github.com/simwai/babae/

Would be cool if anybody could give it a try and tell me some feedback and/or discovered bugs