├── BitsOnNano.exe
├── ContainerImage.ps1xml
├── ContainerImage.psd1
├── ContainerImage.psm1
├── Json.coreclr.dll
├── LICENSE
├── README.md
└── SaveHTTPItemUsingBITS.psm1
/BitsOnNano.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PowerShell/ContainerProvider/266585a3de90c214276ec81dffbe89c9b050f62d/BitsOnNano.exe
--------------------------------------------------------------------------------
/ContainerImage.ps1xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ContainerImage
6 |
7 | ContainerImageItem
8 |
9 |
10 |
11 |
12 | 20
13 |
14 |
15 | 23
16 |
17 |
18 | 20
19 |
20 |
21 | 35
22 |
23 |
24 |
25 |
26 |
27 |
28 | Name
29 |
30 |
31 | Version
32 |
33 |
34 | Source
35 |
36 |
37 | Description
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/ContainerImage.psd1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PowerShell/ContainerProvider/266585a3de90c214276ec81dffbe89c9b050f62d/ContainerImage.psd1
--------------------------------------------------------------------------------
/ContainerImage.psm1:
--------------------------------------------------------------------------------
1 | #region Variables
2 | $script:location_modules = "$env:LOCALAPPDATA\ContainerImage"
3 | $script:file_modules = "$script:location_modules\sources.txt"
4 | $script:ContainerSources = $null
5 | $script:wildcardOptions = [System.Management.Automation.WildcardOptions]::CultureInvariant -bor `
6 | [System.Management.Automation.WildcardOptions]::IgnoreCase
7 | $script:ContainerImageSearchIndex = "ContainerImageSearchIndex.txt"
8 | $script:PSArtifactTypeModule = 'Module'
9 | $script:PSArtifactTypeScript = 'Script'
10 | $script:isNanoServerInitialized = $false
11 | $script:isNanoServer = $false
12 | $script:Providername = "ContainerImage"
13 | $separator = "|#|"
14 |
15 | Microsoft.PowerShell.Core\Set-StrictMode -Version Latest
16 |
17 | #endregion Variables
18 |
19 | #region One-Get Functions
20 |
21 | function Find-Package
22 | {
23 | [CmdletBinding()]
24 | param
25 | (
26 | [string[]]
27 | $names,
28 |
29 | [string]
30 | $RequiredVersion,
31 |
32 | [string]
33 | $MinimumVersion,
34 |
35 | [string]
36 | $MaximumVersion
37 | )
38 |
39 | Set-ModuleSourcesVariable
40 |
41 | $options = $request.Options
42 |
43 | foreach( $o in $options.Keys )
44 | {
45 | Write-Debug ( "OPTION: {0} => {1}" -f ($o, $options[$o]) )
46 | }
47 |
48 | $AllVersions = $null
49 | if($options.ContainsKey("AllVersions"))
50 | {
51 | $AllVersions = $options['AllVersions']
52 | }
53 |
54 | $sources = @()
55 | if($options.ContainsKey('Source'))
56 | {
57 | $sources = $options['Source']
58 | }
59 |
60 | $convertedRequiredVersion = Convert-Version $requiredVersion
61 | $convertedMinVersion = Convert-Version $minimumVersion
62 | $convertedMaxVersion = Convert-Version $maximumVersion
63 |
64 | if(-not (CheckVersion $convertedMinVersion $convertedMaxVersion $convertedRequiredVersion $AllVersions))
65 | {
66 | return $null
67 | }
68 |
69 | if ($null -eq $names -or $names.Count -eq 0)
70 | {
71 | $names = @('')
72 | }
73 |
74 | $allResults = @()
75 | $allSources = Get-Sources $sources
76 | foreach($currSource in $allSources)
77 | {
78 | foreach ($singleName in $names)
79 | {
80 | if ([string]::IsNullOrWhiteSpace($singleName) -or $singleName.Trim() -eq '*')
81 | {
82 | # if no name is supplied but min or max version is supplied, error out
83 | if ($null -ne $convertedMinVersion -or $null -ne $convertedMaxVersion)
84 | {
85 | ThrowError -CallerPSCmdlet $PSCmdlet `
86 | -ExceptionName System.Exception `
87 | -ExceptionMessage "Name is required when either MinimumVersion or MaximumVersion parameter is used" `
88 | -ExceptionObject $singleName `
89 | -ErrorId NameRequiredForMinOrMaxVersion `
90 | -ErrorCategory InvalidData
91 | }
92 | }
93 |
94 | $location = $currSource.SourceLocation
95 | $sourceName = $currSource.Name
96 |
97 | if($location.StartsWith("http://") -or $location.StartsWith("https://"))
98 | {
99 | $allResults += Find-Azure -Name $singleName `
100 | -MinimumVersion $convertedMinVersion `
101 | -MaximumVersion $convertedMaxVersion `
102 | -RequiredVersion $convertedRequiredVersion `
103 | -AllVersions:$AllVersions `
104 | -Location $location `
105 | -SourceName $sourceName
106 | }
107 | elseif($location.StartsWith("\\"))
108 | {
109 | $allResults += Find-UNCPath -Name $singleName `
110 | -MinimumVersion $convertedMinVersion `
111 | -MaximumVersion $convertedMaxVersion `
112 | -RequiredVersion $convertedRequiredVersion `
113 | -AllVersions:$AllVersions `
114 | -localPath $location `
115 | -SourceName $sourceName
116 | }
117 | else
118 | {
119 | Write-Error "Bad source '$sourceName' with location at $location"
120 | }
121 | }
122 | }
123 |
124 | if($null -eq $allResults)
125 | {
126 | return
127 | }
128 |
129 | foreach($result in $allResults)
130 | {
131 | $swid = New-SoftwareIdentityFromContainerImageItemInfo $result
132 | Write-Output $swid
133 | }
134 | }
135 |
136 | function Download-Package
137 | {
138 | [CmdletBinding()]
139 | param
140 | (
141 | [Parameter(Mandatory=$true)]
142 | [ValidateNotNullOrEmpty()]
143 | [string]
144 | $FastPackageReference,
145 |
146 | [Parameter(Mandatory=$true)]
147 | [ValidateNotNullOrEmpty()]
148 | [string]
149 | $Location
150 | )
151 |
152 | DownloadPackageHelper -FastPackageReference $FastPackageReference `
153 | -Request $Request `
154 | -Location $Location
155 | }
156 |
157 | function Install-Package
158 | {
159 | [CmdletBinding()]
160 | param
161 | (
162 | [Parameter(Mandatory=$true)]
163 | [ValidateNotNullOrEmpty()]
164 | [string]
165 | $FastPackageReference
166 | )
167 |
168 | [string[]] $splitterArray = @("$separator")
169 | [string[]] $resultArray = $FastPackageReference.Split($splitterArray, [System.StringSplitOptions]::None)
170 |
171 | $name = $resultArray[0]
172 | $version = $resultArray[1]
173 | $Location = $script:location_modules
174 |
175 | $Destination = GenerateFullPath -Location $Location `
176 | -Name $name `
177 | -Version $Version
178 |
179 | $downloadOutput = DownloadPackageHelper -FastPackageReference $FastPackageReference `
180 | -Request $Request `
181 | -Location $Location
182 |
183 | $startInstallTime = Get-Date
184 |
185 | if(-not (Test-Path $destination))
186 | {
187 | Write-verbose "$Destination does not exist"
188 | }
189 | else
190 | {
191 | Write-verbose "$Destination does exist. I should install"
192 | }
193 |
194 | Write-Verbose "Trying to install the Image: $Destination"
195 |
196 | Install-ContainerOSImage -WimPath $Destination `
197 | -Force
198 |
199 | $endInstallTime = Get-Date
200 | $differenceInstallTime = New-TimeSpan -Start $startInstallTime -End $endInstallTime
201 | $installTime = "Installed in " + $differenceInstallTime.Hours + " hours, " + $differenceInstallTime.Minutes + " minutes, " + $differenceInstallTime.Seconds + " seconds."
202 | Write-Verbose $installTime
203 |
204 | # Clean up
205 | Write-Verbose "Removing the installer: $Destination"
206 | rm $Destination
207 |
208 | Write-Output $downloadOutput
209 | }
210 |
211 | function Get-InstalledPackage
212 | {
213 | }
214 |
215 | function Initialize-Provider
216 | {
217 | write-debug "In $($script:Providername) - Initialize-Provider"
218 | }
219 |
220 | function Get-PackageProviderName
221 | {
222 | return $script:Providername
223 | }
224 |
225 | #endregion One-Get Functions
226 |
227 | #region Stand-Alone Functions
228 |
229 | function Find-ContainerImage
230 | {
231 | <#
232 | .Synopsis
233 | Finds the container image from an online gallery that match specified criteria.
234 | It can also search from other registered sources.
235 | .DESCRIPTION
236 | Find-ContainerImage finds the images from the online gallery that match specified criteria.
237 | .EXAMPLE
238 | Find-ContainerImage -Name ImageName
239 | .EXAMPLE
240 | Find-ContainerImage -MinimumVersion Version
241 | .EXAMPLE
242 | Find-ContainerImage -MaximumVersion Version
243 | .EXAMPLE
244 | Find-ContainerImage -RequiredVersion Version
245 | .EXAMPLE
246 | Find-ContainerImage -AllVersions
247 | #>
248 |
249 | [cmdletbinding()]
250 | param
251 | (
252 | [Parameter(Mandatory=$false,Position=0)]
253 | [string[]]
254 | $Name,
255 |
256 | [System.Version]
257 | $MinimumVersion,
258 |
259 | [System.Version]
260 | $MaximumVersion,
261 |
262 | [System.Version]
263 | $RequiredVersion,
264 |
265 | [switch]
266 | $AllVersions,
267 |
268 | [System.string]
269 | $source
270 | )
271 |
272 | Begin
273 | {
274 | }
275 |
276 | Process
277 | {
278 | $PSBoundParameters["Provider"] = $script:Providername
279 |
280 | PackageManagement\Find-Package @PSBoundParameters
281 | }
282 | }
283 |
284 | function Save-ContainerImage
285 | {
286 | <#
287 | .Synopsis
288 | Saves a container image without installing it.
289 | .DESCRIPTION
290 | The Save-ContainerImage cmdlet lets you save a container image locally without installing it.
291 | This lets you inspect the container image before you install, helping to minimize the risks
292 | of malicious code or malware on your system.
293 | As a best practice, when you have finished evaluating a container image for potential risks,
294 | and before you install the image for use, delete the image from the path to which you have saved.
295 | .EXAMPLE
296 | Save-ContainerImage -Name ImageName -Path C:\temp\
297 | .EXAMPLE
298 | Save-ContainerImage -Name ImageName -LiteralPath C:\temp\
299 | .EXAMPLE
300 | Save-ContainerImage -Name ImageName -MinimumVersion Version -Path .\..\
301 | .EXAMPLE
302 | Save-ContainerImage -Name ImageName -MaximumVersion Version -LiteralPath C:\temp\
303 | .EXAMPLE
304 | Save-ContainerImage -Name ImageName -RequiredVersion Version -Path C:\t*p\
305 | .EXAMPLE
306 | Save-ContainerImage -Name ImageName -RequiredVersion Version -Path C:\t*p\ -Source ContainerImageGallery
307 | .EXAMPLE
308 | Find-ContainerImage -Name ImageName | Save-ContainerImage -LiteralPath C:\temp\
309 | #>
310 |
311 | [CmdletBinding(DefaultParameterSetName='NameAndPathParameterSet',
312 | SupportsShouldProcess=$true)]
313 | Param
314 | (
315 | [Parameter(Mandatory=$true,
316 | ValueFromPipelineByPropertyName=$true,
317 | Position=0,
318 | ParameterSetName='NameAndPathParameterSet')]
319 | [Parameter(Mandatory=$true,
320 | ValueFromPipelineByPropertyName=$true,
321 | Position=0,
322 | ParameterSetName='NameAndLiteralPathParameterSet')]
323 | [ValidateNotNullOrEmpty()]
324 |
325 | [string[]]
326 | $Name,
327 |
328 | [Parameter(Mandatory=$true,
329 | ValueFromPipeline=$true,
330 | ValueFromPipelineByPropertyName=$true,
331 | ParameterSetName='InputOjectAndPathParameterSet')]
332 | [Parameter(Mandatory=$true,
333 | ValueFromPipeline=$true,
334 | ValueFromPipelineByPropertyName=$true,
335 | ParameterSetName='InputOjectAndLiteralPathParameterSet')]
336 | [ValidateNotNull()]
337 | [PSCustomObject[]]
338 | $InputObject,
339 |
340 | [Parameter(ValueFromPipelineByPropertyName=$true,
341 | ParameterSetName='NameAndPathParameterSet')]
342 | [Parameter(ValueFromPipelineByPropertyName=$true,
343 | ParameterSetName='NameAndLiteralPathParameterSet')]
344 | [Version]
345 | $MinimumVersion,
346 |
347 | [Parameter(ValueFromPipelineByPropertyName=$true,
348 | ParameterSetName='NameAndPathParameterSet')]
349 | [Parameter(ValueFromPipelineByPropertyName=$true,
350 | ParameterSetName='NameAndLiteralPathParameterSet')]
351 | [Version]
352 | $MaximumVersion,
353 |
354 | [Parameter(ValueFromPipelineByPropertyName=$true,
355 | ParameterSetName='NameAndPathParameterSet')]
356 | [Parameter(ValueFromPipelineByPropertyName=$true,
357 | ParameterSetName='NameAndLiteralPathParameterSet')]
358 | [Alias('Version')]
359 | [Version]
360 | $RequiredVersion,
361 |
362 | [Parameter(Mandatory=$true, ParameterSetName='NameAndPathParameterSet')]
363 | [Parameter(Mandatory=$true, ParameterSetName='InputOjectAndPathParameterSet')]
364 | [string]
365 | $Path,
366 |
367 | [Parameter(Mandatory=$true, ParameterSetName='NameAndLiteralPathParameterSet')]
368 | [Parameter(Mandatory=$true, ParameterSetName='InputOjectAndLiteralPathParameterSet')]
369 | [string]
370 | $LiteralPath,
371 |
372 | [Parameter()]
373 | [switch]
374 | $Force,
375 |
376 | [Parameter()]
377 | [System.string]
378 | $source
379 | )
380 |
381 | if($InputObject)
382 | {
383 | }
384 | else
385 | {
386 | $PSBoundParameters["Provider"] = $script:Providername
387 | }
388 |
389 | PackageManagement\Save-Package @PSBoundParameters
390 | }
391 |
392 | function Install-ContainerImage
393 | {
394 | <#
395 | .Synopsis
396 | Downloads the image from the cloud and installs them on the local computer.
397 | .DESCRIPTION
398 | The Install-ContainerImage gets the container image that meets the specified cirteria from the cloud.
399 | It saves the image locally and then installs it.
400 | .EXAMPLE
401 | Install-ContainerImage -Name ImageName
402 | .EXAMPLE
403 | Install-ContainerImage -Name ImageName -Source ContainerImageGallery
404 | .EXAMPLE
405 | Install-ContainerImage -Name ImageName -MinimumVersion Version
406 | .EXAMPLE
407 | Install-ContainerImage -Name ImageName -MaximumVersion Version
408 | .EXAMPLE
409 | Install-ContainerImage -Name ImageName -RequiredVersion Version
410 | .EXAMPLE
411 | Find-ContainerImage -Name ImageName | Install-ContainerImage
412 | #>
413 |
414 | [CmdletBinding(DefaultParameterSetName='NameAndPathParameterSet',
415 | SupportsShouldProcess=$true)]
416 | Param
417 | (
418 | [Parameter(Mandatory=$true,
419 | ValueFromPipelineByPropertyName=$true,
420 | Position=0,
421 | ParameterSetName='NameParameterSet')]
422 | [ValidateNotNullOrEmpty()]
423 | [string[]]
424 | $Name,
425 |
426 | [Parameter(Mandatory=$true,
427 | ValueFromPipeline=$true,
428 | ValueFromPipelineByPropertyName=$true,
429 | Position=0,
430 | ParameterSetName='InputObject')]
431 | [ValidateNotNull()]
432 | [PSCustomObject[]]
433 | $InputObject,
434 |
435 | [Parameter(ValueFromPipelineByPropertyName=$true,
436 | ParameterSetName='NameParameterSet')]
437 | [Alias("Version")]
438 | [ValidateNotNull()]
439 | [Version]
440 | $MinimumVersion,
441 |
442 | [Parameter(ValueFromPipelineByPropertyName=$true,
443 | ParameterSetName='NameParameterSet')]
444 | [ValidateNotNull()]
445 | [Version]
446 | $MaximumVersion,
447 |
448 | [Parameter(ValueFromPipelineByPropertyName=$true,
449 | ParameterSetName='NameParameterSet')]
450 | [ValidateNotNull()]
451 | [Version]
452 | $RequiredVersion,
453 |
454 | [Parameter()]
455 | [switch]
456 | $Force,
457 |
458 | [Parameter()]
459 | [System.string]
460 | $Source
461 | )
462 |
463 | if($WhatIfPreference)
464 | {
465 | $null = $PSBoundParameters.Remove("WhatIf")
466 | $findOutput = PackageManagement\Find-Package @PSBoundParameters
467 | $packageName = $findOutput.name
468 | $packageversion = $findOutput.version
469 | $packageSource = $findOutput.Source
470 |
471 | $string = '"Package ' + $packageName + ' version ' + $packageversion + ' from ' + $packageSource + '"'
472 | $messageWhatIf = 'What if: Performing the operation "Install Package" on target ' + $string + ' .'
473 |
474 | Write-Host $messageWhatIf
475 | return
476 | }
477 |
478 | if($InputObject)
479 | {
480 | }
481 | else
482 | {
483 | $PSBoundParameters["Provider"] = $script:Providername
484 | }
485 |
486 | #PackageManagement\Install-Package @PSBoundParameters
487 |
488 | $Location = $script:location_modules
489 |
490 | $PSBoundParameters["Path"] = $Location
491 | $PSBoundParameters["Force"] = $true
492 | $downloadOutput = PackageManagement\Save-Package @PSBoundParameters
493 |
494 | $Destination = GenerateFullPath -Location $Location `
495 | -Name $downloadOutput.Name `
496 | -Version $downloadOutput.Version
497 |
498 | $startInstallTime = Get-Date
499 |
500 | Write-Verbose "Trying to install the Image: $Destination"
501 |
502 | Install-ContainerOSImage -WimPath $Destination `
503 | -Force
504 |
505 | $endInstallTime = Get-Date
506 | $differenceInstallTime = New-TimeSpan -Start $startInstallTime -End $endInstallTime
507 | $installTime = "Installed in " + $differenceInstallTime.Hours + " hours, " + $differenceInstallTime.Minutes + " minutes, " + $differenceInstallTime.Seconds + " seconds."
508 | Write-Verbose $installTime
509 |
510 | # Clean up
511 | Write-Verbose "Removing the installer: $Destination"
512 | rm $Destination
513 | }
514 |
515 | #endregion Stand-Alone Functions
516 |
517 | #region Helper-Functions
518 |
519 | function CheckVersion
520 | {
521 | param
522 | (
523 | [System.Version]$MinimumVersion,
524 | [System.Version]$MaximumVersion,
525 | [System.Version]$RequiredVersion,
526 | [switch]$AllVersions
527 | )
528 |
529 | if($AllVersions -and $RequiredVersion)
530 | {
531 | Write-Error "AllVersions and RequiredVersion cannot be used together"
532 | return $false
533 | }
534 |
535 | if($AllVersions -or $RequiredVersion)
536 | {
537 | if($MinimumVersion -or $MaximumVersion)
538 | {
539 | Write-Error "AllVersions and RequiredVersion switch cannot be used with MinimumVersion or MaximumVersion"
540 | return $false
541 | }
542 | }
543 |
544 | if($MinimumVersion -and $MaximumVersion)
545 | {
546 | if($MaximumVersion -lt $MinimumVersion)
547 | {
548 | Write-Error "Minimum Version cannot be more than Maximum Version"
549 | return $false
550 | }
551 | }
552 |
553 | return $true
554 | }
555 |
556 | function Find-Azure
557 | {
558 | param(
559 | [Parameter(Mandatory=$false,Position=0)]
560 | [string[]]
561 | $Name,
562 |
563 | [System.Version]
564 | $MinimumVersion,
565 |
566 | [System.Version]
567 | $MaximumVersion,
568 |
569 | [System.Version]
570 | $RequiredVersion,
571 |
572 | [switch]
573 | $AllVersions,
574 |
575 | [System.String]
576 | $Location,
577 |
578 | [System.String]
579 | $SourceName
580 | )
581 |
582 | Add-Type -AssemblyName System.Net.Http
583 |
584 | $searchFile = Get-SearchIndex -fwdLink $Location `
585 | -SourceName $SourceName
586 |
587 | $searchFileContent = Get-Content $searchFile
588 |
589 | if($null -eq $searchFileContent)
590 | {
591 | return $null
592 | }
593 |
594 | if(IsNanoServer)
595 | {
596 | $jsonDll = [Microsoft.PowerShell.CoreCLR.AssemblyExtensions]::LoadFrom($PSScriptRoot + "\Json.coreclr.dll")
597 | $jsonParser = $jsonDll.GetTypes() | Where-Object name -match jsonparser
598 | $searchContent = $jsonParser::FromJson($searchFileContent)
599 | $searchStuff = $searchContent.Get_Item("array0")
600 | $searchData = @()
601 | foreach($searchStuffEntry in $searchStuff)
602 | {
603 | $obj = New-Object PSObject
604 | $obj | Add-Member NoteProperty Name $searchStuffEntry.Name
605 | $obj | Add-Member NoteProperty Version $searchStuffEntry.Version
606 | $obj | Add-Member NoteProperty Description $searchStuffEntry.Description
607 | $obj | Add-Member NoteProperty SasToken $searchStuffEntry.SasToken
608 | $searchData += $obj
609 | }
610 | }
611 | else
612 | {
613 | $searchData = $searchFileContent | ConvertFrom-Json
614 | }
615 |
616 | # If name is null or whitespace, interpret as *
617 | if ([string]::IsNullOrWhiteSpace($Name))
618 | {
619 | $Name = "*"
620 | }
621 |
622 | # Handle the version not given scenario
623 | if((-not ($MinimumVersion -or $MaximumVersion -or $RequiredVersion -or $AllVersions)))
624 | {
625 | $MinimumVersion = [System.Version]'0.0.0.0'
626 | }
627 |
628 | $searchResults = @()
629 | $searchDictionary = @{}
630 |
631 | foreach($entry in $searchData)
632 | {
633 | $toggle = $false
634 |
635 | # Check if the search string has * in it
636 | if ([System.Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Name))
637 | {
638 | if($entry.name -like $Name)
639 | {
640 | $toggle = $true
641 | }
642 | else
643 | {
644 | continue
645 | }
646 | }
647 | else
648 | {
649 | if($entry.name -eq $Name)
650 | {
651 | $toggle = $true
652 | }
653 | else
654 | {
655 | continue
656 | }
657 | }
658 |
659 | $thisVersion = Convert-Version $entry.version
660 |
661 | if($MinimumVersion)
662 | {
663 | $convertedMinimumVersion = Convert-Version $MinimumVersion
664 |
665 | if(($thisVersion -ge $convertedMinimumVersion))
666 | {
667 | if($searchDictionary.ContainsKey($entry.name))
668 | {
669 | $objEntry = $searchDictionary[$entry.name]
670 | $objVersion = Convert-Version $objEntry.Version
671 |
672 | if($thisVersion -gt $objVersion)
673 | {
674 | $toggle = $true
675 | }
676 | else
677 | {
678 | $toggle = $false
679 | }
680 | }
681 | else
682 | {
683 | $toggle = $true
684 | }
685 | }
686 | else
687 | {
688 | $toggle = $false
689 | }
690 | }
691 |
692 | if($MaximumVersion)
693 | {
694 | $convertedMaximumVersion = Convert-Version $MaximumVersion
695 |
696 | if(($thisVersion -le $convertedMaximumVersion))
697 | {
698 | if($searchDictionary.ContainsKey($entry.name))
699 | {
700 | $objEntry = $searchDictionary[$entry.name]
701 | $objVersion = Convert-Version $objEntry.Version
702 |
703 | if($thisVersion -gt $objVersion)
704 | {
705 | $toggle = $true
706 | }
707 | else
708 | {
709 | $toggle = $false
710 | }
711 | }
712 | else
713 | {
714 | $toggle = $true
715 | }
716 | }
717 | else
718 | {
719 | $toggle = $false
720 | }
721 | }
722 |
723 | if($RequiredVersion)
724 | {
725 | $convertedRequiredVersion = Convert-Version $RequiredVersion
726 |
727 | if(($thisVersion -eq $convertedRequiredVersion))
728 | {
729 | $toggle = $true
730 | }
731 | else
732 | {
733 | $toggle = $false
734 | }
735 | }
736 |
737 | if($AllVersions)
738 | {
739 | if($toggle)
740 | {
741 | $searchResults += $entry
742 | }
743 | }
744 |
745 | if($toggle)
746 | {
747 | if($searchDictionary.ContainsKey($entry.name))
748 | {
749 | $searchDictionary.Remove($entry.name)
750 | }
751 |
752 | $searchDictionary.Add($entry.name, $entry)
753 | }
754 | }
755 |
756 | if(-not $AllVersions)
757 | {
758 | $searchDictionary.Keys | ForEach-Object {
759 | $searchResults += $searchDictionary.Item($_)
760 | }
761 | }
762 |
763 | $searchEntries = @()
764 |
765 | foreach($searchEntry in $searchResults)
766 | {
767 | $EntryName = $searchEntry.Name
768 | $EntryVersion = $searchEntry.Version
769 | $EntryDescription = $searchEntry.Description
770 | $SasToken = $searchEntry.SasToken
771 | $ResultEntry = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
772 | Name = $EntryName
773 | Version = $EntryVersion
774 | Description = $EntryDescription
775 | SasToken = $SasToken
776 | Source = $SourceName
777 | })
778 |
779 | $searchEntries += $ResultEntry
780 | }
781 |
782 | $searchEntries = $searchEntries | Sort-Object "Version" -Descending
783 |
784 | return $searchEntries
785 | }
786 |
787 | function Find-UNCPath
788 | {
789 | param(
790 | [Parameter(Mandatory=$false,Position=0)]
791 | [string]
792 | $Name,
793 |
794 | [System.Version]
795 | $MinimumVersion,
796 |
797 | [System.Version]
798 | $MaximumVersion,
799 |
800 | [System.Version]
801 | $RequiredVersion,
802 |
803 | [switch]
804 | $AllVersions,
805 |
806 | [System.String]
807 | $localPath,
808 |
809 | [System.String]
810 | $SourceName
811 | )
812 |
813 | $responseArray = @()
814 | try
815 | {
816 | $nameToSearch = ""
817 | if(-not $Name)
818 | {
819 | $nameToSearch = "*.wim"
820 | }
821 | else
822 | {
823 | if(-not($name.ToLower().EndsWith(".wim")))
824 | {
825 | $name = $name + ".wim"
826 | }
827 |
828 | $nameToSearch = $Name
829 | }
830 |
831 | $images = @()
832 | $images = Get-ChildItem -Path $localPath `
833 | -ErrorAction SilentlyContinue `
834 | -Filter $nameToSearch `
835 | -Recurse `
836 | -File `
837 | -Depth 1 `
838 | -Force | % { $_.FullName }
839 |
840 | $searchResults = @()
841 | $searchDictionary = @{}
842 |
843 | # Handle the version not given scenario
844 | if((-not ($MinimumVersion -or $MaximumVersion -or $RequiredVersion -or $AllVersions)))
845 | {
846 | $MinimumVersion = [System.Version]'0.0.0.0'
847 | }
848 |
849 | foreach($image in $images)
850 | {
851 | # Since the Get-ChildItem has filtered images by name
852 | # All images are potentially candidates for result
853 | $toggle = $true
854 | $thisVersion = get-Version $image
855 | $fileName = Split-Path $image -Leaf
856 |
857 | if($MinimumVersion)
858 | {
859 | $convertedMinimumVersion = Convert-Version $MinimumVersion
860 |
861 | if(($thisVersion -ge $convertedMinimumVersion))
862 | {
863 | if($searchDictionary.ContainsKey($fileName))
864 | {
865 | $objEntry = $searchDictionary[$fileName]
866 | $objVersion = Convert-Version $objEntry.Version
867 |
868 | if($thisVersion -gt $objVersion)
869 | {
870 | $toggle = $true
871 | }
872 | else
873 | {
874 | $toggle = $false
875 | }
876 | }
877 | else
878 | {
879 | $toggle = $true
880 | }
881 | }
882 | else
883 | {
884 | $toggle = $false
885 | }
886 | }
887 |
888 | if($MaximumVersion)
889 | {
890 | $convertedMaximumVersion = Convert-Version $MaximumVersion
891 |
892 | if(($thisVersion -le $convertedMaximumVersion))
893 | {
894 | if($searchDictionary.ContainsKey($fileName))
895 | {
896 | $objEntry = $searchDictionary[$fileName]
897 | $objVersion = Convert-Version $objEntry.Version
898 |
899 | if($thisVersion -gt $objVersion)
900 | {
901 | $toggle = $true
902 | }
903 | else
904 | {
905 | $toggle = $false
906 | }
907 | }
908 | else
909 | {
910 | $toggle = $true
911 | }
912 | }
913 | else
914 | {
915 | $toggle = $false
916 | }
917 | }
918 |
919 | if($RequiredVersion)
920 | {
921 | $convertedRequiredVersion = Convert-Version $RequiredVersion
922 |
923 | if(($thisVersion -eq $convertedRequiredVersion))
924 | {
925 | $toggle = $true
926 | }
927 | else
928 | {
929 | $toggle = $false
930 | }
931 | }
932 |
933 | if($AllVersions)
934 | {
935 | if($toggle)
936 | {
937 | $searchResults += $image
938 | }
939 | }
940 |
941 | if($toggle)
942 | {
943 | if($searchDictionary.ContainsKey($fileName))
944 | {
945 | $searchDictionary.Remove($fileName)
946 | }
947 |
948 | $searchDictionary.Add($fileName, $image)
949 | }
950 | }
951 |
952 | if(-not $AllVersions)
953 | {
954 | $searchDictionary.Keys | ForEach-Object {
955 | $searchResults += $searchDictionary.Item($_)
956 | }
957 | }
958 |
959 | $searchEntries = @()
960 |
961 | foreach($searchEntry in $searchResults)
962 | {
963 | $entryName = Split-Path $searchEntry -Leaf
964 | $entryVersion = get-Version $searchEntry
965 | $entryDesc = $entryName
966 | $path = $localPath
967 | $ResultEntry = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
968 | Name = $EntryName
969 | Version = $EntryVersion
970 | Description = $EntryDesc
971 | SasToken = $path
972 | Source = $SourceName
973 | })
974 |
975 | $searchEntries += $ResultEntry
976 | }
977 |
978 | return $searchEntries
979 | }
980 | catch
981 | {
982 | Write-Error "Unable to access the sub-folders of $localPath"
983 | return
984 | }
985 | }
986 |
987 | function Convert-Version([string]$version)
988 | {
989 | if ([string]::IsNullOrWhiteSpace($version))
990 | {
991 | return $null;
992 | }
993 |
994 | # not supporting semver here. let's try to normalize the versions
995 | if ($version.StartsWith("."))
996 | {
997 | # add leading zeros
998 | $version = "0" + $version
999 | }
1000 |
1001 | # let's see how many parts are we given with the version
1002 | $parts = $version.Split(".").Count
1003 |
1004 | # add .0 dependending number of parts since we need 4 parts
1005 | while ($parts -lt 4)
1006 | {
1007 | $version = $version + ".0"
1008 | $parts += 1
1009 | }
1010 |
1011 | [version]$convertedVersion = $null
1012 |
1013 | # try to convert
1014 | if ([version]::TryParse($version, [ref]$convertedVersion))
1015 | {
1016 | return $convertedVersion
1017 | }
1018 |
1019 | return $null;
1020 | }
1021 |
1022 | function IsNanoServer
1023 | {
1024 | if ($script:isNanoServerInitialized)
1025 | {
1026 | return $script:isNanoServer
1027 | }
1028 | else
1029 | {
1030 | $operatingSystem = Get-CimInstance -ClassName win32_operatingsystem
1031 | $systemSKU = $operatingSystem.OperatingSystemSKU
1032 | $script:isNanoServer = ($systemSKU -eq 109) -or ($systemSKU -eq 144) -or ($systemSKU -eq 143)
1033 | $script:isNanoServerInitialized = $true
1034 | return $script:isNanoServer
1035 | }
1036 | }
1037 |
1038 | function Resolve-FwdLink
1039 | {
1040 | param
1041 | (
1042 | [parameter(Mandatory=$false)]
1043 | [System.String]$Uri
1044 | )
1045 |
1046 | Add-Type -AssemblyName System.Net.Http
1047 | $httpClient = New-Object System.Net.Http.HttpClient
1048 | $response = $httpclient.GetAsync($Uri)
1049 | $link = $response.Result.RequestMessage.RequestUri
1050 |
1051 | return $link
1052 | }
1053 |
1054 | function Get-SearchIndex
1055 | {
1056 | param
1057 | (
1058 | [Parameter(Mandatory=$true)]
1059 | [string]
1060 | $fwdLink,
1061 |
1062 | [Parameter(Mandatory=$true)]
1063 | [string]
1064 | $SourceName
1065 | )
1066 |
1067 | $fullUrl = Resolve-FwdLink $fwdLink
1068 | $fullUrl = $fullUrl.AbsoluteUri
1069 | $searchIndex = $SourceName + "_" + $script:ContainerImageSearchIndex
1070 | $destination = Join-Path $script:location_modules $searchIndex
1071 |
1072 | if(-not(Test-Path $script:location_modules))
1073 | {
1074 | md $script:location_modules
1075 | }
1076 |
1077 | if(Test-Path $destination)
1078 | {
1079 | Remove-Item $destination
1080 | DownloadFile -downloadURL $fullUrl `
1081 | -destination $destination
1082 | }
1083 | else
1084 | {
1085 | DownloadFile -downloadURL $fullUrl `
1086 | -destination $destination
1087 | }
1088 |
1089 | return $destination
1090 | }
1091 |
1092 | function DownloadFile
1093 | {
1094 | [CmdletBinding()]
1095 | param($downloadURL, $destination)
1096 |
1097 | try
1098 | {
1099 | # Download the file
1100 | if($downloadURL.StartsWith("http://") -or $downloadURL.StartsWith("https://"))
1101 | {
1102 | if(-not (CheckDiskSpace $destination $downloadURL))
1103 | {
1104 | return
1105 | }
1106 |
1107 | Write-Verbose "Downloading $downloadUrl to $destination"
1108 | $saveItemPath = $PSScriptRoot + "\SaveHTTPItemUsingBITS.psm1"
1109 | Import-Module "$saveItemPath"
1110 | $startTime = Get-Date
1111 | Save-HTTPItemUsingBitsTransfer -Uri $downloadURL `
1112 | -Destination $destination
1113 |
1114 | Write-Verbose "Finished downloading"
1115 | $endTime = Get-Date
1116 | $difference = New-TimeSpan -Start $startTime -End $endTime
1117 | $downloadTime = "Downloaded in " + $difference.Hours + " hours, " + $difference.Minutes + " minutes, " + $difference.Seconds + " seconds."
1118 | Write-Verbose $downloadTime
1119 | }
1120 | elseif($downloadURL.StartsWith("\\"))
1121 | {
1122 | $startTime = Get-Date
1123 | cp $downloadURL $destination
1124 | $endTime = Get-Date
1125 | $difference = New-TimeSpan -Start $startTime -End $endTime
1126 | $downloadTime = "Downloaded in " + $difference.Hours + " hours, " + $difference.Minutes + " minutes, " + $difference.Seconds + " seconds."
1127 | Write-Verbose $downloadTime
1128 | }
1129 | }
1130 | catch
1131 | {
1132 | ThrowError -CallerPSCmdlet $PSCmdlet `
1133 | -ExceptionName $_.Exception.GetType().FullName `
1134 | -ExceptionMessage $_.Exception.Message `
1135 | -ExceptionObject $downloadURL `
1136 | -ErrorId FailedToDownload `
1137 | -ErrorCategory InvalidOperation
1138 | }
1139 | }
1140 |
1141 | function New-SoftwareIdentityFromContainerImageItemInfo
1142 | {
1143 | [Cmdletbinding()]
1144 | param(
1145 | [PSCustomObject]
1146 | $package
1147 | )
1148 |
1149 | $fastPackageReference = $package.Name +
1150 | $separator + $package.version +
1151 | $separator + $package.Description +
1152 | $separator + $package.Source +
1153 | $separator + $package.SasToken
1154 |
1155 | $Name = [System.IO.Path]::GetFileNameWithoutExtension($package.Name)
1156 |
1157 | $params = @{
1158 | FastPackageReference = $fastPackageReference;
1159 | Name = $Name;
1160 | Version = $package.version.ToString();
1161 | versionScheme = "MultiPartNumeric";
1162 | Source = $package.Source;
1163 | Summary = $package.Description;
1164 | }
1165 | New-SoftwareIdentity @params
1166 | }
1167 |
1168 | function get-Version
1169 | {
1170 | param($fullPath)
1171 |
1172 | # Throw error if the given File is folder or doesn't exist
1173 | if((Get-Item $fullPath) -is [System.IO.DirectoryInfo])
1174 | {
1175 | Write-Error "Please enter a file name not a folder."
1176 | throw "$fullPath is a folder not file"
1177 | }
1178 |
1179 | $containerImageInfo = Get-WindowsImage -ImagePath $fullPath -Index 1
1180 | $containerImageVersion = $containerImageInfo.Version
1181 |
1182 | return $containerImageVersion
1183 | }
1184 |
1185 | # Utility to throw an errorrecord
1186 | function ThrowError
1187 | {
1188 | param
1189 | (
1190 | [parameter(Mandatory = $true)]
1191 | [ValidateNotNullOrEmpty()]
1192 | [System.Management.Automation.PSCmdlet]
1193 | $CallerPSCmdlet,
1194 |
1195 | [parameter(Mandatory = $true)]
1196 | [ValidateNotNullOrEmpty()]
1197 | [System.String]
1198 | $ExceptionName,
1199 |
1200 | [parameter(Mandatory = $true)]
1201 | [ValidateNotNullOrEmpty()]
1202 | [System.String]
1203 | $ExceptionMessage,
1204 |
1205 | [System.Object]
1206 | $ExceptionObject,
1207 |
1208 | [parameter(Mandatory = $true)]
1209 | [ValidateNotNullOrEmpty()]
1210 | [System.String]
1211 | $ErrorId,
1212 |
1213 | [parameter(Mandatory = $true)]
1214 | [ValidateNotNull()]
1215 | [System.Management.Automation.ErrorCategory]
1216 | $ErrorCategory
1217 | )
1218 |
1219 | $exception = New-Object $ExceptionName $ExceptionMessage;
1220 | $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $ErrorId, $ErrorCategory, $ExceptionObject
1221 | $CallerPSCmdlet.ThrowTerminatingError($errorRecord)
1222 | }
1223 |
1224 | function DownloadPackageHelper
1225 | {
1226 | [CmdletBinding()]
1227 | param
1228 | (
1229 | [Parameter(Mandatory=$true)]
1230 | [ValidateNotNullOrEmpty()]
1231 | [string]
1232 | $FastPackageReference,
1233 |
1234 | [Parameter()]
1235 | [ValidateNotNullOrEmpty()]
1236 | [string]
1237 | $Location,
1238 |
1239 | [Parameter(Mandatory=$true)]
1240 | [ValidateNotNullOrEmpty()]
1241 | $request
1242 | )
1243 |
1244 | [string[]] $splitterArray = @("$separator")
1245 |
1246 | [string[]] $resultArray = $fastPackageReference.Split($splitterArray, [System.StringSplitOptions]::None)
1247 |
1248 | $name = $resultArray[0]
1249 | $version = $resultArray[1]
1250 | $description = $resultArray[2]
1251 | $source = $resultArray[3]
1252 | $sasToken = $resultArray[4]
1253 |
1254 | if($sasToken.StartsWith("\\"))
1255 | {
1256 | $sasToken = Join-Path $sasToken $name
1257 | }
1258 |
1259 | $options = $request.Options
1260 |
1261 | foreach( $o in $options.Keys )
1262 | {
1263 | Write-Debug ( "OPTION: {0} => {1}" -f ($o, $options[$o]) )
1264 | }
1265 |
1266 | $Force = $false
1267 | if($options.ContainsKey("Force"))
1268 | {
1269 | $Force = $options['Force']
1270 | }
1271 |
1272 | if(-not (Test-Path $Location))
1273 | {
1274 | if($Force)
1275 | {
1276 | Write-Verbose "Creating: $Location as it doesn't exist."
1277 | mkdir $Location
1278 | }
1279 | else
1280 | {
1281 | $errorMessage = ("Cannot find the path '{0}' because it does not exist" -f $Location)
1282 | ThrowError -ExceptionName "System.ArgumentException" `
1283 | -ExceptionMessage $errorMessage `
1284 | -ErrorId "PathNotFound" `
1285 | -CallerPSCmdlet $PSCmdlet `
1286 | -ExceptionObject $Location `
1287 | -ErrorCategory InvalidArgument
1288 | }
1289 | }
1290 |
1291 | $fullPath = GenerateFullPath -Location $Location `
1292 | -Name $name `
1293 | -Version $Version
1294 |
1295 | if(Test-Path $fullPath)
1296 | {
1297 | if($Force)
1298 | {
1299 | $existingFileItem = get-item $fullPath
1300 | if($existingFileItem.isreadonly)
1301 | {
1302 | throw "Cannot remove read-only file $fullPath. Remove read-only and use -Force again."
1303 | }
1304 | else
1305 | {
1306 | Remove-Item $fullPath
1307 | DownloadFile $sasToken $fullPath
1308 | }
1309 | }
1310 | else
1311 | {
1312 | Write-Verbose "$fullPath already exists. Skipping save. Use -Force to overwrite."
1313 | }
1314 | }
1315 | else
1316 | {
1317 | DownloadFile $sasToken $fullPath
1318 | }
1319 |
1320 | $savedWindowsPackageItem = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
1321 | Name = $name
1322 | Version = $version
1323 | Description = $description
1324 | SasToken = $sasToken
1325 | Source = $source
1326 | FullPath = $fullPath
1327 | })
1328 |
1329 | Write-Output (New-SoftwareIdentityFromContainerImageItemInfo $savedWindowsPackageItem)
1330 | }
1331 |
1332 | function GenerateFullPath
1333 | {
1334 | param
1335 | (
1336 | [Parameter(Mandatory=$true)]
1337 | [System.String]
1338 | $Location,
1339 |
1340 | [Parameter(Mandatory=$true)]
1341 | [System.String]
1342 | $Name,
1343 |
1344 | [Parameter(Mandatory=$true)]
1345 | [System.Version]
1346 | $Version
1347 | )
1348 |
1349 | $fileExtension = ".wim"
1350 |
1351 | if($Name.EndsWith($fileExtension))
1352 | {
1353 | $Name = $name.TrimEnd($fileExtension)
1354 | }
1355 |
1356 | $fileName = $name + "-" + $Version.ToString().replace('.','-') + $fileExtension
1357 | $fullPath = Join-Path $Location $fileName
1358 | return $fullPath
1359 | }
1360 |
1361 | function CheckDiskSpace
1362 | {
1363 | param($Destination, $token)
1364 |
1365 | $headers = @{'x-ms-client-request-id'=$(hostname);'x-ms-version'='2015-02-21'}
1366 | $httpresponse = Invoke-HttpClient -FullUri $token `
1367 | -Headers $headers `
1368 | -Method Head `
1369 | -ea SilentlyContinue `
1370 | -ev ev
1371 |
1372 | $contentLength = $httpresponse.Headers.ContentLength
1373 | $parent = Split-Path $Destination -Parent
1374 | $Drive = (Get-Item $parent).PSDrive.Name
1375 | $getDriveSpace = get-ciminstance win32_logicaldisk | Where-Object {$_.DeviceID -match $Drive} | % Freespace
1376 |
1377 | $contentLengthInMB = [math]::Round($contentLength/1mb, 2)
1378 | $driveSpaceInIMB = [math]::Round($getDriveSpace/1mb, 2)
1379 |
1380 | Write-Verbose "Download size: $($contentLengthInMB)MB"
1381 | Write-Verbose "Free space on the drive: $($driveSpaceInIMB)MB"
1382 |
1383 | if($contentLength -ge ($getDriveSpace * 0.95))
1384 | {
1385 | Write-Error "Not enough space to save the file"
1386 | return $false
1387 | }
1388 | return $true
1389 | }
1390 |
1391 | function Invoke-HTTPClient
1392 | {
1393 | param(
1394 | [Uri] $FullUri,
1395 | [Hashtable] $Headers,
1396 | [ValidateSet('Get','Head')]
1397 | [string] $httpMethod,
1398 | [int] $retryCount = 0
1399 | )
1400 |
1401 | Add-Type -AssemblyName System.Net.Http
1402 | do
1403 | {
1404 | $httpClient = [System.Net.Http.HttpClient]::new()
1405 | foreach($headerKey in $Headers.Keys)
1406 | {
1407 | $httpClient.DefaultRequestHeaders.Add($headerKey, $Headers[$headerKey])
1408 | }
1409 |
1410 | $HttpCompletionOption = 'ResponseContentRead'
1411 | if ($httpMethod -eq 'Get')
1412 | {
1413 | $httpRequestMessage = [System.Net.Http.HttpRequestMessage]::new([System.Net.Http.HttpMethod]::Get, $fullUri)
1414 | }
1415 | else
1416 | {
1417 | $httpRequestMessage = [System.Net.Http.HttpRequestMessage]::new([System.Net.Http.HttpMethod]::Head, $fullUri)
1418 | $HttpCompletionOption = 'ResponseHeadersRead'
1419 | }
1420 |
1421 | $result = $httpClient.SendAsync($httpRequestMessage, $HttpCompletionOption)
1422 | $null = $result.AsyncWaitHandle.WaitOne()
1423 |
1424 | if ($result.Result.IsSuccessStatusCode)
1425 | {
1426 | break;
1427 | }
1428 | $retryCount--;
1429 | $msg = 'RetryCount: {0}, Http.GetAsync did not return successful status code. Status Code: {1}, {2}' -f `
1430 | $retryCount, $result.Result.StatusCode, $result.Result.ReasonPhrase
1431 | $msg = $msg + ('Result Reason Phrase: {0}' -f $result.Result.ReasonPhrase)
1432 | } while($retryCount -gt 0)
1433 |
1434 | if (-not $result.Result.IsSuccessStatusCode)
1435 | {
1436 | $msg = 'Http.GetAsync did not return successful status code. Status Code: {0}, {1}' -f `
1437 | $result.Result.StatusCode, $result.Result.ReasonPhrase
1438 | throw $msg
1439 | }
1440 | return $result.Result.Content
1441 | }
1442 |
1443 | #endregion Helper-Functions
1444 |
1445 | #region PackageSource Functions
1446 |
1447 | function Get-Sources
1448 | {
1449 | param($sources)
1450 |
1451 | Set-ModuleSourcesVariable
1452 |
1453 | $listOfSources = @()
1454 |
1455 | foreach($mySource in $script:ContainerSources.Values)
1456 | {
1457 | if((-not $sources) -or
1458 | (($mySource.Name -eq $sources) -or
1459 | ($mySource.SourceLocation -eq $sources)))
1460 | {
1461 | $tempHolder = @{}
1462 |
1463 | $location = $mySource."SourceLocation"
1464 | $tempHolder.Add("SourceLocation", $location)
1465 |
1466 | $packageSourceName = $mySource.Name
1467 | $tempHolder.Add("Name", $packageSourceName)
1468 |
1469 | $listOfSources += $tempHolder
1470 | }
1471 | }
1472 |
1473 | return $listOfSources
1474 | }
1475 |
1476 | function DeSerialize-PSObject
1477 | {
1478 | [CmdletBinding(PositionalBinding=$false)]
1479 | Param
1480 | (
1481 | [Parameter(Mandatory=$true)]
1482 | $Path
1483 | )
1484 | $filecontent = Microsoft.PowerShell.Management\Get-Content -Path $Path
1485 | [System.Management.Automation.PSSerializer]::Deserialize($filecontent)
1486 | }
1487 |
1488 | function Set-ModuleSourcesVariable
1489 | {
1490 | [CmdletBinding()]
1491 | param([switch]$Force)
1492 |
1493 | if(Microsoft.PowerShell.Management\Test-Path $script:file_modules)
1494 | {
1495 | $script:ContainerSources = DeSerialize-PSObject -Path $script:file_modules
1496 | }
1497 | else
1498 | {
1499 | $script:ContainerSources = [ordered]@{}
1500 |
1501 | $defaultModuleSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
1502 | Name = "ContainerImageGallery"
1503 | SourceLocation = "http://go.microsoft.com/fwlink/?LinkID=746630&clcid=0x409"
1504 | Trusted=$false
1505 | Registered= $true
1506 | InstallationPolicy = "Untrusted"
1507 | })
1508 |
1509 | $script:ContainerSources.Add("ContainerImageGallery", $defaultModuleSource)
1510 | Save-ModuleSources
1511 | }
1512 | }
1513 |
1514 | function Save-ModuleSources
1515 | {
1516 | # check if exists
1517 | if(-not (Test-Path $script:location_modules))
1518 | {
1519 | $null = md $script:location_modules
1520 | }
1521 |
1522 | # seralize module
1523 | Microsoft.PowerShell.Utility\Out-File -FilePath $script:file_modules `
1524 | -Force `
1525 | -InputObject ([System.Management.Automation.PSSerializer]::Serialize($script:ContainerSources))
1526 | }
1527 |
1528 | function Get-DynamicOptions
1529 | {
1530 | param
1531 | (
1532 | [Microsoft.PackageManagement.MetaProvider.PowerShell.OptionCategory]
1533 | $category
1534 | )
1535 | }
1536 |
1537 | function Add-PackageSource
1538 | {
1539 | [CmdletBinding()]
1540 | param
1541 | (
1542 | [string]
1543 | $Name,
1544 |
1545 | [string]
1546 | $Location,
1547 |
1548 | [bool]
1549 | $Trusted
1550 | )
1551 |
1552 | Set-ModuleSourcesVariable -Force
1553 |
1554 | $Options = $request.Options
1555 |
1556 | # Add new module source
1557 | $moduleSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
1558 | Name = $Name
1559 | SourceLocation = $Location
1560 | Trusted=$Trusted
1561 | Registered= $true
1562 | InstallationPolicy = if($Trusted) {'Trusted'} else {'Untrusted'}
1563 | })
1564 |
1565 | #TODO: Check if name already exists
1566 | $script:ContainerSources.Add($Name, $moduleSource)
1567 |
1568 | Save-ModuleSources
1569 |
1570 | Write-Output -InputObject (New-PackageSourceFromModuleSource -ModuleSource $moduleSource)
1571 | }
1572 |
1573 | function Remove-PackageSource
1574 | {
1575 | param
1576 | (
1577 | [string]
1578 | $Name
1579 | )
1580 |
1581 | Set-ModuleSourcesVariable -Force
1582 |
1583 | if(-not $script:ContainerSources.Contains($Name))
1584 | {
1585 | Write-Error -Message "Package source $Name not found" `
1586 | -ErrorId "Package source $Name not found" `
1587 | -Category InvalidOperation `
1588 | -TargetObject $Name
1589 | continue
1590 | }
1591 |
1592 | $script:ContainerSources.Remove($Name)
1593 |
1594 | Save-ModuleSources
1595 |
1596 | #Write-Verbose ($LocalizedData.PackageSourceUnregistered -f ($Name))
1597 | }
1598 |
1599 | function Resolve-PackageSource
1600 | {
1601 | Set-ModuleSourcesVariable
1602 | $SourceName = $request.PackageSources
1603 |
1604 | if(-not $SourceName)
1605 | {
1606 | $SourceName = "*"
1607 | }
1608 |
1609 | foreach($moduleSourceName in $SourceName)
1610 | {
1611 | if($request.IsCanceled)
1612 | {
1613 | return
1614 | }
1615 |
1616 | $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $moduleSourceName,$script:wildcardOptions
1617 | $moduleSourceFound = $false
1618 |
1619 | $script:ContainerSources.GetEnumerator() |
1620 | Microsoft.PowerShell.Core\Where-Object {$wildcardPattern.IsMatch($_.Key)} |
1621 | Microsoft.PowerShell.Core\ForEach-Object {
1622 |
1623 | $moduleSource = $script:ContainerSources[$_.Key]
1624 |
1625 | $packageSource = New-PackageSourceFromModuleSource -ModuleSource $moduleSource
1626 |
1627 | Write-Output -InputObject $packageSource
1628 |
1629 | $moduleSourceFound = $true
1630 | }
1631 |
1632 | if(-not $moduleSourceFound)
1633 | {
1634 | $sourceName = Get-SourceName -Location $moduleSourceName
1635 |
1636 | if($sourceName)
1637 | {
1638 | $moduleSource = $script:ContainerSources[$sourceName]
1639 |
1640 | $packageSource = New-PackageSourceFromModuleSource -ModuleSource $moduleSource
1641 |
1642 | Write-Output -InputObject $packageSource
1643 | }
1644 |
1645 | }
1646 | }
1647 | }
1648 |
1649 | function New-PackageSourceFromModuleSource
1650 | {
1651 | param
1652 | (
1653 | [Parameter(Mandatory=$true)]
1654 | $ModuleSource
1655 | )
1656 |
1657 | $packageSourceDetails = @{}
1658 |
1659 | # create a new package source
1660 | $src = New-PackageSource -Name $ModuleSource.Name `
1661 | -Location $ModuleSource.SourceLocation `
1662 | -Trusted $ModuleSource.Trusted `
1663 | -Registered $ModuleSource.Registered `
1664 | -Details $packageSourceDetails
1665 |
1666 | # return the package source object.
1667 | Write-Output -InputObject $src
1668 | }
1669 |
1670 | function Get-SourceName
1671 | {
1672 | [CmdletBinding()]
1673 | [OutputType("string")]
1674 | Param
1675 | (
1676 | [Parameter(Mandatory=$true)]
1677 | [ValidateNotNullOrEmpty()]
1678 | [string]
1679 | $Location
1680 | )
1681 |
1682 | Set-ModuleSourcesVariable
1683 |
1684 | foreach($psModuleSource in $script:ContainerSources.Values)
1685 | {
1686 | if(($psModuleSource.Name -eq $Location) -or
1687 | ($psModuleSource.SourceLocation -eq $Location))
1688 | {
1689 | return $psModuleSource.Name
1690 | }
1691 | }
1692 | }
1693 |
1694 | #endregion PackageSource Functions
1695 |
1696 | #region Export
1697 | Export-ModuleMember -Function Find-Package, `
1698 | Download-Package, `
1699 | Install-Package, `
1700 | #Uninstall-Package, `
1701 | Get-InstalledPackage, `
1702 | Add-PackageSource, `
1703 | Remove-PackageSource, `
1704 | Resolve-PackageSource, `
1705 | Get-DynamicOptions, `
1706 | Initialize-Provider, `
1707 | Get-PackageProviderName, `
1708 | Find-ContainerImage, `
1709 | Save-ContainerImage, `
1710 | Install-ContainerImage
1711 | #endregion Export
1712 |
1713 | # SIG # Begin signature block
1714 | # MIIarwYJKoZIhvcNAQcCoIIaoDCCGpwCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
1715 | # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
1716 | # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUhEyF30SeN3pbXMdwtp6G5j74
1717 | # O1egghWCMIIEwzCCA6ugAwIBAgITMwAAAK9TR3dsG/GjAgAAAAAArzANBgkqhkiG
1718 | # 9w0BAQUFADB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G
1719 | # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw
1720 | # HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwHhcNMTYwNTAzMTcxMzI1
1721 | # WhcNMTcwODAzMTcxMzI1WjCBszELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
1722 | # bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
1723 | # b3JhdGlvbjENMAsGA1UECxMETU9QUjEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNO
1724 | # OjMxQzUtMzBCQS03QzkxMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT
1725 | # ZXJ2aWNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvIU6bFARsNjT
1726 | # YwC3p63ceKHrpHQuCZTbNDUUaayYlNptTs9au9YI+P9IBOKErcKjXkxftzeQaum8
1727 | # 6O7IGQlJPvqr0Cms32bitA6yECmWddujRimd4ULql8Imc452jaG1pjiPfq8uZcTg
1728 | # YHkJ5/AMQ+K2NuGTLEw4//BTmnBMOugRKUuUZcVQZG+E9wot5slnIe1p/VgYpt8D
1729 | # ejA4crXFzAeAXtj4XEY7NdE351GaIET0Y1LeKdWjnwhz2dqjhX2BJE/HDid/HYv3
1730 | # bnrgHBlHfmOTkaB799B8amERbJjNJfqrCKofWxUBWq7R1iStUCFjSSvt+Q/OS2ao
1731 | # YsLXObA2rwIDAQABo4IBCTCCAQUwHQYDVR0OBBYEFGgYUtBYbEj/U4U9IDez4/ZM
1732 | # dPF4MB8GA1UdIwQYMBaAFCM0+NlSRnAK7UD7dvuzK7DDNbMPMFQGA1UdHwRNMEsw
1733 | # SaBHoEWGQ2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3Rz
1734 | # L01pY3Jvc29mdFRpbWVTdGFtcFBDQS5jcmwwWAYIKwYBBQUHAQEETDBKMEgGCCsG
1735 | # AQUFBzAChjxodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY3Jv
1736 | # c29mdFRpbWVTdGFtcFBDQS5jcnQwEwYDVR0lBAwwCgYIKwYBBQUHAwgwDQYJKoZI
1737 | # hvcNAQEFBQADggEBAIz32N/DMfk74OzCmb8uSgdkrVDlMU0+O4OWsClrjoUq0o6w
1738 | # 2qNxSX+nzxxbt7e7paBO+0pyf2m4XaGBLfuZW8lBRC2mR+U5K1wXzZTqy/3v1dIK
1739 | # yngU2cPT1L8yaC5v6FkpDljzBfslTmPvPljhN41uKTifBPqxpO+H41lCVaG/zN6H
1740 | # DovSoSt8jMOh01+9VCUsbccY6J7D9iT3erE1a0FVXy7cn9mDckXaeAOfz8cMJWlc
1741 | # NWqN1J+DjUWpArxwQjVX+gxC1CUx8Z1aA+HSBfbCXaOAtLRni3VUf1Wje/mHZevD
1742 | # fUkM2gKd9TcEu2IN1pDcWnjcSb5KLOPfSOU7Xz8wggTsMIID1KADAgECAhMzAAAB
1743 | # Cix5rtd5e6asAAEAAAEKMA0GCSqGSIb3DQEBBQUAMHkxCzAJBgNVBAYTAlVTMRMw
1744 | # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
1745 | # aWNyb3NvZnQgQ29ycG9yYXRpb24xIzAhBgNVBAMTGk1pY3Jvc29mdCBDb2RlIFNp
1746 | # Z25pbmcgUENBMB4XDTE1MDYwNDE3NDI0NVoXDTE2MDkwNDE3NDI0NVowgYMxCzAJ
1747 | # BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
1748 | # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDTALBgNVBAsTBE1PUFIx
1749 | # HjAcBgNVBAMTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjCCASIwDQYJKoZIhvcNAQEB
1750 | # BQADggEPADCCAQoCggEBAJL8bza74QO5KNZG0aJhuqVG+2MWPi75R9LH7O3HmbEm
1751 | # UXW92swPBhQRpGwZnsBfTVSJ5E1Q2I3NoWGldxOaHKftDXT3p1Z56Cj3U9KxemPg
1752 | # 9ZSXt+zZR/hsPfMliLO8CsUEp458hUh2HGFGqhnEemKLwcI1qvtYb8VjC5NJMIEb
1753 | # e99/fE+0R21feByvtveWE1LvudFNOeVz3khOPBSqlw05zItR4VzRO/COZ+owYKlN
1754 | # Wp1DvdsjusAP10sQnZxN8FGihKrknKc91qPvChhIqPqxTqWYDku/8BTzAMiwSNZb
1755 | # /jjXiREtBbpDAk8iAJYlrX01boRoqyAYOCj+HKIQsaUCAwEAAaOCAWAwggFcMBMG
1756 | # A1UdJQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBSJ/gox6ibN5m3HkZG5lIyiGGE3
1757 | # NDBRBgNVHREESjBIpEYwRDENMAsGA1UECxMETU9QUjEzMDEGA1UEBRMqMzE1OTUr
1758 | # MDQwNzkzNTAtMTZmYS00YzYwLWI2YmYtOWQyYjFjZDA1OTg0MB8GA1UdIwQYMBaA
1759 | # FMsR6MrStBZYAck3LjMWFrlMmgofMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9j
1760 | # cmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY0NvZFNpZ1BDQV8w
1761 | # OC0zMS0yMDEwLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6
1762 | # Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljQ29kU2lnUENBXzA4LTMx
1763 | # LTIwMTAuY3J0MA0GCSqGSIb3DQEBBQUAA4IBAQCmqFOR3zsB/mFdBlrrZvAM2PfZ
1764 | # hNMAUQ4Q0aTRFyjnjDM4K9hDxgOLdeszkvSp4mf9AtulHU5DRV0bSePgTxbwfo/w
1765 | # iBHKgq2k+6apX/WXYMh7xL98m2ntH4LB8c2OeEti9dcNHNdTEtaWUu81vRmOoECT
1766 | # oQqlLRacwkZ0COvb9NilSTZUEhFVA7N7FvtH/vto/MBFXOI/Enkzou+Cxd5AGQfu
1767 | # FcUKm1kFQanQl56BngNb/ErjGi4FrFBHL4z6edgeIPgF+ylrGBT6cgS3C6eaZOwR
1768 | # XU9FSY0pGi370LYJU180lOAWxLnqczXoV+/h6xbDGMcGszvPYYTitkSJlKOGMIIF
1769 | # vDCCA6SgAwIBAgIKYTMmGgAAAAAAMTANBgkqhkiG9w0BAQUFADBfMRMwEQYKCZIm
1770 | # iZPyLGQBGRYDY29tMRkwFwYKCZImiZPyLGQBGRYJbWljcm9zb2Z0MS0wKwYDVQQD
1771 | # EyRNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMTAwODMx
1772 | # MjIxOTMyWhcNMjAwODMxMjIyOTMyWjB5MQswCQYDVQQGEwJVUzETMBEGA1UECBMK
1773 | # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
1774 | # IENvcnBvcmF0aW9uMSMwIQYDVQQDExpNaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBD
1775 | # QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJyWVwZMGS/HZpgICBC
1776 | # mXZTbD4b1m/My/Hqa/6XFhDg3zp0gxq3L6Ay7P/ewkJOI9VyANs1VwqJyq4gSfTw
1777 | # aKxNS42lvXlLcZtHB9r9Jd+ddYjPqnNEf9eB2/O98jakyVxF3K+tPeAoaJcap6Vy
1778 | # c1bxF5Tk/TWUcqDWdl8ed0WDhTgW0HNbBbpnUo2lsmkv2hkL/pJ0KeJ2L1TdFDBZ
1779 | # +NKNYv3LyV9GMVC5JxPkQDDPcikQKCLHN049oDI9kM2hOAaFXE5WgigqBTK3S9dP
1780 | # Y+fSLWLxRT3nrAgA9kahntFbjCZT6HqqSvJGzzc8OJ60d1ylF56NyxGPVjzBrAlf
1781 | # A9MCAwEAAaOCAV4wggFaMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMsR6MrS
1782 | # tBZYAck3LjMWFrlMmgofMAsGA1UdDwQEAwIBhjASBgkrBgEEAYI3FQEEBQIDAQAB
1783 | # MCMGCSsGAQQBgjcVAgQWBBT90TFO0yaKleGYYDuoMW+mPLzYLTAZBgkrBgEEAYI3
1784 | # FAIEDB4KAFMAdQBiAEMAQTAfBgNVHSMEGDAWgBQOrIJgQFYnl+UlE/wq4QpTlVnk
1785 | # pDBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtp
1786 | # L2NybC9wcm9kdWN0cy9taWNyb3NvZnRyb290Y2VydC5jcmwwVAYIKwYBBQUHAQEE
1787 | # SDBGMEQGCCsGAQUFBzAChjhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2Nl
1788 | # cnRzL01pY3Jvc29mdFJvb3RDZXJ0LmNydDANBgkqhkiG9w0BAQUFAAOCAgEAWTk+
1789 | # fyZGr+tvQLEytWrrDi9uqEn361917Uw7LddDrQv+y+ktMaMjzHxQmIAhXaw9L0y6
1790 | # oqhWnONwu7i0+Hm1SXL3PupBf8rhDBdpy6WcIC36C1DEVs0t40rSvHDnqA2iA6VW
1791 | # 4LiKS1fylUKc8fPv7uOGHzQ8uFaa8FMjhSqkghyT4pQHHfLiTviMocroE6WRTsgb
1792 | # 0o9ylSpxbZsa+BzwU9ZnzCL/XB3Nooy9J7J5Y1ZEolHN+emjWFbdmwJFRC9f9Nqu
1793 | # 1IIybvyklRPk62nnqaIsvsgrEA5ljpnb9aL6EiYJZTiU8XofSrvR4Vbo0HiWGFzJ
1794 | # NRZf3ZMdSY4tvq00RBzuEBUaAF3dNVshzpjHCe6FDoxPbQ4TTj18KUicctHzbMrB
1795 | # 7HCjV5JXfZSNoBtIA1r3z6NnCnSlNu0tLxfI5nI3EvRvsTxngvlSso0zFmUeDord
1796 | # EN5k9G/ORtTTF+l5xAS00/ss3x+KnqwK+xMnQK3k+eGpf0a7B2BHZWBATrBC7E7t
1797 | # s3Z52Ao0CW0cgDEf4g5U3eWh++VHEK1kmP9QFi58vwUheuKVQSdpw5OPlcmN2Jsh
1798 | # rg1cnPCiroZogwxqLbt2awAdlq3yFnv2FoMkuYjPaqhHMS+a3ONxPdcAfmJH0c6I
1799 | # ybgY+g5yjcGjPa8CQGr/aZuW4hCoELQ3UAjWwz0wggYHMIID76ADAgECAgphFmg0
1800 | # AAAAAAAcMA0GCSqGSIb3DQEBBQUAMF8xEzARBgoJkiaJk/IsZAEZFgNjb20xGTAX
1801 | # BgoJkiaJk/IsZAEZFgltaWNyb3NvZnQxLTArBgNVBAMTJE1pY3Jvc29mdCBSb290
1802 | # IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0wNzA0MDMxMjUzMDlaFw0yMTA0MDMx
1803 | # MzAzMDlaMHcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
1804 | # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xITAf
1805 | # BgNVBAMTGE1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQTCCASIwDQYJKoZIhvcNAQEB
1806 | # BQADggEPADCCAQoCggEBAJ+hbLHf20iSKnxrLhnhveLjxZlRI1Ctzt0YTiQP7tGn
1807 | # 0UytdDAgEesH1VSVFUmUG0KSrphcMCbaAGvoe73siQcP9w4EmPCJzB/LMySHnfL0
1808 | # Zxws/HvniB3q506jocEjU8qN+kXPCdBer9CwQgSi+aZsk2fXKNxGU7CG0OUoRi4n
1809 | # rIZPVVIM5AMs+2qQkDBuh/NZMJ36ftaXs+ghl3740hPzCLdTbVK0RZCfSABKR2YR
1810 | # JylmqJfk0waBSqL5hKcRRxQJgp+E7VV4/gGaHVAIhQAQMEbtt94jRrvELVSfrx54
1811 | # QTF3zJvfO4OToWECtR0Nsfz3m7IBziJLVP/5BcPCIAsCAwEAAaOCAaswggGnMA8G
1812 | # A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFCM0+NlSRnAK7UD7dvuzK7DDNbMPMAsG
1813 | # A1UdDwQEAwIBhjAQBgkrBgEEAYI3FQEEAwIBADCBmAYDVR0jBIGQMIGNgBQOrIJg
1814 | # QFYnl+UlE/wq4QpTlVnkpKFjpGEwXzETMBEGCgmSJomT8ixkARkWA2NvbTEZMBcG
1815 | # CgmSJomT8ixkARkWCW1pY3Jvc29mdDEtMCsGA1UEAxMkTWljcm9zb2Z0IFJvb3Qg
1816 | # Q2VydGlmaWNhdGUgQXV0aG9yaXR5ghB5rRahSqClrUxzWPQHEy5lMFAGA1UdHwRJ
1817 | # MEcwRaBDoEGGP2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1
1818 | # Y3RzL21pY3Jvc29mdHJvb3RjZXJ0LmNybDBUBggrBgEFBQcBAQRIMEYwRAYIKwYB
1819 | # BQUHMAKGOGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljcm9z
1820 | # b2Z0Um9vdENlcnQuY3J0MBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0GCSqGSIb3DQEB
1821 | # BQUAA4ICAQAQl4rDXANENt3ptK132855UU0BsS50cVttDBOrzr57j7gu1BKijG1i
1822 | # uFcCy04gE1CZ3XpA4le7r1iaHOEdAYasu3jyi9DsOwHu4r6PCgXIjUji8FMV3U+r
1823 | # kuTnjWrVgMHmlPIGL4UD6ZEqJCJw+/b85HiZLg33B+JwvBhOnY5rCnKVuKE5nGct
1824 | # xVEO6mJcPxaYiyA/4gcaMvnMMUp2MT0rcgvI6nA9/4UKE9/CCmGO8Ne4F+tOi3/F
1825 | # NSteo7/rvH0LQnvUU3Ih7jDKu3hlXFsBFwoUDtLaFJj1PLlmWLMtL+f5hYbMUVbo
1826 | # nXCUbKw5TNT2eb+qGHpiKe+imyk0BncaYsk9Hm0fgvALxyy7z0Oz5fnsfbXjpKh0
1827 | # NbhOxXEjEiZ2CzxSjHFaRkMUvLOzsE1nyJ9C/4B5IYCeFTBm6EISXhrIniIh0EPp
1828 | # K+m79EjMLNTYMoBMJipIJF9a6lbvpt6Znco6b72BJ3QGEe52Ib+bgsEnVLaxaj2J
1829 | # oXZhtG6hE6a/qkfwEm/9ijJssv7fUciMI8lmvZ0dhxJkAj0tr1mPuOQh5bWwymO0
1830 | # eFQF1EEuUKyUsKV4q7OglnUa2ZKHE3UiLzKoCG6gW4wlv6DvhMoh1useT8ma7kng
1831 | # 9wFlb4kLfchpyOZu6qeXzjEp/w7FW1zYTRuh2Povnj8uVRZryROj/TGCBJcwggST
1832 | # AgEBMIGQMHkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
1833 | # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xIzAh
1834 | # BgNVBAMTGk1pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBAhMzAAABCix5rtd5e6as
1835 | # AAEAAAEKMAkGBSsOAwIaBQCggbAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
1836 | # HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFCnf
1837 | # 8gNYPWZpakYnLulOVI6tN7xxMFAGCisGAQQBgjcCAQwxQjBAoBaAFABQAG8AdwBl
1838 | # AHIAUwBoAGUAbABsoSaAJGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9Qb3dlclNo
1839 | # ZWxsIDANBgkqhkiG9w0BAQEFAASCAQBXJZUTztaRAvpsN06XjraLCv3S5sNZaJHS
1840 | # Yu/AAy1Es98KXGMibNFdM3IPvQEiVrYKSQKMwNOZU0oeFOehDgiV1JdNNKB6so7i
1841 | # 6Z9PQwlUghF6Blx9F8aJS8prFzqgqjzS6k5Q30jyJXexty4stjr6MU4R8WHWxyyG
1842 | # 8zYMskSG647VIaCrFe7m4oEjoAuzWYwyO3QMBL9daq3RgF7sfT92Zaxkx5FPMcqa
1843 | # oSZai6YtjtdYrH/3qQb1o1O54yTGBvFGIRsfcNAi5JtIGPADYyXCWmqfsjckpk7n
1844 | # dx3HzQVfQO0UTiqcAFieYoglOTZQW222aYWzawEVbWvD1sv3qxsFoYICKDCCAiQG
1845 | # CSqGSIb3DQEJBjGCAhUwggIRAgEBMIGOMHcxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
1846 | # EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
1847 | # ZnQgQ29ycG9yYXRpb24xITAfBgNVBAMTGE1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD
1848 | # QQITMwAAAK9TR3dsG/GjAgAAAAAArzAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkD
1849 | # MQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTYwNjI4MTY1MzQ4WjAjBgkq
1850 | # hkiG9w0BCQQxFgQU6t6JulCaS0YjAEOQxaa0DvpMZ/AwDQYJKoZIhvcNAQEFBQAE
1851 | # ggEApEkTkl859ZLFfXAZPsxkyDdbKfpRclUFLOactrY2L5EfPmKL185mP8ZzcA/p
1852 | # lk0YKR4Dh513q7dLG/lPx2sKTh9mbOToK4qz6eeJV//Np9/+m4GJnRwydBS5JMSq
1853 | # t6f5NItj/sYV1/sMq9McfL8UhAtUzXWnEsiparth4MXEVTmRa+8EsaTn2TM0nxid
1854 | # Jg2P7V/lv6F7s2yjONAtg3kt+uGLM1ilhlClCuyOppkqLGU0oMC75yz6WCyaR2cG
1855 | # FeulvLI4Nm4BH/xSUv0SeeRJN7EUc8dDMHgQxkTox+ErgIxvuWuF0Y5k1O6weq6G
1856 | # l63xIr1phQ8YfWuubOSVPdVTsg==
1857 | # SIG # End signature block
1858 |
--------------------------------------------------------------------------------
/Json.coreclr.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PowerShell/ContainerProvider/266585a3de90c214276ec81dffbe89c9b050f62d/Json.coreclr.dll
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 |
4 | Copyright (c) 2015 Microsoft Corporation.
5 |
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### Introduction
2 | #### Install a Container image from the online Package repository
3 |
4 | The Container OS images for Nano Server and Windows Server Core are now available in an online package repository. They can be found and installed using the ContainerImage provider of PackageManagement (a.k.a. OneGet) PowerShell module. The provider needs to be installed before using it. The following PowerShell cmdlets can be used to install the provider.
5 | * Install-PackageProvider ContainerImage
6 | * Import-ContainerImage ContainerImage
7 |
8 | Once the provider is installed and imported, you can search, download, or install Container images using PowerShell cmdlets. There are two sets of cmdlets, the first set is specific for the Container OS images, including:
9 | * Find-ContainerImage
10 | * Save-ContainerImage
11 | * Install-ContainerImage
12 |
13 | The 2nd set is generic PackageManagement cmdlets, including:
14 | * Find-Package
15 | * Save-Package
16 | * Get-Package
17 |
18 | The 2nd set of cmdlets are performed the same as the 1st set, with specifying –provider ContainerImage. Without specifying the –provider parameter, it may perform slightly slower as PackageManagement will iterate all its providers. Below is the detailed usage. For a complete usage of the cmdlets, use get-help . For the general usage of the Containers, read the container MSDN doc.
19 |
20 | #### Search a Container Image
21 | Both Find-ContainerImage and Find-Package search and return a list of Container images available in the online repository.
22 |
23 | ##### Example 1: Find the latest version of all available Container images.
24 | Find-ContainerImage
25 | Find-Package –provider ContainerImage
26 |
27 | ##### Example 2: Search by the image name. The –name parameter accepts wildcard.
28 | Find-ContainerImage -Name *nano*
29 | Find-Package –provider ContainerImage -Name *nano *
30 |
31 | ##### Example 3: Search by version, according to –RequiredVersion, -MinimumVersion, and –MaximumVersion requirements. With –AllVersions parameter, all available versions of a Container image are returned. Without it, only the latest version is returned.
32 | Find-ContainerImage -Name *nano* -RequiredVersion 10.0.14300.1000
33 | Find-Package –provider ContainerImage –AllVersions -Name *nano*
34 |
35 | #### Install a Container
36 | Install-ContainerImage installs a Container image to the local machine. Both cmdlets accept pipeline result from search cmdlets. The operating system:
37 | 1.must have the Containers Package (i.e. Microsoft-NanoServer-Containers-Package Windows package) installed
38 | 2.version must match the version of Container OS image, i.e. 10.0.14300.1000
39 | Otherwise, the installation will fail.
40 |
41 | ##### Example 1: Install the latest version of a Container image to the local machine.
42 | Install-ContainerImage -Name NanoServer
43 |
44 | ##### Example 2: Install a Container image with pipeline result from the search cmdlets.
45 | Find-ContainerImage *nano* | Install-ContainerImage
46 | Find-ContainerImage -Name *windowsServercore * |Install-ContainerImage
47 |
48 | #### Download a Container image
49 | You can download and save a Container image without installation, using Save-ContainerImage or Save-Package. Both cmdlets accept pipeline result from the search cmdlets.
50 |
51 | ##### Example 1: Download and save a Container image to a directory that matches the wildcard path. The latest version will be saved if you do not specify the version requirements.
52 | Save-ContainerImage -Name NanoServer -Path C:\t*p\
53 | Save-Package –provider ContainerImage -Name WindowsServerCore -Path .\temp -MinimumVersion 10.0.14300.1000
54 |
55 | ##### Example 2: Download and save a ContainerImage from the search cmdlets.
56 | Find-ContainerImage -Name *nano* -MaximumVersion 10.2 -MinimumVersion 1.0 | Save-ContainerImage -Path c:\
57 | Find-Package -provider ContainerImage -Name *shield* -Culture es-es | Save-Package -Path .
58 |
59 | #### Inventory installed Container images
60 | You can inventory what Container images are installed, using PackageManagement Get-Package cmdlet.
61 |
62 | ##### Example 1: Inventory what Container images are installed in the local machine.
63 | Get-Package –provider ContainerImage
64 |
65 | ### ContainerImage cmdlets
66 | - Find-ContainerImage [[-Name] ] [-MinimumVersion ] [-MaximumVersion ] [-RequiredVersion ] [-AllVersions] [-source ] []
67 | - Save-ContainerImage [-Name] -Path [-MinimumVersion ] [-MaximumVersion ] [-RequiredVersion ] [-Force] [-source ] [-WhatIf] [-Confirm] []
68 | - Save-ContainerImage [-Name] -LiteralPath [-MinimumVersion ] [-MaximumVersion ] [-RequiredVersion ] [-Force] [-source ] [-WhatIf] [-Confirm] []
69 | - Install-ContainerImage [-Force] [-Source ] [-WhatIf] [-Confirm] []
70 | - Install-ContainerImage [-Name] [-MinimumVersion ] [-MaximumVersion ] [-RequiredVersion ] [-Force] [-Source ] [-WhatIf] [-Confirm] []
71 |
72 | ### More examples
73 | #Finds the container image from an online gallery that match specified criteria. It can also search from other registered sources.
74 | # Find the latest version of all available container images
75 | Find-ContainerImage
76 |
77 | # Find thethe latest version of container image with the given name
78 | -Find-ContainerImage -Name ImageName
79 |
80 | # Find the latest version of all available container images that do not have version less than the given version
81 | -Find-ContainerImage -MinimumVersion Version
82 |
83 | # Find the latest version of all available container images that do not have version more than the given version
84 | -Find-ContainerImage -MaximumVersion Version
85 |
86 | # Find the latest version of all available container images that have the given version
87 | -Find-ContainerImage -RequiredVersion Version
88 |
89 | # Find the latest version of all versions of all available container images
90 | -Find-ContainerImage –AllVersions
91 |
92 | #Saves a container image without installing it. 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.
93 |
94 | # Save the latest version of the given name to the directory that matches the wildcard Path
95 | -Save-ContainerImage -Name ImageName -Path C:\t*p\
96 |
97 | # Save the latest version of the given name to the directory that matches the LiteralPath
98 | -Save-ContainerImage -Name ImageName -LiteralPath C:\temp\
99 |
100 | # Save the latest version no less than the minimum version of the given name to the relative directory given by Path
101 | -Save -ContainerImage -Name ImageName -MinimumVersion Version -Path .\..\
102 |
103 | # Save the latest version no more than the maximum version of the given name to the directory that matches the LiteralPath
104 | -Save-ContainerImage -Name ImageName -MaximumVersion Version -LiteralPath C:\temp\
105 |
106 | # Save the given version of the given name to the directory that matches the Path
107 | -Save-ContainerImage -Name ImageName -RequiredVersion Version -Path C:\t*p\
108 |
109 | # Save the given version of the given name to the directory that matches the Path of the default Source
110 | -Save-ContainerImage -Name ImageName -RequiredVersion Version -Path C:\t*p\ -Source ContainerImageGallery
111 |
112 | # All results of the find will be saved in the given LiteralPath
113 | -Find-ContainerImage -Name ImageName | Save-ContainerImage -LiteralPath C:\temp\
114 |
115 | #Downloads the image from the cloud and installs them on the local computer. The Install-ContainerImage gets the container image that meets the specified cirteria from the cloud. It saves the image locally and then installs it.
116 |
117 | # Installing the latest version of the given name to the local machine
118 | -Install-ContainerImage -Name ImageName
119 |
120 | # Installing the latest version of the given name from ContainerImageGallery to the local machine
121 | -Install-ContainerImage -Name ImageName -Source ContainerImageGallery
122 |
123 | # Installing the latest version greater the given version of the given name to the local machine
124 | -Install-ContainerImage -Name ImageName -MinimumVersion Version
125 |
126 | # Installing the latest version less than or equal to the given version of the given name to the local machine
127 | -Install-ContainerImage -Name ImageName -MaximumVersion Version
128 |
129 | # Installing the given version of the given name to the local machine
130 | -Install-ContainerImage -Name ImageName -RequiredVersion Version
131 |
132 | # Install all the results of find
133 | -Find-ContainerImage -Name ImageName | Install-ContainerImage
134 |
135 | ### Version
136 | 0.6.5.0
137 |
138 | ### Version History
139 |
140 | #### 0.5.2
141 | Initial public release for ContainerProvider
142 |
143 | #### 0.5.3
144 | Adding capacity to handle folders on share
145 |
146 | #### 0.6.4.0
147 | #####Revamped the provider:
148 | ######1. Renamed to ContainerImage
149 | ######2. Abides by all OneGet Provider Rules
150 | ######3. Updated the parameter Destination to Path/LiteralPath
151 | ######4. Can handle folders on share
152 | ######5. Fixed the issue of downloading large installer on Nano and remoting via BITS
153 | ######6. This version needs the Windows Server 2016 Technical Preview 5 operating system, otherwise the commands will fail
154 |
155 | ### 0.6.4.1
156 | Fixed the issue of loading System assemblies
157 |
158 | ### Dependencies
159 | This module has no dependencies
--------------------------------------------------------------------------------
/SaveHTTPItemUsingBITS.psm1:
--------------------------------------------------------------------------------
1 | function Save-HTTPItemUsingBitsTransfer
2 | {
3 | [CmdletBinding()]
4 | param(
5 | [Parameter(Mandatory=$true)]
6 | $Uri,
7 | [Parameter(Mandatory=$true)]
8 | $Destination
9 | )
10 |
11 | begin
12 | {
13 | $fullUri = [Uri]$Uri
14 | if (($fullUri.Scheme -ne 'http') -and ($fullUri.Scheme -ne 'https'))
15 | {
16 | throw "Uri: $uri is not supported. Only http or https schema are supported."
17 | }
18 | }
19 |
20 | end
21 | {
22 | $jstate = $null
23 | [bool] $isTransferCompleted = $false
24 | try
25 | {
26 | $mycurrentPath = $script:MyInvocation.MyCommand.Path
27 | $myCurrentDirectory = Split-Path $mycurrentPath
28 | $bitsCommandPath = join-path $myCurrentDirectory "BitsOnNano.exe"
29 | $jobNameTemp = "SH{0}" -f (get-date).Ticks
30 | $output = & $bitsCommandPath -Start-Transfer -DisplayName $jobNameTemp -Source $Uri -Destination $Destination
31 | $le = $lastexitcode
32 | $id = Write-Progress -ParentId 0 -Activity "Downloading from $Uri"
33 |
34 | if ($id -eq $null) {
35 | $id = 1
36 | }
37 |
38 | do
39 | {
40 | $jname,$jid,$jstate,$jbytesTransferred,$jbytesTotal,$null = $output -split ":"
41 |
42 | if ( (@("BG_JOB_STATE_ERROR", "BG_JOB_STATE_TRANSIENT_ERROR", "BG_JOB_STATE_CANCELLED") -contains $jstate) -or ($le))
43 | {
44 | & $bitsCommandPath -Stop-Transfer -ID $jid | Out-Null
45 |
46 | throw "Save-HTTPItem: Bits Transfer failed. Job State: $jstate ExitCode = $le"
47 | }
48 |
49 | if (@("BG_JOB_STATE_TRANSFERRING") -contains $jstate)
50 | {
51 | $percentComplete = ($jbytesTransferred / $jbytesTotal) * 100
52 | $status = "Downloaded {0}MB of total {1}MB" -f ($jbytesTransferred/1mb),($jbytesTotal/1mb)
53 | $null = Write-Progress -Activity "Downloading from $Uri" -PercentComplete $percentComplete -Id $id
54 | }
55 | elseif (@("BG_JOB_STATE_TRANSFERRED") -contains $jstate)
56 | {
57 | & $bitsCommandPath -Remove-Transfer -ID $jid | Out-Null
58 | $isTransferCompleted = $true
59 | break;
60 | }
61 | elseif (@("BG_JOB_STATE_QUEUED") -contains $jstate)
62 | {
63 | $null = Write-Progress -Activity "QUEUED" -PercentComplete 0 -Id $id
64 | }
65 | elseif (@("BG_JOB_STATE_CONNECTING") -contains $jstate)
66 | {
67 | $null = Write-Progress -Activity "CONNECTING" -PercentComplete 0 -Id $id
68 | }
69 | elseif (@("BG_JOB_STATE_ACKNOWLEDGED") -contains $jstate)
70 | {
71 | $null = Write-Progress -Activity "ACKNOWLEDGED" -PercentComplete 0 -Id $id
72 | }
73 |
74 | Start-Sleep -Seconds 1
75 | $output = & $bitsCommandPath -Get-TransferStatus -ID $jid
76 | $le = $lastExitCode
77 | }while($true);
78 | }
79 | finally
80 | {
81 | #"Calling finally: jstate:$jstate isTC:$isTransferCompleted"
82 | $null = Write-Progress -Completed -Activity "Downloading from $Uri" -Id $id
83 |
84 | if ((-not $jstate) -and (-not $isTransferCompleted))
85 | {
86 | "CleanUp:"
87 | & $bitsCommandPath -Stop-Transfer -ID $jid | Out-Null
88 | }
89 | }
90 | }
91 | }
92 |
93 | # SIG # Begin signature block
94 | # MIIarwYJKoZIhvcNAQcCoIIaoDCCGpwCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
95 | # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
96 | # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQULpdn3qSmV6PT6964rUllsXvf
97 | # eSSgghWCMIIEwzCCA6ugAwIBAgITMwAAAJb6gDHvN2RGRQAAAAAAljANBgkqhkiG
98 | # 9w0BAQUFADB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G
99 | # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw
100 | # HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwHhcNMTUxMDA3MTgxNDI0
101 | # WhcNMTcwMTA3MTgxNDI0WjCBszELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
102 | # bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
103 | # b3JhdGlvbjENMAsGA1UECxMETU9QUjEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNO
104 | # OkJCRUMtMzBDQS0yREJFMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT
105 | # ZXJ2aWNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm1pYSwjyVGa6
106 | # tIZe8M6+zXQQ33WKYIyKYcI3oiZcZgVcxdizVjv3hKmjqmRTC5REuLtaSYbdeCuG
107 | # bdMP2+NGWrqeWKLQIxb/Gs/BkEzrr+ewnZ+UQ7xON8jkhPhMSdT5ZiVVNdhVgo+y
108 | # 3hvrk0tk4iDpr5Xwqk5U2W5yZkXras/mIIfO54mjfS31tKQbIsxxubm8Np9ioBit
109 | # boqgiC1iwSxGh7/LGPp1NJVacuQc1JMuzkhRNXxwALbWbyrsUV8Aztz5eaUASLoF
110 | # jkK43ety0X/rV9Qlws43Q2LjKhztpEaxloEr0gioCAEmkJssDjd1qqCZ6X/bht1e
111 | # ggluXnz2tQIDAQABo4IBCTCCAQUwHQYDVR0OBBYEFMfD/XvxW9NCtvwEw94qmvuS
112 | # ht7IMB8GA1UdIwQYMBaAFCM0+NlSRnAK7UD7dvuzK7DDNbMPMFQGA1UdHwRNMEsw
113 | # SaBHoEWGQ2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3Rz
114 | # L01pY3Jvc29mdFRpbWVTdGFtcFBDQS5jcmwwWAYIKwYBBQUHAQEETDBKMEgGCCsG
115 | # AQUFBzAChjxodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY3Jv
116 | # c29mdFRpbWVTdGFtcFBDQS5jcnQwEwYDVR0lBAwwCgYIKwYBBQUHAwgwDQYJKoZI
117 | # hvcNAQEFBQADggEBADQzONHGQV0X/NPCsvaZQv26Syn1rUGW85E9wUCgtf0iWG55
118 | # ntOcHryYkkVIkjB/vd9ixfzGlW2Bz08YdPHJc5he9ZNkfwhjHqW9r6ii06pa4kzE
119 | # PbgYlLwVRRvxzJwLZpSe56UceM8FmEnsRUSVKzabhLjmiIAFpnNlGgYd6g0eDvxT
120 | # FM9SOJozV4Mjyb7e+Gv//ZxUeZcTK2S/Nam+B6m/mlRVajUYotCDwziVxrm1irMt
121 | # a15M55pT3aawt+QrwXaRUMRSRmIgXTHgFWdM3AksQGA0a77rRKGYldX0iPyH2XOw
122 | # rTHQww9kEcX1r+2R+9QjmsljYc3ZPGnA+2YCADEwggTsMIID1KADAgECAhMzAAAB
123 | # Cix5rtd5e6asAAEAAAEKMA0GCSqGSIb3DQEBBQUAMHkxCzAJBgNVBAYTAlVTMRMw
124 | # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
125 | # aWNyb3NvZnQgQ29ycG9yYXRpb24xIzAhBgNVBAMTGk1pY3Jvc29mdCBDb2RlIFNp
126 | # Z25pbmcgUENBMB4XDTE1MDYwNDE3NDI0NVoXDTE2MDkwNDE3NDI0NVowgYMxCzAJ
127 | # BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
128 | # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDTALBgNVBAsTBE1PUFIx
129 | # HjAcBgNVBAMTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjCCASIwDQYJKoZIhvcNAQEB
130 | # BQADggEPADCCAQoCggEBAJL8bza74QO5KNZG0aJhuqVG+2MWPi75R9LH7O3HmbEm
131 | # UXW92swPBhQRpGwZnsBfTVSJ5E1Q2I3NoWGldxOaHKftDXT3p1Z56Cj3U9KxemPg
132 | # 9ZSXt+zZR/hsPfMliLO8CsUEp458hUh2HGFGqhnEemKLwcI1qvtYb8VjC5NJMIEb
133 | # e99/fE+0R21feByvtveWE1LvudFNOeVz3khOPBSqlw05zItR4VzRO/COZ+owYKlN
134 | # Wp1DvdsjusAP10sQnZxN8FGihKrknKc91qPvChhIqPqxTqWYDku/8BTzAMiwSNZb
135 | # /jjXiREtBbpDAk8iAJYlrX01boRoqyAYOCj+HKIQsaUCAwEAAaOCAWAwggFcMBMG
136 | # A1UdJQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBSJ/gox6ibN5m3HkZG5lIyiGGE3
137 | # NDBRBgNVHREESjBIpEYwRDENMAsGA1UECxMETU9QUjEzMDEGA1UEBRMqMzE1OTUr
138 | # MDQwNzkzNTAtMTZmYS00YzYwLWI2YmYtOWQyYjFjZDA1OTg0MB8GA1UdIwQYMBaA
139 | # FMsR6MrStBZYAck3LjMWFrlMmgofMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9j
140 | # cmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY0NvZFNpZ1BDQV8w
141 | # OC0zMS0yMDEwLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6
142 | # Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljQ29kU2lnUENBXzA4LTMx
143 | # LTIwMTAuY3J0MA0GCSqGSIb3DQEBBQUAA4IBAQCmqFOR3zsB/mFdBlrrZvAM2PfZ
144 | # hNMAUQ4Q0aTRFyjnjDM4K9hDxgOLdeszkvSp4mf9AtulHU5DRV0bSePgTxbwfo/w
145 | # iBHKgq2k+6apX/WXYMh7xL98m2ntH4LB8c2OeEti9dcNHNdTEtaWUu81vRmOoECT
146 | # oQqlLRacwkZ0COvb9NilSTZUEhFVA7N7FvtH/vto/MBFXOI/Enkzou+Cxd5AGQfu
147 | # FcUKm1kFQanQl56BngNb/ErjGi4FrFBHL4z6edgeIPgF+ylrGBT6cgS3C6eaZOwR
148 | # XU9FSY0pGi370LYJU180lOAWxLnqczXoV+/h6xbDGMcGszvPYYTitkSJlKOGMIIF
149 | # vDCCA6SgAwIBAgIKYTMmGgAAAAAAMTANBgkqhkiG9w0BAQUFADBfMRMwEQYKCZIm
150 | # iZPyLGQBGRYDY29tMRkwFwYKCZImiZPyLGQBGRYJbWljcm9zb2Z0MS0wKwYDVQQD
151 | # EyRNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMTAwODMx
152 | # MjIxOTMyWhcNMjAwODMxMjIyOTMyWjB5MQswCQYDVQQGEwJVUzETMBEGA1UECBMK
153 | # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
154 | # IENvcnBvcmF0aW9uMSMwIQYDVQQDExpNaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBD
155 | # QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJyWVwZMGS/HZpgICBC
156 | # mXZTbD4b1m/My/Hqa/6XFhDg3zp0gxq3L6Ay7P/ewkJOI9VyANs1VwqJyq4gSfTw
157 | # aKxNS42lvXlLcZtHB9r9Jd+ddYjPqnNEf9eB2/O98jakyVxF3K+tPeAoaJcap6Vy
158 | # c1bxF5Tk/TWUcqDWdl8ed0WDhTgW0HNbBbpnUo2lsmkv2hkL/pJ0KeJ2L1TdFDBZ
159 | # +NKNYv3LyV9GMVC5JxPkQDDPcikQKCLHN049oDI9kM2hOAaFXE5WgigqBTK3S9dP
160 | # Y+fSLWLxRT3nrAgA9kahntFbjCZT6HqqSvJGzzc8OJ60d1ylF56NyxGPVjzBrAlf
161 | # A9MCAwEAAaOCAV4wggFaMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMsR6MrS
162 | # tBZYAck3LjMWFrlMmgofMAsGA1UdDwQEAwIBhjASBgkrBgEEAYI3FQEEBQIDAQAB
163 | # MCMGCSsGAQQBgjcVAgQWBBT90TFO0yaKleGYYDuoMW+mPLzYLTAZBgkrBgEEAYI3
164 | # FAIEDB4KAFMAdQBiAEMAQTAfBgNVHSMEGDAWgBQOrIJgQFYnl+UlE/wq4QpTlVnk
165 | # pDBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtp
166 | # L2NybC9wcm9kdWN0cy9taWNyb3NvZnRyb290Y2VydC5jcmwwVAYIKwYBBQUHAQEE
167 | # SDBGMEQGCCsGAQUFBzAChjhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2Nl
168 | # cnRzL01pY3Jvc29mdFJvb3RDZXJ0LmNydDANBgkqhkiG9w0BAQUFAAOCAgEAWTk+
169 | # fyZGr+tvQLEytWrrDi9uqEn361917Uw7LddDrQv+y+ktMaMjzHxQmIAhXaw9L0y6
170 | # oqhWnONwu7i0+Hm1SXL3PupBf8rhDBdpy6WcIC36C1DEVs0t40rSvHDnqA2iA6VW
171 | # 4LiKS1fylUKc8fPv7uOGHzQ8uFaa8FMjhSqkghyT4pQHHfLiTviMocroE6WRTsgb
172 | # 0o9ylSpxbZsa+BzwU9ZnzCL/XB3Nooy9J7J5Y1ZEolHN+emjWFbdmwJFRC9f9Nqu
173 | # 1IIybvyklRPk62nnqaIsvsgrEA5ljpnb9aL6EiYJZTiU8XofSrvR4Vbo0HiWGFzJ
174 | # NRZf3ZMdSY4tvq00RBzuEBUaAF3dNVshzpjHCe6FDoxPbQ4TTj18KUicctHzbMrB
175 | # 7HCjV5JXfZSNoBtIA1r3z6NnCnSlNu0tLxfI5nI3EvRvsTxngvlSso0zFmUeDord
176 | # EN5k9G/ORtTTF+l5xAS00/ss3x+KnqwK+xMnQK3k+eGpf0a7B2BHZWBATrBC7E7t
177 | # s3Z52Ao0CW0cgDEf4g5U3eWh++VHEK1kmP9QFi58vwUheuKVQSdpw5OPlcmN2Jsh
178 | # rg1cnPCiroZogwxqLbt2awAdlq3yFnv2FoMkuYjPaqhHMS+a3ONxPdcAfmJH0c6I
179 | # ybgY+g5yjcGjPa8CQGr/aZuW4hCoELQ3UAjWwz0wggYHMIID76ADAgECAgphFmg0
180 | # AAAAAAAcMA0GCSqGSIb3DQEBBQUAMF8xEzARBgoJkiaJk/IsZAEZFgNjb20xGTAX
181 | # BgoJkiaJk/IsZAEZFgltaWNyb3NvZnQxLTArBgNVBAMTJE1pY3Jvc29mdCBSb290
182 | # IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0wNzA0MDMxMjUzMDlaFw0yMTA0MDMx
183 | # MzAzMDlaMHcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
184 | # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xITAf
185 | # BgNVBAMTGE1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQTCCASIwDQYJKoZIhvcNAQEB
186 | # BQADggEPADCCAQoCggEBAJ+hbLHf20iSKnxrLhnhveLjxZlRI1Ctzt0YTiQP7tGn
187 | # 0UytdDAgEesH1VSVFUmUG0KSrphcMCbaAGvoe73siQcP9w4EmPCJzB/LMySHnfL0
188 | # Zxws/HvniB3q506jocEjU8qN+kXPCdBer9CwQgSi+aZsk2fXKNxGU7CG0OUoRi4n
189 | # rIZPVVIM5AMs+2qQkDBuh/NZMJ36ftaXs+ghl3740hPzCLdTbVK0RZCfSABKR2YR
190 | # JylmqJfk0waBSqL5hKcRRxQJgp+E7VV4/gGaHVAIhQAQMEbtt94jRrvELVSfrx54
191 | # QTF3zJvfO4OToWECtR0Nsfz3m7IBziJLVP/5BcPCIAsCAwEAAaOCAaswggGnMA8G
192 | # A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFCM0+NlSRnAK7UD7dvuzK7DDNbMPMAsG
193 | # A1UdDwQEAwIBhjAQBgkrBgEEAYI3FQEEAwIBADCBmAYDVR0jBIGQMIGNgBQOrIJg
194 | # QFYnl+UlE/wq4QpTlVnkpKFjpGEwXzETMBEGCgmSJomT8ixkARkWA2NvbTEZMBcG
195 | # CgmSJomT8ixkARkWCW1pY3Jvc29mdDEtMCsGA1UEAxMkTWljcm9zb2Z0IFJvb3Qg
196 | # Q2VydGlmaWNhdGUgQXV0aG9yaXR5ghB5rRahSqClrUxzWPQHEy5lMFAGA1UdHwRJ
197 | # MEcwRaBDoEGGP2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1
198 | # Y3RzL21pY3Jvc29mdHJvb3RjZXJ0LmNybDBUBggrBgEFBQcBAQRIMEYwRAYIKwYB
199 | # BQUHMAKGOGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljcm9z
200 | # b2Z0Um9vdENlcnQuY3J0MBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0GCSqGSIb3DQEB
201 | # BQUAA4ICAQAQl4rDXANENt3ptK132855UU0BsS50cVttDBOrzr57j7gu1BKijG1i
202 | # uFcCy04gE1CZ3XpA4le7r1iaHOEdAYasu3jyi9DsOwHu4r6PCgXIjUji8FMV3U+r
203 | # kuTnjWrVgMHmlPIGL4UD6ZEqJCJw+/b85HiZLg33B+JwvBhOnY5rCnKVuKE5nGct
204 | # xVEO6mJcPxaYiyA/4gcaMvnMMUp2MT0rcgvI6nA9/4UKE9/CCmGO8Ne4F+tOi3/F
205 | # NSteo7/rvH0LQnvUU3Ih7jDKu3hlXFsBFwoUDtLaFJj1PLlmWLMtL+f5hYbMUVbo
206 | # nXCUbKw5TNT2eb+qGHpiKe+imyk0BncaYsk9Hm0fgvALxyy7z0Oz5fnsfbXjpKh0
207 | # NbhOxXEjEiZ2CzxSjHFaRkMUvLOzsE1nyJ9C/4B5IYCeFTBm6EISXhrIniIh0EPp
208 | # K+m79EjMLNTYMoBMJipIJF9a6lbvpt6Znco6b72BJ3QGEe52Ib+bgsEnVLaxaj2J
209 | # oXZhtG6hE6a/qkfwEm/9ijJssv7fUciMI8lmvZ0dhxJkAj0tr1mPuOQh5bWwymO0
210 | # eFQF1EEuUKyUsKV4q7OglnUa2ZKHE3UiLzKoCG6gW4wlv6DvhMoh1useT8ma7kng
211 | # 9wFlb4kLfchpyOZu6qeXzjEp/w7FW1zYTRuh2Povnj8uVRZryROj/TGCBJcwggST
212 | # AgEBMIGQMHkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
213 | # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xIzAh
214 | # BgNVBAMTGk1pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBAhMzAAABCix5rtd5e6as
215 | # AAEAAAEKMAkGBSsOAwIaBQCggbAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
216 | # HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFOnw
217 | # E72BG3SgJzTuScoCSxxOruLdMFAGCisGAQQBgjcCAQwxQjBAoBaAFABQAG8AdwBl
218 | # AHIAUwBoAGUAbABsoSaAJGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9Qb3dlclNo
219 | # ZWxsIDANBgkqhkiG9w0BAQEFAASCAQByobPvDrRGQpJf/r/uVnQXjROseTdYd07U
220 | # ot8WtQlCdFkXKs/bqOlOKQtxKN2iGgnb7w2nFcL/O+faVyfh9rkpgJTLX8CGCoVg
221 | # RxWO7fUD/gb7tDRw2jpvmq7AVrC46f5jh61YDzBerV544PNNjiLBfVgyVbrbd02n
222 | # LxMfsQCHVr7twl/h8JYC0olcllrJu1rGag7AJIaXMRYB/0ConzwHyXzM7H1aNRYz
223 | # 8UIPZNdAFAmASbsXZW6t/IvBYjelpCOcqIXalYHUZTlbWmMn67FovXk946aIXU8/
224 | # WrQM8gWG/r30hc+AuPhQrFkK5ueDgm0kAhvWc3/LOEcSYMDg/r6HoYICKDCCAiQG
225 | # CSqGSIb3DQEJBjGCAhUwggIRAgEBMIGOMHcxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
226 | # EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
227 | # ZnQgQ29ycG9yYXRpb24xITAfBgNVBAMTGE1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD
228 | # QQITMwAAAJb6gDHvN2RGRQAAAAAAljAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkD
229 | # MQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTYwNDE5MTgyNDI2WjAjBgkq
230 | # hkiG9w0BCQQxFgQU39hqK636kNFUIGIvYe+c6/aGwYswDQYJKoZIhvcNAQEFBQAE
231 | # ggEAj6qFQtwjSy8gv69zTQUXk4HyL+VA8cnG3RQRqpVGCF0G1pYs6kMTX0TCT7U1
232 | # IKUBJbqtBCdi0XFPWIySF0YIHRPMu6eJzJYRPe8cn4qACONE5ca3bj8oFgOTrtwY
233 | # rpsbTNjXxb35GkhdiJxLJk7MqdSnUB64rcSGsHm8/J8/kf3/rxxl1eVsOj9AZqb9
234 | # aQ5GzsuGrQ8+ZUas3lAeXA2ym/4oedbGugXt9uCwZYCt6q3hIot3stwkY0+69yc+
235 | # MBM0LPeBoybL4poJN8r2a0j10A7jJi7GO620OcoJf2/bepykJn+CtIbybqKhNnXY
236 | # VEE5GxewUMr8EjEgAcV0m5n3EQ==
237 | # SIG # End signature block
238 |
--------------------------------------------------------------------------------