major update
This commit is contained in:
@@ -1,32 +0,0 @@
|
||||
#Requires -Version 3.0
|
||||
|
||||
param([string]$User)
|
||||
|
||||
## Install ExchangeOnlineManagement module if it doesn't already exist
|
||||
If ( !(Get-Module -ListAvailable -Name ExchangeOnlineManagement) )
|
||||
{
|
||||
Try { Install-Module -Name ExchangeOnlineManagement }
|
||||
Catch { Write-Output $_.Exception.Message ; Exit }
|
||||
}
|
||||
Import-Module ExchangeOnlineManagement
|
||||
|
||||
Connect-ExchangeOnline -UserPrincipalName $User -ShowProgress $true
|
||||
|
||||
|
||||
#$Groups = Get-UnifiedGroup -ResultSize Unlimited
|
||||
#$Groups | ForEach-Object {
|
||||
# $group = Get-UnifiedGroupLinks -Identity $_.Name -LinkType Members -ResultSize Unlimited
|
||||
# $group | ForEach-Object {
|
||||
# New-Object -TypeName PSObject -Property @{
|
||||
# Group = $group.DisplayName
|
||||
# Member = $_.Name
|
||||
# EmailAddress = $_.PrimarySMTPAddress
|
||||
# RecipientType= $_.RecipientType
|
||||
# }
|
||||
# }
|
||||
#} | Export-CSV “${Env:UserProfile}\Desktop\group-export.csv" -NoTypeInformation -Encoding UTF8
|
||||
|
||||
|
||||
|
||||
|
||||
Disconnect-ExchangeOnline
|
||||
@@ -1,32 +0,0 @@
|
||||
## Stop a process
|
||||
Function End-Process
|
||||
{
|
||||
param(
|
||||
[Parameter(Mandatory=$true,ValueFromPipeline=$true)][string[]]$Name,
|
||||
[Parameter(Mandatory=$false)][switch]$Match=$false,
|
||||
[Parameter(Mandatory=$false)][switch]$Force
|
||||
)
|
||||
ForEach ( $item in $Name ) {
|
||||
$process = Get-Process -Name $item -ErrorAction SilentlyContinue
|
||||
If ( !($process) ) {
|
||||
LogMsg "Cannot find the process '${item}'"
|
||||
If ( $Match ) {
|
||||
LogMsg "Attempting to match '${item}' to all running process names"
|
||||
ForEach ( $proc in ((Get-Process | Where { $_.Name -match $item }).Name) ) {
|
||||
If ( $Force ) { End-Process -Name $proc -Force } Else { End-Process -Name $proc }
|
||||
}
|
||||
}
|
||||
}
|
||||
Else {
|
||||
$name = $process.Name
|
||||
If ( $Force ) {
|
||||
LogMsg "Forcefully stopping '${name}' process"
|
||||
Stop-Process $process -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
Else {
|
||||
LogMsg "Attempting to gracefully close '${name}' process"
|
||||
$process.CloseMainWindow() | Out-Null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
#Requires -Version 3.0
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
This script will mount an ISO file and share it on the network.
|
||||
.DESCRIPTION
|
||||
The ISO file can be a local path or fetched from a URL. The share this script creates will allow 'Everyone' read-only access.
|
||||
.PARAMETER ShareName
|
||||
This is the name of the Windows share that will be created.
|
||||
.PARAMETER ISOPath
|
||||
The full absolute path to the ISO. This can be a local path or a URL.
|
||||
.PARAMETER NoShare
|
||||
Will prevent the script from creating a network share. It will return only the drive letter for the mounted ISO file.
|
||||
.PARAMETER Persist
|
||||
Will cause the ISO to remain mounted even after rebooting the endpoint.
|
||||
.PARAMETER Redownload
|
||||
If -ISOPath is a URL, this parameter will delete an existing ISO file with the same name and download a fresh copy.
|
||||
.PARAMETER Remove
|
||||
Will remove the network share, and dismount the ISO file. This will not delete the ISO file.
|
||||
.INPUTS
|
||||
None. This script does not accept pipeline input.
|
||||
.OUTPUTS
|
||||
This script will output only a string containing the status of the shared ISO file.
|
||||
.EXAMPLE
|
||||
.\Create-ISOShare.ps1 -ShareName 'Win10Setup' -ISOPath 'D:\path\to\windows_10_setup.iso'
|
||||
.EXAMPLE
|
||||
.\Create-ISOShare.ps1 -ShareName 'Win10Setup' -ISOPath 'D:\path\to\windows_10_setup.iso' -Remove
|
||||
.EXAMPLE
|
||||
.\Create-ISOShare.ps1 -ShareName 'Win10Setup' -ISOPath 'https://hosted.net/path/to/windows_10_setup.iso'
|
||||
.EXAMPLE
|
||||
.\Create-ISOShare.ps1 -ISOPath 'https://hosted.net/path/to/windows_10_setup.iso' -NoShare
|
||||
.NOTES
|
||||
This script requires an administrative token to run properly.
|
||||
.LINK
|
||||
https://www.microsoft.com/en-us/software-download/windows10
|
||||
#>
|
||||
|
||||
param(
|
||||
[string]$ShareName,
|
||||
[string]$ISOPath,
|
||||
[switch]$NoShare,
|
||||
[switch]$Persist=$false,
|
||||
[switch]$Redownload,
|
||||
[switch]$Remove
|
||||
)
|
||||
|
||||
## Set the download directory for downloaded ISO file
|
||||
## Note: This is only needed if a URL is passed to -ISOPath
|
||||
$DownloadDirectory = $Env:SYSTEMDRIVE
|
||||
|
||||
## Download the ISO if a URL is specified
|
||||
If ( $ISOPath.StartsWith('http') )
|
||||
{
|
||||
## Get the URL into its own variable
|
||||
$DownloadURL = $ISOPath
|
||||
|
||||
## Get the file name from the URL
|
||||
$filename = Split-Path -Path $DownloadURL -Leaf
|
||||
|
||||
## Set the path to the soon-to-be-downloaded ISO file
|
||||
$ISOPath = "${DownloadDirectory}\${filename}"
|
||||
|
||||
## If $Redownload is specified, delete the ISO so we can redownload it
|
||||
If ( ($Redownload) -and (Test-Path $ISOPath) ) { Remove-Item $ISOPath -Force }
|
||||
}
|
||||
|
||||
## Function to remove the share and dismount the ISO
|
||||
Function Remove-ISOShare
|
||||
{
|
||||
## Remove the share
|
||||
Remove-SMBShare -Name $ShareName -Force -ErrorAction SilentlyContinue
|
||||
|
||||
## Dismount the ISO file
|
||||
If ( Test-Path $ISOPath ) { Dismount-DiskImage -ImagePath $ISOPath -StorageType ISO | Out-Null }
|
||||
}
|
||||
|
||||
## Just remove the share and dismount the ISO if $Remove is specified
|
||||
If ( $Remove ) { Remove-ISOShare }
|
||||
|
||||
## If $Remove is not specified, mount the ISO and create a network share
|
||||
Else
|
||||
{
|
||||
## If $DownloadURL exists and the ISO doesn't, download it
|
||||
If ( ($DownloadURL) -and (!(Test-Path $ISOPath)) )
|
||||
{
|
||||
(New-Object System.Net.WebClient).DownloadFile($DownloadURL, $ISOPath)
|
||||
}
|
||||
|
||||
## Make sure we remove the share and mounted ISO, since both might already exist
|
||||
Remove-ISOShare
|
||||
|
||||
## Mount the ISO and get the drive letter
|
||||
$MountResult = Mount-DiskImage -ImagePath $ISOPath -StorageType ISO -Access ReadOnly -PassThru
|
||||
$DriveLetter = ($MountResult | Get-Volume).DriveLetter
|
||||
|
||||
## Create network share
|
||||
If (! ($NoShare) )
|
||||
{
|
||||
New-SMBShare -Name $ShareName -Path "${DriveLetter}:\" -ContinuouslyAvailable:$Persist -ReadAccess 'Everyone' | Out-Null
|
||||
}
|
||||
|
||||
## Get the share path (or local path if it isn't shared)
|
||||
If ( $NoShare ) { $SharePath = "${DriveLetter}:\" }
|
||||
Else { $SharePath = "\\${Env:COMPUTERNAME}\${ShareName}" }
|
||||
If ( Test-Path $SharePath )
|
||||
{
|
||||
## Return the full share path
|
||||
Write-Output "ISO Share Path:`n`r${SharePath}"
|
||||
|
||||
## Return the full command to upgrade Windows 10 using this share
|
||||
Write-Output "Windows 10 upgrade command:`n`r${SharePath}\setup.exe /auto upgrade /dynamicupdate disable /showoobe none /quiet"
|
||||
|
||||
} Else { Write-Output "ISO could not be shared." }
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
@echo off
|
||||
|
||||
rem Print a quick help message if nothing is passed to this script
|
||||
if "%~1"=="" (
|
||||
set SCRIPT=%~0
|
||||
echo Create local administrator user account
|
||||
echo.
|
||||
echo Usage:
|
||||
echo %SCRIPT% -u [username] -p [password] -n [display name]
|
||||
echo.
|
||||
echo Example:
|
||||
echo %SCRIPT% -u myadmin -p p@ssw0rd -n "My Admin"
|
||||
goto end
|
||||
)
|
||||
|
||||
rem Get the params passed in on the command line
|
||||
:parse
|
||||
if "%~1"=="" goto endparse
|
||||
if "%~1"=="-u" set USER=%2
|
||||
if "%~1"=="-p" set PASS=%2
|
||||
if "%~1"=="-n" set NAME=%2
|
||||
shift
|
||||
shift
|
||||
goto parse
|
||||
:endparse
|
||||
|
||||
rem Make sure we don't run this on a domain controller
|
||||
wmic os get producttype | find "2" 1>nul 2>nul && goto domain-controller
|
||||
|
||||
rem Make sure the specified user doesn't already exist
|
||||
net user | find /i "%USER%" >nul || goto create-admin
|
||||
goto reset-password
|
||||
|
||||
rem Create a new user with the specified name and password
|
||||
:create-admin
|
||||
net user %USER% %PASS% /add /fullname:"%NAME%" /active:yes /expires:never /passwordreq:yes /times:all
|
||||
goto make-admin
|
||||
|
||||
rem If the specified user already exists, reset it's password
|
||||
:reset-password
|
||||
net user %USER% %PASS% /fullname:"%NAME%" /active:yes /expires:never /passwordreq:yes /times:all
|
||||
|
||||
rem Add the specified user to the local Administrators group if it isn't already a member
|
||||
rem Note: if you're using Restricted Groups in an Active Directory GPO, this change may be overwritten at the next policy application
|
||||
net localgroup Administrators | find /i "%USER%" >nul || goto make-admin
|
||||
goto remove-logon
|
||||
:make-admin
|
||||
net localgroup Administrators %USER% /add
|
||||
|
||||
rem Remove user from logon screen
|
||||
:remove-logon
|
||||
if exist "%ProgramFiles(x86)%" (
|
||||
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" /v "%USER%" /t REG_DWORD /d 0 /f /reg:64 >nul
|
||||
goto finish-remove-logon
|
||||
)
|
||||
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" /v "%USER%" /t REG_DWORD /d 0 /f >nul
|
||||
:finish-remove-logon
|
||||
goto end
|
||||
|
||||
:domain-controller
|
||||
rem This computer is a domain controller. The local %USER% account cannot be created.
|
||||
|
||||
:end
|
||||
@@ -1,57 +0,0 @@
|
||||
## Set the MSP name and environment variable
|
||||
$MSPName = "Emberkom"
|
||||
|
||||
## Set the name of the module to deploy
|
||||
$ModuleName = "PSModule"
|
||||
|
||||
## Define base URL for downloading module file
|
||||
$ModuleURL = "https://dev.emberkom.com/emberkom/management-scripts/raw/branch/master/${ModuleName}/${ModuleName}.psm1"
|
||||
|
||||
## Setup the MSP management directories
|
||||
If ( Test-Path ${Env:ProgramData} )
|
||||
{ $MSPRoot = "${Env:ProgramData}\${MSPName}" } Else { $MSPRoot = "${Env:SystemDrive}\${MSPName}" }
|
||||
$MSPScripts = "${MSPRoot}\Scripts"
|
||||
$MSPTools = "${MSPRoot}\Tools"
|
||||
$MSPLogs = "${MSPRoot}\Logs"
|
||||
|
||||
## Set the path to this module and make the directory for it
|
||||
$ModulePath = "${MSPRoot}\Scripts\${ModuleName}"
|
||||
|
||||
## Create the path to the module
|
||||
If ( !(Test-Path $ModulePath) )
|
||||
{
|
||||
Try { New-Item -Path $ModulePath -ItemType Directory -Force | Out-Null }
|
||||
Catch { Write-Output $_.Exception.Message }
|
||||
}
|
||||
|
||||
## Set the environment variable to the module
|
||||
[System.Environment]::SetEnvironmentVariable('MSPPSModule',"${MSPRoot}\Scripts\${ModuleName}",[System.EnvironmentVariableTarget]::Machine)
|
||||
|
||||
## Make sure all the management directories exist
|
||||
If ( !(Test-Path $MSPRoot) )
|
||||
{
|
||||
Try { New-Item -Path $MSPRoot -ItemType Directory -Force | Out-Null }
|
||||
Catch { Write-Output $_.Exception.Message }
|
||||
}
|
||||
If ( !(Test-Path $MSPScripts) )
|
||||
{
|
||||
Try { New-Item -Path $MSPScripts -ItemType Directory -Force | Out-Null }
|
||||
Catch { Write-Output $_.Exception.Message }
|
||||
}
|
||||
If ( !(Test-Path $MSPTools) )
|
||||
{
|
||||
Try { New-Item -Path $MSPTools -ItemType Directory -Force | Out-Null }
|
||||
Catch { Write-Output $_.Exception.Message }
|
||||
}
|
||||
If ( !(Test-Path $MSPLogs) )
|
||||
{
|
||||
Try { New-Item -Path $MSPLogs -ItemType Directory -Force | Out-Null }
|
||||
Catch { Write-Output $_.Exception.Message }
|
||||
}
|
||||
|
||||
## Create environment variable for the root MSP directory
|
||||
[System.Environment]::SetEnvironmentVariable('MSPDir',"${MSPRoot}",[System.EnvironmentVariableTarget]::Machine)
|
||||
|
||||
## Download the module file
|
||||
Try { (New-Object Net.WebClient).DownloadFile($ModuleURL, "${MSPRoot}\Scripts\${ModuleName}\${ModuleName}.psm1") }
|
||||
Catch { Write-Output $_.Exception.Message }
|
||||
@@ -1,5 +1,5 @@
|
||||
$RegKey = 'HKCU:SOFTWARE\Microsoft\Windows\CurrentVersion\ImmersiveShell'
|
||||
. 'C:\Users\dyoder\Emberkom\Data\Projects\development\management-scripts\Tools.ps1'
|
||||
|
||||
## Make sure endpoint is running at least Windows 8
|
||||
If ( IsWindowsVersion -ge '6.3' )
|
||||
{
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[switch]$SkipDiskRepair=$true,
|
||||
[switch]$PostRestart=$false
|
||||
)
|
||||
|
||||
## Set the file name for this script when copying to $ScriptDirectory
|
||||
## Note: the .ps1 file extension will be automatically added
|
||||
$ScriptName = "Fix-WindowsHealth"
|
||||
|
||||
## File to log messages into
|
||||
$LogFile = "${MSPLogs}\${ScriptName}.log"
|
||||
|
||||
## Copy script locally and schedule chkdsk at next boot
|
||||
If ( ($PostRestart -eq $false) -and ($SkipDiskRepair -eq $false) ) {
|
||||
|
||||
## Copy this script so it can be run post-reboot
|
||||
If (! (Test-Path $ScriptDirectory) ) { New-Item -Path $ScriptDirectory -ItemType Directory -Force | Out-Null }
|
||||
$ScriptFile = "${ScriptDirectory}\${ScriptName}.ps1"
|
||||
If ( $ScriptFile -ne $MyInvocation.MyCommand.Definition ) {
|
||||
If ( Test-Path $ScriptFile ) {
|
||||
Remove-Item $ScriptFile -Force
|
||||
}
|
||||
Copy-Item -Path $MyInvocation.MyCommand.Definition -Destination $ScriptFile -Force
|
||||
If ( Test-Path $ScriptFile ) {
|
||||
Log $LogFile "Successfully copied running script to: ${ScriptFile}"
|
||||
} Else { Log $LogFile "Failed to copy running script to: ${ScriptFile}" }
|
||||
}
|
||||
|
||||
## Schedule chkdsk for next reboot
|
||||
& cmd.exe /c echo y `| chkdsk.exe /f /r /x
|
||||
Log $LogFile "Scheduled chkdsk.exe for next reboot"
|
||||
|
||||
## Create a RunOnce task to resume this script after the disk has been repaired
|
||||
$command = """%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe"" -ExecutionPolicy Bypass -File ""${ScriptFile}"" -PostRestart"
|
||||
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" -Name $ScriptName -Value $command
|
||||
If ( (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" -Name $ScriptName) ) {
|
||||
Log $LogFile "Successfully scheduled post-reboot task: ${command}"
|
||||
} Else { Log $LogFile "Failed to schedule post-reboot task" }
|
||||
}
|
||||
|
||||
## Get the last log entry from chkdsk
|
||||
If ( $PostRestart ) {
|
||||
|
||||
## Get the last event chkdsk recorded in the Event Log
|
||||
$chkdskmsg = Get-EventLog -LogName 'Application' -Source 'Wininit' -Newest 1 -ErrorAction SilentlyContinue
|
||||
If ( $chkdskmsg ) {
|
||||
|
||||
## Export the chkdsk log to a separate file for review
|
||||
$ChkdskLog = "${LogDirectory}\${ScriptName}-Chkdsk.log"
|
||||
If ( Test-Path $ChkdskLog ) {
|
||||
Remove-Item $ChkdskLog -Force
|
||||
}
|
||||
New-Item -Path $ChkdskLog -ItemType File -Value $chkdskmsg.Message.ToString()
|
||||
If ( Test-Path $ChkdskLog ) {
|
||||
Log $LogFile "Successfully exported chkdsk result"
|
||||
} Else { Log $LogFile "Failed to export chkdsk result" }
|
||||
|
||||
} Else { Log $LogFile "Last chkdsk result could not be obtained" }
|
||||
}
|
||||
|
||||
## Cleanup online image and restore health
|
||||
If ( $PostRestart -or $SkipDiskRepair ) {
|
||||
|
||||
## Run enhanced DISM for Windows 8 and higher assets
|
||||
If ( IsWindowsVersion -ge "6.2" ) {
|
||||
|
||||
$BeginDISMRun = $(Get-Date).AddSeconds(-1)
|
||||
|
||||
## Scan the Windows Component Store for problems
|
||||
Log $LogFile "Beginning Windows Component Store scan"
|
||||
Start-Process "dism.exe" -ArgumentList "/online /cleanup-image /scanhealth" -Wait
|
||||
Log $LogFile "Completed Windows Component Store scan"
|
||||
|
||||
## Check to see if the previous command recorded any problems that need repairing
|
||||
Log $LogFile "Beginning Windows Component Store health check"
|
||||
$CheckHealthOutput = $(dism /online /cleanup-image /checkhealth) | Out-String
|
||||
If ( $CheckHealthOutput -match "repairable" ) {
|
||||
|
||||
Log $LogFile "Completed Windows Component Store health check: Problems found"
|
||||
|
||||
## Repair problems with the Windows Component Store
|
||||
Log $LogFile "Beginning Windows Component Store restoration"
|
||||
Start-Process "dism.exe" -ArgumentList "/online /cleanup-image /restorehealth" -Wait
|
||||
Log $LogFile "Completed Windows Component Store restoration"
|
||||
} Else { Log $LogFile "Completed Windows Component Store health check: No problems found" }
|
||||
|
||||
$EndDISMRun = $(Get-Date).AddSeconds(1)
|
||||
|
||||
## Parse DISM log file for recent activity
|
||||
$DISMLogFile = "${LogDirectory}\${ScriptName}-DISM.log"
|
||||
If ( Test-Path $DISMLogFile ) { Remove-Item $DISMLogFile -Force }
|
||||
New-Item -Path $DISMLogFile -ItemType File
|
||||
Log $LogFile "Beginning Windows Component Store log data collection"
|
||||
Get-Content -Path "${Env:WinDir}\Logs\DISM\dism.log" | Select-String -Pattern '^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})' |
|
||||
% { If ( ((Get-Date $_.Line.Substring(0,19)) -gt $BeginDISMRun) -and ((Get-Date $_.Line.Substring(0,19)) -le $EndDISMRun) ) {
|
||||
Add-Content -Path $DISMLogFile -Value $_.Line
|
||||
}
|
||||
}
|
||||
|
||||
Log $LogFile "Completed Windows Component Store log data collection"
|
||||
|
||||
} Else { Log $LogFile "Online image cleanup and restoration is only supported on Windows 8 and higher" }
|
||||
}
|
||||
|
||||
## Run SFC
|
||||
If ( $PostRestart -or $SkipDiskRepair ) {
|
||||
|
||||
## Start the TrustedInstaller service if it isn't running
|
||||
## Note: this is necessary for the SFC utility to function properly
|
||||
If ( (Get-Service -Name TrustedInstaller).Status -ne "Running" ) {
|
||||
Restart-Service -Name TrustedInstaller -Force
|
||||
Log $LogFile "Started TrustedInstaller service"
|
||||
}
|
||||
|
||||
## Start the SFC utility to check validity of Windows system files
|
||||
Log $LogFile "Beginning SFC scan and fix"
|
||||
|
||||
$BeginSFCRun = $(Get-Date).AddSeconds(-1)
|
||||
Start-Process "sfc" -ArgumentList "/scannow" -Wait
|
||||
$EndSFCRun = $(Get-Date).AddSeconds(1)
|
||||
Log $LogFile "Completed SFC scan and fix"
|
||||
|
||||
## Parse the CBS.log file and export any SFC related messages
|
||||
$SFCLogFile = "${LogDirectory}\${ScriptName}-SFC.log"
|
||||
If ( Test-Path $SFCLogFile ) { Remove-Item $SFCLogFile -Force }
|
||||
New-Item -Path $SFCLogFile -ItemType File
|
||||
Log $LogFile "Beginning SFC log data collection"
|
||||
Get-Content -Path "${Env:WinDir}\Logs\CBS\CBS.log" | Select-String -Pattern '^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}).+\[SR\]' |
|
||||
% { If ( ((Get-Date $_.Line.Substring(0,19)) -gt $BeginSFCRun) -and ((Get-Date $_.Line.Substring(0,19)) -le $EndSFCRun) ) {
|
||||
Add-Content -Path $SFCLogFile -Value $_.Line
|
||||
}
|
||||
}
|
||||
Log $LogFile "Completed SFC log data collection"
|
||||
}
|
||||
|
||||
## Prepare Log File Upload
|
||||
@@ -1,34 +0,0 @@
|
||||
@echo off
|
||||
|
||||
rem ## Scan the Windows Component Store for problems
|
||||
dism /online /cleanup-image /scanhealth >nul
|
||||
|
||||
rem ## Check to see if the previous command recorded any problems that need repairing
|
||||
rem ## If there aren't any problems, jump to the section labeled skip-restorehealth
|
||||
dism /online /cleanup-image /checkhealth | find /i "repairable" >nul || goto :skip-restorehealth
|
||||
|
||||
rem ## If there are problems with the Windows Component Store, repair them
|
||||
rem ## Once the repair operation completes, jump to the section labeled run-sfc
|
||||
dism /online /cleanup-image /restorehealth >nul
|
||||
|
||||
rem ## If the Windows Component Store gets repaired, the Ninja activity feed will
|
||||
rem ## see the following line:
|
||||
echo The component store has been repaired.
|
||||
goto run-sfc
|
||||
|
||||
rem ## This scetion only runs if there aren't any problems to repair
|
||||
:skip-restorehealth
|
||||
|
||||
rem ## If the Windows Component Store is healthy, the Ninja activity feed will
|
||||
rem ## see the following line:
|
||||
echo No component store corruption detected.
|
||||
|
||||
rem ## This section runs the sfc utility
|
||||
:run-sfc
|
||||
|
||||
rem ## Check to see if the TrustedInstaller is running, if not then start it
|
||||
rem ## This avoids a common problem with sfc not starting
|
||||
sc query trustedinstaller | find /i "running" >nul || net start trustedinstaller >nul
|
||||
|
||||
rem ## This will take a while and the output of sfc will be recorded in a text file
|
||||
sfc /scannow > %SystemDrive%\sfcoutput.txt
|
||||
+22
-35
@@ -1,48 +1,35 @@
|
||||
param([switch]$WSUS)
|
||||
## This is the folder we need to rename
|
||||
$TARGET_DIR = "${Env:WinDir}\SoftwareDistribution"
|
||||
|
||||
LogMsg "Fix-WindowsUpdate.ps1"
|
||||
## This is what we're renaming it to
|
||||
$DEST_DIR = "${Env:WinDir}\SoftwareDistribution.old"
|
||||
|
||||
## Delete any existing folder from a previous execution of this script
|
||||
If ( Test-Path "${Env:WinDir}\SoftwareDistribution.old" )
|
||||
{
|
||||
LogMsg "Deleting ""${Env:WinDir}\SoftwareDistribution.old"""
|
||||
Try { Remove-Item "${Env:WinDir}\SoftwareDistribution.old" -Recurse -Force }
|
||||
Catch { LogErr $_.Exception.Message }
|
||||
}
|
||||
LogMsg "Deleting ""${DEST_DIR}"""
|
||||
Try { Remove-Item $DEST_DIR -Recurse -Force -ErrorAction SilentlyContinue }
|
||||
Catch { LogErr $_.Exception.Message }
|
||||
|
||||
## Stop Background Intelligent Transfer Services and Windows Update
|
||||
LogMsg "Stopping BITS service"
|
||||
Try { Stop-Service BITS }
|
||||
Catch { LogErr $_.Exception.Message }
|
||||
LogMsg "Stopping wuauserv service"
|
||||
Try { Stop-Service wuauserv }
|
||||
Catch { LogErr $_.Exception.Message }
|
||||
Control-Service -Stop -Name BITS
|
||||
Control-Service -Stop -Name wuauserv
|
||||
|
||||
## Rename the SoftwareDistribution folder, forcing Windows Update to recreate all metrics and redownload all updates
|
||||
LogMsg "Renaming ""${Env:WinDir}\SoftwareDistribution"" to ""${Env:WinDir}\SoftwareDistribution.old"""
|
||||
Try { Rename-Item -Path "${Env:WinDir}\SoftwareDistribution" -NewName "${Env:WinDir}\SoftwareDistribution.old" -Force }
|
||||
LogMsg "Renaming ""${TARGET_DIR}"" to ""${DEST_DIR}"""
|
||||
Try { Rename-Item -Path $TARGET_DIR -NewName $DEST_DIR -Force }
|
||||
Catch { LogErr $_.Exception.Message }
|
||||
|
||||
## Start Windows Update and Background Intelligent Transfer Services
|
||||
LogMsg "Starting wuauserv service"
|
||||
Try { Start-Service wuauserv }
|
||||
Catch { LogErr $_.Exception.Message }
|
||||
LogMsg "Starting BITS service"
|
||||
Try { Start-Service BITS }
|
||||
Catch { LogErr $_.Exception.Message }
|
||||
Control-Service -Start -Name BITS
|
||||
Control-Service -Start -Name wuauserv
|
||||
|
||||
## Delete SoftwareDistribution.old from this execution of this script
|
||||
If ( Test-Path "${Env:WinDir}\SoftwareDistribution.old" )
|
||||
{
|
||||
LogMsg "Deleting ""${Env:WinDir}\SoftwareDistribution.old"""
|
||||
Try { Remove-Item "${Env:WinDir}\SoftwareDistribution.old" -Recurse -Force }
|
||||
Catch { LogErr $_.Exception.Message }
|
||||
}
|
||||
## Comment this section out if you want to leave the renamed folder there for some reason,
|
||||
## but keep in mind this folder can be very large and takes up a lot of space.
|
||||
LogMsg "Deleting ""${DEST_DIR}"""
|
||||
Try { Remove-Item $DEST_DIR -Recurse -Force -ErrorAction SilentlyContinue }
|
||||
Catch { LogErr $_.Exception.Message }
|
||||
|
||||
## If using WSUS, reset authorization with server and detect new updates
|
||||
If ( $WSUS )
|
||||
{
|
||||
LogMsg "Resetting WSUS authorization and starting update detection"
|
||||
Try { Start-Process "${Env:WinDir}\System32\wuauctl.exe" -ArgumentList "/resetauthorization /detectnow" }
|
||||
Catch { LogErr $_.Exception.Message }
|
||||
}
|
||||
## Force the Windows Update client to check for new updates
|
||||
LogMsg "Resetting WSUS authorization and starting update detection"
|
||||
Try { Start-Process "${Env:WinDir}\System32\wuauctl.exe" -ArgumentList "/resetauthorization /detectnow" }
|
||||
Catch { LogErr $_.Exception.Message }
|
||||
@@ -1,8 +0,0 @@
|
||||
@echo off
|
||||
|
||||
rem This script will return the highest installed version of the .NET Framework (versions 1.0 to 4.6.2)
|
||||
|
||||
rem Test for .NET 4.6.2
|
||||
rem reg query HLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Client 1>NUL 2>NUL || SET /A "INSTALL=INSTALL-1"
|
||||
|
||||
reg query HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Client /v Release
|
||||
@@ -1,32 +0,0 @@
|
||||
###
|
||||
# This script exists in N-Central's Automation Manager
|
||||
###
|
||||
|
||||
param(
|
||||
[string]$ShortName = "EK",
|
||||
[string]$LongName = "Emberkom",
|
||||
[string]$NotificationEmail = "notification@emberkom.com"
|
||||
)
|
||||
|
||||
Function source { . 'C:\Users\dyoder\Emberkom\Data\Projects\development\management-scripts\Tools.ps1' }
|
||||
source
|
||||
|
||||
## Because the N-Central Automation Manager can't actually read the full Powershell syntax, we have to first put the passed in variables
|
||||
## into new variables so we can reference the RMM generated data in the standard form and not with the curly braces
|
||||
$short = $ShortName
|
||||
$long = $LongName
|
||||
$email = $NotificationEmail
|
||||
|
||||
$account = "${short}_${Env:COMPUTERNAME}".ToUpper()
|
||||
$email = $email.ToLower()
|
||||
|
||||
## URL to download the branded WholesaleBackup installer
|
||||
$URL = "http://downloads.backupops.com/4Windows/${MSPName}Backup_installer.exe"
|
||||
|
||||
## Silent installation options
|
||||
$Arguments = "/SP- /VERYSILENT /NORESTART /WPUSH /WACCOUNT ""${account}"" /WORG ""${long}"" /WEMAIL ""${email}"""
|
||||
|
||||
## Install Emberkom Backup
|
||||
#Install-Program -Path $(Download-File -URL $URL) -Arguments $Arguments -Delete
|
||||
|
||||
Write-Output $Arguments
|
||||
@@ -18,9 +18,7 @@ Catch { LogErr $_.Exception.Message }
|
||||
|
||||
## Delete installer
|
||||
Try {
|
||||
If ( Test-Path $INSTALLER ) {
|
||||
LogMsg "Deleting downloaded installation package"
|
||||
Remove-Item $INSTALLER -Force
|
||||
}
|
||||
LogMsg "Deleting downloaded installation package"
|
||||
Remove-Item $INSTALLER -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
Catch { LogErr $_.Exception.Message }
|
||||
@@ -1,9 +1,6 @@
|
||||
## Define URL for downloading the installer
|
||||
$URL = 'https://dev.emberkom.com/emberkom/management-scripts/raw/branch/master/resources/Nextcloud-3.0.3-setup.exe'
|
||||
|
||||
#$FILE = '{0}{1}' -f (GetTempPath), (Split-Path $URL -Leaf)
|
||||
#$FILE = Download-File -URL $URL -File $FILE
|
||||
|
||||
## Stop app if it's currently running
|
||||
End-Process -Name 'nextcloud' -Force
|
||||
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
Function global:Set-WinEvtLog {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Enable/Disable an event log.
|
||||
.DESCRIPTION
|
||||
Enable or disable a Windows Event Log using the System.Diagnostics.Eventing.Reader.EventLogConfiguration object.
|
||||
This function only outputs terminating errors to the console. If you want to see more detail use -verbose
|
||||
.EXAMPLE
|
||||
Set-WinEvtLog -Enable -Log "Microsoft-Windows-DNS-Client/Operational"
|
||||
.EXAMPLE
|
||||
Set-WinEvtLog -Disable -Log (Get-Content ListOfLogs.txt)
|
||||
.EXAMPLE
|
||||
Get-Content ListOfLogs.txt | Set-WinEvtLog -Enable
|
||||
.PARAMETER Log
|
||||
The log(s) to modIfy.
|
||||
.PARAMETER Enable
|
||||
Enables the log(s).
|
||||
.PARAMETER Disable
|
||||
Disables the log(s).
|
||||
#>
|
||||
|
||||
[CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact='Low')]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory=$True,
|
||||
ValueFromPipeline=$False,
|
||||
ValueFromPipelineByPropertyName=$True,
|
||||
HelpMessage='Which log do you want to enable?')]
|
||||
[string[]]$Log,
|
||||
[Parameter(Mandatory=$True,
|
||||
ValueFromPipelineByPropertyName=$True,
|
||||
ParameterSetName = 'Enable')]
|
||||
[Switch]$Enable,
|
||||
[Parameter(Mandatory=$True,
|
||||
ValueFromPipelineByPropertyName=$True,
|
||||
ParameterSetName = 'Disable')]
|
||||
[Switch]$Disable
|
||||
)
|
||||
|
||||
Begin
|
||||
{
|
||||
# Keep track of changes made to event logs in a separate file.
|
||||
$RecordLog = "${Env:MSPDir}\Logs\WinEvtLogs-Enabled.log"
|
||||
|
||||
If ( !(Test-Path -Path $RecordLog) )
|
||||
{
|
||||
# Create the record keeping log file If it doesn't exist.
|
||||
$NewFile = ((New-Item -Path $RecordLog -ItemType file).name | Out-String)
|
||||
$NewFile = $NewFile.Trim()
|
||||
Write-Verbose "$NewFile did not exist and has been created."
|
||||
}
|
||||
}
|
||||
|
||||
Process
|
||||
{
|
||||
# Make sure Record Keeping is properly configured, otherwise exit.
|
||||
If ( !($RecordLog) )
|
||||
{
|
||||
Write-Verbose "The record keeping log does not exist, this function will not continue."
|
||||
Return
|
||||
}
|
||||
|
||||
# Loop through the name(s) in the $Log variable passed to this function.
|
||||
ForEach ($name in $Log)
|
||||
{
|
||||
# Process the data only If the script should Process data.
|
||||
If ( $pscmdlet.ShouldProcess($name, 'Enable Log') )
|
||||
{
|
||||
# Load the RecordLog into a variable.
|
||||
$PreviouslyEnabledLogs = Get-Content $RecordLog
|
||||
|
||||
# Determine whether to Enable or Disable logging of the specIfied log.
|
||||
Switch ($PSCmdlet.ParameterSetName)
|
||||
{
|
||||
'Enable' { $SetEnable = $True }
|
||||
'Disable' { $SetEnable = $False }
|
||||
}
|
||||
|
||||
# Create a new object for the specIfied log.
|
||||
$LogObject = New-Object System.Diagnostics.Eventing.Reader.EventLogConfiguration $name
|
||||
|
||||
# Set the variable to determine whether the log has been enabled by this script or not
|
||||
$IsEnabledByFunction = $False
|
||||
|
||||
# Determine whether or not the log had been enabled by this function.
|
||||
ForEach ($item in $PreviouslyEnabledLogs)
|
||||
{ If ($item -eq $name) { $IsEnabledByFunction = $True } }
|
||||
|
||||
# Act based on whether the log is already enabled or not.
|
||||
Switch ($logObject.IsEnabled)
|
||||
{
|
||||
$True
|
||||
{
|
||||
# Inform user whether this log has been enabled by this function or not.
|
||||
If ($IsEnabledByFunction)
|
||||
{ Write-Verbose "$name has previously been enabled by this function." }
|
||||
Else { Write-Verbose "$name has previously been enabled, but not by this function." }
|
||||
}
|
||||
|
||||
$False
|
||||
{
|
||||
# Inform user that this log has been disabled by something other than this function.
|
||||
If ($IsEnabledByFunction)
|
||||
{ Write-Verbose "$name should already be enabled by this function, but has been disabled by other means." }
|
||||
}
|
||||
}
|
||||
|
||||
# ModIfy the log to either enable or disable it.
|
||||
If ($LogObject.IsEnabled -eq $SetEnable)
|
||||
{ Write-Verbose "$name is already in the desired state." }
|
||||
Else
|
||||
{
|
||||
# Set the log to the desired state.
|
||||
$LogObject.IsEnabled = $SetEnable
|
||||
|
||||
# Save changes to the log.
|
||||
$LogObject.SaveChanges()
|
||||
|
||||
# VerIfy the change has been made.
|
||||
Switch ($LogObject.IsEnabled)
|
||||
{
|
||||
$True
|
||||
{
|
||||
Write-Verbose "$name has been enabled."
|
||||
|
||||
# Make sure this log wasn't already enabled by this function so we don't write the same name more than once in $RecordLog
|
||||
If (!($IsEnabledByFunction)) { Add-Content -Path $RecordLog "$name" }
|
||||
}
|
||||
|
||||
$False
|
||||
{
|
||||
# Remove $name from $RecordLog If it was put there by this function.
|
||||
If ($IsEnabledByFunction)
|
||||
{
|
||||
# Clear the contents of $RecordLog
|
||||
Clear-Content -Path $RecordLog
|
||||
|
||||
# Add each item back in that was already there except for the current $name
|
||||
ForEach ($filename In $PreviouslyEnabledLogs)
|
||||
{ If ($filename -ne $name) { Add-Content -Path $RecordLog $filename} }
|
||||
}
|
||||
Write-Verbose "$name has been disabled."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end {}
|
||||
}
|
||||
Export-ModuleMember -Function Set-WinEvtLog
|
||||
@@ -1,158 +0,0 @@
|
||||
#Requires -Version 2.0
|
||||
|
||||
## Set the name of this module
|
||||
$ModuleName = "PSModule"
|
||||
|
||||
## Define base URL for updating modules and resources
|
||||
$BaseURL = "https://dev.emberkom.com/emberkom/management-scripts/raw/branch/master/${ModuleName}"
|
||||
|
||||
## Set the path to this module
|
||||
$ModulePath = "${Env:MSPDir}\Scripts\${ModuleName}"
|
||||
|
||||
## Define the paths for where we'll place stuff on the endpoint
|
||||
$MSPRoot = $Env:MSPDir
|
||||
$MSPScripts = "${MSPRoot}\Scripts"
|
||||
$MSPTools = "${MSPRoot}\Tools"
|
||||
$MSPLogs = "${MSPRoot}\Logs"
|
||||
|
||||
## Function to simply import a module and return an error message if it fails
|
||||
Function Load-Module
|
||||
{
|
||||
param([string]$modulename)
|
||||
|
||||
## Get a new copy of the module
|
||||
Get-Module $modulename
|
||||
|
||||
## Form the local file path to the specified module
|
||||
$FilePath = "${ModulePath}\${modulename}.psm1"
|
||||
|
||||
## Import the module
|
||||
If ( Test-Path $FilePath )
|
||||
{
|
||||
Try { Import-Module -Name $FilePath }
|
||||
Catch { Write-Output $_.Exception.Message }
|
||||
} Else { Write-Output "Module does not exist: ${FilePath}" }
|
||||
}
|
||||
|
||||
## Function to update or install a module
|
||||
Function Get-Module
|
||||
{
|
||||
param([string]$modulename)
|
||||
|
||||
## Form the URL to the specified module
|
||||
$ModuleURL = "${BaseURL}/${modulename}.psm1"
|
||||
|
||||
## Form the local file path to the specified module
|
||||
$FilePath = "${ModulePath}\${modulename}.psm1"
|
||||
|
||||
## Download the new file, overwriting the local copy
|
||||
If ( IsDownloadable $ModuleURL )
|
||||
{
|
||||
Try { (New-Object Net.WebClient).DownloadFile($ModuleURL, $FilePath) }
|
||||
Catch { Write-Output $_.Exception.Message }
|
||||
} Else { Write-Output "Could not download ${ModuleURL}" }
|
||||
}
|
||||
|
||||
## Determines whether a file can be downloaded or not
|
||||
Function IsDownloadable
|
||||
{
|
||||
param([string]$url)
|
||||
|
||||
## Create a web request
|
||||
$HTTPRequest = [System.Net.WebRequest]::Create($url)
|
||||
|
||||
Try
|
||||
{
|
||||
## Get the response
|
||||
$HTTPResponse = $HTTPRequest.GetResponse()
|
||||
|
||||
## Save the status code
|
||||
$HTTPStatus = [int]$HTTPResponse.StatusCode
|
||||
}
|
||||
Catch [System.Net.WebException] { $HTTPResponse = $_.Exception.Response }
|
||||
|
||||
## Close the connection, because we're done with it
|
||||
Finally { $HTTPResponse.Close() }
|
||||
|
||||
## Test to make sure we received a status of 200 "OK" from the resource
|
||||
If ($HTTPStatus -eq 200) { Return $true }
|
||||
|
||||
## If the status code is anything other than 200, return $false
|
||||
Else { Return $false }
|
||||
}
|
||||
|
||||
## EXPORT FUNCTION
|
||||
## Function to log activity to the configured log directory
|
||||
Function global:Log
|
||||
{
|
||||
Begin {}
|
||||
Process {}
|
||||
End {}
|
||||
}
|
||||
|
||||
## EXPORT FUNCTION
|
||||
## Function to determine if the current user context is an Administrator
|
||||
Function global:IsAdmin
|
||||
{
|
||||
Begin {}
|
||||
Process
|
||||
{
|
||||
If ( ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) )
|
||||
{ Return $true } Else { Return $false }
|
||||
}
|
||||
End {}
|
||||
}
|
||||
|
||||
## EXPORT FUNCTION
|
||||
## Function to retrieve and run a powershell script
|
||||
Function Run-PSScript
|
||||
{
|
||||
param(
|
||||
[string]$Type='management-scripts',
|
||||
[string]$Name,
|
||||
[string]$Arguments
|
||||
)
|
||||
|
||||
## Form the URL to the specified script
|
||||
$URL = "https://dev.emberkom.com/emberkom/${Type}/raw/branch/master/${Name}.ps1"
|
||||
|
||||
If ( IsDownloadable $URL )
|
||||
{
|
||||
$Script = (New-Object Net.WebClient).DownloadString($URL)
|
||||
$ScriptBlock = [Scriptblock]::Create($Script)
|
||||
Try { Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $Arguments }
|
||||
Catch { Write-Output $_.Exception.Message }
|
||||
} Else { Write-Output "Could not retrieve ${URL}" }
|
||||
}
|
||||
|
||||
## Make sure all the management directories exist
|
||||
If ( !(Test-Path $MSPRoot) )
|
||||
{
|
||||
Try { New-Item -Path $MSPRoot -ItemType Directory -Force | Out-Null }
|
||||
Catch { Write-Output $_.Exception.Message }
|
||||
}
|
||||
If ( !(Test-Path $MSPScripts) )
|
||||
{
|
||||
Try { New-Item -Path $MSPScripts -ItemType Directory -Force | Out-Null }
|
||||
Catch { Write-Output $_.Exception.Message }
|
||||
}
|
||||
If ( !(Test-Path $MSPTools) )
|
||||
{
|
||||
Try { New-Item -Path $MSPTools -ItemType Directory -Force | Out-Null }
|
||||
Catch { Write-Output $_.Exception.Message }
|
||||
}
|
||||
If ( !(Test-Path $MSPLogs) )
|
||||
{
|
||||
Try { New-Item -Path $MSPLogs -ItemType Directory -Force | Out-Null }
|
||||
Catch { Write-Output $_.Exception.Message }
|
||||
}
|
||||
|
||||
## Import all modules
|
||||
$ListOfModules = @(
|
||||
"PSModule",
|
||||
"PSModule-SetWinEvtLog"
|
||||
)
|
||||
ForEach ($module in $ListOfModules) { Load-Module $module }
|
||||
|
||||
## Make sure this module exports only the functions that should be exported
|
||||
Export-ModuleMember -Function Log,IsAdmin,Run-PSScript
|
||||
@@ -1,32 +0,0 @@
|
||||
param([string]$Name,[switch]$Force=$false)
|
||||
|
||||
If ( $Name )
|
||||
{
|
||||
## Get all matching processes
|
||||
$Processes = Get-Process | Where { $_.Name -ilike $Name }
|
||||
|
||||
## Get the total number of matching processes
|
||||
$NumMatches = $Processes.Count
|
||||
|
||||
If ( $NumMatches -ge 1 )
|
||||
{
|
||||
## Forcefully close matching processes
|
||||
If ( $Force )
|
||||
{
|
||||
Foreach ( $proc in $Processes ) { Stop-Process $proc -Force -ErrorAction SilentlyContinue }
|
||||
Write-Output "Forcefully closed ${NumMatches} matching instance(s) of ${Name}"
|
||||
}
|
||||
|
||||
## Gracefully close matching processes
|
||||
Else
|
||||
{
|
||||
Foreach ( $proc in $Processes ) { $proc.CloseMainWindow() | Out-Null }
|
||||
Write-Output "Gracefully closed ${NumMatches} matching instance(s) of ${Name}"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Else { Write-Output "No running processes match the name ${Name}" }
|
||||
}
|
||||
|
||||
Else { Write-Output "No process name was specified!" }
|
||||
@@ -1,3 +0,0 @@
|
||||
## Cleanup Ninja's 3pp cache
|
||||
If ( Test-Path "${Env:SystemDrive}\ProgramData\NinjaRMMAgent\components\app-patching\SIGNATURES" )
|
||||
{ Remove-Item "${Env:SystemDrive}\ProgramData\NinjaRMMAgent\components\app-patching\SIGNATURES" -Force -Recurse }
|
||||
@@ -1,31 +0,0 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Remove files older than the specified number of days.
|
||||
|
||||
.DESCRIPTION
|
||||
This script will delete all files in a directory which are older than the specified number of days.
|
||||
It will not search recursively for files and will only look in the directory specified.
|
||||
|
||||
.PARAMETER
|
||||
-Path
|
||||
This is the directory to search for old files
|
||||
|
||||
.PARAMETER
|
||||
-OlderThan
|
||||
This is the number of days that limits the files that are deleted.
|
||||
Anything newer than the value specified here will be retained, while anything older than the value specified here will be deleted.
|
||||
|
||||
.EXAMPLE
|
||||
Remove-OldFiles -Path "C:\Windows\TEMP" -OlderThan 30
|
||||
This will remove all files in C:\Windows\TEMP that are older than 30 days
|
||||
#>
|
||||
|
||||
Param(
|
||||
[string]$Path="C:\Users\dyoder\Desktop",
|
||||
[int]$OlderThan=7
|
||||
)
|
||||
|
||||
If ( Test-Path $Path ) {
|
||||
$files = Get-ChildItem $Path | Where { !$_.PSIsContainer -and $_.LastWriteTime -lt (Get-Date).AddDays(-${OlderThan}) }
|
||||
foreach ( $f in $files ) { write-host $f.FullName }
|
||||
} Else { Write-Host "The path does not exist: ${Path}" }
|
||||
@@ -1,678 +0,0 @@
|
||||
<#
|
||||
|
||||
.SYNOPSIS
|
||||
Provides friendly messages reminding a user to restart their computer based on events that require it.
|
||||
|
||||
.DESCRIPTION
|
||||
The Set-RebootSchedule script is called from any computer management software to notify a user of a required restart.
|
||||
This script accepts several different parameters which change the messages displayed to the user.
|
||||
Some logic is used when determining the best time to remind the user to restart.
|
||||
|
||||
.PARAMETER SysPerf
|
||||
The -SysPerf parameter will remind the user to restart due to system performance.
|
||||
This parameter should be called if the computer has had consistently high memory usage, recurring application hangs, or stuck processes.
|
||||
If this parameter is used it will simply tell the user that a restart is needed to improve overall stability.
|
||||
|
||||
.PARAMETER OSUpdate
|
||||
The -OSUpdate parameter will remind the user to restart due to operating system updates.
|
||||
|
||||
.PARAMETER Uptime
|
||||
The -Uptime parameter will remind the user to restart due to long uptimes.
|
||||
This script does not define the length of time the computer has been on, but will display the number of days to the end user.
|
||||
If the computer has been on for 10 days and this parameter is used, it will tell the user this computer has been on for 10 days.
|
||||
|
||||
.PARAMETER AllowMinimize
|
||||
The -AllowMinimize parameter will let the prompts and reminders be minimized by the user.
|
||||
By default, the user is not allowed to minimize the window.
|
||||
|
||||
.PARAMETER Override
|
||||
The -Override parameter is used with either the -OSUpdate or -Uptime parameters.
|
||||
This parameter will override the priority of the existing reminder schedule and overwrite any existing schedule with the one set when -Override is called.
|
||||
See the NOTES section for additional information on schedule priorities.
|
||||
|
||||
.PARAMETER Remove
|
||||
The -Remove parameter will simply delete any scheduled restart reminder.
|
||||
|
||||
.PARAMETER Task
|
||||
The -Task parameter will allow this script to run without scheduling a task. This switch is called when this task creates a scheduled task of itself.
|
||||
|
||||
.EXAMPLE
|
||||
Set-RebootSchedule -SysPerf
|
||||
Prompt the user to restart because you've seen problems in multiple areas of the computer.
|
||||
|
||||
.EXAMPLE
|
||||
Set-RebootSchedule -OSUpdate
|
||||
Prompt the user to restart because Windows was recently updated.
|
||||
|
||||
.EXAMPLE
|
||||
Set-RebootSchedule -Uptime
|
||||
Prompt the user to restart because the computer has been up for a long time.
|
||||
|
||||
.EXAMPLE
|
||||
Set-RebootSchedule -OSUpdate -Override
|
||||
Prompt the user to restart because Windows was recently updated, overwriting any existing reminder schedule.
|
||||
|
||||
.EXAMPLE
|
||||
Set-RebootSchedule -Uptime -Override
|
||||
Prompt the user to restart because the computer has been up for a long time, overwriting any existing reminder schedule.
|
||||
|
||||
.EXAMPLE
|
||||
Set-RebootSchedule -Remove
|
||||
There is no longer a need to remind the user to restart, or you just want to clear an existing reminder schedule.
|
||||
|
||||
.NOTES
|
||||
Calling this script with no parameters does nothing, the script will just exit without prompting the user for anything.
|
||||
|
||||
This is the order of schedule priority when this script is called:
|
||||
1.) SysPerf
|
||||
2.) OSUpdate
|
||||
3.) Uptime
|
||||
|
||||
If -Uptime is called but a schedule has already been set by -OSUpdate, the user will not be prompted to schedule a restart.
|
||||
If -OSUpdate is called but a schedule has already been set by -SysPerf, the user will not be prompted to schedule a restart.
|
||||
If -SysPerf is called but a schedule has already been set by -OSUpdate, the user will be prompted to schedule a restart and the existing schedule will be overwritten.
|
||||
|
||||
The -Override parameter is used to modify this logic such that a lower priority schedule can overwrite a higher priority schedule.
|
||||
|
||||
#>
|
||||
|
||||
## Define parameters
|
||||
Param(
|
||||
[switch]$SysPerf,
|
||||
[switch]$OSUpdate,
|
||||
[switch]$Uptime,
|
||||
[switch]$AllowMinimize=$false,
|
||||
[switch]$Override,
|
||||
[switch]$Force,
|
||||
[switch]$Remove
|
||||
)
|
||||
|
||||
## Add Windows Forms support to this script
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
[System.Windows.Forms.Application]::EnableVisualStyles()
|
||||
|
||||
## Functions and subroutines
|
||||
#region begin FUNCTIONS {
|
||||
|
||||
## Copy this script to a directory where it can be called by a scheduled task
|
||||
Function Copy-ThisScript {
|
||||
|
||||
## Get the current directory path and file name of this script
|
||||
$ThisDirectory = Split-Path -Parent $MyInvocation.PSCommandPath
|
||||
$ThisScript = Split-Path -Leaf $MyInvocation.PSCommandPath
|
||||
|
||||
## Check to make sure we don't copy this script if it's already been copied to $CopyDirectory
|
||||
If ( !($ThisDirectory -eq $CopyDirectory) ) {
|
||||
|
||||
## Create the destination directory if it doesn't already exist
|
||||
If ( !(Test-Path -Path $CopyDirectory) ) { New-Item -ItemType Directory -Force -Path $CopyDirectory }
|
||||
|
||||
## Delete the existing script in $CopyDirectory
|
||||
If ( Test-Path -Path "${CopyDirectory}\${CopyFilename}" ) { Remove-Item -Path "${CopyDirectory}\${CopyFilename}" -Force }
|
||||
|
||||
## Copy the script to $CopyDirectory\$CopyFilename
|
||||
Copy-Item -Path "${ThisDirectory}\${ThisScript}" -Destination "${CopyDirectory}\${CopyFilename}"
|
||||
}
|
||||
}
|
||||
|
||||
## Gets the number of days the system has been up.
|
||||
Function Get-UptimeDays {
|
||||
|
||||
## Get a new instance of the Win32_OperatingSystem WMI object
|
||||
$WMIOS = Get-WmiObject Win32_OperatingSystem
|
||||
|
||||
## Get the last boot time and convert it to a DateTime value
|
||||
$LastBootTime = $WMIOS.ConvertToDateTime($WMIOS.LastBootUpTime)
|
||||
|
||||
## Get the number of days since the last time the system was powered on
|
||||
[string]$Uptime = (New-TimeSpan -Start $LastBootTime -End $(Get-Date)).Days.ToString()
|
||||
|
||||
Return $Uptime
|
||||
}
|
||||
|
||||
## Determines whether the logo can be downloaded or not
|
||||
Function IsLogoDownloadable {
|
||||
|
||||
## Create a web request
|
||||
$HTTPRequest = [System.Net.WebRequest]::Create($LogoURL)
|
||||
|
||||
## Get the response
|
||||
Try { $HTTPResponse = $HTTPRequest.GetResponse() }
|
||||
|
||||
## Catch any error2 when trying to connect to the resource (including 404)
|
||||
Catch [System.Net.WebException] { $HTTPResponse = $_.Exception.Response }
|
||||
|
||||
## Save the status code
|
||||
$HTTPStatus = [int]$HTTPResponse.StatusCode
|
||||
|
||||
## Close the connection, because we're done with it
|
||||
$HTTPResponse.Close()
|
||||
|
||||
## Test to make sure we received a status of 200 "OK" from the resource
|
||||
If ($HTTPStatus -eq 200) { Return $true }
|
||||
|
||||
## If the status code is anything other than 200, return $false so we can do something else
|
||||
Else { Return $false }
|
||||
}
|
||||
|
||||
## Returns the local path of a file downloaded from a URL
|
||||
Function Get-LogoPath {
|
||||
|
||||
## Get the file name from $url
|
||||
$filename = [System.IO.Path]::GetFileName($LogoURL)
|
||||
|
||||
## Set the destination to download to
|
||||
$localpath = "${Env:TEMP}\${filename}"
|
||||
|
||||
## Make sure the file is downloadable
|
||||
If ( IsLogoDownloadable ) {
|
||||
|
||||
## Try downloading the file
|
||||
Try { (New-Object Net.WebClient).DownloadFile($LogoURL, $localpath) }
|
||||
|
||||
## If you want to handle any download errors, put that code in here
|
||||
Catch { $_ }
|
||||
}
|
||||
|
||||
## Now that the file *may* be downloaded, check to make sure it exists
|
||||
If ( Test-Path $localpath ) {
|
||||
|
||||
## Return $localpath to the caller
|
||||
Return $localpath
|
||||
}
|
||||
|
||||
## If $localpath doesn't exist (ie: from a previous execution of this script) then return $false
|
||||
Else { Return $false }
|
||||
}
|
||||
|
||||
## Base64 encode something
|
||||
Function Get-Base64($data) {
|
||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($data)
|
||||
$encoded = [Convert]::ToBase64String($bytes)
|
||||
Return $encoded
|
||||
}
|
||||
|
||||
## Create a scheduled task
|
||||
Function Create-ScheduledTask([string]$name,[string]$description,$action,$principal,$trigger) {
|
||||
|
||||
## Unregister any existing task with the same name as the one we're trying to create
|
||||
## This needs to be fixed. If the task does not exist, it throws an error.
|
||||
Try { Unregister-ScheduledTask -TaskName $name -Confirm:$false }
|
||||
Catch { $_ }
|
||||
|
||||
## Configure the task
|
||||
$Task = New-ScheduledTask -Description $description -Action $action -Principal $principal -Trigger $trigger
|
||||
|
||||
## Register the scheduled task
|
||||
Register-ScheduledTask -TaskName $name -InputObject $Task
|
||||
}
|
||||
|
||||
## Create a task to delete another task
|
||||
## This will run at boot time to make sure that the user doesn't get unnessarily disrupted by
|
||||
## a previously scheduled restart task after the computer has already been restarted.
|
||||
Function Create-DeleteTask([string]$tasktodelete) {
|
||||
|
||||
## Create a RunOnce task to delete the specified task in the Task Scheduler
|
||||
## PROBLEM: How can this occur if the user isn't an admin?
|
||||
## Will this work the same if we write to HKCU instead?
|
||||
#Set-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" -Name '!DeleteScheduledRebootReminder' -Value "schtasks.exe /Delete /TN ${tasktodelete} /F"
|
||||
|
||||
## Set the task name
|
||||
$TaskName = "${CompanyAbbr} - Delete Task: ${tasktodelete}"
|
||||
|
||||
## Se the task description
|
||||
$TaskDescription = "This task deletes the task: ${tasktodelete}"
|
||||
|
||||
## Configure the task action
|
||||
$args = "/delete /tn " + '"' + "\${tasktodelete}" + '"' + " /f"
|
||||
$TaskAction = New-ScheduledTaskAction -Execute "schtasks.exe" -Argument $args
|
||||
|
||||
## Configure the user account the task will run under
|
||||
$TaskPrincipal = New-ScheduledTaskPrincipal -UserId "LOCALSERVICE" -LogonType ServiceAccount
|
||||
|
||||
## Configure the trigger to start at the specified time
|
||||
$Trigger = New-ScheduledTaskTrigger -AtStartup
|
||||
|
||||
}
|
||||
|
||||
## Create a restart task
|
||||
#Function Create-RestartTask([datetime]$starttime) {
|
||||
#
|
||||
# ## Set the task name
|
||||
# $TaskName = "${CompanyAbbr} - Computer Restart Task"
|
||||
#
|
||||
# ## Set the task description
|
||||
# $TaskDescription = "This task restarts the computer"
|
||||
#
|
||||
# ## Convert $script to Base64
|
||||
# $EncodedScript = Get-Base64 $RestartComputerTaskScript
|
||||
#
|
||||
# ## Configure the task action
|
||||
# $TaskAction = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-WindowStyle Hidden -NonInteractive -ExecutionPolicy Bypass -EncodedCommand ${EncodedScript}"
|
||||
#
|
||||
# ## Configure the user account the task will run under
|
||||
# $TaskPrincipal = New-ScheduledTaskPrincipal -UserId "LOCALSERVICE" -LogonType ServiceAccount
|
||||
#
|
||||
# ## Configure the trigger to start at the specific time
|
||||
# $Trigger = New-ScheduledTaskTrigger -Once -At $starttime
|
||||
#
|
||||
# ## Create a new task to delete the one we're about to create the next time the compter boots
|
||||
# Create-DeleteTask $TaskName
|
||||
#
|
||||
# ## Create the restart task
|
||||
# Create-ScheduledTask $TaskName $TaskDescription $TaskAction $TaskPrincipal $TaskTrigger
|
||||
#}
|
||||
|
||||
## Create a reminder task
|
||||
#Function Create-ReminderTask([datetime]$starttime) {
|
||||
#
|
||||
# ## Set the task name
|
||||
# $TaskName = "${CompanyAbbr} - Computer Restart Reminder Task"
|
||||
#
|
||||
# ## Set the task description
|
||||
# $TaskDescription = "This task reminds the user to restart their computer"
|
||||
#
|
||||
# ## Convert $script to Base64
|
||||
# $EncodedScript = Get-Base64 $ReminderTaskScript
|
||||
#
|
||||
# ## Configure the task action
|
||||
# $TaskAction = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-WindowStyle Hidden -NonInteractive -ExecutionPolicy Bypass -EncodedCommand ${EncodedScript}"
|
||||
#
|
||||
# ## Configure the user account the task will run under
|
||||
# $TaskPrincipal = New-ScheduledTaskPrincipal -UserId "LOCALSERVICE" -LogonType ServiceAccount
|
||||
#
|
||||
# ## Configure the trigger to start at boot
|
||||
# $Trigger = New-ScheduledTaskTrigger -Once -At $starttime
|
||||
#
|
||||
# ## Create the restart task
|
||||
# Create-ScheduledTask $TaskName $TaskDescription $TaskAction $TaskPrincipal $TaskTrigger
|
||||
#
|
||||
# ## Create a new task to delete the one we just created the next time the compter boots
|
||||
# Create-DeleteTask $TaskName
|
||||
#}
|
||||
|
||||
## Create a reminder task
|
||||
Function Create-ReminderTask([datetime]$starttime) {
|
||||
|
||||
## Set the task name
|
||||
$TaskName = "${CompanyAbbr} - Computer Restart Reminder Task"
|
||||
|
||||
## Set the task description
|
||||
$TaskDescription = "This task reminds the user to restart their computer"
|
||||
|
||||
## Convert $script to Base64
|
||||
$EncodedScript = Get-Base64 $ReminderTaskScript
|
||||
|
||||
## Configure the task action
|
||||
$TaskAction = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-ExecutionPolicy Bypass -File `"${CopyDirectory}\${CopyFilename}`""
|
||||
|
||||
## Configure the user account the task will run under
|
||||
$TaskPrincipal = New-ScheduledTaskPrincipal -UserId "LOCALSERVICE" -LogonType ServiceAccount
|
||||
|
||||
## Configure the trigger to start at boot
|
||||
$Trigger = New-ScheduledTaskTrigger -Once -At $starttime
|
||||
|
||||
## Create the restart task
|
||||
Create-ScheduledTask $TaskName $TaskDescription $TaskAction $TaskPrincipal $TaskTrigger
|
||||
|
||||
## Create a new task to delete the one we just created the next time the compter boots
|
||||
Create-DeleteTask $TaskName
|
||||
}
|
||||
|
||||
## Determine if the current time is earlier than the given time
|
||||
#Function EarlierThan($time) {
|
||||
#
|
||||
# ## If it's earlier, return $true
|
||||
# If ( (Get-Date) -lt $time ) { Return $true }
|
||||
#
|
||||
# ## If it's later, return false
|
||||
# Else { Return $false }
|
||||
#}
|
||||
|
||||
## Get the closest time to schedule a restart
|
||||
#Function Get-NearestRestartTime {
|
||||
#
|
||||
# ## Find out what day it is
|
||||
# switch ( (Get-Date).DayOfWeek ) {
|
||||
#
|
||||
# ## On weekends, the nearest time to schedule a restart will be:
|
||||
# ## 1.) Lunch time
|
||||
# ## 2.) Sometime in the afternoon
|
||||
# ## 3.) About 20 minutes from the current time
|
||||
# { $WeekendDays -contains $_ } {
|
||||
#
|
||||
# ## If it's earlier than $Lunchime, return $LunchTime
|
||||
# If ( EarlierThan $LunchTime ) { Return $LunchTime }
|
||||
#
|
||||
# ## If it's earlier than $AfternoonTime, return $AfternoonTime
|
||||
# ElseIf ( EarlierThan $AfternoonTime ) { Return $AfternoonTime }
|
||||
#
|
||||
# ## If it's after $AfternoonTime, return $ShortTimeFromNow
|
||||
# Else { Return $ShortTimeFromNow }
|
||||
# break
|
||||
# }
|
||||
# ## Throughout the week the nearest time to remind to restart will be:
|
||||
# ## 1.) Lunch time
|
||||
# ## 2.) Close of business
|
||||
# ## 3.) Late at night
|
||||
# { $WeekDays -contains $_ } {
|
||||
#
|
||||
# ## If it's earlier than $LunchTime, return $LunchTime
|
||||
# If ( EarlierThan $LunchTime ) { Return $LunchTime }
|
||||
#
|
||||
# ## If it's earlier than $CloseOfBusiness, return $CloseOfBusiness
|
||||
# ElseIf ( EarlierThan $CloseOfBusiness ) { Return $CloseOfBusiness }
|
||||
#
|
||||
# ## If it's after $CloseOfBusiness, return $LateAtNight
|
||||
# Else { Return $LateAtNight }
|
||||
# break
|
||||
# }
|
||||
# default { break }
|
||||
# }
|
||||
#}
|
||||
|
||||
## Get the next time to remind the user to restart
|
||||
#Function Get-NextReminderTime {
|
||||
#
|
||||
# ## Find out what day it is
|
||||
# switch ( (Get-Date).DayOfWeek ) {
|
||||
#
|
||||
# { $TwoDayReminderDays -contains $_ } {
|
||||
#
|
||||
# ## Add 2 days to the current day, then add the $ReminderDelay
|
||||
# $next = $StartOfBusiness + (New-TimeSpan -Days 2) + $ReminderDelay
|
||||
# Return $next
|
||||
# break
|
||||
# }
|
||||
#
|
||||
# { $OneDayReminderDays -contains $_ } {
|
||||
#
|
||||
# ## Add 1 day to the current day, then add the $ReminderDelay
|
||||
# $next = $StartOfBusiness + (New-TimeSpan -Days 1) + $ReminderDelay
|
||||
# Return $next
|
||||
# break
|
||||
# }
|
||||
# default { break }
|
||||
# }
|
||||
#}
|
||||
|
||||
Function Get-NextReminderTime {
|
||||
|
||||
$next = (Get-Date) + $ReminderInterval
|
||||
Return $next
|
||||
|
||||
}
|
||||
|
||||
## Builds the Windows form to display to the user
|
||||
Function Display-Prompt([string]$message) {
|
||||
|
||||
## Set the form's overall parameters
|
||||
$Form = New-Object System.Windows.Forms.Form
|
||||
$Form.ClientSize = '400,360'
|
||||
$Form.Text = $WindowTitle
|
||||
$Form.TopMost = $true
|
||||
$Form.MaximizeBox = $false
|
||||
$Form.MinimizeBox = $AllowMinimize
|
||||
$Form.FormBorderStyle = 'FixedDialog'
|
||||
$Form.StartPosition = 'CenterScreen'
|
||||
|
||||
## Download the logo
|
||||
$Logo = (Get-LogoPath)
|
||||
|
||||
## Add a picturebox to the form
|
||||
If ( $Logo ) {
|
||||
$pbLogo = New-Object system.Windows.Forms.PictureBox
|
||||
$pbLogo.Width = $Form.ClientSize.Width - 20
|
||||
$pbLogo.Height = 90
|
||||
$pbLogo.Anchor = [System.Windows.Forms.AnchorStyles]::None
|
||||
$pbLogo.Location = New-Object System.Drawing.Point(10,10)
|
||||
$pbLogo.ImageLocation = $Logo
|
||||
$pbLogo.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::CenterImage
|
||||
$Form.Controls.Add($pbLogo)
|
||||
}
|
||||
|
||||
## If the logo isn't available, add label to the form instead of a picturebox
|
||||
Else {
|
||||
$lblCompany = New-Object System.Windows.Forms.Label
|
||||
$lblCompany.Text = $CompanyName
|
||||
$lblCompany.AutoSize = $false
|
||||
## The TextAlign enumerations can be found here:
|
||||
## https://docs.microsoft.com/en-us/dotnet/api/system.drawing.contentalignment?view=netframework-2.0
|
||||
$lblCompany.TextAlign = 32
|
||||
$lblCompany.Width = $Form.ClientSize.Width - 20
|
||||
$lblCompany.Height = 60
|
||||
$lblCompany.Location = New-Object System.Drawing.Point(10,10)
|
||||
$lblCompany.Font = 'Microsoft Sans Serif,24,style=Bold'
|
||||
$Form.Controls.Add($lblCompany)
|
||||
}
|
||||
|
||||
## This is the label that contains the reason for the restart
|
||||
$lblReason = New-Object System.Windows.Forms.Label
|
||||
$lblReason.Text = $message
|
||||
$lblReason.AutoSize = $false
|
||||
$lblReason.TextAlign = 1
|
||||
$lblReason.Width = $Form.ClientSize.Width - 50
|
||||
$lblReason.Height = 180
|
||||
$lblReason.Location = New-Object System.Drawing.Point(25,100)
|
||||
$lblReason.Font = 'Microsoft Sans Serif,11'
|
||||
$Form.Controls.Add($lblReason)
|
||||
|
||||
## This is the label that contains a static message about how to proceed
|
||||
$lblProceed = New-Object System.Windows.Forms.Label
|
||||
$lblProceed.Text = $ProceedText
|
||||
$lblProceed.AutoSize = $true
|
||||
$lblProceed.TextAlign = 1
|
||||
$lblProceed.Location = New-Object System.Drawing.Point(25,280)
|
||||
$lblProceed.Font = 'Microsoft Sans Serif,11'
|
||||
$Form.Controls.Add($lblProceed)
|
||||
|
||||
# ## This is the button that displays the nearest time to schedule a reboot
|
||||
# $btnNearestTime = New-Object System.Windows.Forms.Button
|
||||
# $btnNearestTime.Text = (Get-Date -Date $NearestRestartTime -Format "hh:mm tt").ToString()
|
||||
# $btnNearestTime.Width = 130
|
||||
# $btnNearestTime.Height = 30
|
||||
# $btnNearestTime.Location = New-Object System.Drawing.Point(45,310)
|
||||
# $btnNearestTime.Font = 'Microsoft Sans Serif,11'
|
||||
# $btnNearestTime.Add_Click({
|
||||
#
|
||||
# ## Create the "Computer Restart Task" scheduled task
|
||||
# Create-ReminderTask $NearestRestartTime
|
||||
#
|
||||
# ## We're done for now, just close the window.
|
||||
# $Form.Close()
|
||||
# })
|
||||
|
||||
## This is the button that displays the nearest time to schedule a reboot
|
||||
$btnNearestTime = New-Object System.Windows.Forms.Button
|
||||
$btnNearestTime.Text = $RebootNowText
|
||||
$btnNearestTime.Width = 130
|
||||
$btnNearestTime.Height = 30
|
||||
$btnNearestTime.Location = New-Object System.Drawing.Point(45,310)
|
||||
$btnNearestTime.Font = 'Microsoft Sans Serif,11'
|
||||
$btnNearestTime.Add_Click({
|
||||
|
||||
## Create the "Computer Restart Task" scheduled task
|
||||
Restart-Computer
|
||||
|
||||
## We're done for now, just close the window.
|
||||
$Form.Close()
|
||||
})
|
||||
|
||||
$Form.AcceptButton = $btmNearestTime
|
||||
$Form.Controls.Add($btnNearestTime)
|
||||
|
||||
## This is the placebo button, it just closes the form when clicked.
|
||||
## The reminder schedule has already been created, so this button doesn't need to do anything.
|
||||
$btnPlacebo = New-Object System.Windows.Forms.Button
|
||||
$btnPlacebo.Text = $PlaceboText
|
||||
$btnPlacebo.Width = 130
|
||||
$btnPlacebo.Height = 30
|
||||
$btnPlacebo.Location = New-Object System.Drawing.Point(225,310)
|
||||
$btnPlacebo.Font = 'Microsoft Sans Serif,11'
|
||||
$btnPlacebo.Add_Click({ $Form.Close() })
|
||||
$Form.Controls.Add($btnPlacebo)
|
||||
|
||||
|
||||
[void]$Form.ShowDialog()
|
||||
}
|
||||
|
||||
#endregion FUNCTIONS }
|
||||
|
||||
#region begin SCRIPTS {
|
||||
|
||||
## This script is used to remind the user to restart their computer
|
||||
$ReminderTaskScript = '&{
|
||||
## code here
|
||||
}'
|
||||
|
||||
#endregion SCRIPTS }
|
||||
|
||||
## Define custom company name, logo, window title, and messages
|
||||
#region begin CUSTOMIZATIONS {
|
||||
|
||||
## The following 2 settings are specific to your company
|
||||
## This is the name of your company.
|
||||
$CompanyName = "Emberkom"
|
||||
## This is the short or abbreviated name of your company
|
||||
## It's used to prefix the scheduled tasks so they're easy to identify
|
||||
$CompanyAbbr = "EK"
|
||||
## This is the URL to your company logo.
|
||||
## If your company logo cannot be downloaded, $CompanyName will be used instead.
|
||||
## If the image you specify is larger than 380x90, it will shrink to fit that size.
|
||||
$LogoURL = 'https://emberkom.s3.amazonaws.com/management/scripts/resources/small-web-logo.jpg'
|
||||
|
||||
## This script will start by copying itself into a local directory on the computer.
|
||||
## This will allow the scheduled tasks this script creates to call it later.
|
||||
## Directory to copy this script into (do not put in an ending "\")
|
||||
$CopyDirectory = "${Env:ProgramData}\${CompanyName}\Scripts"
|
||||
## The name of the file this script should have when copied to the $CopyDirectory
|
||||
$CopyFilename = "Set-RebootSchedule.ps1"
|
||||
|
||||
## The following 6 settings control text displayed on the form when prompting the user to choose a time to restart their computer
|
||||
## The title of the window
|
||||
$WindowTitle = "Restart Required - ${CompanyName}"
|
||||
## The message displayed to the user when -SysPerf is called.
|
||||
$SysPerfText = "It looks like your computer isn't performing like it should.`n`nRestarting it will help to resolve some of the problems its been having."
|
||||
## The message displayed to the user when -OSUpdate is called.
|
||||
$OSUpdateText = "Good news!`n`nYour computer has recently installed some updates and it needs to be restarted soon."
|
||||
## Thhe message displayed to the user when -Uptime is called.
|
||||
$UptimeText = "It looks like your computer has been on for more than $(Get-UptimeDays) days.`n`nIt's probably best to restart soon so it doesn't start causing problems for you."
|
||||
## This is the message displayed just above the buttons - it should ask the user how they want to proceed
|
||||
$ProceedText = "When can we make this happen?"
|
||||
## This is the text for a placebo button. Regardless of whether the user clicks this button or not,
|
||||
## a reminder has already been created. Clicking the button will just close the form.
|
||||
## This is simply because I don't want the user to be able to dismiss restarting their
|
||||
## computer, but I still want them to feel like they're involved and have some control
|
||||
## over the situation. Automatically reminding them some other time won't hurt anything.
|
||||
$PlaceboText = "Remind me later"
|
||||
|
||||
|
||||
############### NEW SETTINGS ###############
|
||||
|
||||
## The message on the button that immediately restarts the computer
|
||||
$RebootNowText = "Restart Now"
|
||||
|
||||
## When to begin notifying the user they need to reboot their computer
|
||||
$StartReminderAt = Get-Date -Hour 9 -Minute 0 -Second 0
|
||||
|
||||
## When to stop notifying the user to reboot.
|
||||
## If the next notification to restart is scheduled to happen after this time,
|
||||
## it will be automatically rescheduled until $StartReminderAt of the following day.
|
||||
$StopReminderAt = Get-Date -Hour 16 -Minute 50 -Second 0
|
||||
|
||||
## The amount of time between restart notifications
|
||||
$ReminderInterval = New-TimeSpan -Hours 2 -Minutes 45
|
||||
|
||||
|
||||
## This is some small amount of time in the future where the user can schedule a reboot. This isn't used often, but is used
|
||||
## The formula used here will add 20 minutes to the current time and round it to the nearest 5 minute mark.
|
||||
## I referenced the code by Tony Hinkle in this post:
|
||||
## https://stackoverflow.com/questions/39728485/rounding-down-minutes-to-the-nearest-10-minutes#39728699
|
||||
$ShortTimeFromNow = (Get-Date).AddMinutes(-(((Get-Date).Minute % 5) - 20))
|
||||
|
||||
## The following 5 settings configure the date and time this script will use to schedule reminders and restarts
|
||||
## All times will be today's date at the hour, minute, and second specified.
|
||||
## Specify the business start time.
|
||||
## This time is used to remind the user to restart their computer. The reminder won't show up until at least the value defined here.
|
||||
## The $ReminderDelay time will be added to $StartOfBusiness to come up with the time to remind the user to restart their computer.
|
||||
$StartOfBusiness = Get-Date -Hour 8 -Minute 30 -Second 0
|
||||
## Specify the lunch time
|
||||
## This time is used to schedule a restart all through the week and weekends.
|
||||
$LunchTime = Get-Date -Hour 12 -Minute 0 -Second 0
|
||||
## Specify the afternoon time
|
||||
## This time is used to schedule a restart only on the weekends and is based on $LunchTime
|
||||
$AfternoonTime = $LunchTime + (New-TimeSpan -Hours 2 -Minutes 30)
|
||||
## Specify the close-of-business time. In reality this should be a little bit before the actual close of business time.
|
||||
## This time is used to remind to restart only during the weekdays. This should be just before everyone starts leaving the office.
|
||||
$CloseOfBusiness = Get-Date -Hour 16 -Minute 50 -Second 0
|
||||
## Specify the late-at-night time
|
||||
## This time is used to schedule a restart only during the weekdays. You should use a time when users are least likely to work
|
||||
$LateAtNight = Get-Date -Hour 22 -Minute 0 -Second 0
|
||||
|
||||
## Specify delay after the $StartOfBusiness when the user will be reminded to restart
|
||||
## If the user does not restart, this is used to delay the reminder until most people are in the office
|
||||
## For example: if $StartOfBusiness is 8am, but most people aren't in the office until 8:30am,
|
||||
## you'll want to specify a value of 30 minutes here.
|
||||
## They probably don't want to come in and immediately see a reminder to restart their computer. Let them get coffee first :-)
|
||||
$ReminderDelay = New-TimeSpan -Minutes 40
|
||||
|
||||
## The next two settings define the week for your customer.
|
||||
## If their weekend is not Saturday and Sunday, define that here.
|
||||
## Weekend days
|
||||
$WeekendDays = @("Saturday","Sunday")
|
||||
## Week days
|
||||
$WeekDays = @("Monday","Tuesday","Wednesday","Thursday","Friday")
|
||||
|
||||
## The next two settings define the 2-day reminders and the 1-day reminders.
|
||||
## On the day this script is run, a reminder is automatically created.
|
||||
## If the user closes the window or clicks the placebo button, the reminder is already created
|
||||
## for either the next day, or 2 days from now.
|
||||
## If you changed the previous 2 settings to specify different weekend and week days,
|
||||
## you'll probably want to change this setting too.
|
||||
## The idea behind this is to guide the user to restarting their computer sooner rather than later.
|
||||
## The default options will push them towards restarting at the end of the work week, but if the
|
||||
## script runs on the weekend, the reminder won't bother them again until the start of the work week.
|
||||
## Specify the 2-day reminder days (user will be reminded 2 days after the days in this setting)
|
||||
$TwoDayReminderDays = @("Monday","Tuesday","Wednesday","Saturday")
|
||||
## Specify the 1-day reminder days (user will be reminded the day after the days in this setting)
|
||||
$OneDayReminderDays = @("Thursday","Friday","Sunday")
|
||||
|
||||
#endregion CUSTOMIZATIONS }
|
||||
|
||||
## This is where we do everything needed to either prompt or remind the user to restart their computer
|
||||
## This will involve copying the script locally, checking for existing reminder priorities, etc...
|
||||
#region begin PREFLIGHT {
|
||||
|
||||
## Copy this script to $CopyDirectory if it isn't being run from $CopyDirectory
|
||||
If ( $MyInvocation.PSCommandPath -ne "${CopyDirectory}\${CopyFilename}" ) { Copy-ThisScript }
|
||||
|
||||
## Disallow this script to display to the user before we check the parameters
|
||||
$AllowDisplay = $false
|
||||
|
||||
## If the last argument is -Task, then make sure we allow this script to display to the user
|
||||
If ( $args[$args.Count - 1].ToString() -ieq "-Task" ) { $AllowDisplay = $true }
|
||||
|
||||
## If the last argument isn't -Task, then we need to create a scheduled task for 10 seconds from now to run this script
|
||||
Else {
|
||||
|
||||
Write-Host "No Task"
|
||||
}
|
||||
|
||||
|
||||
#endregion PREFLIGHT }
|
||||
|
||||
## This is where we gather the necessary info and prompt the user to restart
|
||||
#region begin DISPLAY_FORM
|
||||
|
||||
## Get the nearest time to schedule a restart
|
||||
#$NearestRestartTime = Get-NearestRestartTime
|
||||
|
||||
## Get the next reminder time
|
||||
$NextReminderTime = Get-NextReminderTime
|
||||
|
||||
##
|
||||
|
||||
## Display the form
|
||||
If ( $AllowDisplay ) { Display-Prompt $SysPerfText }
|
||||
|
||||
#endregion DISPLAY_FORM
|
||||
@@ -1,280 +0,0 @@
|
||||
<#
|
||||
|
||||
.SYNOPSIS
|
||||
Provides friendly messages reminding a user to restart their computer based on events that require it.
|
||||
|
||||
.DESCRIPTION
|
||||
The Set-RebootSchedule script is called from any computer management software to notify a user of a required restart.
|
||||
This script accepts several different parameters which change the messages displayed to the user.
|
||||
|
||||
.PARAMETER SysPerf
|
||||
The -SysPerf parameter will remind the user to restart due to system performance.
|
||||
This parameter should be called if the computer has had consistently high memory usage, recurring application hangs, or stuck processes.
|
||||
If this parameter is used it will simply tell the user that a restart is needed to improve overall stability.
|
||||
|
||||
.PARAMETER OSUpdate
|
||||
The -OSUpdate parameter will remind the user to restart due to operating system updates.
|
||||
|
||||
.PARAMETER Uptime
|
||||
The -Uptime parameter will remind the user to restart due to long uptimes.
|
||||
This script does not define the length of time the computer has been on, but will display the number of days to the end user.
|
||||
If the computer has been on for 10 days and this parameter is used, it will tell the user this computer has been on for 10 days.
|
||||
|
||||
.PARAMETER AllowMinimize
|
||||
The -AllowMinimize parameter will let the prompt be minimized by the user.
|
||||
By default, the user is not allowed to minimize the window.
|
||||
|
||||
.EXAMPLE
|
||||
Set-RebootSchedule -SysPerf
|
||||
Prompt the user to restart because you've seen problems in multiple areas of the computer.
|
||||
|
||||
.EXAMPLE
|
||||
Set-RebootSchedule -OSUpdate
|
||||
Prompt the user to restart because Windows was recently updated.
|
||||
|
||||
.EXAMPLE
|
||||
Set-RebootSchedule -Uptime
|
||||
Prompt the user to restart because the computer has been up for a long time.
|
||||
|
||||
.NOTES
|
||||
Calling this script with no parameters does nothing, the script will just exit without prompting the user for anything.
|
||||
#>
|
||||
|
||||
## Define parameters
|
||||
|
||||
Param(
|
||||
[switch]$SysPerf=$false,
|
||||
[switch]$OSUpdate=$false,
|
||||
[switch]$Uptime=$false,
|
||||
[switch]$AllowMinimize=$false
|
||||
)
|
||||
|
||||
## Get the name of this script
|
||||
$ScriptName = $MyInvocation.MyCommand.Name
|
||||
|
||||
## Get a list of running PowerShell scripts
|
||||
$RUnningPSScripts = Get-WmiObject Win32_Process -Filter "Name='powershell.exe'" | Select-Object ProcessId,CommandLine
|
||||
|
||||
## Loop through all other running instances of this script and kill each one that isn't the current instance.
|
||||
ForEach ( $script in $RUnningPSScripts ) {
|
||||
$OtherPID = $script.ProcessId
|
||||
$OtherCMD = $script.CommandLine
|
||||
|
||||
## Check for other instances of this script that might be running
|
||||
If ( ($OtherCMD -like "*${ScriptName}*") -and ($OtherPID -ne $PID) ) {
|
||||
|
||||
## Kill the other instance
|
||||
Stop-Process -Id $script.ProcessId -Force
|
||||
}
|
||||
}
|
||||
|
||||
## Add Windows Forms support to this script
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
[System.Windows.Forms.Application]::EnableVisualStyles()
|
||||
|
||||
## Functions and subroutines
|
||||
#region begin FUNCTIONS {
|
||||
|
||||
## Gets the number of days the system has been up.
|
||||
Function Get-UptimeDays {
|
||||
|
||||
## Get a new instance of the Win32_OperatingSystem WMI object
|
||||
$WMIOS = Get-WmiObject Win32_OperatingSystem
|
||||
|
||||
## Get the last boot time and convert it to a DateTime value
|
||||
$LastBootTime = $WMIOS.ConvertToDateTime($WMIOS.LastBootUpTime)
|
||||
|
||||
## Get the number of days since the last time the system was powered on
|
||||
[string]$Uptime = (New-TimeSpan -Start $LastBootTime -End $(Get-Date)).Days.ToString()
|
||||
|
||||
Return $Uptime
|
||||
}
|
||||
|
||||
## Determines whether the logo can be downloaded or not
|
||||
Function IsLogoDownloadable {
|
||||
|
||||
## Create a web request
|
||||
$HTTPRequest = [System.Net.WebRequest]::Create($LogoURL)
|
||||
|
||||
## Get the response
|
||||
Try { $HTTPResponse = $HTTPRequest.GetResponse() }
|
||||
|
||||
## Catch any error2 when trying to connect to the resource (including 404)
|
||||
Catch [System.Net.WebException] { $HTTPResponse = $_.Exception.Response }
|
||||
|
||||
## Save the status code
|
||||
$HTTPStatus = [int]$HTTPResponse.StatusCode
|
||||
|
||||
## Close the connection, because we're done with it
|
||||
$HTTPResponse.Close()
|
||||
|
||||
## Test to make sure we received a status of 200 "OK" from the resource
|
||||
If ($HTTPStatus -eq 200) { Return $true }
|
||||
|
||||
## If the status code is anything other than 200, return $false so we can do something else
|
||||
Else { Return $false }
|
||||
}
|
||||
|
||||
## Returns the local path of a file downloaded from a URL
|
||||
Function Get-LogoPath {
|
||||
|
||||
## Get the file name from $url
|
||||
$filename = [System.IO.Path]::GetFileName($LogoURL)
|
||||
|
||||
## Set the destination to download to
|
||||
$localpath = "${Env:TEMP}\${filename}"
|
||||
|
||||
## Make sure the file is downloadable
|
||||
If ( IsLogoDownloadable ) {
|
||||
|
||||
## Try downloading the file
|
||||
Try { (New-Object Net.WebClient).DownloadFile($LogoURL, $localpath) }
|
||||
|
||||
## If you want to handle any download errors, put that code in here
|
||||
Catch { $_ }
|
||||
}
|
||||
|
||||
## Now that the file *may* be downloaded, check to make sure it exists
|
||||
If ( Test-Path $localpath ) {
|
||||
|
||||
## Return $localpath to the caller
|
||||
Return $localpath
|
||||
}
|
||||
|
||||
## If $localpath doesn't exist (ie: from a previous execution of this script) then return $false
|
||||
Else { Return $false }
|
||||
}
|
||||
|
||||
|
||||
## Builds the Windows form to display to the user
|
||||
Function Display-Prompt([string]$message) {
|
||||
|
||||
## Set the form's overall parameters
|
||||
$Form = New-Object System.Windows.Forms.Form
|
||||
$Form.ClientSize = '400,360'
|
||||
$Form.Text = $WindowTitle
|
||||
$Form.TopMost = $true
|
||||
$Form.MaximizeBox = $false
|
||||
$Form.MinimizeBox = $AllowMinimize
|
||||
$Form.FormBorderStyle = 'FixedDialog'
|
||||
$Form.StartPosition = 'CenterScreen'
|
||||
|
||||
## Download the logo
|
||||
$Logo = (Get-LogoPath)
|
||||
|
||||
## Add a picturebox to the form
|
||||
If ( $Logo ) {
|
||||
$pbLogo = New-Object system.Windows.Forms.PictureBox
|
||||
$pbLogo.Width = $Form.ClientSize.Width - 20
|
||||
$pbLogo.Height = 90
|
||||
$pbLogo.Anchor = [System.Windows.Forms.AnchorStyles]::None
|
||||
$pbLogo.Location = New-Object System.Drawing.Point(10,10)
|
||||
$pbLogo.ImageLocation = $Logo
|
||||
$pbLogo.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::CenterImage
|
||||
$Form.Controls.Add($pbLogo)
|
||||
}
|
||||
|
||||
## If the logo isn't available, add label to the form instead of a picturebox
|
||||
Else {
|
||||
$lblCompany = New-Object System.Windows.Forms.Label
|
||||
$lblCompany.Text = $CompanyName
|
||||
$lblCompany.AutoSize = $false
|
||||
## The TextAlign enumerations can be found here:
|
||||
## https://docs.microsoft.com/en-us/dotnet/api/system.drawing.contentalignment?view=netframework-2.0
|
||||
$lblCompany.TextAlign = 32
|
||||
$lblCompany.Width = $Form.ClientSize.Width - 20
|
||||
$lblCompany.Height = 60
|
||||
$lblCompany.Location = New-Object System.Drawing.Point(10,10)
|
||||
$lblCompany.Font = 'Microsoft Sans Serif,24,style=Bold'
|
||||
$Form.Controls.Add($lblCompany)
|
||||
}
|
||||
|
||||
## This is the label that contains the reason for the restart
|
||||
$lblReason = New-Object System.Windows.Forms.Label
|
||||
$lblReason.Text = $message
|
||||
$lblReason.AutoSize = $false
|
||||
$lblReason.TextAlign = 1
|
||||
$lblReason.Width = $Form.ClientSize.Width - 50
|
||||
$lblReason.Height = 180
|
||||
$lblReason.Location = New-Object System.Drawing.Point(25,100)
|
||||
$lblReason.Font = 'Microsoft Sans Serif,11'
|
||||
$Form.Controls.Add($lblReason)
|
||||
|
||||
## This is the label that contains a static message about how to proceed
|
||||
$lblProceed = New-Object System.Windows.Forms.Label
|
||||
$lblProceed.Text = $ProceedText
|
||||
$lblProceed.AutoSize = $true
|
||||
$lblProceed.TextAlign = 1
|
||||
$lblProceed.Location = New-Object System.Drawing.Point(25,280)
|
||||
$lblProceed.Font = 'Microsoft Sans Serif,11'
|
||||
$Form.Controls.Add($lblProceed)
|
||||
|
||||
## This is the button that displays the nearest time to schedule a reboot
|
||||
$btnRestartNow = New-Object System.Windows.Forms.Button
|
||||
$btnRestartNow.Text = $RestartNowText
|
||||
$btnRestartNow.Width = 130
|
||||
$btnRestartNow.Height = 30
|
||||
$btnRestartNow.Location = New-Object System.Drawing.Point(45,310)
|
||||
$btnRestartNow.Font = 'Microsoft Sans Serif,11'
|
||||
$btnRestartNow.Add_Click({
|
||||
|
||||
## Restart the computer
|
||||
Restart-Computer
|
||||
|
||||
## We're done for now, just close the window.
|
||||
$Form.Close()
|
||||
})
|
||||
|
||||
$Form.AcceptButton = $btmRestartNow
|
||||
$Form.Controls.Add($btnRestartNow)
|
||||
|
||||
## This is the placebo button, it just closes the form when clicked.
|
||||
## The reminder schedule has already been created, so this button doesn't need to do anything.
|
||||
$btnCancel = New-Object System.Windows.Forms.Button
|
||||
$btnCancel.Text = $CancelText
|
||||
$btnCancel.Width = 130
|
||||
$btnCancel.Height = 30
|
||||
$btnCancel.Location = New-Object System.Drawing.Point(225,310)
|
||||
$btnCancel.Font = 'Microsoft Sans Serif,11'
|
||||
$btnCancel.Add_Click({ $Form.Close() })
|
||||
$Form.Controls.Add($btnCancel)
|
||||
|
||||
|
||||
[void]$Form.ShowDialog()
|
||||
}
|
||||
|
||||
#endregion FUNCTIONS }
|
||||
|
||||
## Define custom company name, logo, window title, and messages
|
||||
#region begin CUSTOMIZATIONS {
|
||||
|
||||
## The following 2 settings are specific to your company
|
||||
## This is the name of your company.
|
||||
$CompanyName = "Emberkom"
|
||||
## This is the URL to your company logo.
|
||||
## If your company logo cannot be downloaded, $CompanyName will be used instead.
|
||||
## If the image you specify is larger than 380x90, it will be centered in that area (clipping will occur).
|
||||
$LogoURL = 'https://emberkom.s3.amazonaws.com/management/scripts/resources/small-web-logo.png'
|
||||
|
||||
## The following 7 settings control text displayed on the form when prompting the user to choose a time to restart their computer
|
||||
## The title of the window
|
||||
$WindowTitle = "Restart Required - ${CompanyName}"
|
||||
## The message displayed to the user when -SysPerf is called.
|
||||
$SysPerfText = "It looks like your computer isn't performing like it should.`n`nRestarting it will help to resolve some of the problems its been having."
|
||||
## The message displayed to the user when -OSUpdate is called.
|
||||
$OSUpdateText = "Good news!`n`nYour computer has recently installed some updates and it needs to be restarted soon."
|
||||
## The message displayed to the user when -Uptime is called.
|
||||
$UptimeText = "It looks like your computer has been on for more than $(Get-UptimeDays) days.`n`nIt's probably best to restart soon so it doesn't start causing problems for you."
|
||||
## This is the message displayed just above the buttons - it should ask the user how they want to proceed
|
||||
$ProceedText = "Can we make this happen?"
|
||||
## This is the text for the cancel button. Clicking this button will just close the form
|
||||
$CancelText = "Remind me later"
|
||||
## The message on the button that immediately restarts the computer
|
||||
$RestartNowText = "Restart Now"
|
||||
|
||||
#endregion CUSTOMIZATIONS }
|
||||
|
||||
## Display the form
|
||||
If ( $SysPerf ) { Display-Prompt $SysPerfText }
|
||||
ElseIf ( $OSUpdate ) { Display-Prompt $OSUpdateText }
|
||||
ElseIF ( $Uptime ) { Display-Prompt $UptimeText }
|
||||
@@ -1,152 +0,0 @@
|
||||
Function global:Set-WinEvtLog {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Enable/Disable an event log.
|
||||
.DESCRIPTION
|
||||
Enable or disable a Windows Event Log using the System.Diagnostics.Eventing.Reader.EventLogConfiguration object.
|
||||
This function only outputs terminating errors to the console. If you want to see more detail use -verbose
|
||||
.EXAMPLE
|
||||
Set-WinEvtLog -Enable -Log "Microsoft-Windows-DNS-Client/Operational"
|
||||
.EXAMPLE
|
||||
Set-WinEvtLog -Disable -Log (Get-Content ListOfLogs.txt)
|
||||
.EXAMPLE
|
||||
Get-Content ListOfLogs.txt | Set-WinEvtLog -Enable
|
||||
.PARAMETER Log
|
||||
The log(s) to modIfy.
|
||||
.PARAMETER Enable
|
||||
Enables the log(s).
|
||||
.PARAMETER Disable
|
||||
Disables the log(s).
|
||||
#>
|
||||
|
||||
[CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact='Low')]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory=$True,
|
||||
ValueFromPipeline=$False,
|
||||
ValueFromPipelineByPropertyName=$True,
|
||||
HelpMessage='Which log do you want to enable?')]
|
||||
[string[]]$Log,
|
||||
[Parameter(Mandatory=$True,
|
||||
ValueFromPipelineByPropertyName=$True,
|
||||
ParameterSetName = 'Enable')]
|
||||
[Switch]$Enable,
|
||||
[Parameter(Mandatory=$True,
|
||||
ValueFromPipelineByPropertyName=$True,
|
||||
ParameterSetName = 'Disable')]
|
||||
[Switch]$Disable
|
||||
)
|
||||
|
||||
Begin
|
||||
{
|
||||
# Keep track of changes made to event logs in a separate file.
|
||||
$RecordLog = "${Env:MSPDir}\Logs\WinEvtLogs-Enabled.log"
|
||||
|
||||
If ( !(Test-Path -Path $RecordLog) )
|
||||
{
|
||||
# Create the record keeping log file If it doesn't exist.
|
||||
$NewFile = ((New-Item -Path $RecordLog -ItemType file).name | Out-String)
|
||||
$NewFile = $NewFile.Trim()
|
||||
Write-Verbose "$NewFile did not exist and has been created."
|
||||
}
|
||||
}
|
||||
|
||||
Process
|
||||
{
|
||||
# Make sure Record Keeping is properly configured, otherwise exit.
|
||||
If ( !($RecordLog) )
|
||||
{
|
||||
Write-Verbose "The record keeping log does not exist, this function will not continue."
|
||||
Return
|
||||
}
|
||||
|
||||
# Loop through the name(s) in the $Log variable passed to this function.
|
||||
ForEach ($name in $Log)
|
||||
{
|
||||
# Process the data only If the script should Process data.
|
||||
If ( $pscmdlet.ShouldProcess($name, 'Enable Log') )
|
||||
{
|
||||
# Load the RecordLog into a variable.
|
||||
$PreviouslyEnabledLogs = Get-Content $RecordLog
|
||||
|
||||
# Determine whether to Enable or Disable logging of the specIfied log.
|
||||
Switch ($PSCmdlet.ParameterSetName)
|
||||
{
|
||||
'Enable' { $SetEnable = $True }
|
||||
'Disable' { $SetEnable = $False }
|
||||
}
|
||||
|
||||
# Create a new object for the specIfied log.
|
||||
$LogObject = New-Object System.Diagnostics.Eventing.Reader.EventLogConfiguration $name
|
||||
|
||||
# Set the variable to determine whether the log has been enabled by this script or not
|
||||
$IsEnabledByFunction = $False
|
||||
|
||||
# Determine whether or not the log had been enabled by this function.
|
||||
ForEach ($item in $PreviouslyEnabledLogs)
|
||||
{ If ($item -eq $name) { $IsEnabledByFunction = $True } }
|
||||
|
||||
# Act based on whether the log is already enabled or not.
|
||||
Switch ($logObject.IsEnabled)
|
||||
{
|
||||
$True
|
||||
{
|
||||
# Inform user whether this log has been enabled by this function or not.
|
||||
If ($IsEnabledByFunction)
|
||||
{ Write-Verbose "$name has previously been enabled by this function." }
|
||||
Else { Write-Verbose "$name has previously been enabled, but not by this function." }
|
||||
}
|
||||
|
||||
$False
|
||||
{
|
||||
# Inform user that this log has been disabled by something other than this function.
|
||||
If ($IsEnabledByFunction)
|
||||
{ Write-Verbose "$name should already be enabled by this function, but has been disabled by other means." }
|
||||
}
|
||||
}
|
||||
|
||||
# ModIfy the log to either enable or disable it.
|
||||
If ($LogObject.IsEnabled -eq $SetEnable)
|
||||
{ Write-Verbose "$name is already in the desired state." }
|
||||
Else
|
||||
{
|
||||
# Set the log to the desired state.
|
||||
$LogObject.IsEnabled = $SetEnable
|
||||
|
||||
# Save changes to the log.
|
||||
$LogObject.SaveChanges()
|
||||
|
||||
# VerIfy the change has been made.
|
||||
Switch ($LogObject.IsEnabled)
|
||||
{
|
||||
$True
|
||||
{
|
||||
Write-Verbose "$name has been enabled."
|
||||
|
||||
# Make sure this log wasn't already enabled by this function so we don't write the same name more than once in $RecordLog
|
||||
If (!($IsEnabledByFunction)) { Add-Content -Path $RecordLog "$name" }
|
||||
}
|
||||
|
||||
$False
|
||||
{
|
||||
# Remove $name from $RecordLog If it was put there by this function.
|
||||
If ($IsEnabledByFunction)
|
||||
{
|
||||
# Clear the contents of $RecordLog
|
||||
Clear-Content -Path $RecordLog
|
||||
|
||||
# Add each item back in that was already there except for the current $name
|
||||
ForEach ($filename In $PreviouslyEnabledLogs)
|
||||
{ If ($filename -ne $name) { Add-Content -Path $RecordLog $filename} }
|
||||
}
|
||||
Write-Verbose "$name has been disabled."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end {}
|
||||
}
|
||||
Export-ModuleMember -Function Set-WinEvtLog
|
||||
@@ -6,7 +6,7 @@ function process_debian()
|
||||
apt-get update
|
||||
|
||||
## Upgrade packages
|
||||
apt-get upgrade -y
|
||||
apt-get upgrade --with-new-pkgs -y
|
||||
|
||||
## Remove unused packages
|
||||
apt autoremove
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
@echo off
|
||||
|
||||
REM Windows Server 2012 x64
|
||||
set Win62x64=https://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/W2K12-KB3191565-x64.msu
|
||||
set Win62x64File=W2K12-KB3191565-x64.msu
|
||||
|
||||
REM Windows 8.1 x86
|
||||
set Win63x86=https://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/Win8.1-KB3191564-x86.msu
|
||||
set Win63x86File=Win8.1-KB3191564-x86.msu
|
||||
|
||||
REM Windows 8.1 and Server 2012 R2 x64
|
||||
set Win63x64=https://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/Win8.1AndW2K12R2-KB3191564-x64.msu
|
||||
set Win63x64File=Win8.1AndW2K12R2-KB3191564-x64.msu
|
||||
|
||||
REM Windows 7 x86
|
||||
set Win61x86=https://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/Win7-KB3191566-x86.zip
|
||||
set Win61x86File=Win7-KB3191566-x86.zip
|
||||
|
||||
Rem Windows 7 and Server 2008 R2 x64
|
||||
set Win61x64=https://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/Win7AndW2K8R2-KB3191566-x64.zip
|
||||
set Win61x64File=Win7AndW2K8R2-KB3191566-x64.zip
|
||||
@@ -1,74 +0,0 @@
|
||||
#Requires -version 2
|
||||
|
||||
## Get the Windows version information
|
||||
$WinVersion = "{0}.{1}" -f ([System.Environment]::OSVersion.Version).Major,([System.Environment]::OSVersion.Version).Minor
|
||||
$WinBuild = ([System.Environment]::OSVersion.Version).Build
|
||||
|
||||
## Get PowerShell version information
|
||||
$CurrentVersion = "{0}.{1}" -f $PSVersionTable.PSVersion.Major,$PSVersionTable.PSVersion.Minor
|
||||
|
||||
## Check the OS architecture
|
||||
If ( Test-Path -PathType Container -Path ${env:ProgramFiles(x86)} ) { $Is64bit = $true } Else { $Is64bit = $false }
|
||||
|
||||
## Set a variable to make sure the current Windows version is supported
|
||||
$InstallSupported = $true
|
||||
|
||||
Switch ( $WinVersion ) {
|
||||
|
||||
## Windows Vista
|
||||
"6.0" {
|
||||
If ( $Is64bit ) { $URL = 'https://download.microsoft.com/download/E/7/6/E76850B8-DA6E-4FF5-8CCE-A24FC513FD16/Windows6.0-KB2506146-x64.msu' }
|
||||
Else { $URL = 'https://download.microsoft.com/download/E/7/6/E76850B8-DA6E-4FF5-8CCE-A24FC513FD16/Windows6.0-KB2506146-x86.msu' }
|
||||
$UpgradeVersion = 3.0
|
||||
; break }
|
||||
|
||||
## Windows 7
|
||||
"6.1" {
|
||||
## PowerShell 4.0
|
||||
If ( $Is64bit ) { $URL = 'https://download.microsoft.com/download/3/D/6/3D61D262-8549-4769-A660-230B67E15B25/Windows6.1-KB2819745-x64-MultiPkg.msu' }
|
||||
Else { $URL = 'https://download.microsoft.com/download/3/D/6/3D61D262-8549-4769-A660-230B67E15B25/Windows6.1-KB2819745-x86-MultiPkg.msu' }
|
||||
$UpgradeVersion = 4.0
|
||||
; break }
|
||||
|
||||
## Windows 8
|
||||
#"6.2" {; break }
|
||||
|
||||
## Windows 8.1
|
||||
#"6.3" {; break }
|
||||
|
||||
## Windows 10
|
||||
#"10.0" {; break }
|
||||
|
||||
## Not Supported
|
||||
default { $InstallSupported = $false ; break }
|
||||
}
|
||||
|
||||
## Make sure installation is supported
|
||||
If ( ($InstallSupported) -and ($CurrentVersion -lt $UpgradeVersion) ) {
|
||||
|
||||
## Get the file type so we install it the correct way
|
||||
$FileType = ([System.IO.Path]::GetExtension($File)).ToUpper()
|
||||
|
||||
## Set the destination file for the downloaded package
|
||||
$File = "${env:TEMP}\$(Split-Path -Leaf $URL)"
|
||||
|
||||
## Download the installation package
|
||||
(New-Object Net.WebClient).DownloadFile($URL,$File)
|
||||
|
||||
If ( Test-Path $File ) {
|
||||
|
||||
## Get the file extension so we use the correct method to install the update
|
||||
$FileType = [System.IO.Path]::GetExtension($File)
|
||||
|
||||
## Write a message so we know what version was upgraded.
|
||||
Write-Host "Upgrading PowerShell ${CurrentVersion} to version ${UpgradeVersion}"
|
||||
|
||||
## Install the package
|
||||
If ( $FileType -ieq "MSU" ) { Start-Process wusa.exe -ArgumentList "${File} /quiet /norestart" -Wait }
|
||||
If ( $FileType -ieq "MSI" ) { Start-Process msiexec.exe -ArgumentList "/i ${File} /qn /norestart" -Wait }
|
||||
|
||||
## Delete the downloaded package
|
||||
Remove-Item -Path $File -Force
|
||||
}
|
||||
|
||||
} Else { Write-Host "This script cannot upgrade PowerShell on this endpoint." }
|
||||
@@ -426,4 +426,20 @@ Function Create-Shortcut {
|
||||
Catch { LogErr $_.Exception.Message }
|
||||
}
|
||||
Else { LogMsg "Cannot create shortcut because the target path does not exist" }
|
||||
}
|
||||
|
||||
# Function to enable or disable a specified log
|
||||
function Toggle-Log {
|
||||
param (
|
||||
[Parameter(Mandatory = $true)][string]$Name,
|
||||
[Parameter(Mandatory = $true, ParameterSetName = 'Enable')][switch]$Enable,
|
||||
[Parameter(Mandatory = $true, ParameterSetName = 'Disable')][switch]$Disable
|
||||
)
|
||||
Try {
|
||||
$log = New-Object System.Diagnostics.Eventing.Reader.EventLogConfiguration $Name
|
||||
If ( $Enable ) { $log.IsEnabled = $true }
|
||||
If ( $Disable ) { $log.IsEnabled = $false }
|
||||
$log.SaveChanges()
|
||||
}
|
||||
Catch { LogMsg $_.Exception.Message }
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
@echo off
|
||||
if exist "%ProgramFiles(x86)%\CCleaner Cloud\uninst.exe" start "" /w "%ProgramFiles(x86)%\CCleaner Cloud\uninst.exe" /S
|
||||
goto end
|
||||
if exist "%ProgramFiles%\CCleaner Cloud\uninst.exe" start "" /w "%ProgramFiles%\CCleaner Cloud\uninst.exe" /S
|
||||
:end
|
||||
@@ -2,7 +2,7 @@
|
||||
$AppList = @(
|
||||
## Office Apps
|
||||
'Microsoft.Office.Sway',
|
||||
'Microsoft.Office.OneNote',
|
||||
#'Microsoft.Office.OneNote',
|
||||
'Microsoft.MicrosoftOfficeHub',
|
||||
'Microsoft.Office.Desktop',
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
If ( Test-Path "${Env:SystemDrive}\ProgramData\Autodesk\Revit Server 2016\Config\RSN.ini")
|
||||
{
|
||||
Remove-Item "${Env:SystemDrive}\ProgramData\Autodesk\Revit Server 2016\Config\RSN.ini"
|
||||
$server = "va01rvt02.dbia.com"
|
||||
$server | Out-File "${Env:SystemDrive}\ProgramData\Autodesk\Revit Server 2016\Config\RSN.ini"
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
param (
|
||||
[string]$Path,
|
||||
[string]$Password,
|
||||
[int]$SpeedLimit=300,
|
||||
[switch]$SelfDestruct
|
||||
)
|
||||
|
||||
## Immediately delete this script from disk, if requested
|
||||
if ( $SelfDestruct ) {
|
||||
try { Remove-Item $MyINvocation.InvocationName -Force }
|
||||
catch { Write-Host "Self destruct failed, killing script!"; exit } }
|
||||
|
||||
## Download required tools
|
||||
$DOWNLOAD_TOOLS_SCRIPT = "https://emberkom.s3.amazonaws.com/management/scripts/Download-Tools.ps1"
|
||||
try { Invoke-Expression ((New-Object System.Net.WebClient).DownloadString($DOWNLOAD_TOOLS_SCRIPT)) }
|
||||
catch { Write-Host "Required tools failed to download!"; exit }
|
||||
|
||||
## Make sure WinSCP exists
|
||||
$WINSCP = "${Env:Temp}\Emberkom\Tools\winscp.com"
|
||||
if ( !(Test-Path "${WINSCP}") ) {
|
||||
if ( Test-Path "${Env:ProgramData}\Emberkom\Tools\winscp.com" ) {
|
||||
$WINSCP = "${Env:ProgramData}\Emberkom\Tools\winscp.com"
|
||||
} else { Write-Host "WinSCP does not exist!"; exit } }
|
||||
|
||||
## Prepare WinSCP script file
|
||||
$HOSTNAME = 'xfer.emberkom.net'
|
||||
$HOSTKEY = 'ecdsa-sha2-nistp256 256 5iJFeMzLK5Ld7gbLn+NlcYyI+DvbSXB8fmFJLLDh7s0='
|
||||
$USERNAME = 'JeQCXVBI80Pj3nL'
|
||||
#$PASSWORD = ''
|
||||
$SCRIPT_FILE = [System.IO.Path]::GetTempFileName()
|
||||
$UPLOAD_SCRIPT = @(
|
||||
"echo off",
|
||||
"option batch on",
|
||||
"option confirm off",
|
||||
"open sftp://${USERNAME}:${Password}@${HOSTNAME}/ -hostkey=`"${HOSTKEY}`"",
|
||||
"mkdir `"${Env:ComputerName}`"",
|
||||
"cd `"${Env:ComputerName}`"",
|
||||
"mkdir `"${Env:Username}`"",
|
||||
"cd `"${Env:Username}`"",
|
||||
"mkdir `"Manual Upload`"",
|
||||
"cd `"Manual Upload`"",
|
||||
"put -resume -nopermissions -preservetime -speed=${SpeedLimit} -resumesupport=on -neweronly `"${Path}`"",
|
||||
"exit")
|
||||
try { ForEach ($line in $UPLOAD_SCRIPT) { $line | Out-File "${SCRIPT_FILE}" -Append } }
|
||||
catch { Write-Host "Script file could not be created: ${SCRIPT_FILE}"; exit }
|
||||
|
||||
## Upload the data
|
||||
try { Start-Process -WindowStyle Hidden "${WINSCP}" -ArgumentList "/script=`"${SCRIPT_FILE}`"" -Wait }
|
||||
catch { Write-Host "Data transfer failed!" }
|
||||
|
||||
## Delete the script file
|
||||
try { Remove-Item -Path "${SCRIPT_FILE}" -Force }
|
||||
catch { Write-Host "Script file could not be deleted: ${SCRIPT_FILE}" }
|
||||
@@ -1,70 +0,0 @@
|
||||
param (
|
||||
[string]$Path,
|
||||
[string]$Filedrop = 'https://xfer.emberkom.net/filedrop/cmd',
|
||||
[string]$From,
|
||||
[string]$Subject = "Upload from ${Env:COMPUTERNAME}",
|
||||
[string]$Message = ""
|
||||
)
|
||||
|
||||
## Build the from address if it isn't specified
|
||||
If ( !($From) )
|
||||
{
|
||||
If ( "${Env:USERDOMAIN}" -eq "${Env:COMPUTERNAME}" ) { $From = "${Env:COMPUTERNAME}@localdomain.local".ToLower() }
|
||||
Else { $From = "${Env:COMPUTERNAME}@${Env:USERDOMAIN}".ToLower() }
|
||||
}
|
||||
|
||||
## Download required tools
|
||||
$DOWNLOAD_TOOLS_SCRIPT = "https://emberkom.s3.amazonaws.com/management/scripts/Download-Tools.ps1"
|
||||
Try { Invoke-Expression ((New-Object System.Net.WebClient).DownloadString($DOWNLOAD_TOOLS_SCRIPT)) }
|
||||
Catch { Write-Host "Required tools failed to download!" }
|
||||
|
||||
## Get the path to the LiquidFilesCLI application
|
||||
If ( Test-Path "${Env:ProgramData}\Emberkom\Tools\LiquidFilesCLI.exe" ) { $LFCLI = "${Env:ProgramData}\Emberkom\Tools\LiquidFilesCLI.exe" }
|
||||
ElseIf ( Test-Path "${Env:AppData}\Emberkom\Tools\LiquidFilesCLI.exe" ) { $LFCLI = "${Env:AppData}\Emberkom\Tools\LiquidFilesCLI.exe" }
|
||||
Else { Write-Host "Could not find LiquidFilesCLI.exe"; exit }
|
||||
|
||||
## Get the path to the 7za.exe application
|
||||
If ( Test-Path "${Env:ProgramData}\Emberkom\Tools\7za.exe" ) { $ZIPUTIL = "${Env:ProgramData}\Emberkom\Tools\7za.exe" }
|
||||
ElseIf ( Test-Path "${Env:AppData}\Emberkom\Tools\7za.exe" ) { $ZIPUTIL = "${Env:AppData}\Emberkom\Tools\7za.exe" }
|
||||
Else { Write-Host "Could not find 7za.exe"; exit }
|
||||
|
||||
## Set the base args
|
||||
$ARGS = "filedrop /url:${Filedrop} /from:`"${From}`" /subject:`"${Subject}`" /msg:`"${Message}`" /c:s"
|
||||
|
||||
## Make sure $Path exists
|
||||
If ( Test-Path $Path )
|
||||
{
|
||||
## If $Path is a folder...
|
||||
If ( Test-Path $Path -PathType Container )
|
||||
{
|
||||
## Set the archive type
|
||||
$ARCHIVE_TYPE = "7z"
|
||||
|
||||
## Set the temporary archive
|
||||
$TEMP_PATH = [System.IO.Path]::GetTempPath()
|
||||
$TEMP_FILE = Split-Path $Path -Leaf
|
||||
$TEMP_ARCHIVE = "${TEMP_PATH}${TEMP_FILE}.${ARCHIVE_TYPE}"
|
||||
|
||||
## Delete $TEMP_ARCHIVE if it somehow already exists
|
||||
If ( Test-Path $TEMP_ARCHIVE ) { Remove-Item $TEMP_ARCHIVE -Force }
|
||||
|
||||
## Compress the folder into the archive
|
||||
Try { Start-Process -WindowStyle Hidden "${ZIPUTIL}" -ArgumentList "a -r -t${ARCHIVE_TYPE} -w `"${TEMP_ARCHIVE}`" `"${Path}`"" -Wait }
|
||||
Catch { Write-Host "Could not create ${TEMP_ARCHIVE}"; exit }
|
||||
|
||||
$ARGS = "${ARGS} /f:`"${TEMP_ARCHIVE}`""
|
||||
}
|
||||
|
||||
## If $Path is a file...
|
||||
ElseIf ( Test-Path $Path -PathType Leaf ) { $ARGS = "${ARGS} /f:`"${Path}`"" }
|
||||
|
||||
## If $Path doesn't exist...
|
||||
Else { Write-Host "${Path} doesn't exist!"; exit }
|
||||
}
|
||||
|
||||
## Upload the file
|
||||
Try { Start-Process -WindowStyle Hidden "${LFCLI}" -ArgumentList "${ARGS}" -Wait }
|
||||
Catch { Write-Host "Upload failed!" }
|
||||
|
||||
## Delete the local archive (if it exists)
|
||||
Finally { If ( Test-Path $TEMP_ARCHIVE ) { Remove-Item $TEMP_ARCHIVE -Force } }
|
||||
Reference in New Issue
Block a user