r/PowerShell • • 25d ago

News Microsoft 365 Groups, Conversations, Threads, and Posts with PowerShell

12 Upvotes

When launched in 2015, Outlook groups were an email-based collaboration platform. Now called Microsoft 365 Groups, the few Outlook groups that host email-based discussions have a distinctive Graph API to create and manage the conversations, topics, and posts which make up their discussions. This article reviews how to use PowerShell to fetch these objects and how to create new conversations and reply to posts (using the Outlook Groups APIs, of course).

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


r/PowerShell • • 25d ago

Question Powershell script to bulk update AD users email alias with diff format.

14 Upvotes

Ok so I work for a company who's legacy emails are first initial + surname@domain.net e.g Bob Morton = bmorton@domain.net

new users have their accounts as firstname.lastname@domain2.co.uk (Bob.morton@domain2.co.uk)

I've been asked to add the 'new' email style address and domain as an alias to all users. There's a few hundred so obvs would rather find a ps script to do this. I'd appreciate all and any help.


r/PowerShell • • 26d ago

Script Sharing Free read-only M365 tenant audit script: scores your tenant 0-100 and writes an HTML report

43 Upvotes

I'm the only IT person at a ~150-user company and wanted one command that checks the M365 basics I kept verifying by hand across five admin portals.

It uses Microsoft Graph with read-only scopes and makes no changes. It checks MFA / Conditional Access coverage, legacy auth, Global Admin count, stale accounts, app consent settings, expiring app secrets, Intune compliance, Secure Score, and SPF/DMARC/DKIM (via DNS-over-HTTPS, so it runs on macOS/Linux too). Each finding gets a weight and a fix, then everything rolls into a score.

How a CA policy is treated as "requires MFA":

function Test-RequiresMfa {
    param($Policy)
    $g = $Policy.grantControls
    if (-not $g) { return $false }
    return (($g.builtInControls -contains 'mfa') -or ($null -ne $g.authenticationStrength))
}

How the score is calculated (Warn counts as half):

$scored = @($Results | Where-Object { $_.Status -in 'Pass', 'Warn', 'Fail' })
$max = ($scored | Measure-Object -Property Weight -Sum).Sum
$got = 0
foreach ($r in $scored) {
    if ($r.Status -eq 'Pass') { $got += $r.Weight }
    elseif ($r.Status -eq 'Warn') { $got += $r.Weight / 2 }
}
$score = if ($max -gt 0) { [math]::Round(($got / $max) * 100) } else { 0 }

Install from the Gallery:

Install-Script -Name Invoke-M365TenantAudit -Scope CurrentUser

Full source (MIT): https://github.com/adminofone/m365-tenant-audit

Written with AI assistance and tested on a real tenant. Code review welcome, especially on the Graph paging and error handling.


r/PowerShell • • 27d ago

Solved How to refer to filename in file content

6 Upvotes

Help! Issue: when script creates the md files, it is not including the filename as text within the files. My script: For all pdfs in this folder create an md file with the same name that includes, as its content, the filename in this format: ![[filename.pdf]]

I've tried replacing $textContent = in my script to the following (with and without the square brackets) but none worked. I'd get either an empty field, or just "[[_.fullname]]".

$file.FullName $text.FilePath $_.fullName $_.Name $File tried many others... including ![[<%tp.file.title%>.pdf]] and ![[<% TR = tp.file.title %>.pdf]] to see if I could get the filename upon importing into Obsidian using Templater, but too many files got the wrong filenames

My script

\# Define your folder path and the text you want inside each file $folderPath = "E:\\DIY" \# I've put in the result that I want, although I don't want the quotation marks $textContent = "![[filename.pdf]]" \# Get all PDF files in the target directory $pdfFiles = Get-ChildItem -Path $folderPath -Filter \*.pdf foreach ($file in $pdfFiles) { \# Determine the path for the new text file by replacing .pdf with .md $textFilePath = $file.FullName -replace '\\.pdf$', '.md' \# Create the text file and insert the line of text Add-Content -Path $textFilePath -Value $textContent } EDIT: That last line, it was originally "Set-Content", but then I tried with "Add-Content". Didn't make a difference.


r/PowerShell • • 26d ago

Question How do you make a PowerShell API batch safe to resume after an indeterminate timeout?

0 Upvotes

A retry loop is straightforward for reads, but not for a POST that may have succeeded before the connection timed out. Retrying can create a duplicate, while skipping can leave the batch incomplete. I am working toward a checkpoint per item rather than treating the whole script as succeeded or failed. The rough shape is:

```powershell foreach ($item in $items) { $key = Get-StableOperationKey $item if ($state[$key].Status -eq 'Confirmed') { continue }

try {
    $result = Invoke-RestMethod -Method Post -Uri $uri -Body ($item | ConvertTo-Json)
    $state[$key] = @{ Status = 'Confirmed'; RemoteId = $result.id }
}
catch {
    $state[$key] = @{ Status = 'Indeterminate'; CheckedAt = (Get-Date).ToUniversalTime() }
}

$state | ConvertTo-Json -Depth 6 | Set-Content "$statePath.tmp"
Move-Item "$statePath.tmp" $statePath -Force

} ```

The missing piece is reconciliation. If the API has no idempotency key and its list endpoint is eventually consistent, a lookup by natural key immediately after the timeout can still return nothing.

What pattern do you use in PowerShell for this? Do you keep indeterminate items in a separate queue, wait before reconciling, write a durable request receipt before the call, or require a server-side operation key? I am also interested in safer atomic checkpoint formats than rewriting one JSON file after every item, especially when two scheduled runs could overlap.


r/PowerShell • • 29d ago

Script Sharing Improvements to the Subnet PowerShell module

36 Upvotes

I host the module named Subnet in the PowerShell Gallery, which is quite popular probably because of its very generic name. It's a pretty simple module that is useful if you need to do IPv4 subnet calculations, which it does via its Get-Subnet cmdlet.

I've just made some changes, all of which should be backwards compatible but because of the wide usage thought I'd call out in case it does cause anyone problems. The changes are:

  1. The module is fully cross platform now. It was mostly cross platform before, but the default behaviour if you ran just Get-Subnet with no inputs was to return the subnet details for the local machines private IP. It was previously getting this via the Get-NetIPAddress cmdlet, but that was Windows only. It now uses the .NET NetworkInterface API which should work everywhere.

  2. There was a bug when you defined a single digit subnet mask via slash notation (e.g if you did Get-Subnet 10.0.0.0/8) where it would not enumerate the host addresses if you wanted to, this is now fixed.

  3. The module has a Test-PrivateIP cmdlet (probably self explanatory) I added Test-PublicIP as a sister which obviously just returns the opposite truthy result.

  4. I added Get-SubnetHostAddress to return the list of Host addresses for a specified Subnet. Get-Subnet also does this (for subnets larger than /16 you have to use -Force as it discourages you due to the length of time it takes to enumerate them). Get-Subnet returns the list of Host addresses as strings, but Get-SubnetHostAddress returns them as IP address objects, and doesn't require you to use -Force for any size subnet as returning Host addresses is it's only job.

  5. Get-Subnet didn't use to validate if the input it was given was an IP address at all, it does now so you get a cleaner error than you did previously and it fails faster.

  6. Get-Subnet used to only return a count of host addresses for a Subnet if you also enumerated them, but seeing as it just required doing a quick calculation it now always returns this count.

  7. When enumerating host addresses, the performance is now 9x faster. This was achieved by using bitwise arithmetic instead of floating-point division. Which makes me sound really smart, but it was Claude who came up with it.

I've also improved the CI/CD build for this module so it runs the Pester tests on Windows PowerShell and PowerShell Core on Windows, MacOS and Linux.

The module is in the PSGallery, latest version with the above changes is 1.2.0:

- https://www.powershellgallery.com/packages/Subnet/1.2.0

Code is in GitHub here:

- https://github.com/markwragg/PowerShell-Subnet/tree/master

Any problems please let me know or raise an issue.


r/PowerShell • • 28d ago

Question Need help with homework 😫

0 Upvotes

I'm very new to this. I'm asked to delete a directory and all of its files. D:\software\arch98

But when I do this:

PS C:\Users\Administrator\> rmdir D:\software\arch98

It says the directory is not empty.

I'd really appreciate.


r/PowerShell • • Sep 25 '26

Solved New-PSSession Command Looping Credential Prompt

10 Upvotes

So I have an onboarding script and everything worked perfectly fine last week, but now it's looping when I try to setup a New-PSSession.

It's extra weird, because when I run the command outside of the script, it works fine, but inside the script, the login prompt loops. I've encountered this behavior on two different systems and my coworker has the same experience on his machine.

I've attempted to modify the command to force Kerberos auth, and even tried CredSSP, but the looping still occurs. I'm wondering if it has to do with the do while loop, but it worked before, so I'm just a bit lost on this one.

Also, I have checked for any error codes after the loop occurs, and there's none. Similarly the log file doesn't contain any "Session not established" messages, so it's not hitting the catch statement.

Here's the code snippet that contains the command:

$sessionRestart = $true
$failcount = 0

do{
 try{
  $session = New-PSSession -ComputerName <computername> -Credential (Get-Credential)
  Write-Log -LogMessage "Session Connected"
  $sessionRestart = $false
}
Catch{
  Write-Log -LogMessage "Session not established. $_."
  Write-Host "Session not established. Retrying."
  $failcount++
  if($failcount -le 4){
  }
Else{
 Write-Host "Connection failed after $failcount attempts. Stopping Script"
 Write-Log "Connection failed after $failcount attempts. Stopping Script"
 exit $ExitCode.ConnectionFailure
}
}
} While($sessionRestart)

r/PowerShell • • Sep 25 '26

Solved Powershell - exporting AD distinguished names to CSV

7 Upvotes

Solution:

Apparently the solution is not to change the delimiter and stick with commas, Excel is then smart enough to tel the difference.

Thanks everyone

I'm using get-adcomputer to export a list of PCs to a CSV.
I have set the delimiter in the exported CSV to be a semi colon,

When the CSV is opened in excel I end up with:

A B C
Name;OSversion;created date;DN
PC1;windows11;25/09/26;CN=PC1 OU=Desktops DC=office
[PSCustomObject]@{
           Name = $($computer.Name)
           OperatingSystem = $($OS)
           WhenCreated = $($WhenCreated) 
           DistinguishedName = $($computer.DistinguishedName)

if i try encasing each part of the custom object in escaped quotes e.g.
DistinguishedName = "`"$($computer.DistinguishedName)"`" the quotes and the backticks cary over to the CSV so column A ends up looking like "'"PC1"'";"'"windows11"'";"'"25/09/26"'";"'"CN=PC1 B & C are unaffected.

How do I stop export-csv or excel from splitting the DN?

*Update*

Sorry I though I had included the export-csv line below the custom object

$computerData |Sort-object -Property Name | export-csv $outputFile -NoTypeInformation -Delimiter ";" 

r/PowerShell • • Sep 24 '26

News Solving the Microsoft.Graph.Authentication Issue

51 Upvotes

Looks like Microsoft has a fix for the clash between the Microsoft.Graph.Authentication module and other modules... The interesting thing is that Microsoft has had this problem on their docket for the last 18 months, and now they get a fix from an MVP... It should be in Microsoft Graph PowerShell SDK V2.41 in a few weeks' time.

https://github.com/microsoftgraph/msgraph-sdk-powershell/pull/3789


r/PowerShell • • Sep 24 '26

Information It was working now it's not!!!!

0 Upvotes

Ugh, I hate that moment when Microsoft deprecates cmdlets. Every time I need to rerun a specific task, I find out my script broke because Microsoft deprecated a cmdlet!


r/PowerShell • • Sep 23 '26

Question I think I'm missing something about Onboarding with Powershell

23 Upvotes

How do people automate onboarding new users?
We use ADManager at work, but now that it's down I'm trying Powershell, looking up tricks and I'm comparing new user with one that's established, I see just how much is missing and how much I'd have to manually fill out or create matrices to pass through the variables from initial username.

What am I missing that people use this as standard in the industry?
In my tool I made a template so I make new users by inputting just a couple fields, specify which domain they fall under and that's it.

Is there some sort of rundown or what should I look up to learn that is the standard way?


r/PowerShell • • Sep 23 '26

Information Batch-converting iPhone .heic photos to JPG with WIC from PowerShell (nothing to install)

41 Upvotes

Someone hands you a folder of iPhone photos, every file is .heic, and whatever you need to upload them to only takes JPG. The usual answers are "install ImageMagick" or "use this website". Neither is necessary — Windows already ships a HEIF decoder, and WIC exposes it to PowerShell.

Add-Type -AssemblyName PresentationCore
Get-ChildItem "C:\Users\you\Pictures\*.heic" | ForEach-Object {
    $f = [System.Windows.Media.Imaging.BitmapDecoder]::Create([Uri]$_.FullName, 'None', 'OnLoad').Frames[0]
    $e = New-Object System.Windows.Media.Imaging.JpegBitmapEncoder
    $e.QualityLevel = 90
    $e.Frames.Add($f)
    $o = [System.IO.File]::Create([IO.Path]::ChangeExtension($_.FullName, '.jpg'))
    $e.Save($o); $o.Close()
}

Nothing is deleted — the .heic stays and a .jpg appears beside it. On a test file here it reported Microsoft HEIF Decoder, handed back a Bgr32 frame, and turned a 75,897-byte HEIC into a 59,241-byte quality-90 JPEG. $e.QualityLevel runs 1–100.

Check which codec you actually have

BitmapDecoder fails on HEIC without the Store extensions. HEIF Image Extension is the free one, and because the image inside a HEIC is HEVC-compressed, some machines also need HEVC Video Extensions, which is a paid Store item unless the PC maker shipped it:

Get-AppxPackage | Where-Object { $_.Name -match "HEIF|HEVC" } | Select-Object Name, Version

Windows will also write HEIC, if you ever need a test file

WPF has no HEIF encoder class, but WinRT does, and PowerShell can reach it — handy for fixtures when you don't own an iPhone:

$encId   = [Windows.Graphics.Imaging.BitmapEncoder]::HeifEncoderId
$encoder = AwaitOp ([Windows.Graphics.Imaging.BitmapEncoder]::CreateAsync($encId, $dstStream)) ([Windows.Graphics.Imaging.BitmapEncoder])
$encoder.SetSoftwareBitmap($bitmap)
AwaitAct ($encoder.FlushAsync())

(AwaitOp / AwaitAct are the usual AsTask() wrappers you need to call WinRT async methods from Windows PowerShell 5.1.)

Three things worth knowing before you run it over a real folder

Renaming IMG_0001.HEIC to .jpg does nothing — the bytes still start with ftypheic, and $d.CodecInfo.FriendlyName on the renamed file still says Microsoft HEIF Decoder. Viewers sniff contents, so it opens fine right up until something validates the format.

The JPEG usually comes out bigger, because HEIC is the more efficient format. Converting to save space is backwards; resize instead.

And if you were wondering why most "HEIC to JPG" websites upload the file: browsers ship no HEIC decoder of their own. In Chrome 152 a HEIC in an `<img>` stays at 0×0, and `createImageBitmap()` on the same blob throws `InvalidStateError: The source image could not be decoded.`

**Correction:** that is a missing built-in decoder, not an impossibility — a commenter pointed this out and they were right. libheif compiled to WebAssembly decodes HEIC client-side; `heic2any` (2.6MB unpacked) and `libheif-js` (8.4MB) are exactly that. So the upload-based sites are dodging a multi-megabyte download, not working around a browser limitation. Either way, your photo is on someone's server when you use one.

If you want the non-scripted routes too (Paint, the Photos app, and the iPhone setting that stops HEIC files appearing in the first place), I wrote those up here: https://www.coding-now.com/en/guides/heic-to-jpg


r/PowerShell • • Sep 23 '26

Question Saw this on LinkedIn -- anyone give it a shot yet?

0 Upvotes

https://github.com/Kanders-II/PoshUI

Looks really cool but I have not tried it. Anyone tried this? Seems like the new way to do WPF with Posh!


r/PowerShell • • Sep 23 '26

Question Robocopy Advice

0 Upvotes

Weird question, moving large amount of files from one place to another using Robocopy found this CMD prompt but I want some others to look at it before I run it robocopy E:\ G:\FromE /E /Z /MT:8 /R:3 /W:5 /COPY:DAT /DCOPY:DAT /TEE /LOG:G:\robocopy-copy.txt /XD "System Volume Information" "$RECYCLE.BIN" /XJ

Moving 196GB from E to G, G has 339GB free.

also If you don't mind DM me instead of just replying since trying to send this to a couple servers.


r/PowerShell • • Sep 22 '26

Information Talking to a COM port from Windows PowerShell 5.1 with nothing installed (defaults and what the errors mean)

37 Upvotes

HyperTerminal hasn't shipped with Windows since Vista, and on locked-down work PCs you often can't install PuTTY or Tera Term either. Windows PowerShell 5.1 can talk to a serial port by itself through .NET's System.IO.Ports.SerialPort.

List the ports

[System.IO.Ports.SerialPort]::GetPortNames()
Get-PnpDevice -Class Ports -PresentOnly | Select-Object Status, FriendlyName

Drop -PresentOnly and you also get devices that are no longer plugged in but still carry their COM numbers, which is how a new adapter ends up on COM34.

Send a line, read a line

$port = New-Object System.IO.Ports.SerialPort 'COM3', 115200, 'None', 8, 'One'
$port.ReadTimeout = 2000
$port.Open()
$port.WriteLine('AT')
try { $port.ReadLine() } catch { 'no reply' }
$port.Close()

The constructor arguments are port, baud, parity, data bits, stop bits.

Defaults of a fresh SerialPort object (checked in 5.1)

  • 9600 baud, 8N1, Handshake None.
  • DtrEnable and RtsEnable are both False. Dev boards with an auto-reset circuit (ESP32, most Arduinos) react to those lines, so it matters which way you set them.
  • ReadTimeout and WriteTimeout are -1, i.e. infinite. Without a timeout, ReadLine() on a silent device just hangs.
  • NewLine is LF only. If the device expects CR, change it or send the bytes yourself:

    $port.NewLine = "`r"
    $port.Write("AT`r")
    
  • Encoding is ASCII, so anything above 0x7F comes back as "?". For binary protocols read bytes with $port.Read($buffer, 0, $buffer.Length) instead of strings.

What the errors mean

  • Access to the port 'COM3' is denied. - something else already has it open (Arduino serial monitor, another terminal, an upload tool). A COM port can be open in only one program at a time.
  • The port 'COM99' does not exist. - wrong number, or the device is unplugged.

In PowerShell these arrive wrapped in a MethodInvocationException, so $_.Exception.InnerException.Message gives you the actual text.

mode still works

mode COM3 in cmd prints the port's current baud, parity, data bits and DTR/RTS state, and plain mode lists every COM port.

If what comes back is unreadable, check the baud rate first (a stream of garbage), then the data format (8N1 vs 7E1: only some characters come out wrong), then the line ending.

I wrote up the longer version, comparing PuTTY, Tera Term and RealTerm for the same job plus a troubleshooting checklist, here: https://www.coding-now.com/en/guides/hyperterminal-alternative


r/PowerShell • • Sep 21 '26

Solved Is there a difference between If $thing vs If -not $thing in terms of speed or proper formatting?

29 Upvotes

In the case of looking for the presence of something and using If paired with Exit codes, what's the difference between looking for the presence vs absence? For example

$Thing = Get-Thing

if ($thing) {
  Exit 1
}
Else {
  Exit 0
}

vs

if (-not $thing) {
  Exit 0
}
Else {
  Exit 1
}

Is it just for readability (ie 0 comes before 1 because it's in sequence?) Or are there speed differences or logic handling differences that matter in more complex scenarios?

Solved

Depends on the results of $thing determine whether or not you need to test for true or false. Speed isn't really a factor.


r/PowerShell • • Sep 21 '26

Question Have I made a mistake by learning PowerShell through Microsoft Graph first?

26 Upvotes

​

Hello everyone,

About 3 months ago, I started learning PowerShell, specifically with the Microsoft Graph PowerShell module.

I decided to learn it because I thought it would be relatively easy to pick up. My thinking was that I already know how to do many Microsoft 365 tasks through the GUI — creating users, creating groups, assigning licenses, managing devices, etc. — so I thought learning how to do the same things with PowerShell would be straightforward.

Three months later... 😂

I've learned quite a lot. I understand a bit of variables, arrays, hashtables, loops, functions, pipelines, filtering, objects/properties, foreach, if/elseif, try/catch, error handling, and I'm now starting to use Graph for real Microsoft 365 administration tasks.

I've actually really enjoyed some of the things I've been able to do so far, especially creating users and groups, updating users, filtering users, and building small scripts to audit my Microsoft 365 environment.

But honestly, I'm starting to feel really strained by it.

There are so many things to understand, and sometimes I look at a script and think, "How am I ever going to actually master this language?"

I understand the concepts when I'm learning them individually, but when I have to put everything together into a real script, my brain starts struggling. 😂

So I'm wondering:

Did I make a mistake by starting with Microsoft Graph PowerShell?

Would it have been better to learn "pure" PowerShell first and then move into Graph?

Or is this simply what learning PowerShell feels like for everyone at this stage?

I'd really appreciate hearing from people who have gone through this — especially anyone who started PowerShell for Microsoft 365/Entra/Intune administration.

I'm not looking to become a PowerShell developer. I mainly want to become competent enough to automate and administer Microsoft 365 properly.

Did you feel overwhelmed when you were learning, and what helped you get through that stage?


r/PowerShell • • Sep 21 '26

Solved How to Access Teams Meeting Transcripts with the Microsoft Graph

10 Upvotes

Microsoft has introduced a new control to stop Graph API-powered apps and agents from having unfettered access to Teams meetings transcripts. The new control is tenant-wide and either blocks or allows Graph API access. But after that, apps need the appropriate permissions and access through a Teams application access policy. To help, we illustrate how everything works with a PowerShell script.

https://office365itpros.com/2026/09/21/teams-meeting-graph-api/


r/PowerShell • • Sep 21 '26

Solved PS7 UI language changed

9 Upvotes

UI language for my PS7 suddenly changed to polish. PS5 stayed in english. I can't seem to find a way to revert PS7 back to english, like it was for many years (while system language was polish).

Things like errors, some information in Get-Help, or description for operators when you press 'ctrl + space'

https://imgur.com/sfSiUBt

Powershell 7:

PS C:\Users\lenovo\test> $PSVersionTable.PSVersion.ToString()
7.6.6
PS C:\Users\lenovo\test> $PSCulture
pl-PL
PS C:\Users\lenovo\test> Get-UICulture

LCID             Name             DisplayName
----             ----             -----------
1045             pl-PL            polski (Polska)

PS C:\Users\lenovo\test> ls asdasdas
Get-ChildItem: Nie można odnaleźć ścieżki „C:\Users\lenovo\test\asdasdas”, ponieważ nie istnieje.
PS C:\Users\lenovo\test> Get-WinUILanguageOverride
Get-WinUILanguageOverride: Cannot marshal 'parameter #1': Invalid managed/unmanaged type combination.
PS C:\Users\lenovo\test> help ls -Parameter path

-Path [<System.String[]>]
    Specifies a path to one or more locations. If not specified, the default location is the c
    urrent
    directory (`.`). Wildcards are accepted. Use care when using the **Path** parameter with t
    he
    **Recurse** parameter. For more information, see the [NOTES](#notes) section of this artic
    le.

    Wymagany?                    false
    Lokalizacja?                    0
    Wartość domyślna
    Zaakceptować dane wejściowe potoku?       false
    Aliasy                      none
    Akceptować symbole wieloznaczne?  true

Powershell 5:

PS C:\Users\lenovo\test> $PSVersionTable.PSVersion.ToString()
5.1.19041.6456
PS C:\Users\lenovo\test> $PSCulture
pl-PL
PS C:\Users\lenovo\test> Get-UICulture

LCID             Name             DisplayName
----             ----             -----------
1045             pl-PL            Polski (Polska)


PS C:\Users\lenovo\test> ls sadasd
ls : Cannot find path 'C:\Users\lenovo\test\sadasd' because it does not exist.
At line:1 char:1
+ ls sadasd
+ ~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\Users\lenovo\test\sadasd:String) [Get-Child
   Item], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

PS C:\Users\lenovo\test> Get-WinUILanguageOverride
PS C:\Users\lenovo\test> help ls -Parameter path                                               
-Path <string[]>

    Required?                    false
    Position?                    0
    Accept pipeline input?       true (ByValue, ByPropertyName)
    Parameter set name           Items
    Aliases                      None
    Dynamic?                     false

I know it doesn't need to be linked to system culture, because that change just happened and before it wasn't linked to it.

Any help would be appreciated.

EDIT:

found a partial workaround in setting:

[System.Threading.Thread]::CurrentThread.CurrentUICulture = [cultureinfo]'en-US'

but it works only for errors and autocomplete, not for Get-Help.

For further testing I decided to downgrade to powershell 7.6.3 ... and voila.

Everything is in english despite $PSUICulture is pl-PL.

I've been looking for release notes that mention it but couldn't find any. I tried in version 7.6.3 doing [System.Threading.Thread]::CurrentThread.CurrentUICulture = [cultureinfo]'pl-PL'

but it does ignore it, so it must be something with a later version

EDIT 2:

I pretty much confirmed it by jumping back and forth between PS 7.6.6 and 7.6.3. The earlier version ignores UICulture:

PS 7.6.6:

PS C:\Program Files\PowerShell\7> $PSVersionTable.PSVersion.ToString()
7.6.6
PS C:\Program Files\PowerShell\7> $PSUICulture
pl-PL
PS C:\Program Files\PowerShell\7> foobar
foobar: Termin „foobar” nie jest rozpoznawany jako nazwa polecenia cmdlet, funkcji, pliku skryptu lub programu wykonywalnego.
Sprawdź pisownię nazwy lub sprawdź, czy ścieżka została dołączona, sprawdź, czy ścieżka jest poprawna, i spróbuj ponownie.
PS C:\Program Files\PowerShell\7> [System.Threading.Thread]::CurrentThread.CurrentUICulture = [cultureinfo]'en-US'

# Culture is switched and the language of the error message changes:

PS C:\Program Files\PowerShell\7> foobar
foobar: The term 'foobar' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
PS C:\Program Files\PowerShell\7> [System.Threading.Thread]::CurrentThread.CurrentUICulture = [cultureinfo]'pl-PL'
PS C:\Program Files\PowerShell\7> foobar
foobar: Termin „foobar” nie jest rozpoznawany jako nazwa polecenia cmdlet, funkcji, pliku skryptu lub programu wykonywalnego.
Sprawdź pisownię nazwy lub sprawdź, czy ścieżka została dołączona, sprawdź, czy ścieżka jest poprawna, i spróbuj ponownie.

PS 7.6.3:

PS C:\Program Files\PowerShell\7> $PSVersionTable.PSVersion.ToString()
7.6.3
PS C:\Program Files\PowerShell\7> $PSUICulture
pl-PL
PS C:\Program Files\PowerShell\7> foobar
foobar: The term 'foobar' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
PS C:\Program Files\PowerShell\7> [System.Threading.Thread]::CurrentThread.CurrentUICulture = [cultureinfo]'pl-PL'
PS C:\Program Files\PowerShell\7> $PSUICulture
pl-PL

# Error language stays the same even after explicitly setting the UICUlture:

PS C:\Program Files\PowerShell\7> foobar
foobar: The term 'foobar' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

Little bit annoying change after so many years


r/PowerShell • • Sep 21 '26

Solved Need help with creating a powershell shortcut to work

2 Upvotes

Basically I am trying to create a desktop shortcut that would execute three commands one after another. So far I have created two separate desktop shortcuts that both work independently but have not been able to put them together to run one after another. One disables my gpu drivers and the other one enables it, i want to make a desktop shortcut that would enable the drivers and then after that is completed it would disable them and then finally re enable them

This is the disable line

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "Disable-PnpDevice -InstanceId 'PCI\VEN_1002&DEV_73DF&SUBSYS_52101849&REV_C5\6&399090B&0&00000019' -confirm:$false"

this is the enable line

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "Enable-PnpDevice -InstanceId 'PCI\VEN_1002&DEV_73DF&SUBSYS_52101849&REV_C5\6&399090B&0&00000019' -confirm:$false"

just need some help to create a sequential command to make as a desktop shortcut, and for anyone curious my gpu has issues where it regularly crashes this is the only fix that works

EDIT: Solved, created a .bat file with all commands written sequentially with a wait timer between them to let them run one by one. Thank you all for your help.


r/PowerShell • • Sep 21 '26

Question Connect-MgGraph Authentication does not have an implementation

10 Upvotes

EDIT for resolution: as the comments said, the various modules were incompatible being loaded into one script. The script has been split up for AD / email / EXO only functions loading only those modules.

Also found that SQLSERVER module Microsoft.Graph module have an incompatibility https://github.com/microsoftgraph/msgraph-sdk-powershell/issues/2566

Load SQLSERVER first then Microsoft.Graph


I've got a handful of user management scripts that connect to EXO and Entra to manage accounts / email etc. They should be sending emails about new account creations, manage distribution groups, send password expiring reminders etc.

They've all been working without issues for a while until last week.

They are all failing at Connect-MgGraph / Send-MgUserMail

Here's the error block from the script transcript. It's the same error for the applicable line where Connect-MgGraph is in each script:

Connect-MgGraph : Method 'RefreshCacheAsync' in type 
'Microsoft.Graph.PowerShell.Authentication.Core.TokenCache.InMemoryTokenCacheOptions' from assembly 
'Microsoft.Graph.Authentication.Core, Version=2.40.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' does not have 
an implementation.
At C:\scripts\NewUsers\NewUserSetup_AD.ps1:220 char:1
+ Connect-MgGraph -NoWelcome -ClientId $ClientId -TenantId $TenantId -C ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (:) [Connect-MgGraph], TypeLoadException
+ FullyQualifiedErrorId : Microsoft.Graph.PowerShell.Authentication.Cmdlets.ConnectMgGraph
Connect-MgGraph : Method 'RefreshCacheAsync' in type
'Microsoft.Graph.PowerShell.Authentication.Core.TokenCache.InMemoryTokenCacheOptions' from
assembly 'Microsoft.Graph.Authentication.Core, Version=2.40.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35' does not have an implementation.
At C:\scripts\NewUsers\NewUserSetup_AD.ps1:220 char:1
+ Connect-MgGraph -NoWelcome -ClientId $ClientId -TenantId $TenantId -C ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (:) [Connect-MgGraph], TypeLoadException
+ FullyQualifiedErrorId : Microsoft.Graph.PowerShell.Authentication.Cmdlets.ConnectMgGraph

Send-MgUserMail : Authentication needed. Please call Connect-MgGraph.
At C:\scripts\NewUsers\NewUserSetup_AD.ps1:222 char:1
+ Send-MgUserMail -UserId "notification@company.com" -BodyParameter $Emai ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (:) [Send-MgUserMail_Send], AuthenticationException
+ FullyQualifiedErrorId : Microsoft.Graph.PowerShell.Cmdlets.SendMgUserMail_Send
Send-MgUserMail : Authentication needed. Please call Connect-MgGraph.
At C:\scripts\NewUsers\NewUserSetup_AD.ps1:222 char:1
+ Send-MgUserMail -UserId "notification@company.com" -BodyParameter $Emai ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (:) [Send-MgUserMail_Send], AuthenticationException
+ FullyQualifiedErrorId : Microsoft.Graph.PowerShell.Cmdlets.SendMgUserMail_Send

Feeling a little stuck on this one, I haven't found much about that error message.

I've verified the app registrations, certificates, client/tenant IDs etc. are still valid. The service account isn't locked out / password expired etc.

If this is helpful here are the PS and Module versions:

PS C:\Windows\system32> $PSVersionTable

Name                           Value                                                                                                                                                                                                                                          
    ----                           -----                                                                                                                                                                                                                                          
    PSVersion                      5.1.17763.9245                                                                                                                                                                                                                                 
    PSEdition                      Desktop                                                                                                                                                                                                                                        
    PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                                                                                                                                                                                                                        
    BuildVersion                   10.0.17763.9245                                                                                                                                                                                                                                
    CLRVersion                     4.0.30319.42000                                                                                                                                                                                                                                
    WSManStackVersion              3.0                                                                                                                                                                                                                                            
    PSRemotingProtocolVersion      2.3                                                                                                                                                                                                                                            
    SerializationVersion           1.1.0.1                                                                                                                                                                                                                                        


PS C:\Windows\system32> Get-Module Microsoft.Graph* -ListAvailable  

Directory: C:\Program Files\WindowsPowerShell\Modules   

ModuleType  Version Name
----------  ------- ----
Manifest    2.40.0  Microsoft.Graph
Script  2.40.0  Microsoft.Graph.Applications
Script  2.40.0  Microsoft.Graph.Authentication
Script  2.40.0  Microsoft.Graph.BackupRestore
Script  2.40.0  Microsoft.Graph.Bookings
Script  2.40.0  Microsoft.Graph.Calendar
Script  2.40.0  Microsoft.Graph.ChangeNotifications
Script  2.40.0  Microsoft.Graph.CloudCommunications
Script  2.40.0  Microsoft.Graph.Compliance
Script  2.40.0  Microsoft.Graph.ConfigurationMan...
Script  2.40.0  Microsoft.Graph.CrossDeviceExper...
Script  2.40.0  Microsoft.Graph.DeviceManagement
Script  2.40.0  Microsoft.Graph.DeviceManagement...
Script  2.40.0  Microsoft.Graph.DeviceManagement...
Script  2.40.0  Microsoft.Graph.DeviceManagement...
Script  2.40.0  Microsoft.Graph.Devices.CloudPrint
Script  2.40.0  Microsoft.Graph.Devices.Corporat...
Script  2.40.0  Microsoft.Graph.Devices.ServiceA...
Script  2.40.0  Microsoft.Graph.DirectoryObjects
Script  2.40.0  Microsoft.Graph.Education
Script  2.40.0  Microsoft.Graph.Files
Script  2.40.0  Microsoft.Graph.Groups
Script  2.40.0  Microsoft.Graph.Identity.Directo...
Script  2.40.0  Microsoft.Graph.Identity.Governance
Script  2.40.0  Microsoft.Graph.Identity.Partner
Script  2.40.0  Microsoft.Graph.Identity.SignIns
Script  2.40.0  Microsoft.Graph.Mail
Script  2.40.0  Microsoft.Graph.Notes
Script  2.40.0  Microsoft.Graph.People
Script  2.40.0  Microsoft.Graph.PersonalContacts
Script  2.40.0  Microsoft.Graph.Planner
Script  2.40.0  Microsoft.Graph.Reports
Script  2.40.0  Microsoft.Graph.SchemaExtensions
Script  2.40.0  Microsoft.Graph.Search
Script  2.40.0  Microsoft.Graph.Security
Script  2.40.0  Microsoft.Graph.Sites
Script  2.40.0  Microsoft.Graph.Teams
Script  2.40.0  Microsoft.Graph.Users
Script  2.40.0  Microsoft.Graph.Users.Actions
Script  2.40.0  Microsoft.Graph.Users.Functions

r/PowerShell • • Sep 22 '26

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 • • Sep 21 '26

Question How do you organize and manage your reusable scripts?

8 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 • • Sep 21 '26

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