ContainerProvider.psm1
### ### SOURCES ### $script:location_modules = "$env:LOCALAPPDATA\containerprovider" $script:file_modules = "$script:location_modules\sources.txt" $script:ContainerSources = $null # Wildcard pattern matching configuration. $script:wildcardOptions = [System.Management.Automation.WildcardOptions]::CultureInvariant -bor ` [System.Management.Automation.WildcardOptions]::IgnoreCase ### ### SEARCH VARS for LIMITED RELEASE SEARCH ### $script:QueryKey = 'QueryKey' $script:IndexName = 'IndexName' ### ### VARS for LOCAL SEARCH ### $script:secondaryPath = 'SecondaryLocation' $apiVersionQP = 'api-version=2015-02-28' $script:location = 'Location' [System.Version] $minVersion = '0.0.0.0' #$script:RegisteredPackageSourcesFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:LocalPath -ChildPath "ContainerProvider.ps1xml" #region Functions ### ### SUMMARY: Finds the container image from the Azure Search Service ### PARAMS: ### 1. Name: Optional param: Name of the image ### 2. Version: Optional param : Version of the image ### function Find-ContainerImage { <# .SYNOPSIS Finds the container image from an online gallery that match specified criteria. .SYNTAX Find-ContainerImage [[-Name] <String>] [[-Version] <Version>] [-SearchKey [String]] .DESCRIPTION Find-ContainerImage finds the images from the online gallery that match specified criteria. For each module found, Find-ContainerImage returns a If the Version is not specified, all versions of the image are returned If the Version parameter is specified, Find-ContainerImage only returns the version of the image that exactly matches the specified version .EXAMPLE Find-ContainerImage -Name ImageName .EXAMPLE Find-ContainerImage -Version 1.2.3.5 .EXAMPLE Find-ContainerImage -Name ImageName -Version 1.2.3.4 #> [cmdletbinding()] # Handle the input parameters param ( [parameter(Mandatory=$false)] [System.String]$Name, [parameter(Mandatory=$false)] [System.Version]$Version, [parameter(Mandatory=$false)] [System.String]$Source ) $result_Search = Find $Name $Version $Source # Handle empty search result if(!$result_Search) { Write-Error "No such module found." return } return $result_Search } ### ### SUMMARY: Downloads and saves the container image ### PARAMS: ### 1. Name: Mandatory param: Name of the image ### 2. Version: Optional param: Version of the image ### 3. Destination: Mandatory param: Destiation where the file needs to be saved ### 4. SearchKey: Searches using this search key ### ### This function will first find the image based on given params ### If version is provided, save that particular version ### Else save the latest version ### function Save-ContainerImage { <# .SYNOPSIS Saves a container image without installing it. .SYNTAX Save-ContainerImage [[-Name] <String>] [[-Destination] <String>] [[-Version] <Version>] .DESCRIPTION The Save-ContainerImage cmdlet lets you save a container image locally without installing it. This lets you inspect the container image before you install, helping to minimize the risks of malicious code or malware on your system As a best practice, when you have finished evaluating a container image for potential risks, and before you install the image for use, dleete the image from the path to which you have saved. .EXAMPLE Save-ContainerImage -Name ImageName -Destination C:\temp\ImageName.wim .EXAMPLE Save-ContainerImage -Name ImageName -Version 1.2.3.5 -Destination C:\temp\ImageName.wim #> [cmdletbinding()] # Handle the input parameters param ( [parameter(Mandatory=$true)] [System.String]$Name, [parameter(Mandatory=$false)] [System.String]$Version = $minVersion, [parameter(Mandatory=$false)] [System.String]$Source, [parameter(Mandatory=$true)] [System.String]$Destination ) if(-not (CheckDestination $Destination)) { return } $result_Search = Find $Name $Version $Source # Handle empty search result if(!$result_Search) { throw [System.IO.FileNotFoundException] "No such module found." } [System.Version] $maxVersion = '0.0.0.0' $maxToken, $maxName if($Version -ne $minVersion) { # If version is provided, download that specific version $image = $result_Search[0] $maxName = $image.name $maxToken = $image.sastoken $maxVersion = $image.version } else { # Else download the latest version ForEach($image in $result_Search) { if($image.version -gt $maxVersion) { $maxName = $image.name $maxToken = $image.sastoken $maxVersion = $image.version } } } Write-Verbose "Downloading $maxName. Version: $maxVersion" Save-File $maxToken $Destination } ### ### SUMMARY: Installs the container image ### PARAMS ### ### 1. Name: Mandatory param: Name of the image ### 2. Version: Optional param: Version of the image ### 3. Destination: Mandatory param: Destiation where the file needs to be saved ### 4. SearchKey: Searches using this search key ### ### This function will first find the image based on given params ### If it finds the image, it will be downloaded ### Then it will be installed ### function Install-ContainerImage { <# .SYNOPSIS Downloads the image from the cloud and installs them on the local computer .SYNTAX Install-ContainerImage [[-Name] <String>] [[-Destination] <String>] [[-Version] <Version>] [-SearchKey [String]] .DESCRIPTION The Install-ContainerImage gets the container image that meets the specified cirteria from the cloud. It saves the image locally and then installs it .EXAMPLE Install-ContainerImage -Name ImageName .EXAMPLE Install-ContainerImage -Name ImageName -Version 1.2.3.5 #> [cmdletbinding()] # Handle the input parameters param ( [parameter(Mandatory=$true)] [System.String]$Name, [parameter(Mandatory=$false)] [System.String]$Version = $minVersion, [parameter(Mandatory=$false)] [System.String]$Source ) $Destination = $env:TEMP + "\" + $Name + ".wim" Write-Verbose "Saving to $Destination" try { Save-ContainerImage -Name $Name ` -Version $Version ` -Destination $Destination } catch { Write-Error "Unable to download." if((Test-Path $Destination)) { Write-Verbose "Removing the installer: $Destination" rm $Destination } return } $startInstallTime = Get-Date Install-ContainerOSImage -WimPath $Destination ` -Force $endInstallTime = Get-Date $differenceInstallTime = New-TimeSpan -Start $startInstallTime -End $endInstallTime $installTime = "Installed in " + $differenceInstallTime.Hours + " hours, " + $differenceInstallTime.Minutes + " minutes, " + $differenceInstallTime.Seconds + " seconds." Write-Verbose $installTime # Clean up Write-Verbose "Removing the installer: $Destination" rm $Destination Write-Verbose "All Done" } ### ### SUMMARY: Installs the container image ### PARAMS ### ### 1. Name: Mandatory param: Name of the image ### 2. Version: Optional param: Version of the image ### 3. Destination: Mandatory param: Destiation where the file needs to be saved ### 4. SearchKey: Searches using this search key ### ### This function will first find the image based on given params ### If it finds the image, it will be downloaded ### Then it will be installed ### function Install-ContainerImageHelper { <# .SYNOPSIS Downloads the image from the cloud and installs them on the local computer .SYNTAX Install-ContainerImage [[-Name] <String>] [[-Destination] <String>] [[-Version] <Version>] [-SearchKey [String]] .DESCRIPTION The Install-ContainerImage gets the container image that meets the specified cirteria from the cloud. It saves the image locally and then installs it .EXAMPLE Install-ContainerImage -Name ImageName .EXAMPLE Install-ContainerImage -Name ImageName -Version 1.2.3.5 #> # Handle the input parameters param ( [parameter(Mandatory=$true)] [System.String]$SasToken, [parameter(Mandatory=$true)] [System.String]$Name ) $Destination = $env:TEMP + "\" + $Name + ".wim" Write-Verbose "Saving to $Destination" try { Save-AzureContainerImageFile -downloadURL $SasToken ` -Destination $Destination } catch { Write-Error "Unable to download." if((Test-Path $Destination)) { Write-Verbose "Removing the installer: $Destination" rm $Destination } return } $startInstallTime = Get-Date Install-ContainerOSImage -WimPath $Destination ` -Force $endInstallTime = Get-Date $differenceInstallTime = New-TimeSpan -Start $startInstallTime -End $endInstallTime "Installed in " + $differenceInstallTime.Hours + " hours, " + $differenceInstallTime.Minutes + " minutes, " + $differenceInstallTime.Seconds + " seconds." # Clean up Write-Verbose "Removing the installer: $Destination" rm $Destination } #endregion Functions #region Helper Functions ### ### SUMMARY: Class for display ### Class ContainerImageItem { [string] $Name; [string] $description; [string] $sasToken; [Version] $version; } ### ### SUMMARY: Displays the search results ### PARAMS: ### 1. SearchResults ### function Display-SearchResults { param ($searchResults) $formatting = @{Expression={$_.Name};Label="Name";width=20}, ` @{Expression={$_.version};Label="Version";width=25}, ` @{Expression={$_.description};Label="Description";width=60} $searchResults | Format-Table $formatting } ### ### SUMMARY: Find ### ### function Find { param($Name, $Version, $sources) $allSources = Get-Sources $sources $allResults = @() foreach($source in $allSources) { $location = $source.$script:location if($location.StartsWith("http://") -or $location.StartsWith("https://")) { $queryKey = $source.$script:QueryKey $index = $source.$script:IndexName $allResults += Find-Azure $Name $Version $location $index $queryKey } elseif($location.StartsWith("\\")) { $sPath = $source.$script:secondaryPath $allResults += Find-UNCPath $Name $Version $location } } return $allResults } ### ### SUMMARY: Gets the source from where to get the images ### Initializes the variables for find, download and install ### RETURN: ### Returns the type of ### function Get-Sources { param($sources) Set-ModuleSourcesVariable $allSources = @() if($script:ContainerSources.Count -eq 0) { Register-PackageSource -name ContainerImageGallery ` -ProviderName ContainerProvider ` -IndexName pshct-pub-srch-index ` -QueryKey 82E9CC3E0342EA5C9B95ED909FC8E039 ` -Location "http://go.microsoft.com/fwlink/?LinkID=627586&clcid=0x409" } foreach($mySource in $script:ContainerSources.Values) { if((-not $sources) -or (($mySource.Name -eq $sources) -or ($mySource.SourceLocation -eq $sources))) { $tempHolder = @{} $location = $mySource."SourceLocation" $tempHolder.Add($script:location, $location) $queryKey = $mySource.$script:QueryKey $tempHolder.Add($script:QueryKey, $queryKey) $indexName = $mySource.$script:IndexName $tempHolder.Add($script:IndexName, $indexName) $allSources += $tempHolder } } return $allSources } ### ### SUMMARY: Deserializes the PSObject ### function DeSerialize-PSObject { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter(Mandatory=$true)] $Path ) $filecontent = Microsoft.PowerShell.Management\Get-Content -Path $Path [System.Management.Automation.PSSerializer]::Deserialize($filecontent) } ### ### SUMMARY: Finds the container image entries on Azure Search ### PARAMS: ### 1. Name: Name of the image ### 2. Version: Version of the image ### function Find-Azure { param($Name, $Version, $fwdLink, $indexName, $queryKey) if(-not (IsNanoServer)) { Add-Type -AssemblyName System.Net.Http } $httpPostClient = New-Object System.Net.Http.HttpClient $httpPostRequestMsg = New-Object System.Net.Http.HttpRequestMessage( [System.Net.Http.HttpMethod]::Post, $fullUrl) # URL $resolvedUrl = Resolve-FwdLink $fwdLink if (($resolvedUrl.Scheme -ne 'http') -and ($resolvedUrl.Scheme -ne 'https')) { throw "Unable to get the resolved URL." } $relativePath = 'indexes/{0}/docs/search?{1}' -f $indexName,$apiVersionQP $httpPostClient.BaseAddress = New-Object System.Uri($resolvedUrl, $relativePath) $acceptHeader = New-Object ` System.Net.Http.Headers.MediaTypeWithQualityHeaderValue( "application/json") $httpPostClient.DefaultRequestHeaders.Accept.Add($acceptHeader) # Headers` $httpPostRequestMsg.Headers.Add("api-key", $queryKey) $httpPostRequestMsg.Headers.Add("charset", "utf-8") # Body <# # Azure search do not support case-insensitive search. # Until this is resolved we are doing client side # filtering if($Name) { $query = "name eq '$Name'" } if($Version -ne $minVersion) { if($query) { $query += " and" } $query += " version eq '$Version'" } #> $httpPostBody = '{ "filter" : "' + $query + '" ,"orderby": "name, version desc" }' $encoding = [System.Text.Encoding]::ASCII $httpPostRequestMsg.Content = New-Object System.Net.Http.StringContent( $httpPostBody, $encoding, "application/json") try { $responseTask = $httpPostClient.SendAsync($httpPostRequestMsg) $responseContent = $responseTask.Result.Content $responseBody = $responseContent.ReadAsStringAsync().Result.ToString() if(IsNanoServer) { $jsonDll = [Microsoft.PowerShell.CoreCLR.AssemblyExtensions]::LoadFrom($PSScriptRoot + "\Json.coreclr.dll") $jsonParser = $jsonDll.GetTypes() | ? name -match jsonparser $response = $jsonParser::FromJson($responseBody) } else { $response = $responseBody | ConvertFrom-Json } $responseValue = $response.value # apply filtering for Name and Version. # These were not applied when HTTP request is sent $NameToUseInQuery = if ($Name) { $Name } else { "*" } $VersionToUseInQuery = if ($Version) { $Version } else { "*" } $responseValue = $responseValue | ? { ($_.name -like "$NameToUseInQuery") -and ($_.version -like "$VersionToUseInQuery") } $responseClassArray = @() foreach($element in $responseValue) { $item = [ContainerImageItem]::new() $item.Name = $element.Name $item.description = $element.Description $item.version = $element.version $item.sasToken = $element.sastoken $responseClassArray += $item } return $responseClassArray } catch [System.Net.Http.HttpRequestException] { Write-Host "Error:System.Net.HttpRequestException" } catch [Exception] { Write-Host "$_.Message" } finally { } } ### ### SUMMARY: Finds the container image entries from the share directory ### PARAMS: ### 1. Name: Name of the image ### 2. Version: Version of the image ### function Find-UNCPath { param($Name, $Version, $localPath) $responseArray = @() $subFolders = Get-ChildItem -Path $localPath | sort LastWriteTime ` -Descending | % { $_.FullName } for($index = 0; $index -le 19; $index++) { $subFolder = $subFolders[$index] $fullPath = Join-Path $subFolder $sPath if((-not $Name) -or ($Name.ToLower().Contains("nano"))) { $search_nano = "*nano*.wim" $images_nano = @() $images_nano = Get-ChildItem -Path $fullPath ` -ErrorAction SilentlyContinue ` -Filter $search_nano ` -Recurse ` -Force | % { $_.FullName } foreach($nanoImage in $images_nano) { $version_nano = get-Version $nanoImage if((-not $Version) -or ($Version -eq $version_nano)) { $item_nano = [ContainerImageItem]::new() $item_nano.Name = "Nano" $item_nano.version = $version_nano $item_nano.sasToken = $nanoImage $item_nano.description = "Nano " + $version_nano $responseArray += $item_nano } } } if((-not $Name) -or ($Name.ToLower().Contains("servercore"))) { $search_server = "*ServerDatacenterCore*.wim" $images_server = @() $images_server = Get-ChildItem -Path $fullPath ` -ErrorAction SilentlyContinue ` -Filter $search_server ` -Recurse ` -Force | % { $_.FullName } foreach($serverImage in $images_server) { $version_server = get-Version $serverImage if((-not $Version) -or ($Version -eq $version_server)) { $item_server = [ContainerImageItem]::new() $item_server.Name = "WindowsServerCore" $item_server.version = $version_server $item_server.sasToken = $serverImage $item_server.description = "Server " + $version_server $responseArray += $item_server } } } } return $responseArray } ### ### SUMMARY: Download the file given the URI to the given location ### function Save-File { param($downloadURL, $destination) $startTime = Get-Date Write-Verbose $downloadURL if($downloadURL.StartsWith("http://") -or $downloadURL.StartsWith("https://")) { # Download the file if ((IsNanoServer) -or (get-variable pssenderinfo -ErrorAction SilentlyContinue)) { # Use custom Save-HTTPItem function if on Nano or in a remote session # This is beacuse BITS service does not work as expected under these circumstances. Import-Module "$PSScriptRoot\Save-HttpItem.psm1" Save-HTTPItem -Uri $downloadURL ` -Destination $destination } else { Start-BitsTransfer -Source $downloadURL ` -Destination $destination } } elseif($downloadURL.StartsWith("\\")) { cp $downloadURL $destination } $endTime = Get-Date $difference = New-TimeSpan -Start $startTime -End $endTime $downloadTime = "Downloaded in " + $difference.Hours + " hours, " + $difference.Minutes + " minutes, " + $difference.Seconds + " seconds." Write-Verbose $downloadTime } ### ### SUMMARY: Resolve the fwdlink to get the actual search URL ### function Resolve-FwdLink { param ( [parameter(Mandatory=$false)] [System.String]$Uri ) if(-not (IsNanoServer)) { Add-Type -AssemblyName System.Net.Http } $httpClient = New-Object System.Net.Http.HttpClient $response = $httpclient.GetAsync($Uri) $link = $response.Result.RequestMessage.RequestUri return $link } ### ### SUMMARY: Checks if the system is nano server or not ### Look into the win32 operating system class ### Returns True if running on Nano ### False otherwise ### function IsNanoServer { $operatingSystem = Get-CimInstance -ClassName win32_operatingsystem $systemSKU = $operatingSystem.OperatingSystemSKU return $systemSKU -eq 109 } ### ### SUMMARY: Checks if the given destination is kosher or not ### 1. Check if the user has provider a folder ### If so, throw an exception, only absolute path with file name is acceptable ### 2. Check if parent path exists ### If not, create it for the user ### 3. Check if the file exists ### If so, ask the user for ability to re-write ### function CheckDestination { param($Destination) # Check if entire path is folder structure # If folder throw error, ask for file path $dest_item = Get-Item $Destination ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue if($dest_item -is [System.IO.DirectoryInfo]) { throw "Please provide file name with path." } # Check the parent (one minus the whole path) # If the given parent directory doesn't exist # create it and return $folderPath = Split-Path $Destination $isFolderPath = Get-Item $folderPath ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue if($isFolderPath -isnot [System.IO.DirectoryInfo]) { Write-Verbose "Creating directory structure: $folderPath" md $folderPath return $true } # If given parent directory exists # Check if given file exists if((Test-Path $Destination)) { # Check for Read-only file $list = dir $Destination | where {$_.attributes -match "ReadOnly"} if($list.Count -gt 0) { Write-Error "Cannot over write read-only file: $Destination" return $false } $title = "Overwrite File" $message = "Do you want to overwrite the existing file: $Destination ?" $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", ` "Overwrite the existing file." $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", ` "Do not overwrite the existing file." $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) $result = $host.ui.PromptForChoice($title, $message, $options, 0) switch ($result) { 0 { # User selects Yes. return $true } 1 { # User selects No. Write-Host "Re-run the script with a different Destination" Write-Host return $false } } return $true } return $true } ### ### SUMMARY: Finds the version of the given image ### ### PARAMS: ### 1. Full Path: Path to the image ### ### RETURNS: ### The version of the image ### function get-Version { param($fullPath) # Throw error if the given File is folder or doesn't exist if((Get-Item $fullPath) -is [System.IO.DirectoryInfo]) { Write-Error "Please enter a file name not a folder." throw "$fullPath is a folder not file" } $containerImageInfo = Get-WindowsImage -ImagePath $fullPath -Index 1 $containerImageVersion = $containerImageInfo.Version return $containerImageVersion } #endregion Helper Functions #region PackageProvider $Providername = "ContainerProvider" $separator = "|#|" <# .Synopsis Short description .DESCRIPTION Long description .EXAMPLE Example of how to use this cmdlet .EXAMPLE Another example of how to use this cmdlet #> function Find-Package { [CmdletBinding()] Param ( [string[]] $names, [string] $requiredVersion, [string] $minimumVersion, [string] $maximumVersion ) $options = $request.Options $null = write-debug "In $($ProviderName)- Find-Package" $sourcesName = $null if ($options -and $options.ContainsKey['Source']) { $sourcesName = $options['Source'] } if ([string]::IsNullOrWhiteSpace($requiredVersion)) { $requiredVersion = [System.Version]::new("0.0.0.0") $null = write-debug "version is null" } else { $requiredVersion = [System.Version]::new($requiredVersion) } foreach($container in (Find -Name $names[0] -Version $requiredVersion -Sources $sourcesName)) { if ($request.IsCancelled) { $null = Write-Verbose "Request has been cancelled." return } $fastPackageReference = $container.Name + $separator + $container.version + $separator + $container.Description + $separator + $container.sasToken $containerSWID = @{ name = $container.Name version = $container.Version versionScheme = "semver" summary = $container.Description source = "Azure Public" fastPackageReference = $fastPackageReference } New-SoftwareIdentity @containerSWID } } <# .Synopsis Short description .DESCRIPTION Long description .EXAMPLE Example of how to use this cmdlet .EXAMPLE Another example of how to use this cmdlet #> function Download-Package { param( [string] $fastPackageReference, [string] $destLocation ) [string[]] $splitterArray = @("$separator") [string[]] $resultArray = $fastPackageReference.Split($splitterArray, [System.StringSplitOptions]::None); if($resultArray.Count -eq 0) { throw new "Error installing package. Unable to get the package reference" } $sasToken = $resultArray[3] Save-AzureContainerImageFile $sasToken $destLocation } function Install-Package { param( [string] $fastPackageReference ) [string[]] $splitterArray = @("$separator") [string[]] $resultArray = $fastPackageReference.Split($splitterArray, [System.StringSplitOptions]::None); if($resultArray.Count -eq 0) { throw new "Error installing package. Unable to get the package reference" } $name = $resultArray[0] $sasToken = $resultArray[3] $null = write-debug "Name of the container is $name and sastoken is $sasToken" Install-ContainerImageHelper -SasToken $sasToken -Name $name } function Initialize-Provider { write-debug "In $($Providername) - Initialize-Provider" } function Get-PackageProviderName { return $Providername } function Get-InstalledPackages { param( [string]$name, [string]$requiredVersion, [string]$minimumVersion, [string]$maximumVersion ) $containers = Get-ContainerImage if ($containers -eq $null -or $containers.Count -eq 0) { return } ForEach($container in Get-ContainerImage) { if ($request.IsCancelled) { $null = Write-Verbose "Request has been cancelled." return } $containerSWID = @{ name = $container.Name version = $container.Version versionScheme = "semver" source = "Azure Public" fastPackageReference = $container.Name } New-SoftwareIdentity @containerSWID } } function Set-ModuleSourcesVariable { [CmdletBinding()] param([switch]$Force) if(-not $script:ContainerSources-or $Force) { if(Microsoft.PowerShell.Management\Test-Path $script:file_modules) { $script:ContainerSources = DeSerialize-PSObject -Path $script:file_modules } else { $script:ContainerSources = [ordered]@{} } } } function Get-DynamicOptions { param ( [Microsoft.PackageManagement.MetaProvider.PowerShell.OptionCategory] $category ) switch($category) { Source { Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:QueryKey -ExpectedType String -IsRequired $false) Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:IndexName -ExpectedType String -IsRequired $false) Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:secondaryPath -ExpectedType String -IsRequired $false) } } } function Add-PackageSource { [CmdletBinding()] param ( [string] $Name, [string] $Location, [bool] $Trusted ) # Validate Name # Validate for wild card pattern # $Name # Validate path # Check if Location is already registered with another Name # $Location Set-ModuleSourcesVariable -Force $Options = $request.Options $query_key = $null if($Options.ContainsKey($script:QueryKey)) { $query_key = $Options[$script:QueryKey] } $index_name = $null if($Options.ContainsKey($script:IndexName)) { $index_name = $Options[$script:IndexName] } $secondary_location = $null if($Options.ContainsKey($script:secondaryPath)) { $secondary_location = $Options[$script:secondaryPath] } # Add new module source $moduleSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ Name = $Name SourceLocation = $Location Trusted=$Trusted Registered= $true InstallationPolicy = if($Trusted) {'Trusted'} else {'Untrusted'} QueryKey = $query_key IndexName = $index_name SecondaryLocation = $secondary_location }) #TODO: Check if name already exists $script:ContainerSources.Add($Name, $moduleSource) Save-ModuleSources Write-Output -InputObject (New-PackageSourceFromModuleSource -ModuleSource $moduleSource) } function Remove-PackageSource { } function Resolve-PackageSource { Set-ModuleSourcesVariable $SourceName = $request.PackageSources if(-not $SourceName) { $SourceName = "*" } foreach($moduleSourceName in $SourceName) { if($request.IsCanceled) { return } $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $moduleSourceName,$script:wildcardOptions $moduleSourceFound = $false $script:ContainerSources.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {$wildcardPattern.IsMatch($_.Key)} | Microsoft.PowerShell.Core\ForEach-Object { $moduleSource = $script:ContainerSources[$_.Key] $packageSource = New-PackageSourceFromModuleSource -ModuleSource $moduleSource Write-Output -InputObject $packageSource $moduleSourceFound = $true } if(-not $moduleSourceFound) { $sourceName = Get-SourceName -Location $moduleSourceName if($sourceName) { $moduleSource = $script:ContainerSources[$sourceName] $packageSource = New-PackageSourceFromModuleSource -ModuleSource $moduleSource Write-Output -InputObject $packageSource } <# elseif( -not (Test-WildcardPattern $moduleSourceName)) { $message = "$moduleSourceName not found" Write-Error -Message $message ` -ErrorId "RepositoryNotFound" ` -Category InvalidOperation ` -TargetObject $moduleSourceName } #> } } } function Save-ModuleSources { # check if exists if(-not (Test-Path $script:location_modules)) { md $script:location_modules } # seralize module Microsoft.PowerShell.Utility\Out-File -FilePath $script:file_modules ` -Force ` -InputObject ([System.Management.Automation.PSSerializer]::Serialize($script:ContainerSources)) } function New-PackageSourceFromModuleSource { param ( [Parameter(Mandatory=$true)] $ModuleSource ) $packageSourceDetails = @{} # check if querykey and index name exist if ([string]::IsNullOrWhiteSpace($ModuleSource.$script:QueryKey)) { $packageSourceDetails[$script:QueryKey] = $ModuleSource.$script:QueryKey } if ([string]::IsNullOrWhiteSpace($ModuleSource.$script:IndexName)) { $packageSourceDetails[$script:IndexName] = $ModuleSource.$script:IndexName } if ([string]::IsNullOrWhiteSpace($ModuleSource.$script:secondaryPath)) { $packageSourceDetails[$script:secondaryPath] = $ModuleSource.$script:secondaryPath } # create a new package source $src = New-PackageSource -Name $ModuleSource.Name ` -Location $ModuleSource.SourceLocation ` -Trusted $ModuleSource.Trusted ` -Registered $ModuleSource.Registered ` -Details $packageSourceDetails # return the package source object. Write-Output -InputObject $src } function Get-SourceName { [CmdletBinding()] [OutputType("string")] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $Location ) Set-ModuleSourcesVariable foreach($psModuleSource in $script:ContainerSources.Values) { if(($psModuleSource.Name -eq $Location) -or ($psModuleSource.SourceLocation -eq $Location)) { return $psModuleSource.Name } } } #endregion PackageProvider |