A collection of commands, code snippets, and scripts tailored for managing and automating tasks in a Windows environment. Designed for experienced administrators, this resource delves beyond basic Powershell usage, offering practical solutions for a variety of scenarios.
You can access a number of these commands via a simple menu by running the following command. The commands are defined in commands.json located in this repo
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/superswan/Powershell-SysAdmin/refs/heads/master/psreference.ps1" -UseBasicParsing | Invoke-ExpressionShort Version:
iwr 3to.moe/psr | iex Invoke-WebRequest -Uri "https://github.com/microsoft/winget-cli/releases/latest/download/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle" -OutFile "C:\WinGet.msixbundle"
Add-AppxPackage "C:\WinGet.msixbundle"
Add-AppxPackage -RegisterByFamilyName -MainPackage Microsoft.Winget.Source_8wekyb3d8bbweNot sure if the slack channel is active usually it's the name of the exercise with a 1 at the end like century1
If a wsl2 distro is installed commands from the default distro can be called with wsl this can be combined with Convert-To-JSON to use common linux data-wrangling tools like awk, sed, and grep
get-hotfix | ConvertTo-Json | wsl jq '.[] | .HotFixID' | wsl sortInvoke-History -Id (Get-History -Count 1).IdGet-Process | Where-Object { $_.MainWindowTitle } | Stop-ProcessLike when you can't uninstall Creative Cloud
Get-Process | Where-Object {$_.Company -like "*Adobe*"} | Stop-Process -ForceGet-WinEvent -LogName System | Where-Object { $_.ID -eq 6006 -or $_.ID -eq 6008 -or $_.ID -eq 1074 } | Format-List -Property TimeCreated, ID, MessageGet-ADUser -Filter "Name -like '*partofname*'"$domainName = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().NameResolve-DnsName -Name "_ldap._tcp.dc._msdcs.$domainName" -Type SRVnet user /domain.\WinDump.exe -i 3 icmp and icmp[icmp-echoreply]=icmp-echoSet-NetFirewallProfile -Profile Domain,Public,Private -Enabled FalseSet-NetFirewallRule -DisplayGroup "File And Printer Sharing" -Enabled TrueEnable Linked Connections (Administrative and regular user accounts can see the same network shares)
reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLinkedConnections /t REG_DWORD /d 1 netsh advfirewall firewall add rule name="Allow incoming ping requests IPv4" dir=in action=allow protocol=icmpv4This adjusts the IPv6 prefix policies so that IPv4 addresses are preferred (Ping, DNS Resolution, etc.). Run both commands.
netsh int ipv6 set prefixpolicy ::ffff:0:0/96 46netsh int ipv6 set prefixpolicy ::/0 45netsh int ip resetnetsh winsock resetmshta.exe "javascript:open();close();"reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\" -Name "UserAuthentication" -Value 1Enable-NetFirewallRule -DisplayGroup "Remote Desktop"iex ((New-Object System.Net.WebClient).DownloadString('https://git.io/debloat'))Set-NetFirewallRule -DisplayGroup 'Remote Event Log Management' -Enabled True -PassThruInvoke-WuJob -ComputerName $Computers -Script { ipmo PSWindowsUpdate; Install-WindowsUpdate -AcceptAll -IgnoreReboot | Out-File "C:\Windows\PSWindowsUpdate.log"} -RunNow -Confirm:$false -Verbose -ErrorAction IgnoreAdd-Type -TypeDefinition 'using System;using System.Runtime.InteropServices;public class Keyboard {[DllImport("user32.dll")]public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);}' ; [Keyboard]::keybd_event(0x11, 0, 0, 0); [Keyboard]::keybd_event(0x10, 0, 0, 0); [Keyboard]::keybd_event(0x5B, 0, 0, 0); [Keyboard]::keybd_event(0x42, 0, 0, 0); [Keyboard]::keybd_event(0x42, 0, 2, 0); [Keyboard]::keybd_event(0x5B, 0, 2, 0); [Keyboard]::keybd_event(0x10, 0, 2, 0); [Keyboard]::keybd_event(0x11, 0, 2, 0)Get-Mailbox | Group-Object -Property Office | Select-Object name,countGet-ADComputer -Filter "Name -like 'PC-*'" | Select-String -Pattern PC-\Get-ADComputer -Filter * | Select-Object -ExpandProperty NameGet-ADComputer -Filter * -Properties Name,OperatingSystem ,lastlogontimestamp | Select Name,OperatingSystem ,@{N='lastlogontimestamp'; E={[DateTime]::FromFileTime($_.lastlogontimestamp)}}query user /server:$SERVERGet-ADComputer -Filter * -Properties * | Sort LastLogon | Select Name, LastLogonDate,@{Name='LastLogon';Expression={[DateTime]::FromFileTime($_.LastLogon)}}Search-ADAccount -AccountDisabled -UsersOnly | Where {$_.DistinguishedName -notlike "*OU=Disabled Users,OU=USERS,DC=EXAMPLE,DC=COM"}Get-ADUser -Identity "username" -Properties "LastLogonDate"Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -AllSet-SmbServerConfiguration -EnableSMB1Protocol $false -Forcepowershell.exe Set-ExecutionPolicy Bypass -ForceInvoke-Command -ComputerName COMPUTER-01 -ScriptBlock { winget list}shutdown -r -t $([int]([datetime]"11PM"-(Get-Date)).TotalSeconds)gps explorer | sppsGet-NetConnectionProfile | Set-NetConnectionProfile -NetworkCategory Private
Enable-PSRemoting -forcew32tm /query /status
w32tm /config /manualpeerlist:"time.google.com,time.cloudflare.com,time.windows.com" /syncfromflags:manual /reliable:YES /update
Restart-Service w32time
w32tm /resync# Stop Windows Update Services
Write-Host "Stopping Windows Update Services..."
Stop-Service -Name wuauserv -Force -ErrorAction SilentlyContinue
Stop-Service -Name cryptSvc -Force -ErrorAction SilentlyContinue
Stop-Service -Name bits -Force -ErrorAction SilentlyContinue
Stop-Service -Name msiserver -Force -ErrorAction SilentlyContinue
# Rename SoftwareDistribution and Catroot2 Folders
Write-Host "Renaming SoftwareDistribution and Catroot2 Folders..."
Rename-Item -Path "C:\Windows\SoftwareDistribution" -NewName "SoftwareDistribution.old" -ErrorAction SilentlyContinue
Rename-Item -Path "C:\Windows\System32\catroot2" -NewName "catroot2.old" -ErrorAction SilentlyContinue
# Re-register Windows Update DLLs
Write-Host "Re-registering Windows Update DLLs..."
$Dlls = @(
"atl.dll", "urlmon.dll", "mshtml.dll", "shdocvw.dll", "browseui.dll",
"jscript.dll", "vbscript.dll", "scrrun.dll", "msxml.dll", "msxml3.dll",
"msxml6.dll", "actxprxy.dll", "softpub.dll", "wintrust.dll", "dssenh.dll",
"rsaenh.dll", "gpkcsp.dll", "sccbase.dll", "slbcsp.dll", "cryptdlg.dll",
"oleaut32.dll", "ole32.dll", "shell32.dll", "initpki.dll", "wuapi.dll",
"wuaueng.dll", "wucltui.dll", "wups.dll", "wups2.dll", "wuweb.dll",
"qmgr.dll", "qmgrprxy.dll", "wucltux.dll", "muweb.dll", "wuwebv.dll"
)
foreach ($Dll in $Dlls) {
Try {
regsvr32.exe /s "C:\Windows\System32\$Dll"
Write-Host "Registered $Dll"
} Catch {
Write-Warning "Failed to register $Dll"
}
}
# Reset Winsock
Write-Host "Resetting Winsock..."
netsh winsock reset
# Restart Windows Update Services
Write-Host "Restarting Windows Update Services..."
Start-Service -Name wuauserv -ErrorAction SilentlyContinue
Start-Service -Name cryptSvc -ErrorAction SilentlyContinue
Start-Service -Name bits -ErrorAction SilentlyContinue
Start-Service -Name msiserver -ErrorAction SilentlyContinue
Write-Host "Windows Update reset complete. You may need to restart your computer."$filename = Join-Path -Path \\server-name\IT-Inventory\ -ChildPath "${env:COMPUTERNAME}.txt"
Get-ComputerInfo |
Select-Object CsName, CsManufacturer, CsModel, BiosSeralNumber, CsProcessors, CsPhyicallyInstalledMemory, OsName, OsVersion, CsUserName |
Sort-Object |
out-file -FilePath $filename# Get the current directory
$currentDirectory = Get-Location
# Define the output CSV file name
$outputCsv = "$currentDirectory\output.csv"
# Initialize an empty array to store the data
$dataArray = @()
# Loop through each file in the current directory
Get-ChildItem -Path $currentDirectory -File | ForEach-Object {
$file = $_.FullName
# Read the file contents
$content = Get-Content -Path $file
# Create a hashtable to store the data for each file
$dataHash = @{}
# Parse each line and extract key-value pairs
foreach ($line in $content) {
if ($line -match "^(.*)\s+:\s+(.*)$") {
$key = $matches[1].Trim()
$value = $matches[2].Trim()
# Add the key-value pair to the hashtable
$dataHash[$key] = $value
}
}
# Convert the hashtable to a custom object and add to the data array
$dataArray += New-Object PSObject -Property $dataHash
}
# Define the custom column headers
$columnHeaders = @{
"CsName" = "Computer Name"
"CsManufacturer" = "Manufacturer"
"CsModel" = "Model"
"BiosSeralNumber" = "BIOS Serial Number"
"CsProcessors" = "Processor"
"CsPhyicallyInstalledMemory" = "Physical Memory (Bytes)"
"OsName" = "Operating System"
"OsVersion" = "OS Version"
"CsUserName" = "User Name"
}
# Create a new array with custom headers
$customDataArray = $dataArray | Select-Object @{Name='Computer Name';Expression={$_.CsName}},
@{Name='Manufacturer';Expression={$_.CsManufacturer}},
@{Name='Model';Expression={$_.CsModel}},
@{Name='BIOS Serial Number';Expression={$_.BiosSeralNumber}},
@{Name='Processor';Expression={$_.CsProcessors}},
@{Name='Physical Memory (Bytes)';Expression={$_.CsPhyicallyInstalledMemory}},
@{Name='Operating System';Expression={$_.OsName}},
@{Name='OS Version';Expression={$_.OsVersion}},
@{Name='User Name';Expression={$_.CsUserName}}
# Export the data to a CSV file
$customDataArray | Export-Csv -Path $outputCsv -NoTypeInformationImport-Module ActiveDirectory
$computers = Get-ADComputer -Filter * -Property Name | ForEach-Object {
$recoveryKeys = Get-ADObject -Filter 'objectclass -eq "msFVE-RecoveryInformation"' -SearchBase $_.DistinguishedName -Properties 'msFVE-RecoveryPassword'
foreach ($key in $recoveryKeys) {
[PSCustomObject]@{
ComputerName = $_.Name
RecoveryKeyID = $key.Name
RecoveryPassword = $key.'msFVE-RecoveryPassword'
}
}
}
$computers | Format-Table -AutoSize# Get all loaded user hives under HKEY_USERS (excluding system accounts)
$UserSIDs = Get-ChildItem -Path Registry::HKEY_USERS |
Where-Object { $_.Name -match 'S-1-5-21-\d+-\d+-\d+-\d+$' } |
Select-Object -ExpandProperty PSChildName
foreach ($SID in $UserSIDs) {
try {
# Translate the SID to a friendly NT Username
$objSID = New-Object System.Security.Principal.SecurityIdentifier($SID)
$Username = $objSID.Translate([System.Security.Principal.NTAccount]).Value
} catch {
$Username = "Unknown ($SID)"
}
# Path to the user's mapped network drives in the registry
$RegPath = "Registry::HKEY_USERS\$SID\Network"
if (Test-Path $RegPath) {
Get-ChildItem -Path $RegPath | ForEach-Object {
[PSCustomObject]@{
Username = $Username
DriveLetter = ($_.PSChildName + ":")
RemotePath = (Get-ItemProperty -Path $_.PSPath).RemotePath
}
}
}
}Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
function Select-FolderDialog {
$folderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog
$folderBrowser.Description = "Select the folder containing HEIC images"
$result = $folderBrowser.ShowDialog()
if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
return $folderBrowser.SelectedPath
}
return $null
}
function Select-SaveFileDialog {
$saveFileDialog = New-Object System.Windows.Forms.SaveFileDialog
$saveFileDialog.Filter = "PDF files (*.pdf)|*.pdf"
$saveFileDialog.Title = "Save PDF As"
$saveFileDialog.DefaultExt = "pdf"
$result = $saveFileDialog.ShowDialog()
if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
return $saveFileDialog.FileName
}
return $null
}
function Convert-HEICtoPDF {
[System.Windows.Forms.Application]::EnableVisualStyles()
$inputDir = Select-FolderDialog
if (-not $inputDir) {
[System.Windows.Forms.MessageBox]::Show("No folder selected. Exiting.")
return
}
$outputPdf = Select-SaveFileDialog
if (-not $outputPdf) {
[System.Windows.Forms.MessageBox]::Show("No output file selected. Exiting.")
return
}
$heicFiles = Get-ChildItem -Path $inputDir -Filter *.heic
if ($heicFiles.Count -eq 0) {
[System.Windows.Forms.MessageBox]::Show("No HEIC files found in the directory.")
return
}
foreach ($file in $heicFiles) {
$jpgFile = [System.IO.Path]::ChangeExtension($file.FullName, ".jpg")
& magick "$($file.FullName)" "$jpgFile"
}
$jpgFiles = Get-ChildItem -Path $inputDir -Filter *.jpg
& magick convert $jpgFiles.FullName $outputPdf
[System.Windows.Forms.MessageBox]::Show("PDF created successfully at $outputPdf")
}
Convert-HEICtoPDF$Computers = @("PC01","PM04","PC06","PC08","PC-JOAN","PC-SARA","LAWOFFICE-2","PC03","PC07")
$OnlineComputers = @()
foreach ($Computer in $Computers) {
if (Test-Connection -ComputerName $Computer -Count 1 -Quiet) {
$OnlineComputers += $Computer
}
else {
Write-Host "$Computer is offline."
}
}
Invoke-WuJob -ComputerName $OnlineComputers -Script {
ipmo PSWindowsUpdate;
Install-WindowsUpdate -AcceptAll -IgnoreReboot -MicrosoftUpdate | Out-File "C:\Windows\PSWindowsUpdate.log"
} -RunNow -Confirm:$false -Verbose -ErrorAction Ignoreif (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) {
if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) {
$CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments
Start-Process -FilePath Powershell.exe -Verb Runas -ArgumentList $CommandLine
Exit
}
}$COMPUTER_LIST = Get-ADComputer -Filter * | Select-Object -ExpandProperty Name
foreach ($COMPUTER in $COMPUTER_LIST) {
echo [$COMPUTER]
query user /server:$COMPUTER
echo `n
}Portable tools and programs are placed in a directory, loops over the directory and adds subfolders to PATH environment variable if they don't already exist.
$binPath = "C:\bin"
Get-ChildItem -Path $binPath -Directory | ForEach-Object {
$currentPath = [System.Environment]::GetEnvironmentVariable("PATH", "Machine")
$newPath = $_.FullName
If (-Not $currentPath.Contains($newPath)) {
[System.Environment]::SetEnvironmentVariable("PATH", "$currentPath;$newPath", "Machine")
}
}$action = New-ScheduledTaskAction -Execute 'Powershell.exe' -Argument '-NoProfile -WindowStyle Hidden -command "& {Restart-Computer -Force -wait}"'
$trigger = New-ScheduledTaskTrigger -Once -At 3am
$taskname = 'ScheduledReboot'
$params = @{
Action = $action
Trigger = $trigger
TaskName = $taskname
}
if(Get-ScheduledTask -TaskName $params.TaskName -EA SilentlyContinue) {
Set-ScheduledTask @params
}
else {
Register-ScheduledTask @params
}$TouchScreenDevices = Get-PnpDevice | Where-Object { $_.FriendlyName -like "*HID-compliant touch screen*" }
foreach ($Device in $TouchScreenDevices) {
if ($Device.Status -eq 'OK') {
Write-Output "Disabling device: $($Device.FriendlyName)..."
Disable-PnpDevice -InstanceId $Device.InstanceId -Confirm:$false
} else {
Write-Output "Enabling device: $($Device.FriendlyName)..."
Enable-PnpDevice -InstanceId $Device.InstanceId -Confirm:$false
}
}$registryPaths = @(
"HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
)
$installedSoftware = Get-ItemProperty -Path $registryPaths |
Select-Object DisplayName, DisplayVersion, Publisher, InstallDate |
Where-Object { $_.DisplayName -and $_.DisplayName -ne "" } |
Sort-Object DisplayName
$installedSoftware$keys = dir HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | where { $_.GetValueNames() -contains 'DisplayName' }
$keys += dir HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall | where { $_.GetValueNames() -contains 'DisplayName' }
$k = $keys | where { $_.GetValue('DisplayName') -eq 'DISPLAYNAMEHERE' }Requires PatchMyPC
# Windows Update
if ((Get-Module -ListAvailable -Name PSWindowsUpdate) -eq $null)
{
Write-Host -ForegroundColor Yellow "Windows Update module not found, installing..."
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
Install-Module -Name PSWindowsUpdate -Force
}
Write-Host -ForegroundColor Yellow "Getting Windows Updates..."
Import-Module PSWindowsUpdate
Install-WindowsUpdate -AcceptAll -IgnoreReboot
# Patch Software
Write-Host -ForegroundColor Yellow "Patching installed software..."
& C:\Users\ITAdmin\Downloads\PatchMyPC.exe /auto -Wait
# System File Check
sfc /scannow
# Cleanup disk
cleanmgr.exe /full# Powershell script to organize files into subdirectories based on file type, without moving existing directories
# ! Use with caution there is no confirmation or undo !
# Prompt user to enter the directory path
$directoryPath = Read-Host -Prompt 'Enter the directory path'
# Check if the directory exists
if (-Not (Test-Path $directoryPath)) {
Write-Host "The directory does not exist."
exit
}
# Define subdirectory names and file extensions
$subdirectories = @{
"Photos" = @("*.jpg", "*.jpeg", "*.png", "*.gif", "*.bmp", "*.tiff");
"Videos" = @("*.mp4", "*.mov", "*.wmv", "*.flv", "*.avi", "*.mkv");
"Documents" = @("*.doc", "*.docx", "*.pdf", "*.txt", "*.xls", "*.xlsx", "*.ppt", "*.pptx");
"Bin" = @("*.exe", "*.bin", "*.dll", "*.bat", "*.msi");
"Other" = @()
}
# Function to move files to their respective subdirectories
function Move-Files {
param(
[string]$SubDir,
[string[]]$Extensions
)
# Create the subdirectory if it doesn't exist
$subDirPath = Join-Path $directoryPath $SubDir
if (-Not (Test-Path $subDirPath)) {
New-Item -Path $subDirPath -ItemType Directory | Out-Null
}
# Move files to the subdirectory
foreach ($extension in $Extensions) {
Get-ChildItem -Path $directoryPath -Filter $extension -File | Move-Item -Destination $subDirPath
}
}
# Move files based on extensions
foreach ($subDir in $subdirectories.Keys) {
Move-Files -SubDir $subDir -Extensions $subdirectories[$subDir]
}
# Move remaining files to 'Other' directory
Get-ChildItem -Path $directoryPath -File |
Where-Object { $_.Extension -notin $subdirectories.Values -and !($_.PSIsContainer) } |
Move-Item -Destination (Join-Path $directoryPath "Other")$profiles = (netsh wlan show profiles) | Select-String "\:(.+)$" | %{$_.Matches.Groups[1].Value.Trim()}
foreach ($profile in $profiles) {
# Get details about the profile, including the password in clear text
$password = (netsh wlan show profile name=$profile key=clear) | Select-String "Key Content\W+\:(.+)$" | %{$_.Matches.Groups[1].Value.Trim()}
# Print the profile name and password
"SSID: $profile"
"Password: $password"
"-------------------------"
}winget install --id=Microsoft.DotNet.Framework.DeveloperPack_4 -e ; winget install --id=Google.Chrome -e ; winget install --id=Microsoft.VCRedist.2013.x64 -e ; winget install --id=Microsoft.VCRedist.2013.x86 -e ; winget install --id=Microsoft.VCRedist.2015+.x64 -e ; winget install --id=Microsoft.VCRedist.2015+.x86 -e ; winget install --id=Microsoft.VCRedist.2012.x64 -e ; winget install --id=Microsoft.VCRedist.2012.x86 -e ; winget install --id=Microsoft.VCRedist.2010.x64 -e ; winget install --id=Microsoft.VCRedist.2010.x86 -e ; winget install --id=Microsoft.VCRedist.2005.x86 -e ; winget install --id=Microsoft.VCRedist.2008.x86 -e ; winget install --id=Microsoft.VCRedist.2008.x64 -e ; winget install --id=Oracle.JavaRuntimeEnvironment -e ; winget install --id=7zip.7zip -e ; winget install --id=Adobe.Acrobat.Reader.64-bit -e Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
curl.exe -L -o debian.appx https://aka.ms/wsl-debian-gnulinux
Rename-Item .\debian.appx debian.zip
Expand-Archive .\debian.zip debian
Expand-Archive .\debian\DistroLauncher-Appx_1.12.1.0_x64.appx
.\debian\DistroLauncher-Appx_1.12.1.0_x64\debian.exe$printers = Get-WmiObject -Query "SELECT * FROM Win32_Printer"
foreach ($printer in $printers) {
$portName = $printer.PortName
$port = Get-WmiObject -Query "SELECT * FROM Win32_TCPIPPrinterPort WHERE Name = '$portName'"
if ($port -ne $null) {
[PSCustomObject]@{
PrinterName = $printer.Name
IPAddress = $port.HostAddress
}
}
}Import-Module ActiveDirectorydig +noall +answer _ldap._tcp.dc._msdcs.<domain-name> SRVnslookup -type=srv _ldap._tcp.dc._msdcs.<domain-name>nltest /dclist:<your-domain-name>Get-ADDomainController -Filter * | Select Name, HostName, Site# Import the Active Directory module
Import-Module ActiveDirectory
# Define the number of days for stale account detection
$StaleDays = 90
# Calculate the date from $StaleDays ago
$Date = (Get-Date).AddDays(-$StaleDays)
# Find computer accounts that haven't logged in since $Date
$StaleComputers = Get-ADComputer -Filter {LastLogonTimeStamp -lt $Date} -Properties LastLogonTimeStamp
# Loop through each stale computer and remove it
foreach ($Computer in $StaleComputers) {
$ComputerName = $Computer.Name
$LastLogonDate = [datetime]::FromFileTime($Computer.LastLogonTimeStamp)
Write-Host "Removing computer: $ComputerName (Last Logon: $LastLogonDate)"
# Remove the computer account from Active Directory
# Uncomment the next line to perform the deletion
# Remove-ADComputer -Identity $Computer.DistinguishedName -Confirm:$false
}
# Output completion message
Write-Host "Completed removal of stale computer accounts."Import-Module ActiveDirectory
$DCs = Get-ADDomainController -Filter *
foreach ($DC in $DCs) {
$roles = @()
$forest = Get-ADForest
if ($DC.HostName -eq $forest.SchemaMaster) { $roles += "Schema Master" }
if ($DC.HostName -eq $forest.DomainNamingMaster) { $roles += "Domain Naming Master" }
$domain = Get-ADDomain
if ($DC.HostName -eq $domain.RIDMaster) { $roles += "RID Master" }
if ($DC.HostName -eq $domain.InfrastructureMaster) { $roles += "Infrastructure Master" }
if ($DC.HostName -eq $domain.PDCEmulator) { $roles += "PDC Emulator" }
[PSCustomObject]@{
DomainController = $DC.HostName
Roles = $roles -join ', '
}
}Install-Module -Name ExchangeOnlineManagement
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName <UPN> [-ExchangeEnvironmentName <Value>] [-ShowBanner:$false] [-DelegatedOrganization <String>] [-SkipLoadingFormatData]Get-Mailbox -RecipientTypeDetails UserMailbox | ForEach-Object {
$mailboxStats = Get-MailboxStatistics $_.Identity
$archiveStats = @{TotalItemSize = "N/A"} # Default value in case there's no archive.
if ($_.ArchiveStatus -eq 'Active') {
$archiveStats = Get-MailboxStatistics $_.Identity -Archive
}
[PSCustomObject]@{
DisplayName = $_.DisplayName
PrimarySmtpAddress = $_.PrimarySmtpAddress
ArchiveStatus = $_.ArchiveStatus
AutoExpandArchive = $_.AutoExpandingArchiveEnabled
TotalItemSize = $mailboxStats.TotalItemSize
ArchiveSize = if ($_.ArchiveStatus -eq 'Active') {$archiveStats.TotalItemSize} else {"Not Applicable"}
}
} | Select-Object DisplayName, PrimarySmtpAddress, ArchiveStatus, AutoExpandArchive, TotalItemSize, ArchiveSize- HP Bloatware Removal (varied results)
- AD Audit
- Microsoft Official Windows Search Reset
- PSCmder (Really bad PDQ alternative, script and
commands.txtare in this repo. Usefull for remote installation or command exec) - CIS Critical Controls
Windows Defender is enough, if you harden it
the GDID (Global Device Identifier) is a persistent, 64-bit Windows fingerprint, revealed in a 2026 criminal complaint, assigned by Microsoft's servers during device registration. The identifier is generated by the
wlidsvcservice, stored in the Windows registry, and then consumed by the Connected Devices Platform (CDPSvc) to register the device into Microsoft's Device Directory Service, where it is also reported by Delivery Optimization. The GDID persists across OS updates but changes after a Windows reinstall or by using discovered techniques.
https://github.com/SmtimesIWndr/gdid-reversal
(Get-ItemProperty 'HKCU:\SOFTWARE\Microsoft\IdentityCRL\ExtendedProperties').LID$hex = (Get-ItemProperty 'HKCU:\SOFTWARE\Microsoft\IdentityCRL\ExtendedProperties').LID
"g:$([Convert]::ToUInt64($hex,16))"https://github.com/gd03gd031/Windows-GDID-Changer
Write-Host "[*] Stopping Identity Service..."
$identityService = Get-Service wlidsvc
if ($identityService.Status -eq "Running") {
net stop wlidsvc | Out-Null
}
$identityPath = "Registry::HKEY_USERS\.DEFAULT\Software\Microsoft\IdentityCRL"
$currentLid = (Get-ItemProperty "$identityPath\ExtendedProperties").LID
Write-Host "`nCurrent GDID: " -NoNewline
Write-Host "g:$([Convert]::ToUInt64($currentLid,16))" -ForegroundColor Yellow
Write-Host "`n[*] Forcing new device registration and GDID assignment..."
Get-ChildItem "$identityPath\Immersive\production\Token" | ForEach-Object {
$tokenInfo = Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue
if ($tokenInfo.DeviceID -eq $currentLid) {
Remove-Item $_.PSPath -Recurse -Force
}
}
$systemDevicePath = "$identityPath\DeviceIdentities\production\S-1-5-18"
Remove-Item $systemDevicePath -Recurse -Force -ErrorAction SilentlyContinue
Write-Host "[*] Starting Identity Service..."
if ((Get-Service wlidsvc).Status -ne "Running") {
net start wlidsvc | Out-Null
}
Write-Host "[*] Waiting for new GDID..." -NoNewline
for ($attempt = 0; $attempt -lt 60; $attempt++) {
Start-Sleep 2
Write-Host "." -NoNewline
try {
$newLid = (Get-ItemProperty "$identityPath\ExtendedProperties" -ErrorAction Stop).LID
if ($newLid -ne $currentLid) {
Write-Host "`n`nNew GDID: " -NoNewline
Write-Host "g:$([Convert]::ToUInt64($newLid,16))" -ForegroundColor Green
Write-Host "`n[+] Complete. New GDID received from device registration service."
Write-Host "`n[!] Note: For the strongest separation, change relevant hardware configuration before forcing a new GDID."
Write-Host " Device association can still be recreated from existing hardware identifiers and machine attributes."
exit
}
}
catch {}
}
Write-Host "`n`n[!] Timed out waiting for a new GDID." -ForegroundColor Yellow[console]::beep(784,300); Start-Sleep -Milliseconds 100; [console]::beep(784,600); [console]::beep(622,600); [console]::beep(698,600); [console]::beep(784,200); Start-Sleep -Milliseconds 200; [console]::beep(698,200); [console]::beep(784,800)Bounces cursor around the screen like the DVD logo
Add-Type -AssemblyName System.Windows.Forms
# Get screen dimensions
$bounds = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds
$maxX = $bounds.Width
$maxY = $bounds.Height
$x = [System.Windows.Forms.Cursor]::Position.X
$y = [System.Windows.Forms.Cursor]::Position.Y
# Movement vector (speed)
$dx = 14
$dy = 14
while ($true) {
$x += $dx
$y += $dy
# Check for screen bounds and reverse direction if needed
if ($x -le 0 -or $x -ge $maxX) {
$dx = -$dx
}
if ($y -le 0 -or $y -ge $maxY) {
$dy = -$dy
}
[System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point($x, $y)
Start-Sleep -Milliseconds 50
}