Files
SRGAdminMenu/SRGAdminMenu.ps1
2025-09-18 10:34:37 +00:00

301 lines
12 KiB
PowerShell

# --- Simple Numbered Menu with Submenus (Local/Remote) ---
# ------- Helpers -------
function Invoke-Remote {
param(
[Parameter(Mandatory)][string]$Computer,
[Parameter(Mandatory)][scriptblock]$ScriptBlock,
[Parameter()][object[]]$ArgumentList
)
try {
return Invoke-Command -ComputerName $Computer -ScriptBlock $ScriptBlock -ArgumentList $ArgumentList -ErrorAction Stop
} catch {
$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
Write-Warning "Implicit auth to '$Computer' failed: $($_.Exception.Message)"
$cred = Get-Credential -UserName $currentUser -Message "Enter the password for $currentUser"
return Invoke-Command -ComputerName $Computer -Credential $cred -ScriptBlock $ScriptBlock -ArgumentList $ArgumentList -ErrorAction Stop
}
}
function Remove-ProvisionedAndExisting {
<#
.SYNOPSIS
Preview + remove provisioned and installed Appx packages, locally or remotely.
.PARAMETER Pattern
-Like pattern, e.g. 'Microsoft.MSPaint*'
.PARAMETER Computer
If provided, runs on remote via Invoke-Remote; otherwise runs locally.
#>
param(
[Parameter(Mandatory)][string]$Pattern,
[string]$Computer
)
# Scriptblocks reused for both local and remote
$sbPreview = {
param($p)
$prov = Get-AppxProvisionedPackage -Online |
Where-Object DisplayName -Like $p |
Select-Object @{n='Type';e={'Provisioned'}}, DisplayName, PackageName
$inst = Get-AppxPackage -AllUsers |
Where-Object Name -Like $p |
Select-Object @{n='Type';e={'Installed'}}, Name, PackageFullName
[PSCustomObject]@{ Provisioned = $prov; Installed = $inst }
}
$sbRemove = {
param($p)
$errs = @()
# Remove from provisioned image (new profiles)
try {
Get-AppxProvisionedPackage -Online |
Where-Object DisplayName -Like $p |
Remove-AppxProvisionedPackage -Online -ErrorAction Stop | Out-Null
Write-Host "Removed provisioned packages matching '$p'."
} catch { $errs += "Provisioned removal: $($_.Exception.Message)" }
# Remove from existing users
try {
$pkgs = Get-AppxPackage -AllUsers | Where-Object Name -Like $p
foreach ($pkg in $pkgs) {
try {
Remove-AppxPackage -Package $pkg.PackageFullName -AllUsers -ErrorAction Stop
Write-Host "Removed installed package: $($pkg.PackageFullName)"
} catch {
# Fallback on older systems without -AllUsers support
try {
Get-AppxPackage -AllUsers | Where-Object Name -eq $pkg.Name |
ForEach-Object { Remove-AppxPackage -Package $_.PackageFullName -ErrorAction Stop }
Write-Host "Removed per-user instances of: $($pkg.Name)"
} catch {
$errs += "Installed removal ($($pkg.Name)): $($_.Exception.Message)"
}
}
}
} catch { $errs += "Installed discovery: $($_.Exception.Message)" }
if ($errs.Count) { Write-Warning ("Errors:`n - " + ($errs -join "`n - ")) }
else { Write-Host "Removal complete." -ForegroundColor Green }
}
$isLocal = [string]::IsNullOrWhiteSpace($Computer) -or $Computer -in @('localhost','127.0.0.1','.')
# --- Preview ---
if ($isLocal) {
$preview = & $sbPreview $Pattern
} else {
$preview = Invoke-Remote -Computer $Computer -ScriptBlock $sbPreview -ArgumentList $Pattern
}
$prov = $preview.Provisioned
$inst = $preview.Installed
if (-not $prov -and -not $inst) {
if ($isLocal) { $scope = "local machine" } else { $scope = $Computer }
Write-Host "No matches for '$Pattern' on $scope." -ForegroundColor Yellow
return
}
if ($prov) {
Write-Host "`nProvisioned packages matching '$Pattern':" -ForegroundColor Cyan
$prov | Format-Table -AutoSize
} else {
Write-Host "`nNo provisioned packages matched '$Pattern'."
}
if ($inst) {
Write-Host "`nInstalled packages (existing profiles) matching '$Pattern':" -ForegroundColor Cyan
$inst | Select-Object Name, PackageFullName | Format-Table -AutoSize
} else {
Write-Host "`nNo installed packages (existing profiles) matched '$Pattern'."
}
$confirm = Read-Host "`nProceed to remove from provisioned image AND existing profiles? (Y/N)"
if ($confirm -notin @('Y','y')) { Write-Host "Cancelled."; return }
# --- Remove ---
if ($isLocal) {
& $sbRemove $Pattern
} else {
Invoke-Remote -Computer $Computer -ScriptBlock $sbRemove -ArgumentList $Pattern | Out-Host
}
}
# ------- Your task functions (menu "sections") -------
function Do-ConnectRemote {
$computer = Read-Host "Enter computer name (e.g. USERS-LAPTOP)"
if ([string]::IsNullOrWhiteSpace($computer)) { return }
try {
Enter-PSSession -ComputerName $computer
} catch {
Write-Warning "Implicit auth to '$computer' failed: $($_.Exception.Message)"
$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$cred = Get-Credential -UserName $currentUser -Message "Enter the password for $currentUser"
Enter-PSSession -ComputerName $computer -Credential $cred
}
}
function Do-RemoveAppxMenu {
# Choose Local or Remote first
$targetType = $null
$computer = $null
do {
Clear-Host
Write-Host "=== Remove Windows Apps ===" -ForegroundColor Cyan
Write-Host " 1) Local machine"
Write-Host " 2) Remote machine"
Write-Host " 0) Back`n"
$t = Read-Host "Choose target"
switch ($t) {
'1' { $targetType = 'Local' }
'2' { $targetType = 'Remote'; $computer = Read-Host "Enter remote computer name"; if ([string]::IsNullOrWhiteSpace($computer)) { $targetType = $null } }
'0' { return }
default { Write-Host "Invalid choice." -ForegroundColor Yellow; Start-Sleep -Milliseconds 800 }
}
} until ($targetType)
if ($targetType -eq 'Local') { $scopeLabel = 'local machine' } else { $scopeLabel = $computer }
# Presets
$presets = @(
@{ Label = 'Paint 3D'; Pattern = 'Microsoft.MSPaint*' }
@{ Label = '3D Viewer'; Pattern = 'Microsoft.Microsoft3DViewer*' }
@{ Label = 'Mail & Calendar'; Pattern = 'microsoft.windowscommunicationsapps*' }
@{ Label = 'Sticky Notes'; Pattern = 'Microsoft.MicrosoftStickyNotes*' }
@{ Label = 'Solitaire Collection'; Pattern = 'Microsoft.MicrosoftSolitaireCollection*' }
@{ Label = 'Xbox (Gaming App)'; Pattern = 'Microsoft.GamingApp*' }
@{ Label = 'Xbox Overlay/Identity'; Pattern = 'Microsoft.Xbox*' }
@{ Label = 'Clipchamp'; Pattern = 'Microsoft.Clipchamp*' }
@{ Label = 'Weather'; Pattern = 'Microsoft.BingWeather*' }
@{ Label = 'News'; Pattern = 'Microsoft.BingNews*' }
)
do {
Clear-Host
Write-Host "=== Remove Apps on $scopeLabel ===" -ForegroundColor Cyan
$i = 1
foreach ($p in $presets) { Write-Host (" {0,2}) {1} (pattern: {2})" -f $i, $p.Label, $p.Pattern); $i++ }
Write-Host (" {0,2}) {1}" -f $i, 'Custom pattern...')
Write-Host " 0) Back`n"
$sub = Read-Host "Choose an option"
if ($sub -eq '0') { break }
if ($sub -as [int]) {
$idx = [int]$sub
if ($idx -ge 1 -and $idx -le $presets.Count) {
$pat = $presets[$idx-1].Pattern
if ($targetType -eq 'Local') { Remove-ProvisionedAndExisting -Pattern $pat }
else { Remove-ProvisionedAndExisting -Pattern $pat -Computer $computer }
Read-Host "`nPress Enter to continue" | Out-Null
continue
} elseif ($idx -eq ($presets.Count + 1)) {
$pat = Read-Host "Enter -Like pattern (use * wildcards, e.g. Microsoft.Todos*)"
if ($pat) {
if ($targetType -eq 'Local') { Remove-ProvisionedAndExisting -Pattern $pat }
else { Remove-ProvisionedAndExisting -Pattern $pat -Computer $computer }
}
Read-Host "`nPress Enter to continue" | Out-Null
continue
}
}
Write-Host "Invalid choice." -ForegroundColor Yellow
Start-Sleep -Milliseconds 800
} while ($true)
}
function Do-ShowIP {
Get-NetIPAddress -AddressFamily IPv4 |
Select-Object InterfaceAlias, IPAddress |
Sort-Object InterfaceAlias |
Format-Table -AutoSize
}
function Do-PingHost {
$h = Read-Host "Enter host or IP"
if ($h) { Test-Connection -TargetName $h -Count 4 | Format-Table Address, Latency -Auto }
}
function Do-RestartServiceMenu {
do {
Clear-Host
Write-Host "=== Restart a Service ===" -ForegroundColor Cyan
Write-Host " 1) Local machine"
Write-Host " 2) Remote machine"
Write-Host " 0) Back`n"
$opt = Read-Host "Choose an option"
switch ($opt) {
'1' {
$svc = Read-Host "Enter service name (e.g., Spooler)"
if ([string]::IsNullOrWhiteSpace($svc)) { break }
try {
Restart-Service -Name $svc -Force -ErrorAction Stop
Get-Service -Name $svc | Select-Object Status, Name, DisplayName | Format-Table -AutoSize
Write-Host "Local service restarted." -ForegroundColor Green
} catch {
Write-Warning "Local restart failed: $($_.Exception.Message)"
}
Read-Host "`nPress Enter to continue" | Out-Null
}
'2' {
$computer = Read-Host "Enter remote computer name"
if ([string]::IsNullOrWhiteSpace($computer)) { break }
$svc = Read-Host "Enter service name on $computer"
if ([string]::IsNullOrWhiteSpace($svc)) { break }
try {
$res = Invoke-Remote -Computer $computer -ScriptBlock {
param($name)
$null = Get-Service -Name $name -ErrorAction Stop
Restart-Service -Name $name -Force -ErrorAction Stop
Get-Service -Name $name | Select-Object Status, Name, DisplayName
} -ArgumentList $svc
if ($res) { $res | Format-Table -AutoSize }
Write-Host "Remote service restarted on $computer." -ForegroundColor Green
} catch {
Write-Warning "Remote restart failed on $($computer): $($_.Exception.Message)"
}
Read-Host "`nPress Enter to continue" | Out-Null
}
'0' { return }
default {
Write-Host "Invalid choice." -ForegroundColor Yellow
Start-Sleep -Milliseconds 800
}
}
} while ($true)
}
# ------- Main Menu -------
do {
Clear-Host
Write-Host "=== My Admin Menu ===" -ForegroundColor Cyan
Write-Host " 1) Connect to a machine (Enter-PSSession as current user)"
Write-Host " 2) Remove Windows apps (local or remote)"
Write-Host " 3) Show IP addresses"
Write-Host " 4) Ping a host"
Write-Host " 5) Restart a service (submenu)"
Write-Host " 0) Quit`n"
$choice = Read-Host "Choose an option"
switch ($choice) {
'1' { Do-ConnectRemote }
'2' { Do-RemoveAppxMenu }
'3' { Do-ShowIP; Read-Host "`nPress Enter to return to menu" | Out-Null }
'4' { Do-PingHost; Read-Host "`nPress Enter to return to menu" | Out-Null }
'5' { Do-RestartServiceMenu }
'0' { exit }
default {
Write-Host "Invalid choice." -ForegroundColor Yellow
Start-Sleep -Milliseconds 800
}
}
} while ($true)