PSBuild.psm1
#region Private Functions function priv_Export-PSArtefact { [CmdletBinding()] [OutputType([void])] param ( #SourcePath [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_Default')] [ValidateScript({ if (-not (test-path $_)) { throw "$_ does not exist" } else { $true } })] [string]$SourcePath, #DestinationPath [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_Default')] [string]$DestinationPath, #ModuleVersion [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [string]$Version, #Type [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_Default')] [ValidateSet('Script','Module')] [string]$Type ) Process { switch ($Type) { 'Script' { #Check if Source and Destination are the same $SourceFolder = Split-Path -Path $SourcePath -Parent -ErrorAction Stop if ($SourceFolder -eq $DestinationPath) { #Do nothing } else { if (-not (Test-Path $DestinationPath)) { $null = New-Item -Path $DestinationPath -ItemType Directory -ErrorAction Stop } $null = Copy-Item -Path $SourcePath -Destination $DestinationPath -Force -ErrorAction Stop } break } 'Module' { $ModuleFolder = New-Object -TypeName System.IO.DirectoryInfo -ArgumentList $SourcePath $ObjectName = $ModuleFolder.BaseName #Calculcate DestinationFolder if ($PSBoundParameters.ContainsKey('Version')) { $ObjectDestinationFolderTemp = Join-Path -Path $DestinationPath -ChildPath $ObjectName -ErrorAction Stop $ObjectDestinationFolder = Join-Path -Path $ObjectDestinationFolderTemp -ChildPath $Version -ErrorAction Stop } else { $ObjectDestinationFolder = Join-Path -Path $DestinationPath -ChildPath $ObjectName -ErrorAction Stop } #Check if Source and Destination are the same $SourceFolder = Split-Path -Path $SourcePath -Parent -ErrorAction Stop if ($SourceFolder -eq $ObjectDestinationFolder) { #Do nothing } else { #Validate DestinationFolder if (Test-Path -Path $ObjectDestinationFolder) { Remove-Item -Path $ObjectDestinationFolder -ErrorAction Stop -Force -Confirm:$false -Recurse } $null = New-Item -Path $ObjectDestinationFolder -ItemType Directory -ErrorAction Stop #Copy Module content $ModuleFilesToExclude = @( 'obj' 'bin' 'CSharpAssemblies' '*.pssproj' '*.pssproj.user' '*.csproj' '*.csproj.user' '*.vspscc' '*.pdb' '*.cs' '*.tests.ps1' 'packages.config' 'Tests' 'System.Management.Automation.dll' ) $null = Copy-Item -Path "$SourcePath\*" -Destination $ObjectDestinationFolder -Recurse -Exclude $ModuleFilesToExclude } break } default { throw "Unknown Type: $Type" } } } } function priv_Publish-PSModule { [CmdletBinding()] [OutputType([void])] param ( #ModuleInfo [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_Default')] [PSModuleInfo]$ModuleInfo, #Credential [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [PScredential]$Credential, #Repository [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [string]$Repository, #NuGetApiKey [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [string]$NuGetApiKey, #Force [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [switch]$Force, #PublishDependantModules [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [switch]$PublishDependantModules = $true, #VerbosePrefix [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [string]$VerbosePrefix ) Begin { } Process { #Resolve ModuleRootFolder try { $ModuleLeafFolder = Split-Path -Path $ModuleInfo.ModuleBase -Leaf $ModuleVersion = New-Object System.Version if ([System.Version]::TryParse($ModuleLeafFolder, [ref]$ModuleVersion)) { $ModuleVersionFolder = Split-Path -Path $ModuleInfo.ModuleBase -Parent $ModuleRootFolder = Split-Path -Path $ModuleVersionFolder -Parent } else { $ModuleRootFolder = Split-Path -Path $ModuleInfo.ModuleBase -Parent } } catch { Write-Error "Resolve ModuleRootFolder failed. Details: $_" -ErrorAction 'Stop' } #Publish RequiredModules $ModsToPublish = $ModuleInfo.RequiredModules | Where-Object {$ModuleInfo.PrivateData.PSData.ExternalModuleDependencies -notcontains $_.Name} foreach ($ReqModule in $ModsToPublish) { $ReqModuleFound = $false #Check if Required Module is present in the same folder as the current module try { $ReqModuleInfo = Get-Module -ListAvailable -FullyQualifiedName "$ModuleRootFolder\$($ReqModule.Name)" -Refresh -ErrorAction Stop if ($ReqModuleInfo) { #If multiple versions are available, select latest one. $ReqModuleInfo = $ReqModuleInfo | Sort-Object -Property Version | select -Last 1 if ($ReqModule.Version -and ($ReqModule.Version -le $ReqModuleInfo.Version)) { $ReqModuleFound = $true } else { $ReqModuleFound = $true } } } catch { } #Check if Required Module is present on the machine if (-not $ReqModuleFound) { try { $ReqModuleInfo = Get-Module -Name $ReqModule.Name -ErrorAction Stop if ($ReqModuleInfo) { #If multiple versions are available, select latest one. $ReqModuleInfo = $ReqModuleInfo | Sort-Object -Property Version | select -Last 1 if ($ReqModule.Version -and ($ReqModule.Version -le $ReqModuleInfo.Version)) { $ReqModuleFound = $true } else { $ReqModuleFound = $true } } } catch { } } if ($ReqModuleFound) { $PublishModuleAndDependacies_Params = @{} + $PSBoundParameters $PublishModuleAndDependacies_Params['ModuleInfo'] = $ReqModuleInfo priv_Publish-PSModule @PublishModuleAndDependacies_Params } else { throw "Unable to find Required Module: $($ReqModule.Name)" } } #Publish Module try { $PublishModule_CommonParams = @{ Repository=$Repository } if ($PSBoundParameters.ContainsKey('Credential')) { $PublishModule_CommonParams.Add('Credential',$Credential) } #Check if module already exist on the Repository try { Remove-Variable -Name ModExist -ErrorAction SilentlyContinue $private:ModExist = Find-Module @PublishModule_CommonParams -Name $ModuleInfo.Name -RequiredVersion $ModuleInfo.Version -ErrorAction Stop } catch { } if ($ModExist) { Write-Verbose "$VerbosePrefix`Module already exist on the PSGetRepo" } else { $PublishModule_Params = @{ Path=$ModuleInfo.ModuleBase } + $PublishModule_CommonParams if ($PSBoundParameters.ContainsKey('NuGetApiKey')) { $PublishModule_Params.Add('NuGetApiKey',$NuGetApiKey) } Write-Verbose "$VerbosePrefix`Publishing new version" Publish-Module @PublishModule_Params -Force -ErrorAction Stop } } catch { Write-Error "Publish Module failed. Details: $_" -ErrorAction 'Stop' } } End { } } function priv_Analyse-ItemDependancies { [CmdletBinding()] param ( #ScriptBlock [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_ScriptBlock')] [scriptblock]$ScriptBlock, #ModulePath [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_Module')] [string]$ModulePath, #ScriptPath [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_Script')] [string]$ScriptPath, #GlobalCommandAnalysis [Parameter(Mandatory=$true)] [ref]$GlobalCommandAnalysis, #PSGetRepository [Parameter(Mandatory=$false)] [hashtable[]]$PSGetRepository, #CurrentDependancies [Parameter(Mandatory=$false)] [string[]]$CurrentDependancies ) Process { #Construct JobParams $JobParams = @{ GlobalCommandAnalysisAsJson=$GlobalCommandAnalysis.Value.ToJson() CurrentDependancies=$CurrentDependancies PSGetRepository=$PSGetRepository PSBuildDllPath=[System.AppDomain]::CurrentDomain.GetAssemblies() | Where-Object {$_.GetName().Name -eq 'PSBuildEntities'} | select -ExpandProperty Location } Switch ($PSCmdlet.ParameterSetName) { 'NoRemoting_ScriptBlock' { $JobParams.Add('ScriptBlock',$ScriptBlock) break } 'NoRemoting_Module' { $JobParams.Add('ModulePath',$ModulePath) break } 'NoRemoting_Script' { $JobParams.Add('ScriptPath',$ScriptPath) break } default { throw "Unknown ParameterSet: $_" } } try { $Job = Start-Job -ScriptBlock { #Wait-Debugger $JobParams = $Using:JobParams Add-Type -Path $JobParams['PSBuildDllPath'] -ErrorAction Stop $GlobalCommandAnalysis = [PSBuildEntities.AnalysisResultCollection]::FromJson($JobParams['GlobalCommandAnalysisAsJson']) $LocalCommandAnalysis = [PSBuildEntities.AnalysisResultCollection]::New() #Get Module ScriptBlockAst if ($JobParams.ContainsKey('ModulePath')) { $OldErrorActionPreference = $ErrorActionPreference $OldVerbosePreference = $VerbosePreference $OldWarningPreference = $WarningPreference $ErrorActionPreference = 'Continue' $VerbosePreference = 'SilentlyContinue' $WarningPreference = 'SilentlyContinue' $ModFresh = Import-Module -FullyQualifiedName $JobParams['ModulePath'] -PassThru -ErrorAction Stop -WarningAction SilentlyContinue -Verbose:$false -ErrorVariable er $ErrorActionPreference = $OldErrorActionPreference $VerbosePreference=$OldVerbosePreference $WarningPreference=$OldWarningPreference if (-not $ModFresh) { throw "Unable to Import Module: $($ModuleValidationCache.Value[$moduleName].ModuleInfo.ModuleBase). Details: $er" } $ModuleSb = [scriptblock]::Create($ModFresh.Definition) $ScriptBlockAst = $ModuleSb.Ast } #Get Script ScriptBlockAst elseif ($JobParams.ContainsKey('ScriptPath')) { $ScriptContent = Get-Command -Name $JobParams['ScriptPath'] -ErrorAction Stop -Verbose:$false $ScriptBlockAst = $ScriptContent.ScriptBlock.Ast } #GetScriptBlockAst elseif ($JobParams.ContainsKey('ScriptBlock')) { $ScriptBlockAst = $ScriptBlock.Ast } else { throw "Unknown ParameterSet" } #Identify NonLocal commands try { $LocalCommands = Get-AstStatement -Ast $ScriptBlockAst -Type FunctionDefinitionAst | Select-Object -ExpandProperty Name $NonLocalCommands = Get-AstStatement -Ast $ScriptBlockAst -Type CommandAst | ForEach-Object {$_.GetCommandName()} | Group-Object -NoElement | Select-Object -ExpandProperty Name | Where-Object {$LocalCommands -notcontains $_} } catch { Write-Error "Identify NonLocal commands failed. Details: $_" -ErrorAction 'Stop' } #Resolve NonLocal commands against GlobalCommandAnalysis try { foreach ($cmd in $NonLocalCommands) { $CmdResult = [PSBuildEntities.AnalysisResult]::new() #Determine CmdName and Module if ($cmd.Contains('\')) { $tempcmd= $cmd -split '\\' $CmdResult.CommandSource = $tempcmd[0] $CmdResult.CommandName = $tempcmd[1] } else { $CmdResult.CommandName = $cmd } #Check if command is already analyzed if (-not $LocalCommandAnalysis.Contains($CmdResult.CommandName)) { #Resolve command Source if ($GlobalCommandAnalysis.Contains($CmdResult.CommandName)) { #Source already resolved $CmdResult = $GlobalCommandAnalysis[$CmdResult.CommandName] $CmdResult.IsReferenced = $false $CmdResult.IsFound = $true } else { #Check if command is local if (-not $CmdResult.IsFound) { try { $GetCommandParams = @{ Name=$CmdResult.CommandName } if ($CmdResult.CommandSource) { $SourceCandidate = $CmdResult.CommandSource } else { if ($JobParams.ContainsKey('CurrentDependancies')) { $SourceCandidate = $JobParams['CurrentDependancies'] } else { Remove-Variable -Name SourceCandidate -ErrorAction SilentlyContinue } } if (-not [string]::IsNullOrEmpty($CmdResult.CommandSource)) { $GetCommandParams.Add('Module',$CmdResult.CommandSource) } try { Remove-Variable -Name TempFindng -ErrorAction SilentlyContinue $TempFindng = Get-Command @GetCommandParams -ErrorAction Stop -Verbose:$false if ((-not $TempFindng) -and ($SourceCandidate)) { $TempFindng = Get-Command @GetCommandParams -Module $SourceCandidate -ErrorAction Stop -Verbose:$false } } catch { } if ($TempFindng) { $CmdResult.CommandType = $TempFindng.CommandType if ($TempFindng.CommandType -eq 'Alias') { $TempFinding2 = Get-Command -Name $TempFindng.Name -ErrorAction Stop -Verbose:$false $CmdResult.CommandSource = $TempFinding2.Source } else { $CmdResult.CommandSource = $TempFindng.Source } $CmdResult.IsFound = $true } } catch { Write-Error "Check if command is local failed. Details: $_" -ErrorAction 'Stop' } } } $null = $LocalCommandAnalysis.Add($CmdResult) } } } catch { Write-Error "Resolve NonLocal Commands against CommandToModuleMapping failed. Details: $_" -ErrorAction Stop } #Resolve Missing commands against Proget if ($JobParams.ContainsKey('PSGetRepository')) { try { $MissingCommandsAnalysis = $LocalCommandAnalysis | Where-Object {$_.IsFound -eq $false} if ($MissingCommandsAnalysis) { Assert-PSRepository -PSGetRepository $JobParams['PSGetRepository'] -ErrorAction Stop foreach ($Repo in $JobParams['PSGetRepository']) { #Refresh MissingCommandsAnalysis $MissingCommandsAnalysis = $LocalCommandAnalysis | Where-Object {$_.IsFound -eq $false} if ($MissingCommandsAnalysis) { #Search for All MissingCommands $FindModule_Params = @{ Command=$MissingCommandsAnalysis.CommandName Repository=$Repo.Name } if ($Repo.ContainsKey('Credential')) { $FindModule_Params.Add('Credential',$Repo.Credential) } Remove-Variable -Name TempNugetResult -ErrorAction SilentlyContinue $private:TempNugetResult = Find-Module @FindModule_Params -ErrorAction Stop #Map search results to MissingCommands if ($TempNugetResult) { foreach ($MissingCmd in $MissingCommandsAnalysis) { $MissingCmdModule = $TempNugetResult | Where-Object {$_.Includes.Command -contains $MissingCmd.CommandName} if ($MissingCmdModule) { $LocalCommandAnalysis[$MissingCmd.CommandName].CommandSource = $MissingCmdModule.Name -join ',' $LocalCommandAnalysis[$MissingCmd.CommandName].CommandType = 'Command' $LocalCommandAnalysis[$MissingCmd.CommandName].SourceLocation = [PSBuildEntities.AnalysisResultSourceLocation]::ProGet $LocalCommandAnalysis[$MissingCmd.CommandName].IsFound = $true } } } } } } } catch { Write-Error "Resolve Missing commands against Proget failed. Details: $_" -ErrorAction Stop } } #Check commands references try { foreach ($Cmd in ($LocalCommandAnalysis | Where-Object {$_.IsFound})) { if ($JobParams['CurrentDependancies'] -contains $cmd.CommandSource) { $cmd.IsReferenced = $true } } } catch { Write-Error "Check commands references failed. Details: $_" -ErrorAction Stop } #Update GlobalCommandAnalysis try { $FoundCommandsAnalysis = $LocalCommandAnalysis | Where-Object {$_.IsFound -eq $true} foreach ($FoundCmd in $FoundCommandsAnalysis) { if (-not $GlobalCommandAnalysis.Contains($FoundCmd.CommandName)) { $null = $GlobalCommandAnalysis.Add($FoundCmd) } } } catch { Write-Error "Update GlobalCommandAnalysis failed. Details: $_" -ErrorAction Stop } #Return result [pscustomobject]@{ LocalCommandAnalysisAsJson=$LocalCommandAnalysis.ToJson() GlobalCommandAnalysisAsJson=$GlobalCommandAnalysis.ToJson() } } $null = Wait-Job -Job $Job $JobResult = Receive-Job -Job $Job } finally { Remove-Job -Job $Job -Force } #Update GlobalCommandAnalysis $GlobalCommandAnalysis.Value = [PSBuildEntities.AnalysisResultCollection]::FromJson($JobResult.GlobalCommandAnalysisAsJson) [PSBuildEntities.AnalysisResultCollection]::FromJson($JobResult.LocalCommandAnalysisAsJson) } } function priv_Validate-Module { [CmdletBinding()] param ( #SourcePath [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_Default')] [System.IO.DirectoryInfo[]]$SourcePath, #ModuleValidation [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_Default')] [ref]$ModuleValidationCache ) Process { foreach ($Module in $SourcePath) { $moduleName = $Module.Name if (-not $ModuleValidationCache.Value.ContainsKey($moduleName)) { $null = $ModuleValidationCache.Value.Add($moduleName,(Test-PSModule -ModulePath $Module.FullName -ErrorAction Stop)) } } } } #endregion #region Public Functions function Build-PSModule { [CmdletBinding()] [OutputType([void])] param ( #SourcePath [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_Default')] [System.IO.DirectoryInfo[]]$SourcePath, #DestinationPath [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_Default')] [System.IO.DirectoryInfo]$DestinationPath, #ResolveDependancies [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [switch]$ResolveDependancies, #CheckCommandReferences [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [switch]$CheckCommandReferences, #CheckCommandReferencesConfiguration [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [psobject]$CheckCommandReferencesConfiguration, #CheckDuplicateCommandNames [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [switch]$CheckDuplicateCommandNames, #UpdateModuleReferences [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [switch]$UpdateModuleReferences, #PSGetRepository [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [hashtable[]]$PSGetRepository, #ModuleValidation [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [ref]$ModuleValidationCache, #PsGetModuleValidation [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [ref]$PsGetModuleValidationCache ) Process { #Add DestinationPath to Process PSModulePath try { Add-PSModulePathEntry -Path $DestinationPath -Scope Process -Force } catch { Write-Error "Add DestinationPath to Process PSModulePath failed. Details: $_" -ErrorAction 'Stop' } #Assert PSRepositories if ($PSBoundParameters.ContainsKey('PSGetRepository')) { #Register PSGetRepo Assert-PSRepository -PSGetRepository $PSGetRepository -ErrorAction Stop } #Validate All Modules try { if (-not $PSBoundParameters.ContainsKey('ModuleValidationCache')) { [ref]$ModuleValidationCache = @{} } priv_Validate-Module -SourcePath $SourcePath -ModuleValidationCache $ModuleValidationCache } catch { Write-Error "Unable to validate $moduleName. Details: $_" -ErrorAction 'Stop' } #Validate All Commands try { [ref]$CommandsToModuleMapping = [PSBuildEntities.AnalysisResultCollection]::new() #Add BuildIn Comands and Aliases to CommandsToModuleMapping (from module 'Microsoft.PowerShell.Core' as they are buildin to PowerShell) Get-Command -Module $PSNativeModules -Verbose:$false | ForEach-Object { #Add Command $Command = [PSBuildEntities.AnalysisResult]::new() $Command.CommandName = "$($_.Name)" $Command.CommandType = $_.CommandType if ($Command.CommandType -eq 'Alias') { try { $TempFinding2 = Get-Command -Name $Command.CommandName -ErrorAction Stop -Verbose:$false $Command.CommandSource = $TempFinding2.Source } catch { } } else { $Command.CommandSource = $_.Source } $Command.SourceLocation = [PSBuildEntities.AnalysisResultSourceLocation]::BuildIn if(-not $CommandsToModuleMapping.Value.Contains($Command.CommandName)) { $CommandsToModuleMapping.Value.add($Command) } #Add Alias if exists Get-Alias -Definition $_.Name -ErrorAction SilentlyContinue | foreach { $Alias = [PSBuildEntities.AnalysisResult]::new() $Alias.CommandName = "$($_.Name)" $Alias.CommandType = 'Alias' $Alias.CommandSource = $Command.CommandSource $Alias.SourceLocation = [PSBuildEntities.AnalysisResultSourceLocation]::BuildIn if (-not $CommandsToModuleMapping.Value.Contains($Alias.CommandName)) { $CommandsToModuleMapping.Value.add($Alias) } } } #Add Solution Commands to CommandsToModuleMapping (from all modules in the solution) foreach ($Mod in $ModuleValidationCache.Value.Keys) { foreach ($cmd in $ModuleValidationCache.Value[$Mod].ModuleInfo.ExportedCommands.Values) { $Command = [PSBuildEntities.AnalysisResult]::new() $Command.CommandName = $cmd.Name $Command.CommandType = $cmd.CommandType $Command.CommandSource = $cmd.Source $Command.SourceLocation = [PSBuildEntities.AnalysisResultSourceLocation]::Solution if (-not $CommandsToModuleMapping.Value.Contains($cmd.Name)) { $CommandsToModuleMapping.Value.Add($Command) } elseif ($CommandsToModuleMapping.Value[$Command.CommandName].CommandSource -ne $Command.CommandSource) { if ($CheckDuplicateCommandNames.IsPresent) { Write-Error "Command with name: $($Command.CommandName) is present in multiple modules: $($CommandsToModuleMapping.Value[$Command.CommandName].CommandSource),$($Command.CommandSource)" -ErrorAction Stop } } } } } catch { Write-Error "Validate All Commands failed. Details: $_" -ErrorAction 'Stop' } #Initialize PSGetModuleValidationCache if (-not $PSBoundParameters.ContainsKey('PsGetModuleValidationCache')) { [ref]$PsGetModuleValidationCache = @{} } #Build Module foreach ($Module in $SourcePath) { $moduleName = $Module.Name if ($ModuleValidationCache.Value[$moduleName].ModuleInfo) { $moduleVersion = $ModuleValidationCache.Value[$moduleName].ModuleInfo.Version Write-Verbose "Build PSModule:$moduleName/$moduleVersion started" #Check if Module is already built try { Remove-Variable -Name ModAlreadyBuildTest -ErrorAction SilentlyContinue $ModuleAlreadyBuild = $false $ModuleDependanciesValid = $true $ModuleVersionBuilded = $false $ModuleBuildDestinationPath = Join-Path -Path $DestinationPath -ChildPath $moduleName -ErrorAction Stop if (Test-Path -Path $ModuleBuildDestinationPath) { $ModAlreadyBuildTest = Test-PSModule -ModulePath $ModuleBuildDestinationPath -ErrorAction Stop } #Check if Module with the same version is already builded if ($ModuleValidationCache.Value[$moduleName].IsValid -and $ModAlreadyBuildTest.IsValid -and ($ModuleValidationCache.Value[$moduleName].ModuleInfo.Version -eq $ModuleValidationCache.Value[$moduleName].ModuleInfo.Version)) { $ModuleVersionBuilded = $true } #Check if Module Dependancies are valid versions foreach ($DepModule in $ModuleValidationCache.Value[$moduleName].ModuleInfo.RequiredModules) { $depModuleName=$DepModule.Name $depModuleVersion=$DepModule.Version $DepModuleDestinationPath = Join-Path -Path $DestinationPath -ChildPath $depModuleName -ErrorAction Stop #Check if DepModule is marked as ExternalModuleDependency if ($ModuleValidationCache.Value[$moduleName].ModuleInfo.PrivateData.PSData.ExternalModuleDependencies -contains $depModuleName) { #Skip this DepModule from validation, as it is marked as external } #Check if DepModule is in the same Solution elseif (($ModuleValidationCache.Value).ContainsKey($depModuleName)) { if ($ModuleValidationCache.Value[$depModuleName].ModuleInfo.Version -gt $depModuleVersion -or (-not $ModuleValidationCache.Value[$depModuleName].IsValid)) { $ModuleDependanciesValid = $false } } #Check if DepModule is in PSGetRepositories elseif ($PSBoundParameters.ContainsKey('PSGetRepository')) { #Check for Module in all Nuget Repos Remove-Variable -Name NugetDependencyList -ErrorAction SilentlyContinue $NugetDependencyList = New-Object -TypeName System.Collections.ArrayList foreach ($item in $PSGetRepository) { #Search for module if (-not $PsGetModuleValidationCache.Value.ContainsKey($depModuleName)) { $PSGet_Params = @{ Name=$depModuleName Repository=$item.Name } if (-not $UpdateModuleReferences.IsPresent) { $PSGet_Params.Add('RequiredVersion',$depModuleVersion) } if ($item.ContainsKey('Credential')) { $PSGet_Params.Add('Credential',$item.Credential) } try { Remove-Variable -Name NugetDependency -ErrorAction SilentlyContinue $private:NugetDependency = Find-Module @PSGet_Params -ErrorAction Stop } catch { } #Add module to PsGetModuleValidationCache if ($private:NugetDependency) { $AddMember_Params = @{ InputObject=$private:NugetDependency MemberType='NoteProperty' Name='PSGetRepoPriority' } if ($item.Priority) { $AddMember_Params.Add('Value',$item.Priority) } else { $AddMember_Params.Add('Value',0) } $null = Add-Member @AddMember_Params -ErrorAction Stop $null = $NugetDependencyList.Add($private:NugetDependency) } } } #Get Latest Version if multiple are present if ($NugetDependencyList) { Remove-Variable -Name NugetDepToADD -ErrorAction SilentlyContinue $NugetDepToADD = $NugetDependencyList | Sort-Object -Property Version -Descending | Sort-Object -Property PSGetRepoPriority | select -First 1 $null = $PsGetModuleValidationCache.Value.Add($depModuleName,$NugetDepToADD) } #Check if DepModule ref version is the latest if ($PsGetModuleValidationCache.Value.ContainsKey($depModuleName) -and ($PsGetModuleValidationCache.Value[$depModuleName].Version -gt $depModuleVersion)) { Write-Warning "Build PSModule:$moduleName/$moduleVersion in progress. PsGet Dependancy: $depModuleName/$depModuleVersion is not the latest version" if ($UpdateModuleReferences.IsPresent) { $ModuleDependanciesValid=$false } } } #Check If Module Dependency is already builded elseif (Test-Path -Path $DepModuleDestinationPath) { try { $Mod = Test-PSModule -ModulePath $DepModuleDestinationPath -ErrorAction Stop if ($Mod.ModuleInfo.Version -lt $depModuleVersion) { $ModuleDependanciesValid = $false } } catch { } } else { $ModuleDependanciesValid = $false } } #Determine if module should be built if ($ModuleDependanciesValid -and $ModuleVersionBuilded) { $ModuleAlreadyBuild = $true } } catch { } #Build Module if not already built if ($ModuleAlreadyBuild) { Write-Verbose "Build PSModule:$moduleName/$moduleVersion skipped, already built" } else { #Build Module Dependancies try { #Resolve Dependancies if ($ResolveDependancies.IsPresent) { $Dependancies = $ModuleValidationCache.Value[$moduleName].ModuleInfo.RequiredModules | Where-Object {$ModuleValidationCache.Value[$moduleName].ModuleInfo.PrivateData.PSData.ExternalModuleDependencies -notcontains $_.Name} foreach ($ModDependency in $Dependancies) { $dependantModuleName = $ModDependency.Name $dependantModuleVersion = $ModDependency.Version Write-Verbose "Build PSModule:$moduleName/$moduleVersion in progress. Build dependant module:$dependantModuleName/$dependantModuleVersion started" $ModDependencyFound = $false #Search for module in the Solution if (-not $ModDependencyFound) { if (($ModuleValidationCache.Value).ContainsKey($dependantModuleName) -and ($ModuleValidationCache.Value[$dependantModuleName].ModuleInfo.Version -ge $dependantModuleVersion)) { $BuildPSModule_Params = @{ SourcePath=$ModuleValidationCache.Value[$dependantModuleName].ModuleInfo.ModuleBase DestinationPath=$DestinationPath ResolveDependancies=$ResolveDependancies ModuleValidationCache=$ModuleValidationCache } if ($PSBoundParameters.ContainsKey('PSGetRepository')) { $BuildPSModule_Params.Add('PSGetRepository',$PSGetRepository) } Build-PSModule @BuildPSModule_Params -ErrorAction Stop $ModDependencyFound = $true } } #Search for module in Solution PSGetRepositories if ((-not $ModDependencyFound) -and ($PsGetModuleValidationCache.Value.ContainsKey($dependantModuleName)) -and ($PSBoundParameters.ContainsKey('PSGetRepository'))) { $NuGetDependancyHandle = $PsGetModuleValidationCache.Value[$dependantModuleName] #Check if NugetPackage is already downloaded try { $ModDependencyExcepctedPath = Join-Path -Path $DestinationPath -ChildPath $dependantModuleName -ErrorAction Stop Remove-Variable -Name ModDependencyExist -ErrorAction SilentlyContinue $ModDependencyExist = Get-Module -ListAvailable -FullyQualifiedName $ModDependencyExcepctedPath -Refresh -ErrorAction Stop -Verbose:$false } catch { } if (($ModDependencyExist) -and ($ModDependencyExist.Version -eq $NuGetDependancyHandle.Version)) { #NugetPackage already downloaded } else { #Determine from which repo to download the module Remove-Variable -Name ModuleRepo -ErrorAction SilentlyContinue $ModuleRepo = $PSGetRepository | Where-Object {$_.Name -eq ($NuGetDependancyHandle.Repository)} #Downloading NugetPackage Write-Verbose "Build PSModule:$moduleName/$moduleVersion in progress. Build dependant module:$dependantModuleName/$dependantModuleVersion in progress. Downloading PSGetPackage: $($NuGetDependancyHandle.Name)/$($NuGetDependancyHandle.Version)" if (-not (Test-Path $DestinationPath)) { $null = New-Item -Path $DestinationPath -ItemType Directory -ErrorAction Stop } $PSGet_Params = @{ Name=$dependantModuleName Repository=$ModuleRepo.Name RequiredVersion=$NuGetDependancyHandle.Version Path=$DestinationPath } if ($ModuleRepo.ContainsKey('Credential')) { $PSGet_Params.Add('Credential',$ModuleRepo.Credential) } Save-Module @PSGet_Params -ErrorAction Stop -Verbose:$false } $ModDependencyFound = $true } #Throw Not Found if ($ModDependencyFound) { Write-Verbose "Build PSModule:$moduleName/$moduleVersion in progress. Build dependant module:$dependantModuleName/$dependantModuleVersion completed" } else { throw "Dependand module: $dependantModuleName/$dependantModuleVersion not found" } } } } catch { Write-Error "Build PSModule:$moduleName/$moduleVersion dependancies failed. Details: $_" } #Build Module try { #Update Module Dependancies definition if (-not $ModuleDependanciesValid) { Write-Warning "Build PSModule:$moduleName/$moduleVersion in progress. RequiredModules specification not valid, updating it..." $ModuleDependanciesDefinition = New-Object -TypeName system.collections.arraylist foreach ($DepModule in $ModuleValidationCache.Value[$moduleName].ModuleInfo.RequiredModules) { $depModuleName=$DepModule.Name $depModuleVersion=$DepModule.Version if (($ModuleValidationCache.Value).ContainsKey($depModuleName)) { $ModSpec = [Microsoft.PowerShell.Commands.ModuleSpecification]::new(@{ ModuleName = $ModuleValidationCache.Value[$depModuleName].ModuleInfo.Name ModuleVersion = $ModuleValidationCache.Value[$depModuleName].ModuleInfo.Version }) $null = $ModuleDependanciesDefinition.Add($ModSpec) } elseif ($PsGetModuleValidationCache.Value.ContainsKey($depModuleName)) { $ModSpec = [Microsoft.PowerShell.Commands.ModuleSpecification]::new(@{ ModuleName = $PsGetModuleValidationCache.Value[$depModuleName].Name ModuleVersion = $PsGetModuleValidationCache.Value[$depModuleName].Version }) $null = $ModuleDependanciesDefinition.Add($ModSpec) } else { if (Test-Path $DepModule.Path) { $tempDepModuleName = $DepModule.Path } else { $tempDepModuleName = $DepModule.Name } $ModSpec = [Microsoft.PowerShell.Commands.ModuleSpecification]::new(@{ ModuleName = $tempDepModuleName ModuleVersion = $DepModule.Version }) $null = $ModuleDependanciesDefinition.Add($ModSpec) } } if ($ModuleDependanciesDefinition.Count -gt 0) { Update-ModuleManifest -Path $ModuleValidationCache.Value[$moduleName].ModuleInfo.Path -RequiredModules $ModuleDependanciesDefinition -ErrorAction Stop } } #Check Module Dependancies if ($CheckCommandReferences.IsPresent) { #if Module is Excluded for CheckCommandReferences if ($PSBoundParameters.ContainsKey('CheckCommandReferencesConfiguration') -and ($CheckCommandReferencesConfiguration.ExcludedSources -contains $moduleName)) { Write-Warning "Build PSModule:$moduleName/$moduleVersion in progress. Skipping CommandReference validation" } #if Module is not Excluded for CheckCommandReferences else { #Analyze Command references $CurrentRequiredModules = $PSNativeModules + $ModuleValidationCache.Value[$moduleName].ModuleInfo.RequiredModules.Name $priv_AnalyseItemDependancies_Params = @{ ModulePath=$ModuleValidationCache.Value[$moduleName].ModuleInfo.ModuleBase GlobalCommandAnalysis=$CommandsToModuleMapping CurrentDependancies=$CurrentRequiredModules } if ($PSBoundParameters.ContainsKey('PSGetRepository')) { $priv_AnalyseItemDependancies_Params.Add('PSGetRepository',$PSGetRepository) } $LocalCommandAnalysis = priv_Analyse-ItemDependancies @priv_AnalyseItemDependancies_Params -ErrorAction Stop $CommandNotReferenced = $LocalCommandAnalysis | Where-Object {$_.IsReferenced -eq $false -and $_.CommandType -ne 'Application'} #Check if command is in CheckCommandReferencesConfiguration.ExcludedCommands list if ($PSBoundParameters.ContainsKey('CheckCommandReferencesConfiguration')) { $CommandNotReferenced = $CommandNotReferenced | Where-Object {$CheckCommandReferencesConfiguration.ExcludedCommands -notcontains $_.CommandName} } if ($CommandNotReferenced) { throw "Missing RequiredModule reference for [Module\Command]: $($CommandNotReferenced.GetCommandFQDN() -join ', ')" } } } #Check Module Integrity if (-not $ModuleValidationCache.Value[$moduleName].IsReadyForPackaging) { throw "Not ready for packaging. Missing either Author or Description." } if (-not $ModuleValidationCache.Value[$moduleName].IsValid) { Write-Warning "Build PSModule:$moduleName/$moduleVersion in progress. Not valid, updating version..." Update-PSModuleVersion -ModulePath $ModuleValidationCache.Value[$moduleName].ModuleInfo.ModuleBase -ErrorAction Stop #Refresh ModuleValidation $ModuleValidationCache.Value[$moduleName] = Test-PSModule -ModulePath $ModuleValidationCache.Value[$moduleName].ModuleInfo.ModuleBase -ErrorAction Stop } #Export Module to DestinationPath try { priv_Export-PSArtefact -Type Module -SourcePath $ModuleValidationCache.Value[$moduleName].ModuleInfo.ModuleBase -Version $ModuleValidationCache.Value[$moduleName].ModuleInfo.Version -DestinationPath $DestinationPath -Verbose:$false } catch { throw "failed to copy module to $DestinationPath. details: $_" } } catch { Write-Error "Build PSModule:$moduleName/$moduleVersion failed. Details: $_" -ErrorAction 'Stop' } } Write-Verbose "Build PSModule:$moduleName/$moduleVersion completed" } else { Write-Error "Build PSModule:$moduleName failed. Missing ModuleInfo." -ErrorAction Stop } } } } function Build-PSScript { [CmdletBinding()] [OutputType([void])] param ( #SourcePath [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_Default')] [System.IO.FileInfo[]]$SourcePath, #DestinationPath [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_Default')] [System.IO.DirectoryInfo]$DestinationPath, #DependencyDestinationPath [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [System.IO.DirectoryInfo]$DependencyDestinationPath, #ResolveDependancies [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [switch]$ResolveDependancies, #CheckCommandReferences [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [switch]$CheckCommandReferences, #CheckCommandReferencesConfiguration [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [psobject]$CheckCommandReferencesConfiguration, #UpdateModuleReferences [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [switch]$UpdateModuleReferences, #PSGetRepository [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [hashtable[]]$PSGetRepository, #ModuleValidation [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [ref]$ModuleValidationCache, #PsGetModuleValidation [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [ref]$PsGetModuleValidationCache ) Process { if (-not $PSBoundParameters.ContainsKey('DependencyDestinationPath')) { $DependencyDestinationPath = $DestinationPath } #Add DependencyDestinationPath to Process PSModulePath try { Add-PSModulePathEntry -Path $DependencyDestinationPath -Scope Process -Force } catch { Write-Error "Add DependencyDestinationPath to Process PSModulePath failed. Details: $_" -ErrorAction 'Stop' } #Assert PSRepositories if ($PSBoundParameters.ContainsKey('PSGetRepository')) { #Register PSGetRepo Assert-PSRepository -PSGetRepository $PSGetRepository -ErrorAction Stop } #Validate All Scripts try { if (-not ($AllScriptValidation)) { $AllScriptValidation = @{} foreach ($Script in $SourcePath) { $scriptName = $Script.BaseName if (-not $AllScriptValidation.ContainsKey($scriptName)) { $null = $AllScriptValidation.Add($scriptName,(Test-PSScript -ScriptPath $Script.FullName -ErrorAction Stop)) } } } } catch { Write-Error "Unable to validate $scriptName. Details: $_" -ErrorAction 'Stop' } #Validate All Commands try { [ref]$CommandsToModuleMapping = [PSBuildEntities.AnalysisResultCollection]::new() #Add BuildIn Comands and Aliases to CommandsToModuleMapping (from module 'Microsoft.PowerShell.Core' as they are buildin to PowerShell) Get-Command -Module $PSNativeModules -Verbose:$false | ForEach-Object { #Add Command $Command = [PSBuildEntities.AnalysisResult]::new() $Command.CommandName = "$($_.Name)" $Command.CommandType = $_.CommandType if ($Command.CommandType -eq 'Alias') { try { $TempFinding2 = Get-Command -Name $Command.CommandName -ErrorAction Stop -Verbose:$false $Command.CommandSource = $TempFinding2.Source } catch { } } else { $Command.CommandSource = $_.Source } $Command.SourceLocation = [PSBuildEntities.AnalysisResultSourceLocation]::BuildIn if(-not $CommandsToModuleMapping.Value.Contains($Command.CommandName)) { $CommandsToModuleMapping.Value.add($Command) } #Add Alias if exists Get-Alias -Definition $_.Name -ErrorAction SilentlyContinue | foreach { $Alias = [PSBuildEntities.AnalysisResult]::new() $Alias.CommandName = "$($_.Name)" $Alias.CommandType = 'Alias' $Alias.CommandSource = $Command.CommandSource $Alias.SourceLocation = [PSBuildEntities.AnalysisResultSourceLocation]::BuildIn if (-not $CommandsToModuleMapping.Value.Contains($Alias.CommandName)) { $CommandsToModuleMapping.Value.add($Alias) } } } #Add Solution Commands to CommandsToModuleMapping (from all modules in the solution) if ($PSBoundParameters.ContainsKey('ModuleValidationCache')) { foreach ($Mod in $ModuleValidationCache.Value.Keys) { foreach ($cmd in $ModuleValidationCache.Value[$Mod].ModuleInfo.ExportedCommands.Values) { $Command = [PSBuildEntities.AnalysisResult]::new() $Command.CommandName = $cmd.Name $Command.CommandType = $cmd.CommandType $Command.CommandSource = $cmd.Source $Command.SourceLocation = [PSBuildEntities.AnalysisResultSourceLocation]::Solution if (-not $CommandsToModuleMapping.Value.Contains($cmd.Name)) { $CommandsToModuleMapping.Value.Add($Command) } elseif ($CommandsToModuleMapping.Value[$Command.CommandName].CommandSource -ne $Command.CommandSource) { if ($CheckDuplicateCommandNames.IsPresent) { Write-Error "Command with name: $($Command.CommandName) is present in multiple modules: $($CommandsToModuleMapping.Value[$Command.CommandName].CommandSource),$($Command.CommandSource)" -ErrorAction Stop } } } } } } catch { Write-Error "Validate All Commands failed. Details: $_" -ErrorAction 'Stop' } #Initialize PSGetModuleValidationCache if (-not $PSBoundParameters.ContainsKey('PsGetModuleValidationCache')) { [ref]$PsGetModuleValidationCache = @{} } #Build Script foreach ($Script in $SourcePath) { $scriptName = $Script.BaseName if ($AllScriptValidation[$scriptName].ScriptInfo) { $scriptVersion = $AllScriptValidation[$scriptName].ScriptInfo.Version Write-Verbose "Build Script:$scriptName/$scriptVersion started" #Check if Script is already built try { $ScriptAlreadyBuild = $false $ScriptDependanciesValid = $true $ScriptVersionBuilded = $false $ScriptBuildDestinationPath = Join-Path -Path $DestinationPath -ChildPath $Script.Name -ErrorAction Stop if (Test-Path -Path $ScriptBuildDestinationPath) { $ScriptAlreadyBuildTest = Test-PSScript -ScriptPath $ScriptBuildDestinationPath -ErrorAction Stop } #Check if Script with the same version is already builded if ($AllScriptValidation[$scriptName].IsValid -and $ScriptAlreadyBuildTest.IsValid -and ($AllScriptValidation[$scriptName].ScriptInfo.Version -eq $ScriptAlreadyBuildTest.ScriptInfo.Version)) { $ScriptVersionBuilded = $true } #Check if Module Dependancies are valid versions foreach ($DepModule in $AllScriptValidation[$scriptName].ScriptInfo.RequiredModules) { $depModuleName=$DepModule.Name $depModuleVersion=$DepModule.Version $DepModuleDestinationPath = Join-Path -Path $DependencyDestinationPath -ChildPath $depModuleName -ErrorAction Stop #Check if DepModule is marked as ExternalModuleDependency if ($AllScriptValidation[$scriptName].ScriptInfo.ExternalModuleDependencies -contains $depModuleName) { #Skip this DepModule from validation, as it is marked as external } #Check if DepModule is in the same Solution elseif (($ModuleValidationCache.Value).ContainsKey($depModuleName)) { if ($ModuleValidationCache.Value[$depModuleName].ModuleInfo.Version -gt $depModuleVersion -or (-not $ModuleValidationCache.Value[$depModuleName].IsValid)) { $ScriptDependanciesValid = $false } } #Check if DepModule is in PSGetRepositories elseif ($PSBoundParameters.ContainsKey('PSGetRepository')) { #Check for Module in all Nuget Repos Remove-Variable -Name NugetDependencyList -ErrorAction SilentlyContinue $NugetDependencyList = New-Object -TypeName System.Collections.ArrayList foreach ($item in $PSGetRepository) { #Search for module if (-not $PsGetModuleValidationCache.Value.ContainsKey($depModuleName)) { $PSGet_Params = @{ Name=$depModuleName Repository=$item.Name } if (-not $UpdateModuleReferences.IsPresent) { $PSGet_Params.Add('RequiredVersion',$depModuleVersion) } if ($item.ContainsKey('Credential')) { $PSGet_Params.Add('Credential',$item.Credential) } try { Remove-Variable -Name NugetDependency -ErrorAction SilentlyContinue $private:NugetDependency = Find-Module @PSGet_Params -ErrorAction Stop } catch { } #Add module to PsGetModuleValidationCache if ($private:NugetDependency) { $AddMember_Params = @{ InputObject=$private:NugetDependency MemberType='NoteProperty' Name='PSGetRepoPriority' } if ($item.Priority) { $AddMember_Params.Add('Value',$item.Priority) } else { $AddMember_Params.Add('Value',0) } $null = Add-Member @AddMember_Params -ErrorAction Stop $null = $NugetDependencyList.Add($private:NugetDependency) } } } #Get Latest Version if multiple are present if ($NugetDependencyList) { Remove-Variable -Name NugetDepToADD -ErrorAction SilentlyContinue $NugetDepToADD = $NugetDependencyList | Sort-Object -Property Version -Descending | Sort-Object -Property PSGetRepoPriority | select -First 1 $null = $PsGetModuleValidationCache.Value.Add($depModuleName,$NugetDepToADD) } #Check if DepModule ref version is the latest if ($PsGetModuleValidationCache.Value.ContainsKey($depModuleName) -and ($PsGetModuleValidationCache.Value[$depModuleName].Version -gt $depModuleVersion)) { Write-Warning "Build Script:$scriptName/$scriptVersion in progress. PsGet Dependancy: $depModuleName/$depModuleVersion is not the latest version" if ($UpdateModuleReferences.IsPresent) { $ScriptDependanciesValid=$false } } } #Check If Module Dependency is already builded elseif (Test-Path -Path $DepModuleDestinationPath) { try { $Mod = Test-PSModule -ModulePath $DepModuleDestinationPath -ErrorAction Stop if ($Mod.ModuleInfo.Version -lt $depModuleVersion) { $ScriptDependanciesValid = $false } } catch { } } else { $ScriptDependanciesValid = $false } } #Determine if script should be built if ($ScriptVersionBuilded -and $ScriptDependanciesValid) { $ScriptAlreadyBuild = $true } } catch { } #Build Script if not already built if ($ScriptAlreadyBuild) { Write-Verbose "Build Script:$scriptName/$scriptVersion skipped, already built" } else { #Build Script Dependancies try { #Resolve Dependancies if ($ResolveDependancies.IsPresent) { $Dependancies = $AllScriptValidation[$scriptName].ScriptInfo.RequiredModules | Where-Object {$AllScriptValidation[$scriptName].ScriptInfo.ExternalModuleDependencies -notcontains $_.Name} foreach ($ModDependency in $Dependancies) { $dependantModuleName = $ModDependency.Name $dependantModuleVersion = $ModDependency.Version Write-Verbose "Build Script:$scriptName/$scriptVersion in progress. Build dependant module:$dependantModuleName/$dependantModuleVersion started" $ModDependencyFound = $false #Search for module in the Solution if ((-not $ModDependencyFound) -and ($ModuleValidationCache.Value).ContainsKey($dependantModuleName)) { Build-PSModule -SourcePath $ModuleValidationCache.Value[$dependantModuleName].ModuleInfo.ModuleBase -DestinationPath $DependencyDestinationPath -ResolveDependancies:$ResolveDependancies.IsPresent -ErrorAction Stop -ModuleValidationCache $ModuleValidationCache $ModDependencyFound = $true } #Search for module in Solution PSGetRepositories if ((-not $ModDependencyFound) -and ($PsGetModuleValidationCache.Value.ContainsKey($dependantModuleName)) -and ($PSBoundParameters.ContainsKey('PSGetRepository'))) { $NuGetDependancyHandle = $PsGetModuleValidationCache.Value[$dependantModuleName] #Check if NugetPackage is already downloaded try { $ModDependencyExcepctedPath = Join-Path -Path $DestinationPath -ChildPath $dependantModuleName -ErrorAction Stop Remove-Variable -Name ModDependencyExist -ErrorAction SilentlyContinue $ModDependencyExist = Get-Module -ListAvailable -FullyQualifiedName $ModDependencyExcepctedPath -Refresh -ErrorAction Stop -Verbose:$false } catch { } if (($ModDependencyExist) -and ($ModDependencyExist.Version -eq $NuGetDependancyHandle.Version)) { #NugetPackage already downloaded } else { #Determine from which repo to download the module Remove-Variable -Name ModuleRepo -ErrorAction SilentlyContinue $ModuleRepo = $PSGetRepository | Where-Object {$_.Name -eq ($NuGetDependancyHandle.Repository)} #Downloading NugetPackage Write-Verbose "Build Script:$scriptName/$scriptVersion in progress. Build dependant module:$dependantModuleName/$dependantModuleVersion in progress. Downloading PSGetPackage: $($NuGetDependancyHandle.Name)/$($NuGetDependancyHandle.Version)" if (-not (Test-Path $DestinationPath)) { $null = New-Item -Path $DestinationPath -ItemType Directory -ErrorAction Stop } $PSGet_Params = @{ Name=$dependantModuleName Repository=$ModuleRepo.Name RequiredVersion=$NuGetDependancyHandle.Version Path=$DestinationPath } if ($ModuleRepo.ContainsKey('Credential')) { $PSGet_Params.Add('Credential',$ModuleRepo.Credential) } Save-Module @PSGet_Params -ErrorAction Stop -Verbose:$false } $ModDependencyFound = $true } #Throw Not Found if ($ModDependencyFound) { Write-Verbose "Build Script:$scriptName/$scriptVersion in progress. Build dependant module:$dependantModuleName/$dependantModuleVersion completed" } else { throw "Dependand PSModule: $dependantModuleName/$dependantModuleVersion not found" } } } } catch { Write-Error "Build PSModule:$moduleName/$moduleVersion dependancies failed. Details: $_" } #Build Script try { #Update Script Dependancies definition if (-not $ScriptDependanciesValid) { Write-Warning "Build Script:$scriptName/$scriptVersion in progress. RequiredModules specification not valid, updating it..." $ScriptDependanciesDefinition = New-Object -TypeName system.collections.arraylist foreach ($DepModule in $AllScriptValidation[$scriptName].ScriptInfo.RequiredModules) { $depModuleName=$DepModule.Name $depModuleVersion=$DepModule.Version if (($ModuleValidationCache.Value).ContainsKey($depModuleName)) { $ModSpec = [Microsoft.PowerShell.Commands.ModuleSpecification]::new(@{ ModuleName = $ModuleValidationCache.Value[$depModuleName].ModuleInfo.Name ModuleVersion = $ModuleValidationCache.Value[$depModuleName].ModuleInfo.Version }) $null = $ScriptDependanciesDefinition.Add($ModSpec) } elseif ($PsGetModuleValidationCache.Value.ContainsKey($depModuleName)) { $ModSpec = [Microsoft.PowerShell.Commands.ModuleSpecification]::new(@{ ModuleName = $PsGetModuleValidationCache.Value[$depModuleName].Name ModuleVersion = $PsGetModuleValidationCache.Value[$depModuleName].Version }) $null = $ScriptDependanciesDefinition.Add($ModSpec) } else { $ModSpec = [Microsoft.PowerShell.Commands.ModuleSpecification]::new(@{ ModuleName = $DepModule.Name ModuleVersion = $DepModule.Version }) $null = $ScriptDependanciesDefinition.Add($ModSpec) } } if ($ScriptDependanciesDefinition.Count -gt 0) { Update-ScriptFileInfo -Path $AllScriptValidation[$scriptName].ScriptInfo.Path -RequiredModules $ScriptDependanciesDefinition -ErrorAction Stop } } #Check Script Dependancies if ($CheckCommandReferences.IsPresent) { #if Script is Excluded for CheckCommandReferences if ($PSBoundParameters.ContainsKey('CheckCommandReferencesConfiguration') -and ($CheckCommandReferencesConfiguration.ExcludedSources -contains $moduleName)) { Write-Warning "Build Script:$scriptName/$scriptVersion in progress. Skipping CommandReference validation" } #if Module is not Excluded for CheckCommandReferences else { #Analyze Command references $CurrentRequiredModules = $PSNativeModules + $AllScriptValidation[$scriptName].ScriptInfo.RequiredModules.Name $priv_AnalyseItemDependancies_Params = @{ ScriptPath=$AllScriptValidation[$scriptName].ScriptInfo.Path GlobalCommandAnalysis=$CommandsToModuleMapping CurrentDependancies=$CurrentRequiredModules } if ($PSBoundParameters.ContainsKey('PSGetRepository')) { $priv_AnalyseItemDependancies_Params.Add('PSGetRepository',$PSGetRepository) } $LocalCommandAnalysis = priv_Analyse-ItemDependancies @priv_AnalyseItemDependancies_Params -ErrorAction Stop $CommandNotReferenced = $LocalCommandAnalysis | Where-Object {($_.IsReferenced -eq $false) -and ($_.CommandType -ne 'Application')} #Check if command is in CheckCommandReferencesConfiguration.ExcludedCommands list if ($PSBoundParameters.ContainsKey('CheckCommandReferencesConfiguration')) { $CommandNotReferenced = $CommandNotReferenced | Where-Object {$CheckCommandReferencesConfiguration.ExcludedCommands -notcontains $_.CommandName} } if ($CommandNotReferenced) { throw "Missing RequiredModule reference for [Module\Command]: $($CommandNotReferenced.GetCommandFQDN() -join ', ')" } } } #Check Script Integrity if (-not $AllScriptValidation[$scriptName].IsValid) { Write-Warning "Build Script:$scriptName/$scriptVersion in progress. Not valid, updating version..." Update-PSScriptVersion -ScriptPath $AllScriptValidation[$scriptName].ScriptInfo.Path -ErrorAction Stop #Refresh ScriptValidation $AllScriptValidation[$scriptName] = Test-PSScript -ScriptPath $AllScriptValidation[$scriptName].ScriptInfo.Path -ErrorAction Stop } elseif (-not $AllScriptValidation[$scriptName].IsReadyForPackaging) { throw "Not ready for packaging. Missing either Author or Description." } #Export Script to DestinationPath try { priv_Export-PSArtefact -Type Script -SourcePath $AllScriptValidation[$scriptName].ScriptInfo.Path -DestinationPath $DestinationPath -Verbose:$false } catch { throw "Unable to copy script to $DestinationPath. Details: $_" } } catch { Write-Error "Build Script:$scriptName/$scriptVersion failed. Details: $_" -ErrorAction 'Stop' } } Write-Verbose "Build Script:$scriptName/$scriptVersion completed" } else { $ErrorMsg = "Build Script:$scriptName failed." if ($AllScriptValidation[$scriptName].ValidationErrors) { $ErrorDetails = $AllScriptValidation[$scriptName].ValidationErrors -join "$([System.Environment]::NewLine) $([System.Environment]::NewLine)" $ErrorMsg += @" Script Parse Errors: $ErrorDetails "@ } else { $ErrorMsg += 'Missing ScriptInfo.' } Write-Error $ErrorMsg -ErrorAction Stop } } } } function Publish-PSModule { [CmdletBinding()] param ( #ModulesFolder [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_Default')] [System.IO.DirectoryInfo[]]$ModulePath, #PSGetRepository [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [hashtable]$PSGetRepository, #SkipVersionValidation [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [switch]$SkipVersionValidation ) Process { #Check if Repository is already registered try { Write-Verbose "Check if Repository is already registered started" Assert-PSRepository -PSGetRepository $PSGetRepository -ErrorAction Stop Write-Verbose "Check if Repository is already registered completed" } catch { Write-Error "Check if Repository is already registered failed. Details: $_" -ErrorAction 'Stop' } #Publish Module foreach ($Module in $ModulePath) { try { $moduleName = $Module.Name Write-Verbose "Publish Module:$moduleName started" #Check if Module is already built $ModInfo = Test-PSModule -ModulePath $Module -ErrorAction Stop if (-not $ModInfo.IsVersionValid -and (-not $SkipVersionValidation.IsPresent)) { throw 'not builded' } #Publish Module $PublishModuleAndDependacies_Params = @{ ModuleInfo=$ModInfo.ModuleInfo Repository=$PSGetRepository.Name PublishDependantModules=$true Force=$true } if ($PSGetRepository.ContainsKey('Credential')) { $PublishModuleAndDependacies_Params.Add('Credential',$PSGetRepository.Credential) } if ($PSGetRepository.ContainsKey('NuGetApiKey')) { $PublishModuleAndDependacies_Params.Add('NuGetApiKey',$PSGetRepository.NuGetApiKey) } priv_Publish-PSModule @PublishModuleAndDependacies_Params -ErrorAction Stop -Verbose -VerbosePrefix "Publish Module:$moduleName in progress. " Write-Verbose "Publish Module:$moduleName completed" } catch { Write-Error "Publish Module:$moduleName failed. Details: $_" -ErrorAction Stop } } } } function Build-PSSolution { [CmdletBinding()] [OutputType([void])] param ( #SolutionConfigPath [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_SolutionByPath')] [System.IO.DirectoryInfo]$SolutionConfigPath, #SolutionConfig [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_SolutionByObject')] [psobject]$SolutionConfigObject ) Process { #Initialize SolutionConfiguration try { Write-Verbose "Initialize SolutionConfiguration started" switch ($PSCmdlet.ParameterSetName) { 'NoRemoting_SolutionByPath' { $SolutionConfig = Get-PSSolutionConfiguration -Path $SolutionConfigPath.FullName -ErrorAction Stop break } 'NoRemoting_SolutionByObject' { $SolutionConfig = $SolutionConfigObject break } default { throw "Unknown ParameterSetName: $($PSCmdlet.ParameterSetName)" } } Write-Verbose "Initialize SolutionConfiguration completed" } catch { Write-Error "Initialize SolutionConfiguration failed. Details: $_" -ErrorAction 'Stop' } #Configure PS Environment try { Write-Verbose "Configure PS Environment started" if ($SolutionConfig.SolutionStructure.ModulesPath.BuildPath) { $TempModulePaths = $SolutionConfig.SolutionStructure.ModulesPath.BuildPath if ($SolutionConfig.Build.AutoloadbuiltModulesForUser) { Write-Verbose "Configure PS Environment in progress. Enable BuildPath($($TempModulePaths -join ',')) Module Autoloading" Add-PSModulePathEntry -Path $TempModulePaths -Scope User,Process -ErrorAction Stop -Force } else { Write-Verbose "Configure PS Environment in progress. Disable BuildPath($($TempModulePaths -join ',')) Module Autoloading" Remove-PSModulePathEntry -Path $TempModulePaths -Scope User,Process -ErrorAction Stop -WarningAction SilentlyContinue } } Write-Verbose "Configure PS Environment completed" } catch { Write-Error "Configure PS Environment failed. Details: $_" -ErrorAction 'Stop' } #Build Solution Modules try { [ref]$ModuleValidationCache = @{} [ref]$PsGetModuleValidationCache = @{} if ($SolutionConfig.SolutionStructure.ModulesPath) { Write-Verbose "Build PSModules started" #Validate All Modules $AllModulesPath = New-Object System.Collections.ArrayList -ErrorAction Stop foreach ($ModulePath in $SolutionConfig.SolutionStructure.ModulesPath) { $null = $AllModulesPath.AddRange((Get-ChildItem -Path $ModulePath.SourcePath -Directory -ErrorAction Stop)) } priv_Validate-Module -SourcePath $AllModulesPath -ModuleValidationCache $ModuleValidationCache foreach ($ModulePath in $SolutionConfig.SolutionStructure.ModulesPath) { $Modules = Get-ChildItem -Path $ModulePath.SourcePath -Directory -ErrorAction Stop $BuildPSSolutionModule_Params = @{ SourcePath=$Modules DestinationPath=$ModulePath.BuildPath ResolveDependancies=$SolutionConfig.Build.AutoResolveDependantModules PSGetRepository=$SolutionConfig.Packaging.PSGetSearchRepositories CheckCommandReferences=$SolutionConfig.Build.CheckCommandReferences.Enabled CheckCommandReferencesConfiguration=$SolutionConfig.Build.CheckCommandReferences ModuleValidationCache=$ModuleValidationCache UpdateModuleReferences=$SolutionConfig.Build.UpdateModuleReferences PsGetModuleValidationCache=$PsGetModuleValidationCache } Build-PSModule @BuildPSSolutionModule_Params -ErrorAction Stop } Write-Verbose "Build PSModules completed" } else { Write-Verbose "Build PSModules skipped" } } catch { Write-Error "Build Solution Modules failed. Details: $_" -ErrorAction 'Stop' } #Build Solution Scripts try { Write-Verbose "Build Solution Scripts started" foreach ($ScriptPath in $SolutionConfig.SolutionStructure.ScriptPath) { $Scripts = Get-ChildItem -Path $ScriptPath.SourcePath -Filter *.ps1 -ErrorAction Stop $BuildPSScript_Params = @{ SourcePath=$Scripts DestinationPath=$ScriptPath.BuildPath ResolveDependancies=$SolutionConfig.Build.AutoResolveDependantModules PSGetRepository=$SolutionConfig.Packaging.PSGetSearchRepositories CheckCommandReferences=$SolutionConfig.Build.CheckCommandReferences.Enabled CheckCommandReferencesConfiguration=$SolutionConfig.Build.CheckCommandReferences ModuleValidationCache=$ModuleValidationCache UpdateModuleReferences=$SolutionConfig.Build.UpdateModuleReferences PsGetModuleValidationCache=$PsGetModuleValidationCache } if ($ScriptPath.ContainsKey('DependencyDestinationPath')) { $BuildPSScript_Params.Add('DependencyDestinationPath',$ScriptPath.DependencyDestinationPath) } Build-PSScript @BuildPSScript_Params -ErrorAction Stop } Write-Verbose "Build Solution Scripts completed" } catch { Write-Error "Build Solution Scripts failed. Details: $_" -ErrorAction 'Stop' } #Run PostBuild Actions try { Write-Verbose "Run PostBuild Actions started" Foreach ($Action in $SolutionConfig.BuildActions.PostBuild) { try { Write-Verbose "Run PostBuild Actions in progress. Action: $($Action['Name']) starting." $Null = Invoke-Command -ScriptBlock $Action['ScriptBlock'] -ErrorAction Stop -NoNewScope Write-Verbose "Run PostBuild Actions in progress. Action: $($Action['Name']) completed." } catch { Write-Warning "Run PostBuild Actions in progress. Action: $($Action['Name']) failed." throw $_ } } Write-Verbose "Run PostBuild Actions completed" } catch { Write-Error "Run PostBuild Actions failed. Details: $_" -ErrorAction 'Stop' } } } function Publish-PSSolution { [CmdletBinding()] [OutputType([void])] param ( #SolutionConfigPath [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_SolutionByPath')] [System.IO.DirectoryInfo]$SolutionConfigPath, #SolutionConfig [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_SolutionByObject')] [psobject]$SolutionConfigObject ) Process { #Initialize SolutionConfiguration try { Write-Verbose "Initialize SolutionConfiguration started" switch ($PSCmdlet.ParameterSetName) { 'NoRemoting_SolutionByPath' { $SolutionConfig = Get-PSSolutionConfiguration -Path $SolutionConfigPath.FullName -ErrorAction Stop break } 'NoRemoting_SolutionByObject' { $SolutionConfig = $SolutionConfigObject break } default { throw "Unknown ParameterSetName: $($PSCmdlet.ParameterSetName)" } } Write-Verbose "Initialize SolutionConfiguration completed" } catch { Write-Error "Initialize SolutionConfiguration failed. Details: $_" -ErrorAction 'Stop' } #Publish Solution Modules try { Write-Verbose "Publish Solution Modules started" #Get All Modules $Modules = New-Object -TypeName system.collections.arraylist foreach ($modPath in $SolutionConfig.SolutionStructure.ModulesPath) { Get-ChildItem -Path $modPath.SourcePath -Directory -ErrorAction Stop | ForEach-Object { $ModuleToPathMapping = @{ Module=$_ SourcePath=Join-Path -Path $modPath.SourcePath -ChildPath $_.Name BuildPath=Join-Path -Path $modPath.BuildPath -ChildPath $_.Name } $null = $Modules.Add($ModuleToPathMapping) } } #Determine which modules should be published if ((-not $SolutionConfig.Packaging.PublishAllModules) -and ($SolutionConfig.Packaging.PublishSpecificModules.Count -gt 0)) { $Modules = $Modules | Where-Object {$SolutionConfig.Packaging.PublishSpecificModules -contains $_.Module.Name} } elseif ($SolutionConfig.Packaging.PublishAllModules -and ($SolutionConfig.Packaging.PublishSpecificModules.Count -gt 0)) { Write-Warning "Publish Solution Modules in progress. No Modules are configured to be published" } if ($SolutionConfig.Packaging.PublishExcludeModules.Count -gt 0) { $Modules = $Modules | Where-Object {$SolutionConfig.Packaging.PublishExcludeModules -ne $_.Module.Name} } #Determine if there are PSGetRepositories specified for publishing if ($Modules) { if ($SolutionConfig.Packaging.PSGetPublishRepositories.Count -eq 0) { Write-Warning "Publish Solution Modules in progress. There are modules for publishing, but no PSGetPublishRepositories are specified" } } else { Write-Warning "Publish Solution Modules in progress. No Modules for publishing" } #Install Nuget PackageProvider try { $NuGetProvider = Get-PackageProvider -Name nuget -ErrorAction Stop | Where-Object {[version]$_.Version -ge [version]'2.8.5.208'} } catch { } if (-not $NuGetProvider) { $null = Install-PackageProvider -Name Nuget -Force -Confirm:$false -Verbose:$false -Scope CurrentUser } #Publish Modules to each PSGetPublishRepositories foreach ($Repo in $SolutionConfig.Packaging.PSGetPublishRepositories) { Add-PSModulePathEntry -Scope Process -Path $Modules.BuildPath -ErrorAction Stop Publish-PSModule -ModulePath $Modules.BuildPath -PSGetRepository $Repo -ErrorAction Stop } Write-Verbose "Publish Solution Modules completed" } catch { Write-Error "Publish Solution Modules failed. Details: $_" -ErrorAction 'Stop' } } } function New-PSSolutionConfiguration { [CmdletBinding()] [OutputType([void])] param ( #Path [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_Default')] [System.IO.FileInfo]$Path, #Force [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [switch]$Force ) Process { $ConfigExist = Test-Path $Path.FullName if (-not $ConfigExist -or $Force.IsPresent) { $SolutionConfigurationAsString = @' $UserVariables = @{ } $SolutionStructure=@{ #Example: @(@{SourcePath='c:\modules'},@{BuildPath='c:\modules bin'}) ModulesPath=@() ScriptPath=@() } $Build=@{ AutoloadbuiltModulesForUser=$true AutoResolveDependantModules=$true CheckCommandReferences=@{ Enabled=$true ExcludedSources=@() ExcludedCommands=@() } CheckDuplicateCommandNames=$true UpdateModuleReferences=$true } $Packaging=@{ #Example: @{Name='';SourceLocation='';PublishLocation='';Credential='';Priority=''} PSGetSearchRepositories=@() PSGetPublishRepositories=@() #List of Modules that should be published to PSGet Repository PublishAllModules=$true PublishSpecificModules=@() PublishExcludeModules=@() } $BuildActions=@{ #Example: @(@{Name='Step1';ScriptBlock={Start-Something}}) PostBuild=@() } '@ Out-File -FilePath $Path.FullName -InputObject $SolutionConfigurationAsString -Force:$Force.IsPresent -Append:$false -ErrorAction Stop } else { Write-Error "File already exist: $($Path.FullName)" -ErrorAction Stop } } } function Get-PSSolutionConfiguration { [CmdletBinding()] [OutputType([void])] param ( #Path [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_Default')] [System.IO.FileInfo]$Path, #UserVariables [Parameter(Mandatory=$false,ParameterSetName='NoRemoting_Default')] [hashtable]$UserVariables ) Process { try { $SolutionConfigRaw = Get-Content -Path $Path.FullName -Raw -ErrorAction Stop $SolutionRootFolder = Split-Path -Path $Path -Parent -ErrorAction Stop if ($PSBoundParameters.ContainsKey('UserVariables')) { Set-Variable -Name UserVariables -Value $UserVariables -Scope global -ErrorAction Stop } $r = "`$env:ScriptRoot = '$SolutionRootFolder'" + "`n" + $SolutionConfigRaw New-DynamicConfiguration -Definition ([scriptblock]::Create($r)) -ErrorAction Stop } catch { Write-Error "Unable to load SolutionConfiguration: $($Path.FullName). Details: $_" } } } function Clear-PSSolution { [CmdletBinding()] [OutputType([void])] param ( #SolutionConfigPath [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_SolutionByPath')] [System.IO.DirectoryInfo]$SolutionConfigPath, #SolutionConfig [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_SolutionByObject')] [psobject]$SolutionConfigObject ) Process { #Initialize SolutionConfiguration try { Write-Verbose "Initialize SolutionConfiguration started" switch ($PSCmdlet.ParameterSetName) { 'NoRemoting_SolutionByPath' { $SolutionConfig = Get-PSSolutionConfiguration -Path $SolutionConfigPath.FullName -ErrorAction Stop break } 'NoRemoting_SolutionByObject' { $SolutionConfig = $SolutionConfigObject break } default { throw "Unknown ParameterSetName: $($PSCmdlet.ParameterSetName)" } } Write-Verbose "Initialize SolutionConfiguration completed" } catch { Write-Error "Initialize SolutionConfiguration failed. Details: $_" -ErrorAction 'Stop' } #Clear Modules try { Write-Verbose "Clear Modules started" foreach ($Entry in $SolutionConfig.SolutionStructure.ModulesPath) { if ($Entry.BuildPath -and (Test-Path -Path $Entry.BuildPath)) { Write-Verbose "Clear Modules in proress. Deleting PSModuleBuildPath: $($Entry.BuildPath)" Remove-Item -Path $Entry.BuildPath -Force -Recurse -ErrorAction Stop } } Write-Verbose "Clear Modules completed" } catch { Write-Error "Clear Modules failed. Details: $_" -ErrorAction 'Stop' } #Clear Scripts try { Write-Verbose "Clear Scripts started" foreach ($Entry in $SolutionConfig.SolutionStructure.ScriptPath) { if ($Entry.BuildPath -and (Test-Path -Path $Entry.BuildPath)) { Write-Verbose "Clear Scripts in proress. Deleting PSScriptBuildPath: $($Entry.BuildPath)" Remove-Item -Path $Entry.BuildPath -Force -Recurse -ErrorAction Stop } if ($Entry.DependencyDestinationPath -and (Test-Path -Path $Entry.DependencyDestinationPath)) { Write-Verbose "Clear Scripts in proress. Deleting PSScriptDependencyDestinationPath: $($Entry.DependencyDestinationPath)" Remove-Item -Path $Entry.DependencyDestinationPath -Force -Recurse -ErrorAction Stop } } Write-Verbose "Clear Scripts completed" } catch { Write-Error "Clear Scripts failed. Details: $_" -ErrorAction 'Stop' } } } function Assert-PSRepository { [CmdletBinding()] [OutputType([void])] param ( #PSGetRepository [Parameter(Mandatory=$true,ParameterSetName='NoRemoting_Default')] [hashtable[]]$PSGetRepository ) Process { foreach ($Repo in $PSGetRepository) { #Check if Repository is already registered $RepoFound = $false try { $RepoCheck = Get-PSRepository -Name $Repo.Name -ErrorAction Stop if ($RepoCheck) { if ($Repo.ContainsKey('SourceLocation') -and ($RepoCheck.SourceLocation -ne $Repo.SourceLocation)) { Set-PSRepository -Name $Repo.Name -SourceLocation $Repo.SourceLocation } if ($Repo.ContainsKey('PublishLocation') -and ($RepoCheck.PublishLocation -ne $Repo.PublishLocation)) { Set-PSRepository -Name $Repo.Name -PublishLocation $Repo.PublishLocation } $RepoFound = $true } } catch { } if (-not $RepoFound) { $null = Register-PSRepository @item -ErrorAction Stop } } } } #endregion #region private Variables $PSNativeModules = @( 'Microsoft.PowerShell.Management' 'Microsoft.PowerShell.Core' 'Microsoft.PowerShell.Utility' 'Microsoft.PowerShell.Security' 'Microsoft.PowerShell.Archive' ) #endregion |