Maintenance.psm1
|
# IMPORTANT: THIS SCRIPT IS A CONCEPT AND IS INCOMPLETE! # Aim: Periodically run script and automatically report any concerns to helpdesk via email. # Bot: Intergrate with SlackBot for self-help where possible. Could use multilpe functions. # Tips: If you remove-module, then try to install-module and it doesnt appear, remove remains of old module from Program Files(86) # Actions: User prompt | Self-elevates PowerShell | Gathers admin credentials | Starts reporting | Updates modules | Creates restore point | Backups .pst files | Queiries packages | Queiries domain | Sets active hours | Disable fast boot | Remove office activiation key | Clear system caches | Delete old files | Empty recycle bin | Gathers CPU usage | Gathers available RAM | Checks defrag percentage | Queries device serial | Queries asset tag | Checks OS build number | Checks total disk space | Checks system temperature | Queries dhcp | Checks bitlocker encryption | Queries Anti-Virus | Queries Trusted Platform Module | Queries Access Control Level | Checks Secure Boot | Runs DISM | Queries software | Checks timezone | Checks system language | Tests gateway | Queries DNS | Queries open ports | Queries mapped drives | Queires system users | Queries drivers | Checks battery status | Checks for critical logs | Runs System File Checker | Updates Group Policy | Queries default printer | Checks system uptime | Enables maximum performance for wireless adapters | Disables monitor timeout | Disables disk timeout | Disables standby timeout | Measure script speed | Sends report to helpdesk if issues detected | Restart system. function Run_Maintenance { # User Prompt. $continue = (Read-Host -p "WARNING: IF YOU'RE UNSURE WHAT THIS SCRIPT DOES, THEN REFRAIN FROM USING IT! Press any button to execute or X to cancel") if ($continue -eq 'X') { return } # Self-elevate. if (-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 } } # Gets credentials. $credentials = (Get-Credential) if ($credentials -eq $null) {exit} # Start Report. #$report = @() # Update Modules. $modules = (Get-Module | Select-Object 'Name') foreach ($module in $modules) { Update-Module -Name $module } # Create Restore Point. $date = (Get-Date) $LastPoint = (Get-ComputerRestorePoint -LastStatus) if ($LastPoint.CreationTime -le $date) { Checkpoint-Computer -Description $date -RestorePointType MODIFY_SETTINGS } else {continue} # Outlook PST Backup. (Need file server address) #Copy-Item "C:\Outlook_Files\*.pst" "\\fileserver\temp-backups\pst\" # Query Packages. (Need file server address) (NuGet + PowerShellGet) #$CurrentPackages = (get-packageprovider) #$packages = (\\fileserver\csv\packages.csv) #Need CSV file for package names #foreach ($package in $packages) #{ #if ($package.Name -eq $CurrentPackages) #{continue} #else #{ # Install-PackageProvider -Name $package.Name -Force #} #} # Query Domain. (Need domain name & domain controllers name) #$domain = 'domain.net' #$DomainChecker = (Get-CimInstance -ClassName Win32_ComputerSystem | select domain) #if ($DomainChecker -eq $domain) #{continue} #else #{Add-Computer -DomainName $domain -Server 'domain.net\DC01'} # Set Active Hours. $start = '9' $finish = '9' $HoursStart = (Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings -Name ActiveHoursStart) $HoursEnd = (Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings -Name ActiveHoursEnd) if (($HoursStart -eq '9') -and ($HoursEnd -eq '9')) {continue} else { New-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings -Name ActiveHoursStart -Value $start -PassThru New-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings -Name ActiveHoursEnd -Value $finish -PassThru } #Disable Fast Boot (Add query) REG ADD "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Power" /v HiberbootEnabled /t REG_DWORD /d "0" /f #New-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Power -Name HiberbootEnabled -Value '0' -PassThru #Office Activiation Fix (Add query or all users will need to login to one of the Microsoft Office applications.) Remove-Item HKLM:SOFTWARE\Microsoft\Office\10.0, HKLM:SOFTWARE\Microsoft\Office\12.0, HKLM:SOFTWARE\Microsoft\Office\15.0, HKLM:SOFTWARE\Microsoft\Office\16.0 -Confirm:$false -Force # Clear Caches. (Add statement to skip showing errors that relate to files being used by another process) $user= ((Get-WMIObject -ClassName Win32_ComputerSystem).PrimaryOwnerName) Remove-Item -Path "C:\Users\$user\AppData\Local\Temp\*" -Force -Recurse Remove-Item -Path "C:\Users\$user\AppData\Local\Microsoft\Windows\Explorer\*" -Force -Recurse Remove-Item -Path "C:\Users\$user\AppData\Roaming\Microsoft\Windows\Recent\*" -Force -Recurse Remove-Item -Path "C:\Windows\Temp\*" -Force -Recurse Remove-Item -Path "C:\Windows\prefetch\*" -Force -Recurse Remove-Item -Path "C:\Windows\SoftwareDistribution\*" -Force -Recurse Clear-DnsClientCache # Deletes files and folders within the downloads folder, older than 30 days. $age = (Get-Date).AddDays(-30) Get-ChildItem 'C:\Users\$user\Downloads\*' -Recurse -File | ForEach-Object{ if ($_.CreationTime -le $age){ Remove-Item $_.fullname -Force -Verbose }else{ continue } } #Empty Recycle Bin Clear-RecycleBin -Force #CPU Usage $pro = ((Get-Counter '\Processor(_Total)\% Processor Time').CounterSamples.CookedValue) #Available RAM $mem = ((Get-Counter '\Memory\Available MBytes').CounterSamples.CookedValue) #Check Drive (GETTING ERROR: Line 63) (Need it to check post defrag report and gather results from that. -replace 'Toalfrgmentdspac', '%') #$frag = Optimize-Volume -DriveLetter C -Analyze -Verbose 4>&1 #$frag | select-string 'Total fragmented space' #if ($frag -ge '10') #{ #Optimize-Volume -DriveLetter C -Defrag -Verbose #} #elseif ($frag -le '10') #{ #continue #} # Check Serials. (Need file server address) #$Serials = Import-Csv -Path '\\fileserver\csv\serials.csv' $SerialNo = (Get-CimInstance -ClassName CIM_BIOSElement | select 'SerialNumber') # Check Asset TAGs. (Need file server address) #$SysDetails = (\\fileserver\csv\) $name = ($env:computername) $tag = (Get-CimInstance -ClassName CIM_Chassis | select 'SMBIOSAssetTag') $descritpion = (Get-WmiObject -Class Win32_OperatingSystem | Select 'Description') #Check Build (How to read specific data from json) #$build = (Get-CimInstance -ClassName CIM_OperatingSystem | select 'BuildNumber', 'Version') #$Response = (Invoke-WebRequest -URI https://learn.microsoft.com/en-us/windows/release-health/windows11-release-informa) # Disk Space. $DiskSpace = (Get-WmiObject -Class Win32_logicalDisk | Where-Object {$_.DeviceID -eq 'C:'}) $FreeSpace = ($DiskSpace.FreeSpace / $DiskSpace.Size) #Get temperature (INCOMPLETE!) #$t = (Get-WmiObject MSAcpi_ThermalZoneTemperature -Namespace "root/wmi") #$returntemp = @() #foreach ($temp in $t.CurrentTemperature) #{ # $currentTempKelvin = $temp / 10 # $currentTempCelsius = $currentTempKelvin - 273.15 # $returntemp += $currentTempCelsius.ToString() #} #return $returntemp #$temp = Get-Temperature #Query if DHCP enabled. $LinkStatus = (Get-NetAdapter | Where-Object -FilterScript {$_.Status -Eq "Up"}) $adapters = (Get-NetIPConfiguration -Detailed | Select-Object InterfaceAlias, @{N="DHCP";E={$_.NetIPv4Interface.DHCP}}) foreach ($adapter in $adapters) { if ($dhcp.DHCP -eq 'Enabled') {continue} elseif ($dhcp.DHCP -eq 'Disabled') { Set-NetIPInterface -dhcp --Enabled $LinkStatus.ifIndex #Might need a ForEach statement for each interface number } } #Check drive encryption status $lock = (Get-BitLockerVolume -MountPoint "C:" | Select-Object volumetype, protectionstatus -Verbose) #Query AV #Updating Antimalware Definitions Update-MpSignature -UpdateSource MicrosoftUpdateServer #Setting configuration to check for definition updates daily. Set-MpPreference -SignatureScheduleDay Everyday #Getting status of Antimalware Protection software $AV = (Get-MpComputerStatus) #Starting quick scan Start-MpScan -ScanType QuickScan #Removing any active threats Remove-MpThreat #Query TPM $tpm = (get-tpm | Select-Object 'TpmEnabled') if ($tpm -eq $true) {continue} elseif ($tpm -eq $false) {Enable-TpmAutoProvisioning #Dont think this is the right command to enable TPM} } #Query ACL (Need file server address) $acls = (get-acl) #$OwnerAccess = (#csv list) #Check if Secure Boot is active $secboot = (Confirm-SecureBootUefi) #DISM will connect to Windows Update online to download and replace damaged files if necessary. Repair-WindowsImage -Online -RestoreHealth $repair = (Repair-Volume -DriveLetter C -Scan) # Software #$AppX = (Get-AppxPackage) #if ($AppX.Name -eq 'Microsoft.DesktopAppInstaller') #{continue} #else #{Add-AppxPackage -RegisterByFamilyName -MainPackage Microsoft.DesktopAppInstaller_8wekyb3d8bbwe} ##Update source repos winget source update ##Search for software and install if not present. #$SoftwarePacks = 'Microsoft Update Health Tools', 'Microsoft Edge' #$searches = (winget search -q $SoftwarePacks) #foreach ($search in $searches) #{ # if ($searches -eq $search) # {continue} # else # { # $install = $SoftwarePacks # winget install -q $install # } #} ##Upgrade all packages to latest version. winget upgrade --all --include-unknown --verbose-logs # Check timezone/language $lang = 'en-GB' $country = 'United Kingdom' $timezone = 'GMT Standard Time' $timezoneId = (get-timezone | Select-Object Id) $WinSysLocale = (get-WinSystemLocale | Select-Object Name) $WinUserLangList = (get-WinUserLanguageList | Select-Object LanguageTag) $HomeLocation = (get-WinHomeLocation | Select-Object 'HomeLocation') if ($timezoneId -eq $timezone) {continue} else { #Set the timezone Set-TimeZone "$timezone" get-winsystemlocale get-winhomelocation } if ($WinSysLocale -eq $lang) {continue} else { #Set system local Set-WinSystemLocale $lang } if ($WinUserLangList -eq $lang) {continue} else {#Override language list with just English GB $1 = New-WinUserLanguageList $lang $1[0].Handwriting = 1 Set-WinUserLanguageList $1 -force Set-WinUILanguageOverride -Language $lang } if ($HomeLocation -eq $country) {continue} else { #Set home location to United Kingdom Set-WinHomeLocation 0xf2 } #Test gateway connection $DefaultGateway = get-netipconfiguration -Detailed $Addresses = $DefaultGateway.IPv4DefaultGateway | Select-Object NextHop $Ping = (Test-Connection $Addresses -Count 1 ) #Check DNS settings $DNS1 = '9.9.9.11' $DNS2 = '142.112.112.11' $DNS = Get-DnsClientServerAddress if ($DNS -eq $DNS1, $DNS2) {continue} else {Set-DnsClientServerAddress -InterfaceAlias WiFi -ServerAddresses ($DNS1,$DNS2)} #Query open ports (Need file server address) #$ports = (Get-NetTCPConnection) #$ActivePorts = ('80') #Create csv of active ports #Query mapped drives (Need file server address) #$drives = (Get-PSDrive) #$MappedDrives = ('\\serveraddress\lists\.csv') #Create csv of active ports #foreach ($drive in $drives) #{ #if ($drive.Provider -eq 'FileSystem' -and $drive.Root -eq $MappedDrives.Root) #{continue} #elseif ($drive.Provider -eq 'FileSystem' -and $drive.Root -ne $MappedDrives.Root) #{ #New-PSDrive -Persist -Name "$MappedDrives.Name" -PSProvider "FileSystem" -Root "$MappedDrives.Root" #} #} #Query system users (Need file server address) (INCOMPLETE!) #$SysUsers = (net user) #$System = (hostname) #$SysUserList = (#csv) #Check and display outdated drivers $date = (Get-Date) $drivers = (Get-WindowsDriver -Online -All | select 'Driver', 'Date', 'Version') # Check battery status and remaining charge $battery = (Get-CimInstance -ClassName CIM_Battery | Select-Object 'Status') #Check for Critical events $LogDate = (get-date) - (New-TimeSpan -Day 1) $logs = (get-winevent | Where-Object {$_.LevelDisplayName -eq $LogDate, 'Critical'}) #SFC sfc /scannow #Force Group Policy Update GPUpdate /Force #Find default printer $printers = Get-WmiObject -Query " SELECT * FROM Win32_Printer WHERE Default=$true" foreach ($printer in $printers) { #Restarting spooler Restart-Service -Name Spooler #Testing default printer {$printers.PrintTestPage()} } #Check Uptime. $uptime = Get-Uptime if ($uptime -ge 1) { #Hibernate timeout powercfg /hibernate off } #Wireless Adapter Power Mode: On battery - Maximum Performance powercfg /SETDCVALUEINDEX SCHEME_CURRENT 19cbb8fa-5279-450e-9fac-8a3d5fedd0c1 12bbebe6-58d6-4636-95bb-3217ef867c1a 0 -Verbose #Wireless Adapter Power Mode: Plugged in - Maximum Performance powercfg /SETACVALUEINDEX SCHEME_CURRENT 19cbb8fa-5279-450e-9fac-8a3d5fedd0c1 12bbebe6-58d6-4636-95bb-3217ef867c1a 0 -Verbose #Monitor timout powercfg /change monitor-timeout-ac 0 powercfg /change monitor-timeout-dc 0 #Disk timeout powercfg /change disk-timeout-ac 0 powercfg /change disk-timeout-dc 0 #Standby timeout powercfg /change standby-timeout-ac 0 powercfg /change standby-timeout-dc 0 #Measure how long it takes script to execute #$script = ('\\fileserver\Maintenance.ps1') #$scripts = (Get-Content $script) #$speed = ((Measure-Command {$scripts}).TotalSeconds) #Send email to admin if any issues occur. () if ($report -eq ($frag -ge '10') -xor (($tag -ne '') -and ($name -ne '') -and ($description -ne '')) -xor ($SerialNo -ne $serial) -xor ($acls.Owner -ne '$OwnerAccess.Owner' -xor $acls.Access -ne '$OwnerAccess.Access') -xor ($ports.State -eq 'Established Internet' -and $ports.LocalPort -ne $ActivePorts) -xor ($SysUsers -and $System -ne $SysUserList.User -and $SysUserList.System) -xor ($speed -ge '1') -xor ($SerialNo -ne '$serial') -xor ($drivers.Date -le $date) -xor ($LastPoint -eq 'The last attempt to restore the computer failed.') -xor ($uptime -ge 100) -xor ($battery -eq 'BAD') -xor ($DomainChecker -eq 'WORKGROUP') -xor ($Ping.Timeout -ge '40000') -xor ($secboot -eq $false) -xor ($uptime -ge '24:00:00.0000000') -xor ($FreeSpace -le '0.100000000000000') -xor ($pro -ge '99.0') -xor ($mem -le '1000') -xor ($temp -ge '60.00') -xor ($lock.ProtectionStatus -eq 'Off') -xor ($AV.AntivirusEnabled -eq $false) -xor ($repair -eq 'ErrorsFound') -xor ($log.LevelDisplayName -eq 'Critical') -xor ($tag -ne '') -xor ($name -ne '') -xor ($description -ne '')) { Export-Csv -Path 'C:\maintenance_report_$date.csv' -NoTypeInformation -Append -Force Send-MailMessage -From 'Automator <automator@domain.co.uk>'-To 'Help Desk <healpdesk@domain.co.uk>' -Subject 'MAINTENNCE ISSUE: Report for $user' -UseSsl -Credential $credentials -SmtpServer smtp.domain.co.uk -Port 587 -Priority High -DeliveryNotificationOption OnFailure -Attachments 'C:\maintenance_report_$date.csv' } # System Restart #Restart-Computer } Export-ModuleMember -Function 'Run_Maintenance' -Alias 'runmain' |