Public/Install-emsScriptModules.ps1
<#PSScriptInfo
.VERSION 1.0.0 .GUID 27a6e509-b2ac-4f24-b0c0-986ef5c59d0d .AUTHOR enthus Managed Services GmbH .COMPANYNAME enthus Managed Services GmbH #> #Requires -Version 5.1 <# .SYNOPSIS Installs PowerShell modules which are defined in a script file info of a specific file. .DESCRIPTION Installs PowerShell modules which are defined in a script file info of a specific file. Depending and interfering modules will be uninstalled at first. Runs with 'ErrorAction' set to 'Error' by default (unless 'ErrorAction' parameter is explicitly set). Hint: Module 'Microsoft.Graph.Authentication' must be declared before all other 'Microsoft.Graph' modules. .NOTES PSVersion: 5.1.x or 7.2.x ENVIRONMENT: [ ] Azure Automation [ ] Azure Function [x] Local [ ] Nerdio [ ] PowerShell Universal [ ] Server [ ] ... REQUIRED CONTEXT: [ ] Application && Delegated [ ] Application [ ] Delegated [x] User REQUIRED PERMISSIONS: Local: - Administrator .OUTPUTS None. .EXAMPLE Install-emsScriptModules -FilePath "C:\development\git\KUD-EMS-Test-O365\Runbooks\TestScript.ps1" Checks required modules of the given file, uninstalls all depending and interfering modules and installs all required modules. #> function Install-emsScriptModules { [CmdletBinding()] param( # string. Path to the file which contains required PowerShell modules to install [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$FilePath ) # TODO 'Remove' active/used modules before uninstalling # TODO Handle modules that can not be found in public PowerShell gallery (e. g. 'Vindesk.Core'), for example by exclusion list # Handle ErrorActionPreference $inputErrorAction = $PSBoundParameters['ErrorAction'] if (!$inputErrorAction) { $activeErrorActionPreference = $ErrorActionPreference $ErrorActionPreference = "Stop" } try { # Modules within one line must not be installed concurrently $interferingModuleNamesLists = @( @("PnP.PowerShell", "SharePointPnPPowerShellOnline"), @("AzureAD", "AzureADPreview"), @() # Workaround to force PowerShell to iterate over inner arrays ) # TODO Extend object with attributes "ModuleBaseName" and "DependencyModuleName" (for module 'Microsoft.Graph.Authentication') $dependingModuleNames = @( "Microsoft.Graph" ) $requiredModules = (Test-ScriptFileInfo -Path $FilePath).RequiredModules if ($requiredModules) { $interferingModuleNames = @() foreach ($interferingModuleNamesList in $interferingModuleNamesLists) { # Get required but interfering modules $requiredInterferingModuleNames = (Compare-Object -ReferenceObject $interferingModuleNamesList -DifferenceObject $requiredModules.Name -ExcludeDifferent -IncludeEqual).InputObject if ($requiredInterferingModuleNames.Count -eq 1) { $interferingModuleNames += $interferingModuleNamesList } elseif ($requiredInterferingModuleNames.Count -gt 1) { Write-Host -ForegroundColor "Red" "Script is not executable because interfering modules are required ($($requiredInterferingModuleNames -join ", "))." exit } } if ($dependingModuleNames) { $installedDependingModules = @() foreach ($dependingModuleName in $dependingModuleNames) { $requiredDependingModules = $requiredModules | Where-Object { $_.Name -like "$($dependingModuleName)*" } if ($requiredDependingModules) { if (($requiredDependingModules.RequiredVersion | Select-Object -Unique).Count -gt 1) { Write-Error "Required '$($dependingModuleName)' modules have different versions." } else { $requiredDependingModuleVersion = $requiredDependingModules[0].RequiredVersion $installedDependingModulesTemp = @() $installedDependingModulesTemp += Get-Module -ListAvailable -Name "$($dependingModuleName)*" | Where-Object { $_.Version -ne $requiredDependingModuleVersion } $installedDependingModules += $installedDependingModulesTemp | Where-Object { $_.Name -ne "Microsoft.Graph.Authentication" } $installedDependingModules += $installedDependingModulesTemp | Where-Object { $_.Name -eq "Microsoft.Graph.Authentication" } } } } if ($installedDependingModules) { Write-Host -ForegroundColor "DarkGray" -Object "Clean up depending modules ..." foreach ($installedDependingModule in $installedDependingModules) { Write-Host -ForegroundColor "Magenta" -Object " Module '$($installedDependingModule.Name)' ($($installedDependingModule.Version)) will be uninstalled ..." Uninstall-Module -Name $installedDependingModule.Name -Force | Out-Null } } } if ($interferingModuleNames) { Write-Host -ForegroundColor "DarkGray" -Object "Clean up interfering modules ..." foreach ($interferingModuleName in $interferingModuleNames) { if ($requiredModules.Name -notContains $interferingModuleName) { $installedInterferingModule = $null $installedInterferingModule = Get-Module -ListAvailable -Name $interferingModuleName if ($installedInterferingModule) { Write-Host -ForegroundColor "Magenta" -Object " Interfering module '$($installedInterferingModule.Name)' ($($installedInterferingModule.Version)) will be uninstalled ..." Uninstall-Module -Name $interferingModuleName -Force | Out-Null } } } } foreach ($requiredModule in $requiredModules) { $requiredModuleVersion = $requiredModule.RequiredVersion -join "." Write-Host -ForegroundColor "DarkGray" -Object "Module '$($requiredModule.Name)' ($requiredModuleVersion) is required ..." $installedModule = Get-Module -ListAvailable -Name $requiredModule.Name if ($installedModule) { $installedModuleVersion = $installedModule.Version -join "." if ($requiredModuleVersion -eq $installedModuleVersion) { Write-Host -ForegroundColor "Green" -Object " Module '$($installedModule.Name)' ($installedModuleVersion) is already installed" } else { Write-Host -ForegroundColor "Magenta" -Object " Module '$($installedModule.Name)' ($installedModuleVersion) will be uninstalled ..." Uninstall-Module -Name $installedModule.Name -Force | Out-Null Write-Host -ForegroundColor "Cyan" -Object " Module '$($requiredModule.Name)' ($requiredModuleVersion) will be installed ..." Install-Module -Name $requiredModule.Name -Scope AllUsers -Force -RequiredVersion $requiredModuleVersion | Out-Null } } else { Write-Host -ForegroundColor "Cyan" -Object " Module '$($requiredModule.Name)' ($requiredModuleVersion) is not present and will be installed ..." Install-Module -Name $requiredModule.Name -Scope AllUsers -Force -RequiredVersion $requiredModuleVersion | Out-Null } } } else { Write-Host -ForegroundColor "DarkGray" -Object "No modules required" } } finally { # Reset ErrorActionPreference if (!$inputErrorAction) { $ErrorActionPreference = $activeErrorActionPreference } } } |