<# .SYNOPSIS Provide a brief description of script purpose .DESCRIPTION Provide a more detailed description of script purpose .EXAMPLE Provide an example usage for the script .NOTES NAME: AUTHOR: LASTEDIT: VERSION: #> #region Parameters param ( # Allows modules required by the script to be predefined, and loaded or installed as needed [Parameter(DontShow = $true)] [Array] $ModuleNames = @(), # Sets the script storage location [Parameter(DontShow = $true)] [ValidateSet('System', 'User', 'Custom')] [String] $ScriptType = "System", # Allows adding verbose logging and what-if command simulation to the script [Parameter(DontShow = $true)] [Switch] $Dev, # Allows for the script logs to output to a nonstandard location. Overrides user/computer script paths [Parameter(Mandatory = $false)] [String] $ScriptDir, # Flag to disable log file output [Parameter(Mandatory = $false)] [Switch] $NoLog, # Allows for uninstallation of script [Parameter(Mandatory = $false)] [Switch] $Uninstall #TODO: Add additional parameters, if appropriate ) #endregion Parameters #region Architecture Check # Verifies script is running in 64-bit PowerShell, if available. Allows for parameters to be passed to relaunched script # Origin: https://z-nerd.com/blog/2020/03/31-intune-win32-apps-powershell-script-installer/ If ($Env:PROCESSOR_ARCHITECTURE -ne "AMD64") { If (Test-Path -Path "$Env:WinDir\SysNative\WindowsPowerShell\v1.0\powershell.exe" -PathType Leaf) { $ArgsString = "" Try { ForEach ($Key in $MyInvocation.BoundParameters.Keys) { Switch ($MyInvocation.BoundParameters[$Key].GetType().Name) { "SwitchParameter" { if ($MyInvocation.BoundParameters[$Key].IsPresent) { $ArgsString += "-$Key " } } "String" { $ArgsString += "-$Key `"$($MyInvocation.BoundParameters[$Key])`" " } "Int32" { $ArgsString += "-$Key $($MyInvocation.BoundParameters[$Key]) " } "Boolean" { $ArgsString += "-$Key `$$($MyInvocation.BoundParameters[$Key]) " } } } Start-Process -FilePath "$ENV:WINDIR\SysNative\WindowsPowershell\v1.0\PowerShell.exe" -ArgumentList ` "-ExecutionPolicy Bypass -NoProfile -File $PSCommandPath $ArgsString" -Wait -NoNewWindow } Catch { Throw "Failed to start `"$PSCommandPath`" in 64-bit PowerShell" } Exit $LASTEXITCODE } } #endregion Architecture Check #region Imports # Import Test-CommandExists, Add-LogEntry, Add-ListItem, Import-JSONConfig, Import-YAMLConfig, Set-RegistryKey, Test-AsAdmin, Format-Hyperlink Invoke-WebRequest "https://gitea.taco.quest/Mindfang/ProjectTools/raw/branch/main/PSUtilities/ScriptTools.ps1" -OutFile "$Env:Temp\ScriptTools.ps1" Import-Module -Name "$Env:Temp\ScriptTools.ps1" -Force #endregion Imports #region Functions #endregion Functions #region Prep # Set the working directory for logs and additional files $ThisScript = ([IO.FileInfo]$MyInvocation.MyCommand.Definition).BaseName Switch ($ScriptType) { "System" { $AppDir = "$Env:AppData\Mindfang\$ThisScript" } "User" { $AppDir = "$Env:ProgramData\Mindfang\$ThisScript" } "Custom" { If ($ScriptDir) { $AppDir = $ScriptDir } Else { $AppDir = $PWD } } } # Create specified appdir if it does not already exist If (-Not (Test-Path $AppDir)) { New-Item $AppDir -ItemType Directory } # Begin recording transcript file If (-Not $NoLog) { If (-not $LogDir) { $LogDir = $AppDir } Add-LogEntry (Start-Transcript "$AppDir\$ThisScript.log" -Append) } # Load any modules required by script If ($ModuleNames) { If ([Net.ServicePointManager]::SecurityProtocol -ne [Net.SecurityProtocolType]::SystemDefault) { Add-LogEntry "Upgrading TLS security protocol to 1.2" Try { [Net.ServicePointManager]::SecurityProtocol = @([Net.SecurityProtocolType]::Tls, [Net.SecurityProtocolType]::Tls11, [Net.SecurityProtocolType]::Tls12) } Catch { Add-LogEntry "TLS upgrade failed, script is exiting" -As Error Exit } } If ((Get-PackageProvider).Name -notcontains "NuGet") { Add-LogEntry "Installing NuGet package provider" Try { Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -ErrorAction Stop | Out-Null } Catch { Add-LogEntry "Installation failed, script is exiting" -As Error Exit } } If ((Get-PSRepository).Name -notcontains "PSGallery") { Add-LogEntry "Registering PSGallery as script source" Try { Register-PSRepository -Default -InstallationPolicy Trusted -ErrorAction Stop } Catch { Add-LogEntry "Unable to register PSGallery, script is exiting" -As Error Exit } } ElseIf (Get-PSRepository | Where-Object { $_.Name -eq "PSGallery" -and $_.InstallationPolicy -ne "Trusted" }) { Add-LogEntry "Trusting packages from PSGallery" Try { Set-PSRepository PSGallery -InstallationPolicy Trusted -ErrorAction Stop } Catch { Add-LogEntry "Unable to set PSGallery as trusted, script is exiting" -As Error Exit } } ForEach ($Module in $ModuleNames) { If (-Not (Get-Module -ListAvailable -Name $Module)) { Try { Add-LogEntry "Module `"$Module`" not found, installing" Install-Module -Name $Module -Scope CurrentUser -Force -AllowClobber } Catch { Add-LogEntry "Module failed to install automatically! Manaully install the module, then re-run the script." -As Error Exit 1 } } Import-Module $Module } } #endregion Prep #region Execution Try { If (-Not $Uninstall) { #TODO: "Install actions" for the script go here } Else { #TODO: "Uninstall actions" for the script go here } } Catch { # Write error to logs, if an exception is caught Write-Host "Script execution failed!" Write-Host $_ Write-Host $_.InvocationInfo Write-Host $_.ScriptStackTrace Exit 1 } Finally { # Stop transcript, even if an error has occurred If (-Not $NoLog) { Stop-Transcript } } #endregion Execution