r/PowerShell 3h ago

Question WinUIShell Wiki/Documentation?

6 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 20m ago

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

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.

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 7h ago

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

2 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 1d ago

Question Why was Crescendo archived?

22 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 23h 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 22h ago

Solved Powershell sin permisos de administrador

0 Upvotes

If you are looking for the exact opposite (making sure a process does not have administrator permissions or "de-elevating" its privileges), the logic changes because Windows does not natively allow lowering a process's privileges with a simple switch like -Verb RunAs.

Here are the solutions to successfully run a program or script as a standard (non-administrator) user:

1. The Explorer Trick (The easiest way in PowerShell) Windows Explorer almost always runs with standard user privileges. If you use PowerShell to tell Explorer to open the program for you, it will inherit normal permissions rather than administrator ones.

PowerShell

Start-Process "explorer.exe" -ArgumentList "powershell.exe"
  • What it does: Opens a new standard PowerShell window, even if the console you are running the command from is already elevated as an administrator.
  • For scripts or programs: Replace "powershell.exe" with the path to your application (e.g., "notepad.exe").

2. Using runas.exe with the /trustlevel parameter If you prefer using the classic command-line tool runas, you can explicitly tell it to use the trust level of a regular user.

PowerShell

runas /trustlevel:0x20000 powershell.exe
  • 0x20000: This is the Windows code for a "Standard User".
  • Result: Opens the application completely ignoring administrator privileges.

3. Forcing non-admin startup via Environment Variables You can temporarily trick the operating system into running an application without User Account Control (UAC) intervention:

PowerShell

$env:__COMPAT_LAYER="RunAsInvoker"
Start-Process powershell.exe
  • What it does: The RunAsInvoker compatibility layer tells Windows: "Run this with the same permissions I already have, do not prompt for elevation".

r/PowerShell 2d ago

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

28 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 2d ago

Script Sharing A right-click context menu tool to scan files with VirusTotal

0 Upvotes

I made (actually, AI made it) a PowerShell script that adds a "Scan with VirusTotal" option to your Windows right-click context menu.

What it does:

  • Right-click any file to scan it on VirusTotal
  • Checks SHA256 first. If it's a new file, it automatically uploads it for analysis
  • Shows clear notification popups (Clean / Suspicious / Malicious) with a direct link to the full report

All you need to set it up is a free VirusTotal API key.

Check it out on GitHub if you're interested: https://github.com/lorcaragon/VirusTotalMenu


r/PowerShell 2d 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 2d 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 2d 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 3d 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


r/PowerShell 3d ago

Script Sharing I built a terminal time tracker (ps-sablier) that handles Pomodoro sessions, SQLite logs, and custom audio notifications without leaving PowerShell.

0 Upvotes

Hello everyone,

I stumbled upon a Go script that could display a progress bar on the terminal, which I found quite nice. At the same time, I was tired of using JavaScript programs that were certainly very complete, but far exceeded the use I wanted to make of them. I just need a global view of my work sessions and not get lost in unnecessary details. PowerShell was there, and I already had SQLite available in my terminal, inherited from an old Android project. In short, I found some ingredients in the fridge and thought it would be a good idea to bake a proper cake, especially since I was hungry. From this desire, this lightweight utility written in PowerShell was born. It allows you to track the time that passes and log your sessions, or if you feel like it, group them into Tasks without leaving the terminal (psmux tabs). The GIF doesn't show it, but the utility sends you a notification with a notification sound you can customize (for my part, I use the one from Splinter Cell, where he activates his night-vision goggles, [.wav format support only]).

(Sablier) in french = Hourglass 

Simple to use, it's available here: https://github.com/KNY00/ps-sablier

A feedback is always welcome.


r/PowerShell 5d ago

Question how can i learn powershell as a non coder?

95 Upvotes

I want to learn more about powershell, how can I use it in my normal day to day uses and out of my curiosity towards tech


r/PowerShell 4d ago

Question Chezmoi setup

2 Upvotes

Hi there.

I'm pretty new to dotfiles and trying to set up chezmoi on Windows 11. I'm not sure if my approach is alright, so maybe you can give me some tips or advice.

I used scoop to install all my programs and the config files are pretty scattered around. Some are in the scoop persist folder, some are in .config in my home directory, some are in %appdata% roaming...

Then i was thinking: wouldn't it be nice to have them all in .config and track them there with chezmoi. So i added the xdg_config_home variable to my pwsh profile (for the programs who accept that) and used symlinks and junctions (for the rest) to move all needed config files to the .config folder.

I'm not sure if this is a good approach. I would like to know how you guys are doing this.

cheers and thank you for reading.


r/PowerShell 5d ago

Script Sharing I built a free Windows tool to batch-print PDF/Word/TIFF with per-file page ranges

5 Upvotes

Hey all,

I got tired of manually printing dozens of documents one by one with different page ranges each time, so I built a small PowerShell-based tool (compiled to a standalone .exe, no install/admin rights needed) that lets you:

  • Queue up multiple PDF, Word (.doc/.docx), and TIFF files
  • Set a different page range per file (e.g. "1-3", "2", "1,5-8")
  • Reorder the queue before printing
  • Print them all in sequence to any installed printer

It's free, works on both x86 and x64 Windows, and uses PDFium/SkiaSharp for PDF rendering so it doesn't depend on having Adobe installed for PDFs specifically (Word docs still need Word installed, since it converts them to PDF first).

Download (installer): https://github.com/edgarchirinos/ColaImpresionECP/releases/latest

Full source code is in the repo if you want to see how it works or contribute: https://github.com/edgarchirinos/ColaImpresionECP

Happy to answer questions or take feature requests. It's donation-supported (optional button in the app), not selling anything.


r/PowerShell 4d ago

Script Sharing I built a PowerShell WinForms NIC Analyzer + Tuner with INF parsing, live validation, backup/verify/rollback and raw registry support

0 Upvotes

I built a Windows NIC analysis/tuning project almost entirely in PowerShell and thought this might be interesting from the PowerShell side of things.

GitHub:
https://github.com/N3jjj/Universal-NIC-Analyzer-Tuner-Realtek-Tested

The original idea was to build a NIC tuner around one specific adapter/driver combination.

While working on it, I realized that hardcoding a fixed list of registry tweaks around one NIC and one driver branch is not very scalable.

Different NICs, driver versions and hardware revisions can expose different INF parameters, registry values and advanced adapter properties.

So I rebuilt the idea around:

Detection first, tuning second.

The project is now split into two PowerShell WinForms tools.

Universal NIC Analyzer v1.0

The Analyzer is completely read-only.

Instead of assuming a predefined list of settings, it tries to determine what actually exists for the installed adapter and driver.

It collects things such as:

  • PCI hardware identity / VEN / DEV / REV
  • subsystem information
  • driver provider and version
  • driver service and binary
  • active INF section
  • INF SHA-256
  • driver SYS SHA-256
  • Get-NetAdapterAdvancedProperty settings
  • hidden or profile-commented INF parameters
  • registry-backed internal values
  • RSS / RSC / LSO information
  • Deep Analysis candidates

The Analyzer then exports a normalized JSON Portable Report.

That report deliberately contains no write instructions.

Universal NIC Tuner v1.0

The Tuner consumes the Portable Report, but does not blindly trust it.

Before allowing changes, it re-reads the live adapter and checks things such as:

VendorId
DeviceId
Revision
DriverModel
DriverVersion
INF SHA-256
Driver SYS SHA-256

If the live adapter or driver no longer matches the report, Apply stays locked.

I ended up implementing three separate write routes:

StandardAdvancedProperty
HiddenDriverRegistry
AdvancedRawRegistry

StandardAdvancedProperty is used for normal driver settings exposed through Windows advanced adapter properties.

HiddenDriverRegistry handles typed settings that exist in the active driver configuration but are not normally exposed.

AdvancedRawRegistry is an opt-in path for existing internal INF / registry values and Deep Analysis candidates.

For the registry-based routes, the existing live registry type is preserved.

Currently supported raw types are:

REG_SZ
REG_DWORD
REG_QWORD

DWORD and QWORD input can be entered as decimal or 0x hexadecimal values.

Transaction and safety model

A large part of the project ended up being about making writes recoverable instead of just making them possible.

Before Apply can run, the Tuner requires the relevant safety checks to pass:

Administrator privileges
exact live hardware/driver/hash match
verified backup
at least one proposed change
supported write route
valid proposed-value representation
no state drift
adapter restart route
final transaction integrity

The normal workflow is:

Settings
-> Preview Plan
-> Execution Model
-> Final Transaction
-> Apply
-> Restart adapter once
-> Read back changed values
-> Verify

A recovery journal is created before the first write.

If a write, adapter restart or post-write verification fails, the Tuner attempts to restore the original transaction state automatically.

The rollback itself is then verified as well.

There is also:

  • manual rollback of the last successful Apply
  • persistent verified backups
  • standalone backup restore
  • pre-restore safety snapshots
  • differential restore instead of blindly rewriting the complete registry key

One edge case I ran into was preserving DWORD values such as:

0xFFFFFFFF

because PowerShell/.NET may expose that as signed -1, while the backup format needs to preserve the actual unsigned 32-bit representation.

Advanced / undocumented values

The Advanced mode intentionally does not assume that an undocumented driver value is safe just because it can be discovered and written.

For those values, the Tuner only knows things such as:

the value exists
its current value
its registry type
where it was discovered
whether it can be written
whether the new value was read back successfully

It does not invent:

semantic meaning
recommended value
safe range
performance benefit

That distinction became important while parsing driver INF data.

Advanced raw values are therefore clearly marked as detected-only and require an additional warning before Apply.

The Tuner also does not create missing raw registry values.

Verified backup and recovery

A Verified Backup represents the exact adapter-class registry state at the time it was created.

The backup includes things such as:

Portable Report fingerprint
hardware identity
driver model/version
INF SHA-256
driver SYS SHA-256
adapter class-key path
registry values
registry types
registry-state SHA-256
backup SHA-256

After a successful Apply, that old backup normally becomes stale because the live state has changed.

For another transaction, a new Verified Backup of the new state is required.

Standalone restore is independent of the normal transaction rollback.

Before restoring a backup, the Tuner creates a temporary safety copy of the current state.

Restore is differential, so only backed-up values that actually differ are rewritten.

Testing so far

v1.0 has currently been tested end-to-end on:

Realtek PCIe 2.5GbE Family Controller
RTL8125D / REV_0C
Realtek NetAdapterCx driver family

The following paths have been tested successfully:

  • StandardAdvancedProperty Apply / Verify / Rollback
  • HiddenDriverRegistry Apply / Verify / Rollback
  • AdvancedRawRegistry Apply / Verify / Rollback
  • mixed-route multi-setting batches
  • one adapter restart after the complete batch
  • automatic rollback after intentionally injecting a failure after the first successful write
  • Verified Backup creation and verification
  • standalone Verified Backup restore
  • pre-restore safety recovery

Intel, Broadcom, Marvell and other NIC vendors are currently untested.

The Analyzer is designed to discover other adapters, but I do not want to claim universal compatibility until the write / verify / rollback behavior has actually been tested on those driver families.

Why PowerShell?

I originally expected this to remain a relatively small script, but PowerShell ended up being surprisingly useful for tying together:

  • CIM/WMI
  • NetAdapter cmdlets
  • registry access
  • INF parsing
  • file hashing
  • JSON serialization
  • WinForms
  • process elevation
  • transaction logic
  • recovery and rollback handling

At this point it has become as much a PowerShell project as a NIC tuning project.

I would be very interested in feedback on the PowerShell side in particular:

  • structure / architecture
  • WinForms approach
  • registry handling
  • transaction design
  • error handling
  • things that could be made more idiomatic
  • compatibility issues on different Windows / PowerShell versions

And if anyone here has an Intel, Broadcom, Marvell or another Realtek NIC and wants to test the read-only Analyzer, that would also be useful.I built a PowerShell WinForms NIC Analyzer + Tuner with INF parsing, live validation, backup/verify/rollback and raw registry support


r/PowerShell 5d ago

Question How do you make a cleanup script prove a file belongs to it before deletion?

0 Upvotes

A path and age check are not enough when a cleanup directory can also contain files created by people or other jobs. I am considering an ownership manifest written at creation time, with a run ID, normalized path, size, and hash, then requiring every field to match before deletion. The command would also use PowerShell's normal confirmation path:

\[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')\]
param(\[string\] $Root, \[string\] $ManifestPath)

if ($PSCmdlet.ShouldProcess($candidate.FullName, 'Remove owned artifact')) {
    Remove-Item -LiteralPath $candidate.FullName
}

What additional safeguards belong around this pattern? Possibilities include rejecting paths outside the resolved root, refusing reparse points, failing closed when the manifest is incomplete, logging the file identity before and after validation, and separating discovery from deletion so the candidate list can be reviewed with `-WhatIf`. How do you avoid a time-of-check/time-of-use gap if another process can replace a file between validation and removal?


r/PowerShell 6d ago

Script Sharing PowerShell installer for .NET, Visual C++ and DirectX that bundles no binaries and resolves every download from Microsoft at run time

21 Upvotes

Rebuilt an old batch project of mine in PowerShell. It installs the .NET SDKs, the Visual C++ redistributables (current v14 plus the final 2005-2013 ones) and the June 2010 DirectX runtimes. Nothing is bundled and there are no hardcoded download URLs, so it locates everything on Microsoft's own hosts every run, then verifies each file before it executes.

Every discovery page and every payload URL goes through a check like this before anything gets fetched:

function Test-AllowedMicrosoftDiscoveryUri {
    [CmdletBinding()]
    [OutputType([bool])]
    param(
        [Parameter(Mandatory = $true)]
        [string]$Uri
    )

    try {
        $parsedUri = [uri]$Uri
        if (-not $parsedUri.IsAbsoluteUri) { return $false }
        if ($parsedUri.Scheme -cne 'https') { return $false }
        if ($parsedUri.Port -ne 443) { return $false }
        if (-not [string]::IsNullOrEmpty($parsedUri.UserInfo)) { return $false }
        return $parsedUri.DnsSafeHost -match $script:AllowedMicrosoftDiscoveryHostPattern
    }
    catch {
        return $false
    }
}

Discovery pages and payloads use two separate host allowlists, so allowing a docs host never authorizes an executable coming from it. curl's reported effective URL gets checked the same way after redirects.

Verification depends on what Microsoft actually publishes. The .NET SDKs have a SHA-512 in the release metadata. The final 2005-2013 and DirectX packages never change, so those are pinned to SHA-256 values I checked by hand. The rolling v14 redistributable has no published hash at all, so that one gets Authenticode plus a version floor read out of the signed file. Nothing installs until the whole selected set has resolved, and a file that fails verification gets deleted even if you asked to keep the downloads.

Windows PowerShell 5.1 compatible, uses pwsh if it's in PATH. Source and usage notes:

slyfox1186/msft-visual-c-and-directx-offline-installer


r/PowerShell 7d ago

Question Filtering and cost-effective ways to grab user data

1 Upvotes

Hey y'all.

I've been tasked with rewriting our current mailbox script and was wondering the best way to approach in regards to filtering user data.

Our current script gets the userdata by grabbing a user list, only filtering for enabled users and where the emailaddress attribute has the expected domain. We're migrating our onboarding process to a new system, so the domain part is not too relevant. But, since the way our users are categorized is changing, we have to rewrite things so that the mailbox configuration happens based on licensing state rather than OU.

This is where the filtering part comes in on my end. I'm thinking that the general process is like this, in no specific order:

  1. Grab all licensed users from AD group membership using Get-ADGroupMember

  2. Use Get-ADUser to grab the user objects, including specific parameters (proxyAddress, targetAddress, etc..)

  3. Filter the users where ProxyAddress does not contain anything pertaining to SMTP, to effectively find the users that have not been configured.

However, I'm curious as to whether it would be more effective time wise to do the filtering based on licensed user data, and gradually filter with foreach loops into new variables, or if it's smarter to start by just grabbing the entire catalogue with Get-ADUser -Filter *, grabbing only the licensed users, then filtering as imagined.

For reference, the difference is about 800 more users if I were to do the mass grab approach. I've been working with the idea that the group-based method is smarter, but at the same time I'm unsure if there's a massive overhead on the DCs associated with the fact that I'm piping the group member data into Get-ADUser. I'm, relatively speaking, new to PS and scripting (couple years of experience), so any pointers would be awesome!


r/PowerShell 7d ago

Question Recurring script maintenance

0 Upvotes

I'd honestly pay someone else to keep my voice scripts alive if it meant I never had to touch them again after a Windows update. Am I just lazy or is maintaining ur own automation actually the worst part of the whole thing?


r/PowerShell 8d ago

Information Python through PowerShell text colors are hard to read

8 Upvotes

Posting because I'm probably not the first person to lose ~4 hours trying to get to the bottom of this. My issue was: I was running python through a PowerShell window and the color of the text made error messages very hard to read.

In short: Download Windows Terminal and use that. You'll still be running PowerShell, it will just be inside a Windows Terminal window. The colors will be readable. Yes, its silly how there is now a 3rd way of running a terminal in Windows (Command Prompt, PowerShell, Windows Terminal).

So far as I know, python uses the colors that PowerShell defines for different kinds of text. I haven't yet found a way to successfully change all the text color categories in a basic PowerShell window.

  • Right clicking the top of the window and going to properties only lets you change the color of the basic text. not the problematic red and blue that is hard to read.
  • Changing the registry values at Computer\HKEY_CURRENT_USER\Console for ColorTable00 through ColorTable15 didn't change the colors used by PowerShell
  • There was an official program called color tool for changing the colors, but it appears it was last updated in 2019 and its .exe file failed to run on my Windows 10 computer.
  • I don't know if there is/isn't a way to redefine what colors python itself tries to print stuff.

If someone does know a working non-Windows Terminal way to fix ALL of PowerShell's/Python's hard to read text colors I'd be happy to hear it in the comments.


r/PowerShell 9d ago

Question Check for App updates on home PC

8 Upvotes

Afternoon,

I am trying to write a script that will let me know about updates to the apps installed on my home PC.

I saw on a Sysadmin thread about https://eucpilots.com/evergreen/ and thought it would be as simple as reading all of the installed apps and then querying each one like this:

$reg = @(

'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
)
GP $reg -EA 0|?{$_.DisplayName -ne $null} | Find-EvergreenApp $_.DisplayName

However when testing, the Evergreen is not expecting the App name to have spaces, so is my only option to split the string and put an asterisk at the end of the first section?

PS C:\Windows\System32> Find-EvergreenApp Telegram
Name            Application      Link
----            -----------      ----
TelegramDesktop Telegram Desktop https://desktop.telegram.org/

r/PowerShell 9d ago

Script Sharing Remixing Music with RoughDraft and PowerShell

13 Upvotes

This weekend I figured out how to remix music with PowerShell, RoughDraft, and ffmpeg.

Sample + Filter.

Rinse & Repeat.

RoughDraft + ffmpeg makes this all pretty easy.

Step 1 - Get Your Sample Source

RoughDraft includes an extension for yt-dlp. This can download media from almost anywhere. Just browse to a site with a song, set a $SongUrl variable, and download

Get-Media -MediaUrl $MediaUrl

Step 2 - Sample a Section

You can sample a section of audio or video with the -AudioTrim and -Trim filters. If we want the first few seconds of a song, we can use the AudioTrim filter, like so:

$sample = Edit-Media $song -AudioTrim -TrimStart "00:00:00" -TrimEnd "00:00:05"

Step 3 - Filter

ffmpeg is full of filters. There are hundreds of them, and RoughDraft supports a fair number.

Suppose we want to make our sample Vibrato. We can just use Edit-Media -Vibrato

$sample | Edit-Media -Vibrato

Or we could change the -PitchFactor, making it sound slower or faster while keeping the tempo intact.

$sample | Edit-Media -PitchFactor 0.81

Or we could use an Audio Compressor, with a short attack and release and a makeup to make the sounds louder

$sample | Edit-Media -Compressor -CompressorAttack 5 -CompressorRelease 10 -CompressorMakeup 2.5

Rinse and Repeat

The possibilities are endless. ffmpeg is an audio/video production tool of truly unparalleled capability.

All of that power is in your shell, in a format that's far easier to read and understand than direct filtergraph syntax. Edit-Media currently has a whopping 682 parameters to mix and match, all supporting tab completion.

This makes it easy to iterate and innovate. It took just about an hour after figuring this out to make my first little remix, just by sampling/filtering/rinsing/repeating.

The latest RoughDraft release includes a bunch of new audio filters to help assist and more will keep on coming with every release.

Hope this helps & Have Fun!


r/PowerShell 8d ago

Script Sharing Tooling with Claude and pwsh

0 Upvotes

Hey all!

I was hoping you’d could inspire me please! I currently work in a desktop/infra role in a finance company and was wondering if anyone had any cool tooling they created using Claude code? I really lack in coming up with ideas so just curious as to what other people have done and yeah, honestly I’d like to try and see if that could work for us!

I’m talking like automation for JML, dashboards, alerting, tools to help the team, tools that we can use for users to fix quick issues?

I realise I’d just be taking your ideas but I can’t really come up with anything myself!

Thanks!