PHP Code:
# This script displays a menu to run the following functions either individually or all of them sequentially.
# Each function prompts to run unless taking the ALL option.
#
# Currently the functions are : Disk Cleanup (all options) using "cleanmgr" command
# Compress OS using "compact" command
# Compress other identified directories using "compact" command
# Delete everything from "SoftwareDistribution\Downloads"
# Delete everything in "%windir%\Temp" and "%localappData%\Temp" (for current user)
# Remove all modern apps (that are possible to remove with "Remove-AppxPackage")
# DISM /online /Cleanup-Image /StartComponentCleanup /ResetBase
# Turn off System Protection
# Turn off hibernation
# Set pageFile to 200MB (minimum recommended to allow memory dumps to be produced)
# Run disk defragmentation/Trim using "defrag.exe"
# Reboot if required
#
# TODO
# 1. Update location of sdelete (or rewrite it)
# 2. The 'quiet' functionality (i.e. start the script with ./Shrink-Windows.ps1 -q) will suppress the menu and any prompts to screen.
# This is not properly implemented yet though - need to add RunOnce key to run stuff after reboot perhaps. Unsure if this is best solution
# 3. Add more stuff to temp file clearer (copy old-timer TFC?). Alternatively just drop this function.
#------------------------------------------------------------------------------------------------------------------------------------------------------
# Initialise
# ~~~~~~~~~~
#------------------------------------------------------------------------------------------------------------------------------------------------------
param ([char]$q)
If ($q -eq 'Q' -or $q -eq 'q') {$quiet=$true}
$ErrorActionPreference="silentlyContinue"
$runAll=$false
$rebootRequired=$false
$global:prompt=0
$sdeletePath="$env:homeDrive$env:homePath\OneDrive\Programs\SysinternalsSuite\sdelete.exe"
$OS=Get-WmiObject Win32_OperatingSystem
If (-not $OS.Caption.Contains("10") -and -not $OS.Caption.Contains("2016")) {
If (-not $quiet) {Read-Host -Prompt "This script only works with Windows 10. Press Enter to exit."}
exit
}
$Manufacturer=Get-WmiObject -Class Win32_BaseBoard | ForEach-Object {$_.Manufacturer}
if (($Manufacturer -eq "Microsoft Corporation") -or ($Manufacturer -eq "VMWARE") -or ($Manufacturer -eq "VirtualBox")) {
$thisIsVirtualMachine=$true
}
Else { $thisIsVirtualMachine=$false }
#------------------------------------------------------------------------------------------------------------------------------------------------------
# Functions
#------------------------------------------------------------------------------------------------------------------------------------------------------
function askQuestion ($caption, $clearHost=1, $defaultAnswer=0)
# Normally, clear the screen and defualt answer (0 = Yes) if not running everything.
{
If ($runAll) {$global:prompt=$defaultAnswer}
Else {
If ($ClearHost) {Clear-Host}
$message="Enter choice"
$choices = @("&Yes","&No")
$choicedesc = New-Object System.Collections.ObjectModel.Collection[System.Management.Automation.Host.ChoiceDescription]
$choices | foreach { $choicedesc.Add((New-Object "System.Management.Automation.Host.ChoiceDescription" -ArgumentList $_))}
$global:prompt = $Host.ui.PromptForChoice($caption, $message, $choicedesc, $defaultAnswer)
}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function PressAnyKey
# This function displays "Press Enter to continue" If running in interactive menu mode.
{ Write-Host; Write-Host
If (-not $quiet) {
Read-Host -Prompt "Press Enter to return to menu"
Clear-Host
mainMenu
}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function bootRequired
# This function asks whether to reboot now or later.
{ If ($rebootRequired) {
If ($runAll -and -$quiet) {} # Add a Run-One Key to call script again? Not sure if this is practical.
ElseIf ($runAll) {Write-Host "Reboot required. Run ALL Option again after reboot to continue." -f yellow}
askQuestion "Choose Y to reboot now or N to reboot manually later" 0 1
Switch ($prompt)
{ 0 {Restart-Computer -ComputerName $Env:COMPUTERNAME -Force}
1 {return}
}
}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function takeOwn-folder ($folder)
{ $toplevel=Split-Path $folder -leaf
# Delete the old .acl file (in case it exists)
If (Test-Path "$PSScriptRoot\$toplevel.acl") {Remove-Item "$PSScriptRoot\$toplevel.acl" -Force -ErrorAction 0}
# backup ACLs for WindowsApps folder
icacls "$folder" /save "$PSScriptRoot\$toplevel.acl" /t
# take ownership
takeown /f "$folder" /r
# Grant full rights to current user
icacls "$folder" --% /grant "%USERDOMAIN%\%USERNAME%":(F) /t
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function restoreOwn-folder ($folder, $owner)
{ $toplevel=Split-Path $folder -leaf
$parentPath=Split-Path -parent $folder
# reset owner of WindowsApps to the owner passed in as parameter - e.g. "NT SERVICE\TrustedInstaller"
icacls "$folder" /setowner "$owner" /t
# Restore ACLs
icacls "$parentPath" /restore "$PSScriptRoot\$toplevel.acl"
# Tidy up
Remove-Item "$PSScriptRoot\$toplevel.acl" -Force -ErrorAction 0
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function DiskCleanup
# This function writes a key StateFlags0032 to all subkeys in HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches
# and then calls cleanmgr.exe /sagerun:32 to process them. The number 32 is not important - only the same of the key in the registry
# must match that on the sagerun parameter.
{
askQuestion "Disk Cleanup?"
Switch ($prompt)
{ 0
{ Try
{ $VName="StateFlags0032"
$DirPath="HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches"
# Folders Names which will been cleaned. Note some of these (for example "RetailDemo Offline Content") are deleted from
# the registry after first run. Messages like "Key not found" are therefore not important and can be ignored.
$TempFolders=@(
"Active Setup Temp Folders",
"BranchCache",
"Content Indexer Cleaner",
"Delivery Optimization Files",
"Downloaded Program Files",
"GameNewsFiles",
"GameStatisticsFiles",
"GameUpdateFiles",
"Internet Cache Files",
"Memory Dump Files",
"Offline Pages Files",
"Old ChkDsk Files",
"Previous Installations",
"Recycle Bin",
"RetailDemo Offline Content",
"Service Pack Cleanup",
"Setup Log Files",
"System error memory dump files",
"System error minidump files",
"Temporary Files",
"Temporary Setup Files",
"Temporary Sync Files",
"Thumbnail Cache",
"Update Cleanup",
"Upgrade Discarded Files",
"User file versions",
"Windows Defender",
"Windows Error Reporting Archive Files",
"Windows Error Reporting Queue Files",
"Windows Error Reporting System Archive Files",
"Windows Error Reporting System Queue Files",
"Windows Error Reporting Temp Files",
"Windows ESD installation files",
"Windows Upgrade Log Files")
Write-Host "The following are selected to be cleaned by cleanmgr" -f cyan
$error.clear()
For($i=0;$i -lt $TempFolders.Count; $i++)
{ $RegKey=$DirPath + "\" + $TempFolders[$i]
$StateValue=(Get-ItemProperty $RegKey).$VName
If ($?)
{ If ($Error.categoryinfo) {write-host "Key not found " -f red -NoNewline; write-host ": " $TempFolders[$i] -f White}
ElseIf (-not $StateValue)
{ New-ItemProperty -Path $RegKey -Name $VName -Value "2" -PropertyType "dword" | out-null
write-host "Key added " -NoNewline; write-host ": " $TempFolders[$i] -f White
}
Else
{ Set-ItemProperty -Path $RegKey -Name $VName -Value "2"
write-host "Key updated " -NoNewline; write-host ": " $TempFolders[$i] -f White
}
}
$error.clear()
$RegKey=$DirPath
}
Write-Host "End of List" -f cyan
# 32 is a random number - just has to match $VName variable
CLEANMGR /sagerun:32
Write-Host "Disk Cleanup running asynchronously..." -f white
}
Catch
{
If (-not $quiet) {Read-Host -Prompt "Disk cleanup failed. Press Enter to continue with other tasks and run it manually afterwards."}
}
}
1 { Write-Host "Request cancelled - cleanmgr.exe not run" -f yellow}
}
If (-not $runAll) {pressAnyKey}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function compactOS
{
# This function sets the compactos flag on. This remains on until turned off again explicity so this only needs to run once.
# Only compact If not already done as it remains the same until turned off.
If ((compact /compactos:query) -like '*The system is in the Compact state*') {
Write-Host 'The system is already in the Compact state'
Sleep 1
}
Else {
askQuestion "Compact OS?"
Switch ($prompt)
{ 0 { compact /compactos:always}
1 { Write-Host "Request cancelled - OS not compacted" -f yellow}
}
If (-not $runAll) {pressAnyKey}
}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function compactOther
# This function compresses named directories (see below) with compression algorithm xpress16k. This does not apply to items added after so
# the directory is then compressed without specIfying /exe:xpress16k. This defaults to xpress4k and will apply only to thinks added later as the
# /f (force) switch is not specIfied.
{
# Array is 3 dimensions.
# Note in Powershell array index starts from 0
# $compactDirectory[$i][0] is the folder
# $compactDirectory[$i][1] is the owner
# $compactDirectory[$i][2] is the compression
# If ownership needs changing put the standard owner in second element so it can be reset correctly. Otherwise leave as ""
$compactDirectory=
@(
("$env:programFiles" ,"" ,"xpress16k"),
("${env:programFiles(x86)}" ,"" ,"xpress16k"),
("$env:homeDrive$env:homePath\Documents" ,"" ,"xpress16k"),
("$env:homeDrive$env:homePath\OneDrive" ,"" ,"xpress16k"),
("$env:homeDrive$env:homePath\Downloads" ,"" ,"xpress16k"),
("$env:LOCALAPPDATA\Packages" ,"" ,"xpress16k")
("$env:windir\Assembly" ,"" ,"xpress8k"),
("$env:windir\Fonts" ,"NT SERVICE\TrustedInstaller" ,"xpress16k"),
("$env:windir\InfusedApps" ,"" ,"xpress16k"),
("$env:windir\Installer" ,"" ,"lzx"),
("$env:windir\Panther" ,"" ,"xpress16k"),
("$env:windir\SoftwareDistribution" ,"" ,"xpress16k"),
("$env:windir\System32\Catroot2" ,"" ,"xpress16k"),
("$env:windir\System32\LogFiles" ,"" ,"xpress16k")
#("$env:windir\WinSxS" ,"NT SERVICE\TrustedInstaller" ,"xpress16k")
)
# these are causing errors (perhaps)
# ("$env:windir\System32\DriverStore\FileRepository" ,"" ,"lzx
# ("$env:programData" ,"NT AUTHORITY\SYSTEM"),
# ("$env:APPDATA" ,"NT AUTHORITY\SYSTEM"),
#
askQuestion "Compact other directories?"
Switch ($prompt)
{ 0
{ For($i=0;$i -lt $compactDirectory.Count; $i++)
{ $folder=$compactDirectory[$i][0]
$owner=$compactDirectory[$i][1]
$compression=$compactDirectory[$i][2]
If (Test-Path $folder)
{
# take ownership If required
If ($owner -ne "") {takeOwn-folder -folder $folder}
# force xpress16k but this doesn't persist
Write-Host "Running " -NoNewLine
Write-Host "compact /c /s /a /f /q /i /exe:"$compression $folder"\*" -f White
compact /c /s /a /f /q /i /exe:$compression $folder\*
#restore ownership
If ($owner -ne "") {restoreOwn-folder -folder $folder -owner $owner}
}
Else { Write-Host "Path not found " -f red -NoNewline; write-host $folder -f White}
}
}
1 { Write-Host "Request cancelled - directories not compressed" -f yellow}
}
If (-not $runAll) {pressAnyKey}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function clearDownloads
# This function clears the C:\Windows\SoftwareDistribution\Download\ folder
{
askQuestion "Clear Windows update downloads?"
Switch ($prompt)
{ 0
{ Remove-Item -path c:\Windows\SoftwareDistribution\Download\* -Recurse -Force -ErrorAction 0
Write-Host "SoftwareDistribution\Download cleared" -f cyan
}
1 {Write-Host "Request cancelled - SoftwareDistribution\Download not cleared" -f yellow}
}
If (-not $runAll) {pressAnyKey}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function clearTemp
# This function clears C:\Windows\Temp and the current users C:\Users\xxxx\AppData\Local\Temp directories
{
askQuestion "Clear temp files?"
Switch ($prompt)
{ 0
{ Remove-Item -path $env:windir\Temp\* -Recurse -Force -ErrorAction 0
Write-Host "$env:windir\Temp cleared" -f cyan
$localAppDataTemp="$Env:TEMP"
If (Test-Path $localAppDataTemp)
{ Remove-Item "$LocalAppDataTemp\*" -Recurse -Force -ErrorAction 0
Write-Host "$env:TEMP cleared" -f cyan
}
}
1 {Write-Host "Request cancelled - temp files not cleared" -f yellow}
}
If (-not $runAll) {pressAnyKey}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function enable-privilege {
param(
## The privilege to adjust. This set is taken from
## http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspx
[ValidateSet(
"SeAssignPrimaryTokenPrivilege", "SeAuditPrivilege", "SeBackupPrivilege",
"SeChangeNotIfyPrivilege", "SeCreateGlobalPrivilege", "SeCreatePagefilePrivilege",
"SeCreatePermanentPrivilege", "SeCreateSymbolicLinkPrivilege", "SeCreateTokenPrivilege",
"SeDebugPrivilege", "SeEnableDelegationPrivilege", "SeImpersonatePrivilege", "SeIncreaseBasePriorityPrivilege",
"SeIncreaseQuotaPrivilege", "SeIncreaseWorkingSetPrivilege", "SeLoadDriverPrivilege",
"SeLockMemoryPrivilege", "SeMachineAccountPrivilege", "SeManageVolumePrivilege",
"SeProfileSingleProcessPrivilege", "SeRelabelPrivilege", "SeRemoteShutdownPrivilege",
"SeRestorePrivilege", "SeSecurityPrivilege", "SeShutdownPrivilege", "SeSyncAgentPrivilege",
"SeSystemEnvironmentPrivilege", "SeSystemProfilePrivilege", "SeSystemtimePrivilege",
"SeTakeOwnershipPrivilege", "SeTcbPrivilege", "SeTimeZonePrivilege", "SeTrustedCredManAccessPrivilege",
"SeUndockPrivilege", "SeUnsolicitedInputPrivilege")]
$Privilege,
## The process on which to adjust the privilege. Defaults to the current process.
$ProcessId=$pid,
## Switch to disable the privilege, rather than enable it.
[Switch] $Disable
)
## Taken from P/Invoke.NET with minor adjustments.
$definition=@'
using System;
using System.Runtime.InteropServices;
public class AdjPriv
{
[DllImport("advapi32.dll", ExactSpelling=true, SetLastError=true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
[DllImport("advapi32.dll", ExactSpelling=true, SetLastError=true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
[DllImport("advapi32.dll", SetLastError=true)]
internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
[StructLayout(LayoutKind.Sequential, Pack=1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}
internal const int SE_PRIVILEGE_ENABLED=0x00000002;
internal const int SE_PRIVILEGE_DISABLED=0x00000000;
internal const int TOKEN_QUERY=0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES=0x00000020;
public static bool EnablePrivilege(long processHandle, string privilege, bool disable)
{
bool retVal;
TokPriv1Luid tp;
IntPtr hproc=new IntPtr(processHandle);
IntPtr htok=IntPtr.Zero;
retVal=OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count=1;
tp.Luid=0;
If (disable)
{
tp.Attr=SE_PRIVILEGE_DISABLED;
}
Else
{
tp.Attr=SE_PRIVILEGE_ENABLED;
}
retVal=LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal=AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
}
'@
$processHandle=(Get-Process -id $ProcessId).Handle
$type=Add-Type $definition -PassThru
$type[0]::EnablePrivilege($processHandle, $Privilege, $Disable)
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function Takeown-Registry($key)
# This function is used by the removeApps function below. Note TODO does not work for all root keys yet
{ switch ($key.split('\')[0])
{ "HKEY_CLASSES_ROOT"
{ $reg=[Microsoft.Win32.Registry]::ClassesRoot
$key=$key.substring(18)
}
"HKEY_CURRENT_USER"
{ $reg=[Microsoft.Win32.Registry]::CurrentUser
$key=$key.substring(18)
}
"HKEY_LOCAL_MACHINE"
{ $reg=[Microsoft.Win32.Registry]::LocalMachine
$key=$key.substring(19)
}
}
# set owner
$key=$reg.OpenSubKey($key, "ReadWriteSubTree", "TakeOwnership")
$owner=[Security.Principal.NTAccount]"Administrators"
$acl=$key.GetAccessControl()
$acl.SetOwner($owner)
$key.SetAccessControl($acl)
# set FullControl
$acl=$key.GetAccessControl()
$rule=New-Object System.Security.AccessControl.RegistryAccessRule("Administrators", "FullControl", "Allow")
$acl.SetAccessRule($rule)
$key.SetAccessControl($acl)
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function removeApps
# This function removes unwanted Apps that come with Windows. If you do not want
# to remove certain Apps comment out the corresponding lines below. Based on https://github.com/W4RH4WK/Debloat-Windows-10
{
askQuestion "Remove all modern apps?"
Switch ($prompt)
{ 0 {$deleteAll=$true}
1 {$deleteAll=$false}
}
If ($deleteAll)
{ #Write-Host "Elevating privileges for this process" -f yellow
#do {$result=enable-privilege SeTakeOwnershipPrivilege}
#until ($result -eq $true -or $xx >10)
$apps=
@(
"4DF9E0F8.Netflix"
"9E2F88E3.Twitter"
"ClearChannelRadioDigital.iHeartRadio"
"D52A8D61.FarmVille2CountryEscape"
"Facebook.Facebook"
"Flipboard.Flipboard"
"king.com.CandyCrushSaga"
"king.com.CandyCrushSodaSaga"
"HoloCamera"
"HoloItemPlayerApp"
"HoloShell"
"Microsoft.3DBuilder"
"Microsoft.Appconnector"
"Microsoft.BingFinance"
"Microsoft.BingNews"
"Microsoft.BingSports"
"Microsoft.BingWeather"
"Microsoft.ConnectivityStore"
"Microsoft.CommsPhone"
"Microsoft.Getstarted"
"Microsoft.Messaging"
"Microsoft.Microsoft3DViewer"
"Microsoft.MicrosoftOfficeHub"
"Microsoft.MicrosoftSolitaireCollection"
"Microsoft.MicrosoftStickyNotes"
"Microsoft.MSPaint"
"Microsoft.Office.OneConnect"
"Microsoft.Office.OneNote"
"Microsoft.Office.Sway"
"Microsoft.OneConnect"
"Microsoft.People"
"Microsoft.SkypeApp"
"Microsoft.Windows.Phone"
"Microsoft.Windows.Photos"
"Microsoft.WindowsAlarms"
#"Microsoft.WindowsCalculator"
"Microsoft.WindowsCamera"
#"Microsoft.WindowsFeedbackApp"
"Microsoft.WindowsMaps"
"Microsoft.WindowsPhone"
"Microsoft.WindowsSoundRecorder"
#"Microsoft.WindowsStore"
"Microsoft.XboxApp"
"Microsoft.XboxSpeechToTextOverlay"
"Microsoft.XboxGameOverlay"
"Microsoft.ZuneMusic"
"Microsoft.ZuneVideo"
"microsoft.windowscommunicationsapps"
"Microsoft.MinecraftUWP"
"PandoraMediaInc.29680B314EFC2"
"ShazamEntertainmentLtd.Shazam"
"Windows.MircastView"
)
Write-Host "Removing default apps" -f yellow
ForEach ($app in $apps) {
Write-Host "Removing " -noNewLine; Write-Host $app -f white
# Need to hide the progress bar as otherwise it remains on the screen
$ProgressPreference="SilentlyContinue"
Get-AppxPackage -Name $app -AllUsers | Remove-AppxPackage
$ProgressPreference="Continue"
Get-AppXProvisionedPackage -Online |
where DisplayName -EQ $app |
Remove-AppxProvisionedPackage -Online
$appPath="$Env:LOCALAPPDATA\Packages\$app*"
Remove-Item $appPath -Recurse -Force -ErrorAction 0
}
}
Else {Write-Host "Request cancelled - apps not removed" -f yellow}
If (-not $runAll) {pressAnyKey}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function runDISM
# This function runs DISM /online /Cleanup-Image /StartComponentCleanup /ResetBase
{
askQuestion "Run DISM /online /Cleanup-Image /StartComponentCleanup /ResetBase?"
Switch ($prompt)
{ 0 {DISM /online /Cleanup-Image /StartComponentCleanup /ResetBase}
1 {Write-Host "Request cancelled - DISM not run" -f yellow}
}
If (-not $runAll) {pressAnyKey}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function sysProtection
# This function turns of system protection and therefore removes all restore points. Space is only reclaimed after reboot.
{ $IsSystemRestoreEnabled=Get-WmiObject -Namespace 'root\default' -Class SystemRestoreConfig | ForEach-Object {$_.RPSessionInterval}
If (-not $IsSystemRestoreEnabled) {Write-Host 'System restore already disabled'; Sleep 1}
Else {
askQuestion "Turn off System Protection?"
Switch ($prompt)
{ 0
{ Disable-ComputerRestore -drive "C:\"
Write-Host "System Protection turned off" -f cyan
Write-Warning "System configuration turned off. Restore point storage will be reclained after reboot."
$rebootRequired=$true
If (-not $runAll) {bootRequired}
}
1 {Write-Host "Request cancelled - System Restore not changed" -f yellow}
}
If (-not $runAll) {pressAnyKey}
}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function powercfgOff
# This function sets powercfg -h off to turn off hibernation. C:\hiberfil.sys is deleted after reboot.
{ $IsHibernateEnabled=Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Power -name HibernateEnabled | ForEach-Object {$_.HibernateEnabled}
If (-not $IsHibernateEnabled) {Write-Host 'Hibernation already disabled'; Sleep 1}
Else {
askQuestion "Turn off hibernation?"
Switch ($prompt)
{ 0
{ powercfg -h off
Write-Host "Hibernation turned off" -f cyan
Write-Warning "Powercfg configuration changed. The computer must be restarted for the changes to take effect."
$rebootRequired=$true
If (-not $runAll) {bootRequired}
}
1 {Write-Host "Request cancelled - Hibernation not changed" -f yellow}
}
If (-not $runAll) {pressAnyKey}
}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function pageFile
# This function sets pagefile to the smallest size that will still allow system dumps to be produced (200MB) If currently set to AutomaticManaged.
# This size is hard coded below.
{ $IsAutomaticManagedPagefile=Get-WmiObject -Class Win32_ComputerSystem |ForEach-Object{$_.AutomaticManagedPagefile}
$PageFileMaximumSize = Get-WmiObject Win32_PageFileSetting |ForEach-Object{$_.MaximumSize}
If ($IsAutomaticManagedPagefile -or $PageFileMaximumSize -eq 200) {Write-Host 'PageFile Size already set'; Sleep 1}
Else {
askQuestion "Set minimum sized (200MB) page file?"
Switch ($prompt)
{ 0
{ Function Set-PageFileSize
{ Param($DL,$InitialSize,$MaximumSize)
# copied this function from:
# https://gallery.technet.microsoft.com/scriptcenter/Script-to-configure-e8d85fee
#The AutomaticManagedPagefile property determines whether the system managed pagefile is enabled.
#This capability is not available on windows server 2003,XP and lower versions.
#Only If it is NOT managed by the system and will also allow you to change these.
$IsAutomaticManagedPagefile=Get-WmiObject -Class Win32_ComputerSystem |ForEach-Object{$_.AutomaticManagedPagefile}
If ($IsAutomaticManagedPagefile)
{
#We must enable all the privileges of the current user before the command makes the WMI call.
$SystemInfo=Get-WmiObject -Class Win32_ComputerSystem -EnableAllPrivileges
$SystemInfo.AutomaticManagedPageFile=$false
[Void]$SystemInfo.Put()
}
Write-Verbose "Setting pagefile on $DL" -cyan
#configuring the page file size
$PageFile=Get-WmiObject -Class Win32_PageFileSetting -Filter "SettingID='pagefile.sys @ $DL'"
Try
{ If ($PageFile -ne $null) {$PageFile.Delete()}
Set-WmiInstance -Class Win32_PageFileSetting -Arguments @{name="$DL\pagefile.sys"; InitialSize=0; MaximumSize=0} `
-EnableAllPrivileges |Out-Null
$PageFile=Get-WmiObject Win32_PageFileSetting -Filter "SettingID='pagefile.sys @ $DL'"
$PageFile.InitialSize=$InitialSize
$PageFile.MaximumSize=$MaximumSize
[Void]$PageFile.Put()
Write-Host "Execution Results: Set page file size on ""$DL"" successful." -f cyan
Write-Warning "Pagefile configuration changed on computer '$Env:COMPUTERNAME'. The computer must be restarted for the changes to take effect."
$rebootRequired=$true
If (-not $runAll) {bootRequired}
}
Catch {Write-Host "Execution Results: No Permission - Failed to set page file size on ""$DL""" -f red}
}
#************************* GO ********************************************************************************#
Set-PageFileSize -DL "C:" -InitialSize 200 -MaximumSize 200
# display current page file size information
Get-WmiObject -Class Win32_PageFileSetting -EnableAllPrivileges|Select-Object Name, `
@{Name="InitialSize(MB)";Expression={If ($_.InitialSize -eq 0){"System Managed"}Else{$_.InitialSize}}}, `
@{Name="MaximumSize(MB)";Expression={If ($_.MaximumSize -eq 0){"System Managed"}Else{$_.MaximumSize}}}| `
Format-Table -AutoSize
}
1 {Write-Host "Request cancelled - page file unchanged" -f yellow}
}
If (-not $runAll) {pressAnyKey}
}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function runDefrag
# This function calls defgag.exe which will either defragment, trim or optimize any attatched drives depending on their type (SSD, HDD, VHD)
{
askQuestion "Run Defrag/Trim?"
Switch ($prompt)
{ 0
{ $Command="$env:windir\System32\defrag.exe"
$Parms="/c /h /o"
$Prms=$Parms.Split(" ")
& "$Command" $Prms
}
1 {Write-Host "Request cancelled - Defrag/Trim not run" -f yellow}
}
If (-not $runAll) {pressAnyKey}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function ShrinkVM
# This function calls defgag.exe /x which will either consolidate free space and then run sdelete
# Should only run this in VM - not on host.
{
askQuestion "Run Defrag & sdelete?"
Switch ($prompt)
{ 0
{ $Command="$env:windir\System32\defrag.exe"
$Parms="C: /h /x"
$Prms=$Parms.Split(" ")
& "$Command" $Prms
$Command="$env:windir\System32\defrag.exe"
$Parms="C: /h /o"
$Prms=$Parms.Split(" ")
& "$Command" $Prms
$Command=$sdeletePath
$Parms="C: /z"
$Prms=$Parms.Split(" ")
& "$Command" $Prms
}
1 {Write-Host "Request cancelled - Defrag not run" -f yellow}
}
If (-not $runAll) {pressAnyKey}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function DrawMenu
# supportfunction to the Menu function below
{ param ($menuItems, $menuPosition, $menuTitel)
$fcolor="Green"
$bcolor="Black"
$l=$menuItems.length + 1
cls
$menuwidth=$menuTitel.length + 4
Write-Host "`t" -NoNewLine
Write-Host ("*" * $menuwidth) -fore $fcolor -back $bcolor
Write-Host "`t" -NoNewLine
Write-Host "* $menuTitel *" -fore $fcolor -back $bcolor
Write-Host "`t" -NoNewLine
Write-Host ("*" * $menuwidth) -fore $fcolor -back $bcolor
Write-Host ""
Write-debug "L: $l MenuItems: $menuItems MenuPosition: $menuposition"
for ($i=0; $i -le $l;$i++)
{ Write-Host "`t" -NoNewLine
If ($i -eq $menuPosition)
{ Write-Host "$($menuItems[$i])" -fore $bcolor -back $fcolor
}
Else
{ Write-Host "$($menuItems[$i])" -fore $fcolor -back $bcolor
}
}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function Menu
# Generate a small "DOS-like" menu.
# Choose a menuitem using up and down arrows, select by pressing ENTER
{ param ([array]$menuItems, $menuTitel="MENU")
$vkeycode=0
$pos=0
DrawMenu $menuItems $pos $menuTitel
While ($vkeycode -ne 13)
{ $press=$host.ui.rawui.readkey("NoEcho,IncludeKeyDown")
$vkeycode=$press.virtualkeycode
Write-host "$($press.character)" -NoNewLine
If ($vkeycode -eq 38) {$pos--}
If ($vkeycode -eq 40) {$pos++}
If ($pos -lt 0) {$pos=$menuItems.length -1}
If ($pos -ge $menuItems.length) {$pos=0}
DrawMenu $menuItems $pos $menuTitel
}
Write-Output $($menuItems[$pos])
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function mainMenu
# This function displays main menu and calls relevant function (or all of them by calling run-All).
# If called in quiet (batch) mode the menu is not displayed.
{ If ($quiet) {run-All}
Else {
Clear-Host
$options=
"ALL",
"Disk Cleanup",
"Clear ""SoftwareDistribution\Downloads""",
"Clear ""Temp"" files",
"Remove modern apps",
"DISM",
"Turn off System Protection",
"Turn off hibernation",
"Set pageFile to 200MB",
"Compact OS",
"Compact other directories",
"Defrag",
"Prepare VM for Shrinking",
"EXIT"
$selection=Menu $options "CHOOSE YOUR COMMAND:"
Switch ($selection)
{ "ALL"{run-All; break}
"Disk Cleanup" {DiskCleanup; break}
"Clear ""SoftwareDistribution\Downloads""" {clearDownloads; break}
"Clear ""Temp"" files" {clearTemp}
"Remove modern apps" {removeApps; break}
"DISM" {runDISM;break}
"Turn off System Protection" {sysProtection; break}
"Turn off hibernation" {powercfgOff; break}
"Set pageFile to 200MB" {pageFile; break}
"Compact OS" {compactOS; break}
"Compact other directories" {compactOther; break}
"Defrag" {runDefrag; break}
"Prepare VM for Shrinking" {ShrinkVM; break}
"EXIT" {exit}
}
}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
function run-All
# This function runs all all functions. If interactive it returns to main menu. In quiet (batch) mode it exits after completion.
{ askQuestion "Run everything without prompting?" 1 1
Switch ($prompt)
{ 0 {
$runAll=$true
sysProtection
powercfgOff
pageFile
bootrequired
DiskCleanup
removeApps
clearDownloads
clearTemp
runDISM
compactOS
compactOther
runDefrag
if ($thisIsVirtualMachine) {ShrinkVM}
$runAll=$false
}
1 {Write-Host "Request cancelled" -f yellow}
}
If ($quiet) {exit}
Else {pressAnyKey}
}
#------------------------------------------------------------------------------------------------------------------------------------------------------
# GO!!!
#------------------------------------------------------------------------------------------------------------------------------------------------------
#Check VM identification is working
If ($thisIsVirtualMachine) {askQuestion "This is a $Manufacturer VM right?"}
Else {askQuestion "This $Manufacturer is not a VM right?"}
Switch ($prompt) {1 {Write-Host "OK Request cancelled " -f yellow; Sleep 1; exit}}
# Now run main loop
while($true) {mainMenu}