EnhancedBoilerPlateAO.psm1
#Region '.\Public\Add-EnvPath.ps1' -1 function Add-EnvPath { <# .SYNOPSIS Adds a specified path to the environment PATH variable. .DESCRIPTION The Add-EnvPath function adds a specified path to the environment PATH variable. The path can be added to the session, user, or machine scope. .PARAMETER Path The path to be added to the environment PATH variable. .PARAMETER Container Specifies the scope of the environment variable. Valid values are 'Machine', 'User', or 'Session'. .EXAMPLE Add-EnvPath -Path 'C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Imaging and Configuration Designer\x86' -Container 'Machine' #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $Path, [ValidateSet('Machine', 'User', 'Session')] [string] $Container = 'Session' ) begin { Write-EnhancedLog -Message "Starting Add-EnvPath function" -Level "INFO" Log-Params -Params @{ Path = $Path Container = $Container } $envPathHashtable = [ordered]@{} $persistedPathsHashtable = [ordered]@{} $containerMapping = @{ Machine = [System.EnvironmentVariableTarget]::Machine User = [System.EnvironmentVariableTarget]::User } } process { try { # Update the PATH variable for User or Machine scope if ($Container -ne 'Session') { $containerType = $containerMapping[$Container] $existingPaths = [System.Environment]::GetEnvironmentVariable('Path', $containerType) -split ';' foreach ($pathItem in $existingPaths) { $persistedPathsHashtable[$pathItem] = $null } if (-not $persistedPathsHashtable.Contains($Path)) { Write-EnhancedLog -Message "Path not found in persisted paths, adding it." -Level "INFO" $persistedPathsHashtable[$Path] = $null [System.Environment]::SetEnvironmentVariable('Path', ($persistedPathsHashtable.Keys -join ';'), $containerType) } } # Update the PATH variable for the current session $existingSessionPaths = $env:Path -split ';' foreach ($sessionPathItem in $existingSessionPaths) { $envPathHashtable[$sessionPathItem] = $null } if (-not $envPathHashtable.Contains($Path)) { Write-EnhancedLog -Message "Path not found in session paths, adding it." -Level "INFO" $envPathHashtable[$Path] = $null $env:Path = $envPathHashtable.Keys -join ';' } } catch { Write-EnhancedLog -Message "An error occurred: $($_.Exception.Message)" -Level "ERROR" Handle-Error -ErrorRecord $_ } } end { Write-EnhancedLog -Message "Exiting Add-EnvPath function" -Level "INFO" Write-Host "The permanent environment PATH variable is:" [System.Environment]::GetEnvironmentVariable('Path', [System.EnvironmentVariableTarget]::Machine) -split ';' Write-Host "The temporary environment PATH variable is:" $env:Path -split ';' } } # # Example usage # $envPathParams = @{ # Path = 'C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Imaging and Configuration Designer\x86' # Container = 'Machine' # } # Add-EnvPath @envPathParams #EndRegion '.\Public\Add-EnvPath.ps1' 97 #Region '.\Public\Check-ModuleVersionStatus.ps1' -1 function Check-ModuleVersionStatus { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string[]]$ModuleNames ) #the following modules PowerShellGet and PackageManagement has to be either automatically imported or manually imported into C:\windows\System32\WindowsPowerShell\v1.0\Modules Import-Module -Name PowerShellGet -ErrorAction SilentlyContinue # Import-Module 'C:\Program Files (x86)\WindowsPowerShell\Modules\PowerShellGet\PSModule.psm1' -ErrorAction SilentlyContinue # Import-Module 'C:\windows\System32\WindowsPowerShell\v1.0\Modules\PowerShellGet\PSModule.psm1' -ErrorAction SilentlyContinue # Import-Module 'C:\Program Files (x86)\WindowsPowerShell\Modules\PackageManagement\PackageProviderFunctions.psm1' -ErrorAction SilentlyContinue # Import-Module 'C:\windows\System32\WindowsPowerShell\v1.0\Modules\PackageManagement\PackageProviderFunctions.psm1' -ErrorAction SilentlyContinue # Import-Module 'C:\Program Files (x86)\WindowsPowerShell\Modules\PackageManagement\PackageManagement.psm1' -ErrorAction SilentlyContinue $results = [System.Collections.Generic.List[PSObject]]::new() # Initialize a List to hold the results foreach ($ModuleName in $ModuleNames) { try { Write-Host 'Checking module '$ModuleName $installedModule = Get-Module -ListAvailable -Name $ModuleName | Sort-Object Version -Descending | Select-Object -First 1 # $installedModule = Check-SystemWideModule -ModuleName 'Pester' $latestModule = Find-Module -Name $ModuleName -ErrorAction SilentlyContinue if ($installedModule -and $latestModule) { if ($installedModule.Version -lt $latestModule.Version) { $results.Add([PSCustomObject]@{ ModuleName = $ModuleName Status = "Outdated" InstalledVersion = $installedModule.Version LatestVersion = $latestModule.Version }) } else { $results.Add([PSCustomObject]@{ ModuleName = $ModuleName Status = "Up-to-date" InstalledVersion = $installedModule.Version LatestVersion = $installedModule.Version }) } } elseif (-not $installedModule) { $results.Add([PSCustomObject]@{ ModuleName = $ModuleName Status = "Not Installed" InstalledVersion = $null LatestVersion = $null }) } else { $results.Add([PSCustomObject]@{ ModuleName = $ModuleName Status = "Not Found in Gallery" InstalledVersion = $null LatestVersion = $null }) } } catch { Write-Error "An error occurred checking module '$ModuleName': $_" } } return $results } # Example usage: # $versionStatuses = Check-ModuleVersionStatus -ModuleNames @('Pester', 'AzureRM', 'PowerShellGet') # $versionStatuses | Format-Table -AutoSize # Display the results in a table format for readability #EndRegion '.\Public\Check-ModuleVersionStatus.ps1' 72 #Region '.\Public\Convert-WindowsPathToLinuxPath.ps1' -1 function Convert-WindowsPathToLinuxPath { <# .SYNOPSIS Converts a Windows file path to a Linux file path. .DESCRIPTION This function takes a Windows file path as input and converts it to a Linux file path. It replaces backslashes with forward slashes and handles the drive letter. .PARAMETER WindowsPath The full file path in Windows format that needs to be converted. .EXAMPLE PS> Convert-WindowsPathToLinuxPath -WindowsPath 'C:\Code\CB\Entra\ARH\Get-EntraConnectSyncErrorsfromEntra copy.ps1' Returns '/mnt/c/Code/CB/Entra/ARH/Get-EntraConnectSyncErrorsfromEntra copy.ps1' #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$WindowsPath ) Begin { Write-Host "Starting the path conversion process..." } Process { try { Write-Host "Input Windows Path: $WindowsPath" # Replace backslashes with forward slashes $linuxPath = $WindowsPath -replace '\\', '/' # Handle drive letter by converting "C:" to "/mnt/c" if ($linuxPath -match '^[A-Za-z]:') { $driveLetter = $linuxPath.Substring(0, 1).ToLower() $linuxPath = "/mnt/$driveLetter" + $linuxPath.Substring(2) } Write-Host "Converted Linux Path: $linuxPath" return $linuxPath } catch { Write-Host "Error during conversion: $_" throw } } End { Write-Host "Path conversion completed." } } # # Example usage # $windowsPath = 'C:\Code\Unified365toolbox\Graph\graphcert.pfx' # $linuxPath = Convert-WindowsPathToLinuxPath -WindowsPath $windowsPath # Write-Host "Linux path: $linuxPath" #EndRegion '.\Public\Convert-WindowsPathToLinuxPath.ps1' 59 #Region '.\Public\Download-Psd1File.ps1' -1 function Download-Psd1File { <# .SYNOPSIS Downloads a PSD1 file from a specified URL and saves it to a local destination. .DESCRIPTION This function downloads a PowerShell Data file (PSD1) from a given URL and saves it to the specified local path. If the download fails, an error is logged and the function throws an exception. .PARAMETER url The URL of the PSD1 file to be downloaded. .PARAMETER destinationPath The local path where the PSD1 file will be saved. .EXAMPLE Download-Psd1File -url "https://example.com/modules.psd1" -destinationPath "$env:TEMP\modules.psd1" Downloads the PSD1 file from the specified URL and saves it to the provided local path. .NOTES This function requires internet access to download the PSD1 file from the specified URL. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$url, [Parameter(Mandatory = $true)] [string]$destinationPath ) begin { Write-EnhancedLog -Message "Starting Download-Psd1File function" -Level "NOTICE" Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters # Validate destination directory $destinationDirectory = [System.IO.Path]::GetDirectoryName($destinationPath) if (-not (Test-Path -Path $destinationDirectory)) { Write-EnhancedLog -Message "Destination directory not found at path: $destinationDirectory" -Level "ERROR" throw "Destination directory not found." } Write-EnhancedLog -Message "Validated destination directory at path: $destinationDirectory" -Level "INFO" } process { try { Write-EnhancedLog -Message "Downloading PSD1 file from URL: $url" -Level "INFO" Invoke-WebRequest -Uri $url -OutFile $destinationPath -UseBasicParsing Write-EnhancedLog -Message "Downloaded PSD1 file to: $destinationPath" -Level "INFO" } catch { Write-EnhancedLog -Message "Failed to download PSD1 file from $url. Error: $_" -Level "ERROR" Handle-Error -ErrorRecord $_ throw $_ } } end { Write-EnhancedLog -Message "Download-Psd1File function execution completed." -Level "NOTICE" } } #EndRegion '.\Public\Download-Psd1File.ps1' 64 #Region '.\Public\Ensure-LoggingFunctionExists.ps1' -1 function Ensure-LoggingFunctionExists { param ( # [string]$LoggingFunctionName = "Write-EnhancedLog" [string]$LoggingFunctionName ) if (Get-Command $LoggingFunctionName -ErrorAction SilentlyContinue) { Write-EnhancedLog -Message "Logging works" -Level "INFO" -ForegroundColor ([ConsoleColor]::Green) } else { throw "$LoggingFunctionName function not found. Terminating script." } } # Example of how to call the function with the default parameter # Ensure-LoggingFunctionExists # Example of how to call the function with a different logging function name # Ensure-LoggingFunctionExists -LoggingFunctionName "Write-EnhancedLog" #EndRegion '.\Public\Ensure-LoggingFunctionExists.ps1' 20 #Region '.\Public\Get-ModulesScriptPathsAndVariables.ps1' -1 # function Get-ModulesScriptPathsAndVariables { # <# # .SYNOPSIS # Dot-sources all PowerShell scripts in the 'Modules' folder relative to the script root. # .DESCRIPTION # This function finds all PowerShell (.ps1) scripts in a 'Modules' folder located in the script root directory and dot-sources them. It logs the process, including any errors encountered, with optional color coding. # .EXAMPLE # Dot-SourceModulesScripts # Dot-sources all scripts in the 'Modules' folder and logs the process. # .NOTES # Ensure the Write-EnhancedLog function is defined before using this function for logging purposes. # #> # param ( # [string]$BaseDirectory # ) # try { # $ModulesFolderPath = Join-Path -Path $BaseDirectory -ChildPath "Modules" # if (-not (Test-Path -Path $ModulesFolderPath)) { # throw "Modules folder path does not exist: $ModulesFolderPath" # } # # Construct and return a PSCustomObject # return [PSCustomObject]@{ # BaseDirectory = $BaseDirectory # ModulesFolderPath = $ModulesFolderPath # } # } # catch { # Write-Host "Error in finding Modules script files: $_" -ForegroundColor Red # # Optionally, you could return a PSCustomObject indicating an error state # # return [PSCustomObject]@{ Error = $_.Exception.Message } # } # } #EndRegion '.\Public\Get-ModulesScriptPathsAndVariables.ps1' 42 #Region '.\Public\Import-Modules.ps1' -1 function Import-Modules { param ( [Parameter(Mandatory = $true)] [string[]]$Modules ) foreach ($module in $Modules) { if (Get-Module -ListAvailable -Name $module) { # Import-Module -Name $module -Force -Verbose Import-Module -Name $module -Force:$true -Global:$true Write-EnhancedLog -Message "Module '$module' imported." -Level "INFO" } else { Write-EnhancedLog -Message "Module '$module' not found. Cannot import." -Level "ERROR" } } } #EndRegion '.\Public\Import-Modules.ps1' 18 #Region '.\Public\Import-ModulesFromLocalRepository.ps1' -1 function Import-ModulesFromLocalRepository { <# .SYNOPSIS Imports all modules found in the specified Modules directory. .DESCRIPTION This function scans the Modules directory for module folders and attempts to import the module. If a module file is not found or if importing fails, appropriate error messages are logged. .PARAMETER ModulesFolderPath The path to the folder containing the modules. .PARAMETER ScriptPath The path to the script directory containing the exclusion file. .EXAMPLE Import-ModulesFromLocalRepository -ModulesFolderPath "C:\code\Modules" -ScriptPath "C:\scripts" This example imports all modules found in the specified Modules directory. #> [CmdletBinding()] param ( [string]$ModulesFolderPath # [string]$ScriptPath ) Begin { # Get the path to the Modules directory $moduleDirectories = Get-ChildItem -Path $ModulesFolderPath -Directory Write-Host "Module directories found: $($moduleDirectories.Count)" -ForegroundColor ([ConsoleColor]::Cyan) # Read the modules exclusion list from the JSON file # $exclusionFilePath = Join-Path -Path $ScriptPath -ChildPath "modulesexclusion.json" # if (Test-Path -Path $exclusionFilePath) { # $excludedModules = Get-Content -Path $exclusionFilePath | ConvertFrom-Json # Write-Host "Excluded modules: $excludedModules" -ForegroundColor ([ConsoleColor]::Cyan) # } else { # $excludedModules = @() # Write-Host "No exclusion file found. Proceeding with all modules." -ForegroundColor ([ConsoleColor]::Yellow) # } } Process { foreach ($moduleDir in $moduleDirectories) { # Skip the module if it is in the exclusion list if ($excludedModules -contains $moduleDir.Name) { Write-Host "Skipping excluded module: $($moduleDir.Name)" -ForegroundColor ([ConsoleColor]::Yellow) continue } # Construct the path to the module file $modulePath = Join-Path -Path $moduleDir.FullName -ChildPath "$($moduleDir.Name).psm1" # Check if the module file exists if (Test-Path -Path $modulePath) { # Import the module with retry logic try { Import-ModuleWithRetry -ModulePath $modulePath Write-Host "Successfully imported module: $($moduleDir.Name)" -ForegroundColor ([ConsoleColor]::Green) } catch { Write-Host "Failed to import module: $($moduleDir.Name). Error: $_" -ForegroundColor ([ConsoleColor]::Red) } } else { Write-Host "Module file not found: $modulePath" -ForegroundColor ([ConsoleColor]::Red) } } } End { Write-Host "Module import process completed." -ForegroundColor ([ConsoleColor]::Cyan) } } #EndRegion '.\Public\Import-ModulesFromLocalRepository.ps1' 76 #Region '.\Public\Import-ModuleWithRetry.ps1' -1 function Import-ModuleWithRetry { <# .SYNOPSIS Imports a PowerShell module with retries on failure. .DESCRIPTION This function attempts to import a specified PowerShell module, retrying the import process up to a specified number of times upon failure. It also checks if the module path exists before attempting to import. .PARAMETER ModulePath The path to the PowerShell module file (.psm1) that should be imported. .PARAMETER MaxRetries The maximum number of retries to attempt if importing the module fails. Default is 3. .PARAMETER WaitTimeSeconds The number of seconds to wait between retry attempts. Default is 2 seconds. .EXAMPLE $modulePath = "C:\Modules\MyPowerShellModule.psm1" Import-ModuleWithRetry -ModulePath $modulePath Tries to import the module located at "C:\Modules\MyPowerShellModule.psm1", with up to 3 retries, waiting 2 seconds between each retry. .NOTES This function requires the `Write-EnhancedLog` function to be defined in the script for logging purposes. .LINK Write-EnhancedLog #> [CmdletBinding()] param ( [Parameter(Mandatory)] [string]$ModulePath, [int]$MaxRetries = 3, [int]$WaitTimeSeconds = 2 ) Begin { $retryCount = 0 $isModuleLoaded = $false Write-Host "Starting to import module from path: $ModulePath" # Check if the module file exists before attempting to load it if (-not (Test-Path -Path $ModulePath -PathType Leaf)) { Write-Host "The module path '$ModulePath' does not exist." return } } Process { while (-not $isModuleLoaded -and $retryCount -lt $MaxRetries) { try { # Import-Module $ModulePath -ErrorAction Stop -Verbose -Global Import-Module $ModulePath -ErrorAction Stop -Global -Force:$true # Import-Module $ModulePath -ErrorAction Stop $isModuleLoaded = $true Write-Host "Module: $ModulePath imported successfully." } catch { $errorMsg = $_.Exception.Message Write-Host "Attempt $retryCount to load module failed: $errorMsg Waiting $WaitTimeSeconds seconds before retrying." Write-Host "Attempt $retryCount to load module failed with error: $errorMsg" Start-Sleep -Seconds $WaitTimeSeconds } finally { $retryCount++ } if ($retryCount -eq $MaxRetries -and -not $isModuleLoaded) { Write-Host "Failed to import module after $MaxRetries retries." Write-Host "Failed to import module after $MaxRetries retries with last error: $errorMsg" break } } } End { if ($isModuleLoaded) { Write-Host "Module: $ModulePath loaded successfully." } else { Write-Host -Message "Failed to load module $ModulePath within the maximum retry limit." } } } #EndRegion '.\Public\Import-ModuleWithRetry.ps1' 89 #Region '.\Public\Install-Modules.ps1' -1 function Install-Modules { param ( [Parameter(Mandatory = $true)] [string[]]$Modules ) # Check if running in PowerShell 5 or in a Windows environment # if ($PSVersionTable.PSVersion.Major -eq 5 -or ($PSVersionTable.Platform -eq 'Win32NT' -or [System.Environment]::OSVersion.Platform -eq [System.PlatformID]::Win32NT)) { # # Install the NuGet package provider if the condition is met # Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope CurrentUser # } if ($PSVersionTable.PSVersion.Major -eq 5) { # Install the NuGet package provider if the condition is met Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope CurrentUser } foreach ($module in $Modules) { if (-not (Get-Module -ListAvailable -Name $module)) { # Install-Module -Name $module -Force -Scope AllUsers Install-Module -Name $module -Force -Scope CurrentUser Write-EnhancedLog -Message "Module '$module' installed." -Level "INFO" -ForegroundColor } else { Write-EnhancedLog -Message "Module '$module' is already installed." -Level "INFO" -ForegroundColor } } } #EndRegion '.\Public\Install-Modules.ps1' 30 #Region '.\Public\Install-ModuleWithPowerShell5Fallback.ps1' -1 function Install-ModuleWithPowerShell5Fallback { param ( [string]$ModuleName ) # Log the start of the module installation process Write-Enhancedlog "Starting the module installation process for: $ModuleName" -Level "NOTICE" $DBG # Check if the current PowerShell version is not 5 if ($PSVersionTable.PSVersion.Major -ne 5) { Write-Enhancedlog "Current PowerShell version is $($PSVersionTable.PSVersion). PowerShell 5 is required." -Level "WARNING" # # Get the path to PowerShell 5 # $ps5Path = "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" # Write-Enhancedlog "PowerShell 5 path: $ps5Path" -Level "INFO" # # Construct the parameters for Start-Process # $startProcessParams = @{ # FilePath = $ps5Path # ArgumentList = @( # "-NoExit", # "-NoProfile", # "-ExecutionPolicy", "Bypass", # "-Command", "Install-Module -Name '$ModuleName' -Force -SkipPublisherCheck -Scope AllUsers" # ) # Verb = "RunAs" # PassThru = $true # } # Write-Enhancedlog "Constructed Start-Process parameters for PowerShell 5: $($startProcessParams | Out-String)" -Level "DEBUG" # # Launch PowerShell 5 to run the module installation # Write-Enhancedlog "Launching PowerShell 5 to install the module: $ModuleName" -Level "INFO" # $DBG # $process = Start-Process @startProcessParams # Write-Enhancedlog "Module installation command executed in PowerShell 5. Exiting current session." -Level "NOTICE" # return } # If already in PowerShell 5, install the module Write-Enhancedlog "Current PowerShell version is 5. Proceeding with module installation." -Level "INFO" Write-Enhancedlog "Installing module: $ModuleName in PowerShell 5" -Level "NOTICE" try { Install-Module -Name $ModuleName -Force -SkipPublisherCheck -Scope AllUsers Write-Enhancedlog "Module $ModuleName installed successfully in PowerShell 5." -Level "INFO" } catch { Write-Enhancedlog "Failed to install module $ModuleName. Error: $_" -Level "ERROR" } } #EndRegion '.\Public\Install-ModuleWithPowerShell5Fallback.ps1' 57 #Region '.\Public\Install-RequiredModules.ps1' -1 # function Install-RequiredModules { # [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 # # $requiredModules = @("Microsoft.Graph", "Microsoft.Graph.Authentication") # $requiredModules = @("Microsoft.Graph.Authentication") # foreach ($module in $requiredModules) { # if (!(Get-Module -ListAvailable -Name $module)) { # Write-EnhancedLog -Message "Installing module: $module" -Level "INFO" -ForegroundColor ([ConsoleColor]::Cyan) # Install-Module -Name $module -Force # Write-EnhancedLog -Message "Module: $module has been installed" -Level "INFO" -ForegroundColor ([ConsoleColor]::Cyan) # } # else { # Write-EnhancedLog -Message "Module $module is already installed" -Level "INFO" -ForegroundColor ([ConsoleColor]::Cyan) # } # } # $ImportedModules = @("Microsoft.Graph.Identity.DirectoryManagement", "Microsoft.Graph.Authentication") # foreach ($Importedmodule in $ImportedModules) { # if ((Get-Module -ListAvailable -Name $Importedmodule)) { # Write-EnhancedLog -Message "Importing module: $Importedmodule" -Level "INFO" -ForegroundColor ([ConsoleColor]::Cyan) # Import-Module -Name $Importedmodule # Write-EnhancedLog -Message "Module: $Importedmodule has been Imported" -Level "INFO" -ForegroundColor ([ConsoleColor]::Cyan) # } # } # } #EndRegion '.\Public\Install-RequiredModules.ps1' 33 #Region '.\Public\InstallAndImportModulesPSGallery.ps1' -1 function InstallAndImportModulesPSGallery { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$modulePsd1Path ) begin { Write-EnhancedLog -Message "Starting InstallAndImportModulesPSGallery function" -Level "INFO" Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters # Initialize counters and lists for summary $moduleSuccessCount = 0 $moduleFailCount = 0 $successModules = [System.Collections.Generic.List[PSCustomObject]]::new() $failedModules = [System.Collections.Generic.List[PSCustomObject]]::new() # Validate PSD1 file path if (-not (Test-Path -Path $modulePsd1Path)) { Write-EnhancedLog -Message "modules.psd1 file not found at path: $modulePsd1Path" -Level "ERROR" throw "modules.psd1 file not found." } Write-EnhancedLog -Message "Found modules.psd1 file at path: $modulePsd1Path" -Level "INFO" } process { try { # Read and import PSD1 data $moduleData = Import-PowerShellDataFile -Path $modulePsd1Path $requiredModules = $moduleData.RequiredModules $importedModules = $moduleData.ImportedModules $myModules = $moduleData.MyModules # Validate, Install, and Import Modules if ($requiredModules) { Write-EnhancedLog -Message "Installing required modules: $($requiredModules -join ', ')" -Level "INFO" foreach ($moduleName in $requiredModules) { try { Update-ModuleIfOldOrMissing -ModuleName $moduleName $moduleInfo = Get-Module -Name $moduleName -ListAvailable | Sort-Object Version -Descending | Select-Object -First 1 $moduleDetails = [PSCustomObject]@{ Name = $moduleName Version = $moduleInfo.Version Path = $moduleInfo.ModuleBase } $successModules.Add($moduleDetails) Write-EnhancedLog -Message "Successfully installed/updated module: $moduleName" -Level "INFO" $moduleSuccessCount++ } catch { $moduleDetails = [PSCustomObject]@{ Name = $moduleName Version = "N/A" Path = "N/A" } $failedModules.Add($moduleDetails) Write-EnhancedLog -Message "Failed to install/update module: $moduleName. Error: $_" -Level "ERROR" $moduleFailCount++ } } Write-EnhancedLog "All module update processes have completed." -Level "NOTICE" } if ($importedModules) { Write-EnhancedLog -Message "Importing modules: $($importedModules -join ', ')" -Level "INFO" foreach ($moduleName in $importedModules) { try { Import-Module -Name $moduleName -Force $moduleInfo = Get-Module -Name $moduleName | Select-Object -First 1 $moduleDetails = [PSCustomObject]@{ Name = $moduleName Version = $moduleInfo.Version Path = $moduleInfo.ModuleBase } $successModules.Add($moduleDetails) Write-EnhancedLog -Message "Successfully imported module: $moduleName" -Level "INFO" $moduleSuccessCount++ } catch { $moduleDetails = [PSCustomObject]@{ Name = $moduleName Version = "N/A" Path = "N/A" } $failedModules.Add($moduleDetails) Write-EnhancedLog -Message "Failed to import module: $moduleName. Error: $_" -Level "ERROR" $moduleFailCount++ } } } if ($myModules) { Write-EnhancedLog -Message "Importing custom modules: $($myModules -join ', ')" -Level "INFO" foreach ($moduleName in $myModules) { try { Import-Module -Name $moduleName -Force $moduleInfo = Get-Module -Name $moduleName | Select-Object -First 1 $moduleDetails = [PSCustomObject]@{ Name = $moduleName Version = $moduleInfo.Version Path = $moduleInfo.ModuleBase } $successModules.Add($moduleDetails) Write-EnhancedLog -Message "Successfully imported custom module: $moduleName" -Level "INFO" $moduleSuccessCount++ } catch { $moduleDetails = [PSCustomObject]@{ Name = $moduleName Version = "N/A" Path = "N/A" } $failedModules.Add($moduleDetails) Write-EnhancedLog -Message "Failed to import custom module: $moduleName. Error: $_" -Level "ERROR" $moduleFailCount++ } } } Write-EnhancedLog -Message "Modules installation and import process completed." -Level "INFO" } catch { Write-EnhancedLog -Message "Error processing modules.psd1: $_" -Level "ERROR" Handle-Error -ErrorRecord $_ throw $_ } } end { # Output summary report Write-EnhancedLog -Message "InstallAndImportModulesPSGallery function execution completed." -Level "INFO" Write-Host "---------- Summary Report ----------" -ForegroundColor Cyan Write-Host "Total Modules Processed: $($moduleSuccessCount + $moduleFailCount)" -ForegroundColor Cyan Write-Host "Modules Successfully Processed: $moduleSuccessCount" -ForegroundColor Green Write-Host "Modules Failed: $moduleFailCount" -ForegroundColor Red if ($successModules.Count -gt 0) { Write-Host "Successful Modules:" -ForegroundColor Green $successModules | Format-Table -Property Name, Version, Path -AutoSize | Out-String | Write-Host } if ($failedModules.Count -gt 0) { Write-Host "Failed Modules:" -ForegroundColor Red $failedModules | Format-Table -Property Name, Version, Path -AutoSize | Out-String | Write-Host } Write-Host "-----------------------------------" -ForegroundColor Cyan } } #EndRegion '.\Public\InstallAndImportModulesPSGallery.ps1' 152 #Region '.\Public\Invoke-InPowerShell5.ps1' -1 function Invoke-InPowerShell5 { param ( [string]$ScriptPath ) if ($PSVersionTable.PSVersion.Major -ne 5) { Write-EnhancedLog "Relaunching script in PowerShell 5 (x64)..." -Level "WARNING" # Get the path to PowerShell 5 (x64) $ps5x64Path = "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" # Launch in PowerShell 5 (x64) $startProcessParams64 = @{ FilePath = $ps5x64Path ArgumentList = @( "-NoExit", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "`"$ScriptPath`"" ) Verb = "RunAs" PassThru = $true } Write-EnhancedLog "Starting PowerShell 5 (x64) to perform the update..." -Level "NOTICE" $process64 = Start-Process @startProcessParams64 $process64.WaitForExit() Write-EnhancedLog "PowerShell 5 (x64) process completed." -Level "NOTICE" Exit } } #EndRegion '.\Public\Invoke-InPowerShell5.ps1' 33 #Region '.\Public\Is-ServerCore.ps1' -1 function Is-ServerCore { $explorerPath = "$env:SystemRoot\explorer.exe" if (Test-Path $explorerPath) { return $false } else { return $true } } Is-ServerCore #EndRegion '.\Public\Is-ServerCore.ps1' 12 #Region '.\Public\Remove-OldVersions.ps1' -1 function Remove-OldVersions { <# .SYNOPSIS Removes older versions of a specified PowerShell module. .DESCRIPTION The Remove-OldVersions function removes all but the latest version of the specified PowerShell module. It ensures that only the most recent version is retained. .PARAMETER ModuleName The name of the module for which older versions will be removed. .EXAMPLE Remove-OldVersions -ModuleName "Pester" Removes all but the latest version of the Pester module. .NOTES This function requires administrative access to manage modules and assumes that the CheckAndElevate function is defined elsewhere in the script. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$ModuleName ) begin { Write-EnhancedLog -Message "Starting Remove-OldVersions function for module: $ModuleName" -Level "INFO" Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters } process { # Get all versions except the latest one $allVersions = Get-Module -ListAvailable -Name $ModuleName | Sort-Object Version $latestVersion = $allVersions | Select-Object -Last 1 $olderVersions = $allVersions | Where-Object { $_.Version -ne $latestVersion.Version } foreach ($version in $olderVersions) { try { Write-EnhancedLog -Message "Removing older version $($version.Version) of $ModuleName..." -Level "INFO" $modulePath = $version.ModuleBase Write-EnhancedLog -Message "Starting takeown and icacls for $modulePath" -Level "INFO" Write-EnhancedLog -Message "Checking and elevating to admin if needed" -Level "INFO" CheckAndElevate & takeown.exe /F $modulePath /A /R & icacls.exe $modulePath /reset & icacls.exe $modulePath /grant "*S-1-5-32-544:F" /inheritance:d /T Remove-Item -Path $modulePath -Recurse -Force -Confirm:$false Write-EnhancedLog -Message "Removed $($version.Version) successfully." -Level "INFO" } catch { Write-EnhancedLog -Message "Failed to remove version $($version.Version) of $ModuleName at $modulePath. Error: $_" -Level "ERROR" Handle-Error -ErrorRecord $_ } } } end { Write-EnhancedLog -Message "Remove-OldVersions function execution completed for module: $ModuleName" -Level "INFO" } } #EndRegion '.\Public\Remove-OldVersions.ps1' 62 #Region '.\Public\Reset-ModulePaths.ps1' -1 function Reset-ModulePaths { [CmdletBinding()] param () begin { # Initialization block, typically used for setup tasks Write-EnhancedLog "Initializing Reset-ModulePaths function..." -Level "DEBUG" } process { try { # Log the start of the process Write-EnhancedLog "Resetting module paths to default values..." -Level "INFO" # Get the current user's Documents path $userModulesPath = [System.IO.Path]::Combine($env:USERPROFILE, 'Documents\WindowsPowerShell\Modules') # Define the default module paths $defaultModulePaths = @( "C:\Program Files\WindowsPowerShell\Modules", $userModulesPath, "C:\Windows\System32\WindowsPowerShell\v1.0\Modules" ) # Attempt to reset the PSModulePath environment variable $env:PSModulePath = [string]::Join(';', $defaultModulePaths) Write-EnhancedLog "PSModulePath successfully set to: $($env:PSModulePath -split ';' | Out-String)" -Level "INFO" # Optionally persist the change for the current user [Environment]::SetEnvironmentVariable("PSModulePath", $env:PSModulePath, [EnvironmentVariableTarget]::User) Write-EnhancedLog "PSModulePath environment variable set for the current user." -Level "INFO" } catch { # Capture and log any errors that occur during the process $errorMessage = $_.Exception.Message Write-EnhancedLog "Error resetting module paths: $errorMessage" -Level "ERROR" # Optionally, you could throw the error to halt the script throw $_ } } end { # Finalization block, typically used for cleanup tasks Write-EnhancedLog "Reset-ModulePaths function completed." -Level "DEBUG" } } #EndRegion '.\Public\Reset-ModulePaths.ps1' 48 #Region '.\Public\Update-ModuleIfOldOrMissing.ps1' -1 function Update-ModuleIfOldOrMissing { <# .SYNOPSIS Updates or installs a specified PowerShell module if it is outdated or missing. .DESCRIPTION The Update-ModuleIfOldOrMissing function checks the status of a specified PowerShell module and updates it if it is outdated. If the module is not installed, it installs the latest version. It also removes older versions after the update. .PARAMETER ModuleName The name of the module to be checked and updated or installed. .EXAMPLE Update-ModuleIfOldOrMissing -ModuleName "Pester" Checks and updates the Pester module if it is outdated or installs it if not present. .NOTES This function requires administrative access to manage modules and assumes that the CheckAndElevate, Check-ModuleVersionStatus, and Remove-OldVersions functions are defined elsewhere in the script. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$ModuleName ) begin { Write-EnhancedLog -Message "Starting Update-ModuleIfOldOrMissing function for module: $ModuleName" -Level "Notice" Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters } process { $moduleStatus = Check-ModuleVersionStatus -ModuleNames @($ModuleName) foreach ($status in $moduleStatus) { switch ($status.Status) { "Outdated" { Write-EnhancedLog -Message "Updating $ModuleName from version $($status.InstalledVersion) to $($status.LatestVersion)." -Level "WARNING" # Remove older versions Remove-OldVersions -ModuleName $ModuleName # Install the latest version of the module # Install-Module -Name $ModuleName -Force -SkipPublisherCheck -Scope AllUsers Install-ModuleWithPowerShell5Fallback -ModuleName $ModuleName Write-EnhancedLog -Message "$ModuleName has been updated to the latest version." -Level "INFO" } "Up-to-date" { Write-EnhancedLog -Message "$ModuleName version $($status.InstalledVersion) is up-to-date. No update necessary." -Level "INFO" Remove-OldVersions -ModuleName $ModuleName } "Not Installed" { Write-EnhancedLog -Message "$ModuleName is not installed. Installing the latest version..." -Level "WARNING" # Install-Module -Name $ModuleName -Force -SkipPublisherCheck -Scope AllUsers $DBG Install-ModuleWithPowerShell5Fallback -ModuleName $ModuleName Write-EnhancedLog -Message "$ModuleName has been installed." -Level "INFO" } "Not Found in Gallery" { Write-EnhancedLog -Message "Unable to find '$ModuleName' in the PowerShell Gallery." -Level "ERROR" } } } } end { Write-EnhancedLog -Message "Update-ModuleIfOldOrMissing function execution completed for module: $ModuleName" -Level "Notice" } } #EndRegion '.\Public\Update-ModuleIfOldOrMissing.ps1' 70 |