2020-09-23 21:32:50 -04:00
## Define the MSP name
2021-08-05 09:42:15 -04:00
[ string ] $Global:MSPName = "Emberkom"
## This section will define several global variables that can be used in scripts that source this one
[ string ] $Global:RootDirectory
[ string ] $Global:ScriptsDirectory
[ string ] $Global:OutputDirectory
[ string ] $Global:ToolsDirectory
[ string ] $Global:LogsDirectory
[ string ] $Global:LogFile
2020-09-09 21:06:44 -04:00
## Setup the MSP management directories
2021-08-05 09:42:15 -04:00
Function Setup-MSPDirectories {
If ( Test-Path ${ Env : ProgramData } ) { $Global:RootDirectory = " ${Env:ProgramData} \ ${MSPName} " } Else { $Global:RootDirectory = " ${Env:SystemDrive} \ ${MSPName} " }
$Global:ScriptsDirectory = " ${RootDirectory} \Scripts"
$Global:OutputDirectory = " ${RootDirectory} \Output"
$Global:ToolsDirectory = " ${RootDirectory} \Tools"
$Global:LogsDirectory = " ${RootDirectory} \Logs"
2020-09-09 21:06:44 -04:00
2021-08-05 09:42:15 -04:00
## Make sure all the management directories exist
$RootDirectory , $ScriptsDirectory , $OutputDirectory , $ToolsDirectory , $LogsDirectory | ForEach-Object {
If ( !( Test-Path $_ ) ) {
Try { New-Item -Path $_ -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null }
Catch { Write-Output $_ . Exception . Message }
}
}
2020-09-23 21:31:52 -04:00
}
2020-09-09 21:06:44 -04:00
2021-08-05 09:42:15 -04:00
## Function to get a datestamp for right now in a long format
Function Get-LongDateTime {
Return $ ( Get-Date -Format "yyyyMMddHHmmssffff" )
}
2020-09-19 15:29:31 -04:00
2021-08-05 09:42:15 -04:00
## Setup the log file for messages generated when this script is run
Function Setup-LogFile {
$LogFilePrefix = "ManagementScript"
$LogFilePostfix = Get-LongDateTime
$Global:LogFile = " ${LogsDirectory} \ ${LogFilePrefix} _ ${LogFilePostfix} .log"
2021-09-23 14:28:01 -04:00
## Delete log files older than 120 days
$LogFileAllowedAge = ( Get-Date ). AddDays ( -120 )
2021-08-05 09:42:15 -04:00
Try {
Get-ChildItem -Path " ${LogsDirectory} \ ${LogFilePrefix} _*.*" -Filter '*.log' | `
Where-Object { $_ . LastWriteTime -lt $LogFileAllowedAge } | `
Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null
}
Catch { Write-Output $_ . Exception . Message }
Try { If ( !( Test-Path $LogFile ) ) { New-Item -Path $LogFile -ItemType File -Force | Out-Null } }
Catch { Write-Output $_ . Exception . Message }
}
2021-05-27 18:07:02 -04:00
2020-10-22 14:01:35 -04:00
## Log a message to the log file
2020-11-06 11:24:16 -05:00
Function LogMsg {
param ([ Parameter ( Mandatory = $true , ValueFromPipeline = $true )][ string ] $Message )
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$LogEntry = " ${Timestamp} - ${Message} "
2021-08-12 17:50:47 -04:00
Add-Content -Path $Global:LogFile -Value $LogEntry
2020-09-09 21:06:44 -04:00
}
2020-10-22 14:01:35 -04:00
## Log an error to the log file
2020-11-06 11:24:16 -05:00
Function LogErr {
param ([ Parameter ( Mandatory = $true , ValueFromPipeline = $true )][ string ] $Message )
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$LogEntry = " ${Timestamp} - Error: ${Message} "
2021-08-12 17:50:47 -04:00
Add-Content -Path $Global:LogFile -Value $LogEntry
2020-09-07 13:43:37 -04:00
}
## Function to determine if the current user context is an Administrator
2020-11-06 11:24:16 -05:00
Function IsAdmin {
If ( ([ Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity ]:: GetCurrent ()). IsInRole ([ Security.Principal.WindowsBuiltInRole ]:: Administrator ) )
{ Return $true } Else { Return $false }
2020-09-07 13:43:37 -04:00
}
2020-09-23 15:24:26 -04:00
## Run a script from the live repo or from a local path
2020-11-06 11:24:16 -05:00
Function Run-Script {
param (
## Parameters for live-ps scripts
[ Parameter ( Mandatory = $false , ParameterSetName = 'live-ps' )]
[ string ] $Type = 'management-scripts' ,
[ Parameter ( Mandatory = $true , ParameterSetName = 'live-ps' )]
[ string ] $LivePSScript ,
## Parameters for local scripts
[ Parameter ( Mandatory = $true , ParameterSetName = 'local' )]
[ string ] $Path ,
#### $NoWait will prevent waiting for the specified script to finish running
[ Parameter ( Mandatory = $false , ParameterSetName = 'local' )]
[ switch ] $NoWait = $false ,
## Parameters for all scripts
[ Parameter ( Mandatory = $false , ParameterSetName = 'live-ps' )]
[ Parameter ( Mandatory = $false , ParameterSetName = 'local' )]
[ string ] $Arguments = 'null' ,
#### $HaltIfRunning is a collection of app names which, if running, will prevent the script from running
[ Parameter ( Mandatory = $false , ParameterSetName = 'live-ps' )]
[ Parameter ( Mandatory = $false , ParameterSetName = 'local' )]
[ string[] ] $HaltIfRunning = 'null' ,
#### $ForceClose will forcefully close all apps specified in $HaltIfRunning
[ Parameter ( Mandatory = $false , ParameterSetName = 'live-ps' )]
[ Parameter ( Mandatory = $false , ParameterSetName = 'local' )]
[ switch ] $ForceClose = $false
)
If ( $Arguments -eq "null" ) { $Arguments = $null }
If ( $HaltIfRunning -eq "null" ) { $HaltIfRunning = $null }
If ( $LivePSScript ) {
$URL = "https://dev.emberkom.com/emberkom/ ${Type} /raw/branch/master/ ${LivePSScript} .ps1"
If ( !( IsURLValid -URL $URL ) ) { LogMsg "The specified script does not exist: ${LivePSScript} " ; Exit }
}
If ( $Path ) { If ( !( Test-Path $Path ) ) { LogMsg "The specified script does not exist: "" ${Path} """ ; Exit } }
If ( ( $HaltIfRunning -ne $null ) -and ( $ForceClose ) -and ( !( IsAdmin ) ) ) { LogMsg "Cannot close dependent apps because this task does not have administrative privileges" ; Exit }
If ( $HaltIfRunning ) {
$Halt = $false
LogMsg "Checking for running instances of the following dependent apps:"
ForEach ( $name in $HaltIfRunning ) {
$RunningInstances = Get-Process | Where { $_ . Name -like " ${name} " }
If ( $RunningInstances ) {
If ( $ForceClose -eq $true ) {
2020-12-03 17:22:02 -05:00
Try { $name | Stop-Process -Force ; LogMsg " "" ${name} "" (force closed)" }
2020-11-06 11:24:16 -05:00
Catch { LogErr $_ . Exception . Message ; Exit }
}
Else { $Halt = $true ; LogMsg " "" ${name} "" (running)" }
2020-09-23 21:31:52 -04:00
}
2020-11-06 11:24:16 -05:00
Else { LogMsg " "" ${name} "" (not running)" }
2020-09-23 20:43:29 -04:00
}
2020-11-06 11:24:16 -05:00
If ( $Halt -eq $true ) { LogMsg "Dependent apps are currently in use and are preventing the specified script from running" ; Exit }
2020-09-23 15:24:26 -04:00
}
2020-11-06 11:24:16 -05:00
switch ( $PSCmdlet . ParameterSetName ) {
'live-ps' {
LogMsg "Retrieving : ${LivePSScript} .ps1"
Try { $Script = ( New-Object Net . WebClient ). DownloadString ( $URL ) }
Catch { LogErr $_ . Exception . Message ; Exit }
Try { $ScriptBlock = [ Scriptblock ]:: Create ( $Script ) }
Catch { LogErr $_ . Exception . Message ; Exit }
2022-03-17 21:48:10 -04:00
LogMsg "Executing: ${LivePSScript} .ps1 ${Arguments} "
2020-11-06 11:24:16 -05:00
Try { Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $Arguments }
Catch { LogErr $_ . Exception . Message ; Exit }
2020-10-22 14:01:35 -04:00
}
2020-11-06 11:24:16 -05:00
'local' {
LogMsg "Executing: ${Path} ${Arguments} "
If ( $NoWait ) {
Try { Start-Process " ${Path} " -ArgumentList "{ $Arguments }" }
Catch { LogErr $_ . Exception . Message }
}
Else {
LogMsg " Waiting for script to finish..."
Try { Start-Process " ${Path} " -ArgumentList "{ $Arguments }" -Wait }
Catch { LogErr $_ . Exception . Message }
LogMsg " Finished"
}
2020-09-23 15:24:26 -04:00
}
}
2021-10-23 13:54:04 -04:00
$LogFileContent = ( Get-Content $LogFile )
2020-11-06 11:24:16 -05:00
## Write the log file output to the console
2021-10-23 13:54:04 -04:00
If ( $LogFileContent ) { Write-Output $LogFileContent }
## Delete the log file if it's empty
Else { Remove-Item $LogFile -Force }
2020-09-23 15:24:26 -04:00
}
2020-10-22 14:01:35 -04:00
## Return a Powershell version object from a string
2020-11-06 11:24:16 -05:00
Function Get-Version {
param ([ Parameter ( Mandatory = $true )][ string ] $Version )
[ int ] $Sets = 4
$VersionArray = $Version . Split ( '.' )
If ( $VersionArray . Count -le $Sets ) { $Sets = $VersionArray . Count }
For ( $i = 0 ; $i -le ( $Sets - 1 ); $i ++) {
$Return = '{0}.{1}' -f $Return , $VersionArray [ $i ] }
Return [ version ] $Return . Trim ( '.' )
2020-09-07 20:18:06 -04:00
}
2020-09-23 21:52:25 -04:00
## Determines whether a URL is valid
2020-11-06 11:24:16 -05:00
Function IsURLValid {
param ([ Parameter ( Mandatory = $true , ValueFromPipeline = $true )][ string ] $URL )
Try {
$HTTPRequest = [ System.Net.WebRequest ]:: Create ( $URL )
$HTTPResponse = $HTTPRequest . GetResponse ()
$HTTPStatus = [ int ] $HTTPResponse . StatusCode
$HTTPResponse . Close ()
}
Catch { }
2021-08-19 12:43:40 -04:00
If ( $HTTPStatus -ne 404 ) { Return $true }
2020-11-06 11:24:16 -05:00
Else { Return $false }
2020-09-23 21:52:25 -04:00
}
2020-10-22 14:01:35 -04:00
## Downloads a file from a URL
2020-11-06 11:24:16 -05:00
Function Download-File {
param (
[ Parameter ( Mandatory = $true , ValueFromPipeline = $true )][ string ] $URL ,
[ Parameter ( Mandatory = $false , ValueFromPipeline = $false )][ string ] $File
)
If ( !( $File ) ) { $File = '{0}{1}' -f ( GetTempPath ), ( Split-Path $URL -Leaf ) }
If ( IsURLValid $URL ) {
If ( Test-Path $File ) {
LogMsg "Deleting existing file: "" ${File} """
Try { Remove-Item $File -Force }
Catch { LogErr $_ . Exception . Message }
}
LogMsg "Downloading "" ${URL} "" to "" ${File} """
Try { ( New-Object System . Net . WebClient ). DownloadFile ( $URL , $File ) }
2020-10-22 14:01:35 -04:00
Catch { LogErr $_ . Exception . Message }
2020-11-06 11:24:16 -05:00
If ( Test-Path " ${File} " ) { Return " ${File} " }
Else { LogMsg "Downloaded file does not exist at "" ${File} """ ; Return $false }
2020-10-19 11:24:07 -04:00
}
2020-11-06 11:24:16 -05:00
Else { LogMsg "URL is not valid or file cannot be reached: ${URL} " }
2020-10-22 14:01:35 -04:00
}
## Install a program from a provided path
2020-11-06 11:24:16 -05:00
Function Install-Program {
param (
[ Parameter ( Mandatory = $true , ValueFromPipeline = $true )][ string ] $Path ,
[ Parameter ( Mandatory = $false )][ string ] $Arguments = '' ,
[ Parameter ( Mandatory = $false )][ switch ] $Delete = $false
)
If ( Test-Path " ${Path} " ) {
LogMsg "Running installer: "" ${Path} "" ${Arguments} "
2020-12-03 17:27:53 -05:00
Try {
If ( $Arguments -eq '' ) { Start-Process " ${Path} " -Wait }
Else { Start-Process " ${Path} " -ArgumentList " ${Arguments} " -Wait }
}
2020-10-22 14:01:35 -04:00
Catch { LogErr $_ . Exception . Message }
2020-11-06 11:24:16 -05:00
LogMsg "Installer finished"
If ( $Delete ) {
LogMsg "Deleting installer: "" ${Path} """
Try { Remove-Item -Path " ${Path} " -Force }
Catch { LogErr $_ . Exception . Message }
}
2020-10-22 14:01:35 -04:00
}
2020-11-06 11:24:16 -05:00
Else { LogMsg "The specified file could not be found: "" ${Path} """ }
2020-10-19 11:24:07 -04:00
}
2020-11-06 11:24:16 -05:00
## Compare current Windows version with a supplied version
2020-09-09 16:59:40 -04:00
## The value supplied must be a string and must include at least 1 decimal
2020-11-06 11:24:16 -05:00
Function IsWindowsVersion {
param (
[ Parameter ( Mandatory = $true , ParameterSetName = 'gt' )][ string ] $gt ,
[ Parameter ( Mandatory = $true , ParameterSetName = 'ge' )][ string ] $ge ,
[ Parameter ( Mandatory = $true , ParameterSetName = 'lt' )][ string ] $lt ,
[ Parameter ( Mandatory = $true , ParameterSetName = 'le' )][ string ] $le ,
[ Parameter ( Mandatory = $true , ParameterSetName = 'eq' )][ string ] $eq
)
[ version ] $WindowsVersion = [ System.Environment ]:: OSVersion . Version
switch ( $PSCmdlet . ParameterSetName ) {
'gt' { If ( $WindowsVersion -gt ( Get-Version $gt ) ) { Return $true } Else { Return $false } }
'ge' { If ( $WindowsVersion -ge ( Get-Version $ge ) ) { Return $true } Else { Return $false } }
'lt' { If ( $WindowsVersion -lt ( Get-Version $lt ) ) { Return $true } Else { Return $false } }
'le' { If ( $WindowsVersion -le ( Get-Version $le ) ) { Return $true } Else { Return $false } }
'eq' { If ( $WindowsVersion -eq ( Get-Version $eq ) ) { Return $true } Else { Return $false } }
}
2020-09-09 16:46:21 -04:00
}
2020-10-22 14:01:35 -04:00
## Compare current Windows build with a supplied version
2020-09-09 16:59:40 -04:00
## The value supplied must be an int
2020-11-06 11:24:16 -05:00
Function IsWindowsBuild {
param (
[ Parameter ( Mandatory = $true , ParameterSetName = 'gt' )][ int ] $gt ,
[ Parameter ( Mandatory = $true , ParameterSetName = 'ge' )][ int ] $ge ,
[ Parameter ( Mandatory = $true , ParameterSetName = 'lt' )][ int ] $lt ,
[ Parameter ( Mandatory = $true , ParameterSetName = 'le' )][ int ] $le ,
[ Parameter ( Mandatory = $true , ParameterSetName = 'eq' )][ int ] $eq
)
[ int ] $WindowsBuild = [ System.Environment ]:: OSVersion . Version . Build
switch ( $PSCmdlet . ParameterSetName ) {
'gt' { If ( $WindowsBuild -gt $gt ) { Return $true } Else { Return $false } }
'ge' { If ( $WindowsBuild -ge $ge ) { Return $true } Else { Return $false } }
'lt' { If ( $WindowsBuild -lt $lt ) { Return $true } Else { Return $false } }
'le' { If ( $WindowsBuild -le $le ) { Return $true } Else { Return $false } }
'eq' { If ( $WindowsBuild -eq $eq ) { Return $true } Else { Return $false } }
}
2020-09-25 13:13:03 -04:00
}
2021-08-11 16:28:03 -04:00
## Get the path to the TEMP folder (context dependent)
2020-11-06 11:24:16 -05:00
Function GetTempPath { Return [ System.IO.Path ]:: GetTempPath () }
2020-10-22 14:01:35 -04:00
## Determine if the system is 64-bit or not
2020-11-06 11:24:16 -05:00
Function Is64bit {
switch ( $ ( Get-CimInstance -ClassName Win32_OperatingSystem -Property OSArchitecture | Select-Object -ExpandProperty OSArchitecture ) )
{ '64-bit' { Return $true } '32-bit' { Return $false } }
2020-09-25 13:13:03 -04:00
}
2020-10-22 14:01:35 -04:00
## Determine if the Powershell process is 64-bit or not
2020-11-06 11:24:16 -05:00
Function Is64bitShell { If ( [ System.Environment ]:: Is64BitProcess ) { Return $true } Else { Return $false } }
2020-10-19 11:24:07 -04:00
2020-10-22 14:01:35 -04:00
## Determine if a user is in a built-in role or specified group
Function IsMemberOf {
2020-11-06 11:24:16 -05:00
param (
[ Parameter ( Mandatory = $false )]
[ switch ] $Builtin = $false ,
[ Parameter ( Mandatory = $true , ValueFromPipeline = $true )]
[ string ] $Group
)
If ( $Builtin ) {
Switch ( $Group ) {
( "Administrator" -or "Administrators" )
{ $Group = [ System.Security.Principal.WindowsBuiltInRole ]:: Administrator ; Break }
( "Backup Operator" -or "Backup Operators" -or "BackupOperator" -or "BackupOperators" )
{ $Group = [ System.Security.Principal.WindowsBuiltInRole ]:: BackupOperator ; Break }
( "System Operator" -or "System Operators" -or "SystemOperator" -or "SystemOperators" )
{ $Group = [ System.Security.Principal.WindowsBuiltInRole ]:: SystemOperator ; Break }
( "Account Operator" -or "Account Operators" -or "AccountOperator" -or "AccountOperators" )
{ $Group = [ System.Security.Principal.WindowsBuiltInRole ]:: AccountOperator ; Break }
( "Print Operator" -or "Print Operators" -or "PrintOperator" -or "PrintOperators" )
{ $Group = [ System.Security.Principal.WindowsBuiltInRole ]:: PrintOperator ; Break }
( "Replicator" -or "Replicators" )
{ $Group = [ System.Security.Principal.WindowsBuiltInRole ]:: Replicator ; Break }
( "Power User" -or "Power Users" -or "PowerUser" -or "PowerUsers" )
{ $Group = [ System.Security.Principal.WindowsBuiltInRole ]:: PowerUser ; Break }
( "User" -or "Users" )
{ $Group = [ System.Security.Principal.WindowsBuiltInRole ]:: User ; Break }
( "Guest" -or "Guests" )
{ $Group = [ System.Security.Principal.WindowsBuiltInRole ]:: Guest ; Break }
default { ; Break }
}
2020-10-22 14:01:35 -04:00
}
2020-11-06 11:24:16 -05:00
Return ([ Security.Principal.WindowsPrincipal][System.Security.Principal.WindowsIdentity ]:: GetCurrent ()). IsInRole ( $Group )
2020-10-22 14:01:35 -04:00
}
2020-11-06 11:24:16 -05:00
2021-07-29 12:57:11 -04:00
## Start, stop, restart, or delete a list of services
2020-11-06 11:24:16 -05:00
Function Control-Service
{
param (
[ Parameter ( Mandatory = $true , ParameterSetName = 'start' )]
[ switch ] $Start ,
[ Parameter ( Mandatory = $true , ParameterSetName = 'stop' )]
[ switch ] $Stop ,
[ Parameter ( Mandatory = $true , ParameterSetName = 'restart' )]
[ switch ] $Restart ,
2021-07-29 12:57:11 -04:00
[ Parameter ( Mandatory = $true , ParameterSetName = 'delete' )]
[ switch ] $Delete ,
2021-10-27 13:11:19 -04:00
[ Parameter ( Mandatory = $true , ParameterSetName = 'disable' )]
[ switch ] $Disable ,
2020-11-06 11:24:16 -05:00
[ Parameter ( Mandatory = $true , ValueFromPipeline = $true , ParameterSetName = 'start' )]
[ Parameter ( Mandatory = $true , ValueFromPipeline = $true , ParameterSetName = 'stop' )]
[ Parameter ( Mandatory = $true , ValueFromPipeline = $true , ParameterSetName = 'restart' )]
2021-07-29 12:57:11 -04:00
[ Parameter ( Mandatory = $true , ValueFromPipeline = $true , ParameterSetName = 'delete' )]
2021-10-27 13:11:19 -04:00
[ Parameter ( Mandatory = $true , ValueFromPipeline = $true , ParameterSetName = 'disable' )]
2020-11-06 11:24:16 -05:00
[ string[] ] $Name ,
[ Parameter ( Mandatory = $false , ParameterSetName = 'start' )]
[ Parameter ( Mandatory = $false , ParameterSetName = 'stop' )]
[ Parameter ( Mandatory = $false , ParameterSetName = 'restart' )]
2021-07-29 12:57:11 -04:00
[ Parameter ( Mandatory = $false , ParameterSetName = 'delete' )]
2021-10-27 13:11:19 -04:00
[ Parameter ( Mandatory = $false , ParameterSetName = 'disable' )]
2020-11-06 11:24:16 -05:00
[ switch ] $Match = $false
)
switch ( $PSCmdlet . ParameterSetName ) {
'start' {
$statuscondition = 'Running'
$verb = 'start'
$verbing = 'Starting'
}
'stop' {
$statuscondition = 'Stopped'
$verb = 'stop'
$verbing = 'Stopping'
}
'restart' {
$ArgString = $MyInvocation . Line
$StopCmd = $ArgString -replace ' -Restart ' , ' -Stop '
$StartCmd = $ArgString -replace ' -Restart ' , ' -Start '
Invoke-Expression $StopCmd
Invoke-Expression $StartCmd
Exit
}
2021-07-29 12:57:11 -04:00
'delete' {
## Delete the service
}
2021-10-27 13:11:19 -04:00
'disable' {
$ArgString = $MyInvocation . Line
$StopCmd = $ArgString -replace ' -Disable ' , ' -Stop '
Invoke-Expression $StopCmd
$statuscondition = 'Disabled'
$verb = 'disable'
$verbing = 'Disabling'
}
2020-11-06 11:24:16 -05:00
}
ForEach ( $item in $Name ) {
$service = Get-Service -Name $item -ErrorAction SilentlyContinue
If ( !( $service ) ) {
LogMsg "Cannot find the service ' ${item} '"
If ( $Match ) {
LogMsg "Attempting to match ' ${item} ' to service display names"
2021-10-27 13:11:19 -04:00
ForEach ( $svc in (( Get-Service | Where-Object { $_ . DisplayName -match $item }). Name ) ) {
2020-11-06 11:24:16 -05:00
Switch ( $verb ) {
'start' { Control-Service -Start -Name $svc }
'stop' { Control-Service -Stop -Name $svc }
2021-10-27 13:11:19 -04:00
'disable' { Control-Service -Disable -Name $svc }
2020-11-06 11:24:16 -05:00
}
}
}
}
Else {
$name = $service . Name
$fullname = $service . DisplayName
2021-10-27 13:11:19 -04:00
If ( ([ string ]:: IsNullOrEmpty ( $fullname )) -or ( $fullname -eq $name ) ) {
2020-11-06 11:24:16 -05:00
$displayname = "' ${name} '"
}
Else {
$displayname = """ ${fullname} "" ( ${name} )"
}
If ( $service . Status -ne $statuscondition ) {
2021-07-29 13:31:55 -04:00
LogMsg " ${verbing} ${displayname} "
2021-10-27 13:11:19 -04:00
Try {
Switch ( $verb ) {
'start' { Start-Service -Name $name }
'stop' { Stop-Service -Name $name -Force }
'disable' { Set-Service -Name " ${name} " -StartupType Disabled }
2020-11-06 11:24:16 -05:00
}
}
2021-10-27 13:11:19 -04:00
Catch { LogErr $_ . Exception . Message }
2020-11-06 11:24:16 -05:00
}
}
}
}
## Stop a process
Function End-Process
{
param (
[ Parameter ( Mandatory = $true , ValueFromPipeline = $true )][ string[] ] $Name ,
[ Parameter ( Mandatory = $false )][ switch ] $Match = $false ,
2021-07-30 09:42:54 -04:00
[ Parameter ( Mandatory = $false )][ switch ] $Force = $false
2020-11-06 11:24:16 -05:00
)
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
}
}
}
2020-10-22 14:01:35 -04:00
}
2020-12-03 18:16:55 -05:00
Function Create-Shortcut {
param (
[ Parameter ( Mandatory = $true )][ string ] $Path ,
[ Parameter ( Mandatory = $true )][ string ] $TargetPath ,
[ Parameter ( Mandatory = $false )][ string ] $Arguments ,
[ Parameter ( Mandatory = $false )][ string ] $Description ,
[ Parameter ( Mandatory = $false )][ string ] $Icon = '' ,
[ Parameter ( Mandatory = $false )][ string ] $WorkingDirectory = ''
)
If ( Test-Path $TargetPath ) {
If ( Test-Path $Path ) {
LogMsg "Deleting existing shortcut at "" ${Path} """
Try { Remove-Item $Path -Force -ErrorAction SilentlyContinue }
Catch { LogErr $_ . Exception . Message }
}
If ( $WorkingDirectory -eq '' ) { $WorkingDirectory = Split-Path $TargetPath -Parent }
If ( $Icon -eq '' ) { $Icon = " ${TargetPath} , 0" }
$WshShell = New-Object -ComObject WScript . Shell
$Shortcut = $WshShell . CreateShortcut ( $Path )
$Shortcut . Arguments = $Arguments
$Shortcut . Description = $Description
$Shortcut . IconLocation = $Icon
$Shortcut . WorkingDirectory = $WorkingDirectory
$Shortcut . TargetPath = $TargetPath
2020-12-03 20:18:23 -05:00
LogMsg "Creating shortcut to "" ${TargetPath} "" at "" ${Path} """
2020-12-03 18:16:55 -05:00
Try { $Shortcut . Save () }
Catch { LogErr $_ . Exception . Message }
}
2020-12-03 20:18:23 -05:00
Else { LogMsg "Cannot create shortcut because the target path does not exist" }
2021-05-24 14:05:59 -04:00
}
# 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
2021-06-02 16:16:24 -04:00
If ( $Enable ) { LogMsg "Enabing ${Name} event log" ; $log . IsEnabled = $true }
If ( $Disable ) { LogMsg "Disabing ${Name} event log" ; $log . IsEnabled = $false }
2021-05-24 14:05:59 -04:00
$log . SaveChanges ()
}
Catch { LogMsg $_ . Exception . Message }
2021-08-05 09:42:15 -04:00
}
2021-09-23 13:14:16 -04:00
# Function to install the PSAtera Powershell module
function Install-PSAteraModule {
Try {
$module = Get-Module -ListAvailable -Name PSAtera
If ( ( -not $module ) -and ( IsAdmin ) ) {
LogMsg "Installing PSAtera Powershell module"
2021-10-04 17:03:54 -04:00
Install-Module -Name PSAtera -Force
2021-09-23 13:14:16 -04:00
}
ElseIf ( ( -not $module ) -and ( -not ( IsAdmin )) ) {
LogMsg "The PSAtera module needs to be installed, but the current security context is not sufficient to install it"
}
}
Catch { LogErr $_ . Exception . Message }
}
# Function to install the MSP360 Powershell module
function Install-MSP360Module {
Try {
$module = Get-Module -ListAvailable -Name MSP360
If ( ( -not $module ) -and ( IsAdmin ) ) {
LogMsg "Installing MSP360 Powershell module"
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process
[ Net.ServicePointManager ]:: SecurityProtocol = [ Net.SecurityProtocolType ]:: Tls12 ; Invoke-Expression ( New-Object System . Net . WebClient ). DownloadString ( 'https://git.io/JUSAA' ); Install-MSP360Module
}
ElseIf ( ( -not $module ) -and ( -not ( IsAdmin )) ) {
LogMsg "The MSP360 Powershell module needs to be installed, but the current security context is not sufficient to install it"
}
}
Catch { LogErr $_ . Exception . Message }
}
2021-10-08 05:42:05 -04:00
# Function to delete a file
function Remove-File ([ Parameter ( ValueFromPipeline = $true )][ string ] $path ) {
If ( Test-Path $path ) {
If ( !(( Get-Item $path ) -is [ System.IO.DirectoryInfo ]) ) {
Try {
LogMsg "Delete "" ${path} """
Remove-Item $path -Force
}
Catch { LogErr $_ . Exception . Message }
}
}
}
2021-11-10 20:18:43 -05:00
# Function to ZIP a file or directory
2021-11-12 11:09:52 -05:00
function Zip-Object {
param (
[ Parameter ( ValueFromPipeline = $true )][ string ] $path ,
[ Parameter ( ValueFromPipeline = $false )][ string ] $dest
)
2021-11-10 20:18:43 -05:00
If ( $ ( Get-Item $path ) -is [ System.IO.DirectoryInfo ] ) {
2021-11-12 11:09:52 -05:00
If ( [ string ]:: IsNullOrEmpty ( $dest ) ) { $dest = '{0}\{1}.zip' -f $ ( Split-Path -Parent $path ), $ ( Split-Path -Leaf $path ) }
2021-11-10 20:18:43 -05:00
LogMsg "Creating zip file of: ${path} "
Try {
Add-Type -Assembly "System.IO.Compression.FileSystem"
[ IO.Compression.ZipFile ]:: CreateFromDirectory ( $path , $dest )
}
Catch { LogErr $_ . Exception . Message }
If ( Test-Path $dest ) { Return $dest } Else { Return $false }
}
ElseIf ( $ ( Get-Item $path ) -is [ System.IO.FileInfo ] ) {
$dir = $path . Substring ( 0 , $path . LastIndexOf ( '.' ))
Try {
LogMsg "Creating directory: ${path} "
New-Item -ItemType Directory -Path $dir -ErrorAction Stop | Out-Null
LogMsg "Moving "" ${path} "" into "" ${dir} """
Move-Item -Path $path -Destination $dir -Force -ErrorAction Stop | Out-Null
}
Catch { LogErr $_ . Exception . Message }
Zip-Object $dir
}
Else { LogMsg "Could not determine the file/folder status: ${path} " }
}
# Function to UNZIP a file or directory
function Unzip-Object ([ Parameter ( ValueFromPipeline = $true )][ string ] $path ) {
2021-11-12 11:09:52 -05:00
If ( [ System.IO.Path ]:: GetExtension ( $path ) -eq ".zip" ) {
2021-11-10 20:18:43 -05:00
$dest = Split-Path -Parent $path
2021-11-12 11:09:52 -05:00
LogMsg "Extracting "" ${path} "" to "" ${dest} """
2021-11-10 20:18:43 -05:00
Try {
Add-Type -Assembly "System.IO.Compression.FileSystem"
[ IO.Compression.ZipFile ]:: ExtractToDirectory ( $path , $dest )
}
Catch { LogErr $_ . Exception . Message }
}
Else { LogMsg "The path specified is not a zip file: ${path} " }
}
2021-11-18 21:03:03 -05:00
# Function to get a copy of the LiquidFiles CLI agent
function Get-LiquidFilesCLI {
$url = 'https://lfupdate.s3.amazonaws.com/clients/windows_cli/LiquidFilesCLI-2.0.128.zip'
$zip_filename = Split-Path -Leaf $url
$zip_path = " ${Global:ToolsDirectory} \ ${zip_filename} "
$exe_path = '{0}\{1}.exe' -f $Global:ToolsDirectory ,[ System.IO.Path ]:: GetFileNameWithoutExtension ( $zip_filename )
If ( Test-Path $zip_path ) {
LogMsg "Deleting existing zip archive: ${zip_path} "
Try { Remove-Item -Path $zip_path -Force }
Catch { LogErr $_ . Exception . Message }
}
If ( Test-Path $exe_path ) {
LogMsg "Deleting existing file: ${exe_path} "
Try { Remove-Item -Path $exe_path -Force }
Catch { LogErr $_ . Exception . Message }
}
Download-File -URL $url -File $zip_path | Out-Null
Unzip-Object $zip_path
Return $exe_path
}
2022-02-03 09:20:26 -05:00
# Function to determine if an app is running
function IsRunning ([ Parameter ( ValueFromPipeline = $true )][ string ] $Name ) {
2022-11-19 14:38:02 -05:00
$RunningInstances = Get-Process | Where-Object { $_ . Name -ilike $Name }
2022-02-03 09:20:26 -05:00
If ( $RunningInstances ) { Return $true } Else { Return $false }
}
2022-03-17 18:09:47 -04:00
# Function to create a local user account
function Create-LocalUser {
param (
[ Parameter ( Mandatory = $true )][ string ] $Username ,
[ Parameter ( Mandatory = $true )][ string ] $Password ,
[ Parameter ( Mandatory = $true )][ string ] $FullName ,
[ Parameter ( Mandatory = $true )][ string ] $Description ,
[ Parameter ( Mandatory = $false )][ switch ] $MakeAdmin = $false ,
[ Parameter ( Mandatory = $false )][ switch ] $Hide = $false
)
## Secure supplied password
Try { $SecurePassword = ConvertTo-SecureString $Password -AsPlainText -Force ; $Password = $null }
Catch { LogErr $_ . Exception . Message ; Exit }
If ( IsAdmin )
{
If ( $ ( Get-CimInstance -ClassName Win32_OperatingSystem -Property ProductType | Select-Object -ExpandProperty ProductType ) -ne "2" )
{
If ( $ ( Get-LocalUser -Name $Username -ErrorAction SilentlyContinue ) )
{
LogMsg "Updating user: ${Username} "
Try { Set-LocalUser -Name $Username -Password $SecurePassword -FullName $FullName -Description $Description -AccountNeverExpires -PasswordNeverExpires }
Catch { LogErr $_ . Exception . Message ; Exit }
}
Else
{
LogMsg "Creating user: ${Username} "
Try { New-LocalUser -Name $Username -Password $SecurePassword -FullName $FullName -Description $Description -AccountNeverExpires -PasswordNeverExpires }
Catch { LogErr $_ . Exception . Message ; Exit }
}
2022-03-17 21:27:22 -04:00
If ( ( -not ( $ ( Get-LocalGroupMember -Group "Administrators" -Member $Username -ErrorAction SilentlyContinue ))) -and $MakeAdmin )
2022-03-17 18:09:47 -04:00
{
LogMsg "Adding "" ${Username} "" to local Administrators group"
2022-03-17 21:27:22 -04:00
Try { Add-LocalGroupMember -Name "Administrators" -Member $ ( Get-LocalUser -Name $Username ) }
2022-03-17 18:09:47 -04:00
Catch { LogErr $_ . Exception . Message ; Exit }
}
}
Else { LogMsg "Cannot create or modify local accounts on a domain controller" }
}
Else { LogMsg "Cannot create or modify a local account without administrative privileges" }
2022-03-24 16:28:30 -04:00
If ( $Hide ) {
# TODO: Hide account from logon screen
#Get-ChildItem "HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList"
}
}
# Returns the number of MB a process is consuming
function Get-MemoryUsage ([ string ] $AppName ) {
[ math ]:: Round (( Get-Process -Name $AppName -ErrorAction SilentlyContinue | Measure-Object -Property WorkingSet -Sum ). Sum / 1 MB)
}
# Kills a process if it's using more than the specified amount of memory
function Stop-MemoryHog ([ string ] $AppName ,[ int ] $MemoryLimit ) {
$MemoryUsed = ( Get-MemoryUsage -AppName $AppName )
If ( $MemoryUsed -gt $MemoryLimit ) {
$MemoryDifference = $MemoryUsed - $MemoryLimit
LogMsg "Killing "" ${AppName} "" for using ${MemoryDifference} MB over the limit of ${MemoryLimit} MB"
Try { Get-Process -Name $AppName -ErrorAction SilentlyContinue | Stop-Process -Force }
Catch { LogErr $_ . Exception . Message }
}
2022-03-17 18:09:47 -04:00
}
2022-11-10 11:22:43 -05:00
# Returns a formatted list of the largest or smallest files in a directory
function Get-FileSizes {
param (
[ Parameter ( ValueFromPipeline = $true )][ string ] $Path ,
[ switch ] $Recurse ,
[ switch ] $IncludeHidden ,
[ Parameter ( ParameterSetName = "largest" )][ int ] $Largest ,
[ Parameter ( ParameterSetName = "smallest" )][ int ] $Smallest ,
[ string ] $Units ,
[ int ] $Precision = 2
)
# If no path is specified, set $Path to the directory containing user profiles
If ( -not $Path ) {
$Path = ( Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' -Name ProfilesDirectory )
$Recurse = $true
$IncludeHidden = $false
}
# Change the sort order depending on which parameter set was specified
Switch ( $PSCmdlet . ParameterSetName ) {
"largest" { $SortOrder = $true ; $Quantity = $Largest }
"smallest" { $SortOrder = $false ; $Quantity = $Smallest }
}
# Set the units to show sizes in output
Switch ( $Units . ToUpper () ) {
"KB" { $UnitLabel = "Kilobytes (KB)" ; $Divisor = 1 KB }
"MB" { $UnitLabel = "Megabytes (MB)" ; $Divisor = 1 MB }
"GB" { $UnitLabel = "Gigabytes (GB)" ; $Divisor = 1 GB }
"TB" { $UnitLabel = "Terabytes (TB)" ; $Divisor = 1 TB }
default { $UnitLabel = "Bytes" ; $Divisor = 1 }
}
# Get the file paths and sizes as specified
$FileSizes = Get-ChildItem $Path -Recurse: $Recurse -Force: $IncludeHidden -ErrorAction SilentlyContinue |
Sort-Object -Descending: $SortOrder -Property Length |
Select-Object -First $Quantity @ { Name = "File Path" ; Expression ={ $_ . DirectoryName + '\' + $_ . Name }}, @ { Name = $UnitLabel ; Expression ={[ Math ]:: Round ( $_ . Length / $Divisor , $Precision )}}
# Set output prefix
$prefix = "The ${Quantity} " + $PSCmdlet . ParameterSetName + " files found at "" ${Path} """
# Output to console
$constr = " ${prefix} " + $ ( $FileSizes | Out-String )
Write-Output $constr
# Output to log file
$logstr = " ${prefix} " + $ ( $FileSizes | Format-List | Out-String )
LogMsg $logstr
}
2022-11-11 15:11:14 -05:00
# Function to write text to a file in UTF8 encoding without BOM
function WriteToFile_UTF8NoBOM {
param (
[ Parameter ( ValueFromPipeline = $false )][ string ] $FilePath ,
[ Parameter ( ValueFromPipeline = $true )][ string ] $Value
)
$UTF8NoBOM = New-Object System . Text . UTF8Encoding $false
Try { [ IO.File ]:: WriteAllText ( $FilePath , $CONFIG , $UTF8NoBOM ) }
Catch { LogErr $_ . Exception . Message }
}
2022-11-19 14:38:02 -05:00
# Function to enumerate all user profile folders
function EnumUserProfiles {
$ProfilePath = ( Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' -Name ProfilesDirectory )
$UserProfilePaths = @ ()
ForEach ( $userProfile in ( Get-ChildItem -Path $ProfilePath | Where-Object { $_ . PSIsContainer }) ) {
$UserProfilePaths += , @ ( $userProfile . FullName )
}
Return $UserProfilePaths
}
2021-08-05 09:42:15 -04:00
Setup-MSPDirectories
2021-11-10 20:19:21 -05:00
Setup-LogFile