diff --git a/.gitmodules b/.gitmodules
index 8a49b569c4..6fc1171a3e 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,3 @@
-[submodule "src/libpsl-native"]
- path = src/libpsl-native
- url = https://github.com/PowerShell/psl-native.git
[submodule "src/omi"]
path = src/omi
url = https://github.com/Microsoft/omi.git
@@ -11,8 +8,12 @@
[submodule "src/windows-build"]
path = src/windows-build
url = https://github.com/PowerShell/psl-windows-build.git
-[submodule "src/Microsoft.PowerShell.Linux.Host/Modules/Pester"]
- path = src/Microsoft.PowerShell.Linux.Host/Modules/Pester
+[submodule "src/Modules/Pester"]
+ path = src/Modules/Pester
url = https://github.com/PowerShell/psl-pester.git
branch = develop
ignore = dirty
+[submodule "src/libpsl-native/test/googletest"]
+ path = src/libpsl-native/test/googletest
+ url = https://github.com/google/googletest.git
+ ignore = dirty
diff --git a/.travis.yml b/.travis.yml
index 8e78e7449b..0ea3ad8e41 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,25 +1,16 @@
language: cpp
sudo: required
dist: trusty
-cache:
- apt: true
- directories:
- - $HOME/.nuget
git:
submodules: false
before_install:
- git config --global url.git@github.com:.insteadOf https://github.com/
- - git submodule update --init --recursive -- src/libpsl-native src/windows-build src/Microsoft.PowerShell.Linux.Host/Modules/Pester
- - sudo sh -c 'echo "deb [arch=amd64] http://apt-mo.trafficmanager.net/repos/dotnet/ trusty main" > /etc/apt/sources.list.d/dotnetdev.list'
- - sudo apt-key adv --keyserver apt-mo.trafficmanager.net --recv-keys 417A0893
- - sudo apt-get -qq update
- - sudo apt-get install -y dotnet=1.0.0.001675-1
+ - git submodule update --init -- src/windows-build src/Modules/Pester src/libpsl-native/test/googletest
+ - ./bootstrap.sh
- ./download.sh
- - sudo dpkg -i powershell.deb
+ - sudo dpkg -i ./powershell.deb
script:
- - powershell -c "Import-Module ./PowerShellGitHubDev.psm1; Start-PSBuild"
- - ./pester.sh
- - ./xunit.sh
+ - powershell -c "Import-Module ./PowerShellGitHubDev.psm1; Start-PSBuild; Start-PSxUnit; Start-PSPester"
notifications:
slack:
secure: sKYd4n61+ZFzGZuWGUl8V1kN0NM16wRVOFVlNhlFCwnkrEsKROb++EvXf5uwnKuzxkhEjvPWO+UFgeshQDoR93y4s5YLfhC5JupK4nUzjPzWs208KTrh8u/x9MY8X6Ojxi85EEAiku5GzMoMlkucSStZUYwbIfnelzqdw8uoRwmm2MW4XCPwsuEuDUVghyiva0Mdx1G6MopCrK8T96WywJXT3chhfZQgVt+sQCBt9g+2kjDaObKrzG0P07IVK43ZpDgnu6AoxlyBzIx9mJH2Oa/tki3/kTO72Wcp3ps3qvmiStADamzVKR9p1VlWCLWAd6VOehxuByCGEyujpzk135Wud2DZYO+8LD6inZVhFe3Wt5pCU9BDXZppiATfMCqgXEH7nK54pEn79yHcjthRJ2+Z9ot7As2fu3RSBmTAi8nRP0fxRyX/jctR3S6P0qt0y1ynx9nzBfhmhPQW0PMVazWS/nruQIvK/3iiYXjZxM5bBwIvabmwV00EYeTdbL6ufXWNgQcG1ZWkDsi2I3vst/ytUbHwaFYg83bXWpxg9DCzJeWLVUvE5/3NfBxRAuCTot/fgTEA9IYScvrlL7Q/bT0cOt0vEM98MPf1UO+WP85uxhsRgHtwDEo+jMaL6ZFkPhlV6mmmED4NdY2//a571cLNXdnuMAze5O3TWGBG53g=
diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1
index fa22c2fe26..1b6605fcd1 100644
--- a/PowerShellGitHubDev.psm1
+++ b/PowerShellGitHubDev.psm1
@@ -17,19 +17,19 @@ try {
$IsWindows = $true
}
-function Start-PSBuild
-{
+
+function Start-PSBuild {
[CmdletBinding(DefaultParameterSetName='CoreCLR')]
param(
[switch]$Restore,
[switch]$Clean,
- [string]$Output,
# These runtimes must match those in project.json
# We do not use ValidateScript since we want tab completion
[ValidateSet("ubuntu.14.04-x64",
"centos.7.1-x64",
"win7-x64",
+ "win81-x64",
"win10-x64",
"osx.10.10-x64",
"osx.10.11-x64")]
@@ -44,185 +44,213 @@ function Start-PSBuild
[Parameter(ParameterSetName='FullCLR')]
[ValidateSet("Debug",
- "Release")]
- [string]$msbuildConfiguration = "Release"
+ "Release")]
+ [string]$msbuildConfiguration = "Release"
)
- function precheck([string]$command, [string]$missedMessage)
- {
- $c = Get-Command $command -ErrorAction SilentlyContinue
- if (-not $c)
- {
- Write-Warning $missedMessage
- return $false
- }
- else
- {
- return $true
- }
- }
-
- function log([string]$message)
- {
- Write-Host -Foreground Green $message
- }
-
- # simplify ParameterSetNames, set output
- if ($PSCmdlet.ParameterSetName -eq 'FullCLR')
- {
+ # simplify ParameterSetNames
+ if ($PSCmdlet.ParameterSetName -eq 'FullCLR') {
$FullCLR = $true
}
- if (-not $Output)
- {
- if ($FullCLR) { $Output = "$PSScriptRoot/binFull" } else { $Output = "$PSScriptRoot/bin" }
- }
-
# verify we have all tools in place to do the build
$precheck = precheck 'dotnet' "Build dependency 'dotnet' not found in PATH! See: https://dotnet.github.io/getting-started/"
- if ($FullCLR)
- {
+ if ($FullCLR) {
# cmake is needed to build powershell.exe
$precheck = $precheck -and (precheck 'cmake' 'cmake not found. You can install it from https://chocolatey.org/packages/cmake.portable')
-
+
# msbuild is needed to build powershell.exe
# msbuild is part of .NET Framework, we can try to get it from well-known location.
- if (-not (Get-Command -Name msbuild -ErrorAction Ignore))
- {
+ if (-not (Get-Command -Name msbuild -ErrorAction Ignore)) {
$env:path += ";${env:SystemRoot}\Microsoft.Net\Framework\v4.0.30319"
}
$precheck = $precheck -and (precheck 'msbuild' 'msbuild not found. Install Visual Studio 2015.')
- }
-
- if (-not $precheck) { return }
+ } elseif ($IsLinux -Or $IsOSX) {
+ $InstallCommand = if ($IsLinux) {
+ 'apt-get'
+ } elseif ($IsOSX) {
+ 'brew'
+ }
- # handle clean
- if ($Clean) {
- Remove-Item -Force -Recurse $Output -ErrorAction SilentlyContinue
+ foreach ($Dependency in 'cmake', 'make', 'g++') {
+ $precheck = $precheck -and (precheck $Dependency "Build dependency '$Dependency' not found. Run '$InstallCommand install $Dependency'")
+ }
}
- New-Item -Force -Type Directory $Output | Out-Null
+ if (-Not $Runtime) {
+ $Runtime = dotnet --info | % {
+ if ($_ -match "RID") {
+ $_ -split "\s+" | Select-Object -Last 1
+ }
+ }
+
+ if (-Not $Runtime) {
+ Write-Warning "Could not determine Runtime Identifier, please update dotnet"
+ $precheck = $false
+ } else {
+ log "Runtime not specified, using $Runtime"
+ }
+ }
+
+ # Abort if any precheck failed
+ if (-not $precheck) {
+ return
+ }
# define key build variables
- if ($FullCLR)
- {
+ if ($FullCLR) {
$Top = "$PSScriptRoot\src\Microsoft.PowerShell.ConsoleHost"
- $framework = 'net451'
+ $Framework = 'net451'
+ } else {
+ $Top = "$PSScriptRoot/src/Microsoft.PowerShell.Host"
+ $Framework = 'netstandardapp1.5'
}
- else
- {
- $Top = "$PSScriptRoot/src/Microsoft.PowerShell.Linux.Host"
- $framework = 'netstandardapp1.5'
+
+ if ($IsLinux -Or $IsOSX) {
+ $Configuration = "Linux"
+ $Executable = "powershell"
+ } else {
+ $Configuration = "Debug"
+ $Executable = "powershell.exe"
}
+ $Arguments = @()
+ $Arguments += "--framework", $Framework
+ $Arguments += "--configuration", $Configuration
+ $Arguments += "--runtime", $Runtime
+
+ # FullCLR only builds a library, so there is no runtime component
+ if ($FullCLR) {
+ $script:Output = [IO.Path]::Combine($Top, "bin", $Configuration, $Framework, $Executable)
+ } else {
+ $script:Output = [IO.Path]::Combine($Top, "bin", $Configuration, $Framework, $Runtime, $Executable)
+ }
+ Write-Verbose "script:Output is $script:Output"
+
# handle Restore
if ($Restore -Or -Not (Test-Path "$Top/project.lock.json")) {
log "Run dotnet restore"
- $Arguments = @("--verbosity")
+ $RestoreArguments = @("--verbosity")
if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) {
- $Arguments += "Info" } else { $Arguments += "Warning" }
+ $RestoreArguments += "Info"
+ } else {
+ $RestoreArguments += "Warning"
+ }
- if ($Runtime) { $Arguments += "--runtime", $Runtime }
+ $RestoreArguments += "$PSScriptRoot"
- $Arguments += "$PSScriptRoot"
-
- dotnet restore $Arguments
+ dotnet restore $RestoreArguments
}
# Build native components
- if (-not $FullCLR)
- {
- if ($IsLinux -Or $IsOSX) {
- log "Start building native components"
- $InstallCommand = if ($IsLinux) { "apt-get" } elseif ($IsOSX) { "brew" }
- foreach ($Dependency in "cmake", "g++") {
- if (-Not (Get-Command $Dependency -ErrorAction SilentlyContinue)) {
- throw "Build dependency '$Dependency' not found in PATH! Run '$InstallCommand install $Dependency'"
- }
- }
-
- $Ext = if ($IsLinux) { "so" } elseif ($IsOSX) { "dylib" }
- $Native = "$PSScriptRoot/src/libpsl-native"
- $Lib = "$Top/libpsl-native.$Ext"
- Write-Verbose "Building $Lib"
-
- try {
- Push-Location $Native
- cmake -DCMAKE_BUILD_TYPE=Debug .
- make -j
- make test
- } finally {
- Pop-Location
- }
-
- if (-Not (Test-Path $Lib)) { throw "Compilation of $Lib failed" }
+ if ($IsLinux -Or $IsOSX) {
+ $Ext = if ($IsLinux) {
+ "so"
+ } elseif ($IsOSX) {
+ "dylib"
}
- }
- else
- {
+
+ $Native = "$PSScriptRoot/src/libpsl-native"
+ $Lib = "$Top/libpsl-native.$Ext"
+ log "Start building $Lib"
+
+ try {
+ Push-Location $Native
+ cmake -DCMAKE_BUILD_TYPE=Debug .
+ make -j
+ make test
+ } finally {
+ Pop-Location
+ }
+
+ if (-Not (Test-Path $Lib)) {
+ throw "Compilation of $Lib failed"
+ }
+ } elseif ($FullCLR) {
log "Start building native powershell.exe"
- $build = "$PSScriptRoot/build"
- if ($Clean) {
- Remove-Item -Force -Recurse $build -ErrorAction SilentlyContinue
- }
- mkdir $build -ErrorAction SilentlyContinue
- try
- {
- Push-Location $build
+ try {
+ Push-Location .\src\powershell-native
- if ($cmakeGenerator)
- {
- cmake -G $cmakeGenerator ..\src\powershell-native
- }
- else
- {
- cmake ..\src\powershell-native
+ if ($cmakeGenerator) {
+ cmake -G $cmakeGenerator .
+ } else {
+ cmake .
}
+
msbuild powershell.vcxproj /p:Configuration=$msbuildConfiguration
- cp -rec $msbuildConfiguration\* $Output
+
+ } finally {
+ Pop-Location
}
- finally { Pop-Location }
}
- log "Building PowerShell"
- $Arguments = "--framework", $framework, "--output", $Output
- if ($IsLinux -Or $IsOSX) { $Arguments += "--configuration", "Linux" }
- if ($Runtime) { $Arguments += "--runtime", $Runtime }
-
- if ($FullCLR)
- {
- # there is a problem with code signing:
- # AssemblyKeyFileAttribute file path cannot be correctly located, if `dotnet publish $TOP` syntax is used
- # we workaround it with calling `dotnet publish` from $TOP directory instead.
+ try {
+ # Relative paths do not work well if cwd is not changed to project
+ log "Run `dotnet build $Arguments` from $pwd"
Push-Location $Top
- }
- else
- {
- $Arguments += $Top
+ dotnet build $Arguments
+ log "PowerShell output: $script:Output"
+ } finally {
+ Pop-Location
}
- Write-Verbose "Run dotnet publish $Arguments from $pwd"
+}
- # this try-finally is part of workaround about AssemblyKeyFileAttribute issue
- try
- {
- dotnet publish $Arguments
+
+function Get-PSOutput {
+ [CmdletBinding()]param()
+ if (-Not $Output) {
+ throw '$script:Output is not defined, run Start-PSBuild'
}
- finally
- {
- if ($FullCLR) { Pop-Location }
+
+ $Output
+}
+
+
+function Start-PSPester {
+ [CmdletBinding()]param(
+ [string]$Flags = '-EnableExit -OutputFile pester-tests.xml -OutputFormat NUnitXml',
+ [string]$Tests = "*",
+ [ValidateScript({ Test-Path -PathType Container $_})]
+ [string]$Directory = "$PSScriptRoot/test/powershell"
+ )
+
+ & (Get-PSOutput) -c "Invoke-Pester $Flags $Directory/$Tests"
+ if ($LASTEXITCODE -ne 0) {
+ throw "$LASTEXITCODE Pester tests failed"
}
}
-function Start-PSPackage
-{
+
+function Start-PSxUnit {
+ [CmdletBinding()]param()
+ if ($IsWindows) {
+ throw "xUnit tests are only currently supported on Linux / OS X"
+ }
+
+ $Content = Split-Path -Parent (Get-PSOutput)
+ $Arguments = "--configuration", "Linux"
+ try {
+ Push-Location $PSScriptRoot/test/csharp
+ dotnet build $Arguments
+ Copy-Item -ErrorAction SilentlyContinue -Recurse -Path $Content/* -Include Modules,libpsl-native* -Destination "./bin/Linux/netstandardapp1.5/ubuntu.14.04-x64"
+ dotnet test $Arguments
+ if ($LASTEXITCODE -ne 0) {
+ throw "$LASTEXITCODE xUnit tests failed"
+ }
+ } finally {
+ Pop-Location
+ }
+}
+
+function Start-PSPackage {
# PowerShell packages use Semantic Versioning http://semver.org/
#
# Ubuntu and OS X packages are supported.
- param(
+ [CmdletBinding()]param(
[string]$Version,
[int]$Iteration = 1,
[ValidateSet("deb", "osxpkg", "rpm")]
@@ -285,8 +313,8 @@ function Start-PSPackage
"$PSScriptRoot/package/powershell=/usr/local/bin"
}
-function Start-DevPSGitHub
-{
+
+function Start-DevPSGitHub {
param(
[switch]$ZapDisable,
[string[]]$ArgumentList = '',
@@ -295,27 +323,23 @@ function Start-DevPSGitHub
[switch]$NoNewWindow
)
- try
- {
- if ($LoadProfile -eq $false)
- {
+ try {
+ if ($LoadProfile -eq $false) {
$ArgumentList = @('-noprofile') + $ArgumentList
}
$env:DEVPATH = $binDir
- if ($ZapDisable)
- {
+ if ($ZapDisable) {
$env:COMPLUS_ZapDisable = 1
}
- if (-Not (Test-Path $binDir\powershell.exe.config))
- {
+ if (-Not (Test-Path $binDir\powershell.exe.config)) {
$configContents = @"
-
-
-
+
+
+
"@
$configContents | Out-File -Encoding Ascii $binDir\powershell.exe.config
@@ -333,71 +357,29 @@ function Start-DevPSGitHub
}
Start-Process @startProcessArgs
- }
- finally
- {
+ } finally {
ri env:DEVPATH
- if ($ZapDisable)
- {
+ if ($ZapDisable) {
ri env:COMPLUS_ZapDisable
}
}
}
-## this function is from Dave Wyatt's answer on
-## http://stackoverflow.com/questions/22002748/hashtables-from-convertfrom-json-have-different-type-from-powershells-built-in-h
-function Convert-PSObjectToHashtable
-{
- param (
- [Parameter(ValueFromPipeline)]
- $InputObject
- )
-
- process
- {
- if ($null -eq $InputObject) { return $null }
-
- if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string])
- {
- $collection = @(
- foreach ($object in $InputObject) { Convert-PSObjectToHashtable $object }
- )
-
- Write-Output -NoEnumerate $collection
- }
- elseif ($InputObject -is [psobject])
- {
- $hash = @{}
-
- foreach ($property in $InputObject.PSObject.Properties)
- {
- $hash[$property.Name] = Convert-PSObjectToHashtable $property.Value
- }
-
- $hash
- }
- else
- {
- $InputObject
- }
- }
-}
<#
.EXAMPLE Copy-SubmoduleFiles # copy files FROM submodule TO src/ folders
.EXAMPLE Copy-SubmoduleFiles -ToSubmodule # copy files FROM src/ folders TO submodule
#>
function Copy-SubmoduleFiles {
-
+
[CmdletBinding()]
param(
[string]$mappingFilePath = "$PSScriptRoot/mapping.json",
[switch]$ToSubmodule
)
-
- if (-not (Test-Path $mappingFilePath))
- {
+
+ if (-not (Test-Path $mappingFilePath)) {
throw "Mapping file not found in $mappingFilePath"
}
@@ -405,47 +387,38 @@ function Copy-SubmoduleFiles {
# mapping.json assumes the root folder
Push-Location $PSScriptRoot
- try
- {
+ try {
$m.GetEnumerator() | % {
- if ($ToSubmodule)
- {
+ if ($ToSubmodule) {
cp $_.Value $_.Key -Verbose:$Verbose
- }
- else
- {
+ } else {
mkdir (Split-Path $_.Value) -ErrorAction SilentlyContinue > $null
- cp $_.Key $_.Value -Verbose:$Verbose
+ cp $_.Key $_.Value -Verbose:$Verbose
}
}
- }
- finally
- {
+ } finally {
Pop-Location
}
}
+
<#
- .EXAMPLE Create-MappingFile # create mapping.json in the root folder from project.json files
+.EXAMPLE Create-MappingFile # create mapping.json in the root folder from project.json files
#>
-function New-MappingFile
-{
+function New-MappingFile {
param(
[string]$mappingFilePath = "$PSScriptRoot/mapping.json",
[switch]$IgnoreCompileFiles,
[switch]$Ignoreresource
)
- function Get-MappingPath([string]$project, [string]$path)
- {
- if ($project -match 'TypeCatalogGen')
- {
+ function Get-MappingPath([string]$project, [string]$path) {
+ if ($project -match 'TypeCatalogGen') {
return Split-Path $path -Leaf
}
-
- if ($project -match 'Microsoft.Management.Infrastructure')
- {
+
+ if ($project -match 'Microsoft.Management.Infrastructure') {
return Split-Path $path -Leaf
}
@@ -456,8 +429,7 @@ function New-MappingFile
# assumes the root folder
Push-Location $PSScriptRoot
- try
- {
+ try {
$projects = ls .\src\ -Recurse -Depth 2 -Filter 'project.json'
$projects | % {
$project = Split-Path $_.FullName
@@ -465,8 +437,7 @@ function New-MappingFile
if (-not $IgnoreCompileFiles) {
$json.compileFiles | % {
if ($_) {
- if (-not $_.EndsWith('AssemblyInfo.cs'))
- {
+ if (-not $_.EndsWith('AssemblyInfo.cs')) {
$fullPath = Join-Path $project (Get-MappingPath -project $project -path $_)
$mapping[$_.Replace('../', 'src/')] = ($fullPath.Replace("$($pwd.Path)\",'')).Replace('\', '/')
}
@@ -485,38 +456,19 @@ function New-MappingFile
}
}
}
- }
- finally
- {
+ } finally {
Pop-Location
}
Set-Content -Value ($mapping | ConvertTo-Json) -Path $mappingFilePath -Encoding Ascii
}
-function Get-InvertedOrderedMap
-{
- param(
- $h
- )
- $res = [ordered]@{}
- foreach ($q in $h.GetEnumerator()) {
- if ($res.Contains($q.Value))
- {
- throw "Cannot invert hashtable: duplicated key $($q.Value)"
- }
-
- $res[$q.Value] = $q.Key
- }
- return $res
-}
<#
-.EXAMPLE Send-GitDiffToSd -diffArg1 45555786714d656bd31cbce67dbccb89c433b9cb -diffArg2 45555786714d656bd31cbce67dbccb89c433b9cb~1 -pathToAdmin d:\e\ps_dev\admin
+.EXAMPLE Send-GitDiffToSd -diffArg1 45555786714d656bd31cbce67dbccb89c433b9cb -diffArg2 45555786714d656bd31cbce67dbccb89c433b9cb~1 -pathToAdmin d:\e\ps_dev\admin
Apply a signle commit to admin folder
#>
-function Send-GitDiffToSd
-{
+function Send-GitDiffToSd {
param(
[Parameter(Mandatory)]
[string]$diffArg1,
@@ -533,32 +485,88 @@ function Send-GitDiffToSd
$affectedFiles = git diff --name-only $diffArg1 $diffArg2
$rev = Get-InvertedOrderedMap $m
foreach ($file in $affectedFiles) {
- if ($rev.Contains)
- {
+ if ($rev.Contains) {
$sdFilePath = Join-Path $pathToAdmin $rev[$file].Substring('src/monad/'.Length)
$diff = git diff $diffArg1 $diffArg2 -- $file
- if ($diff)
- {
+ if ($diff) {
Write-Host -Foreground Green "Apply patch to $sdFilePath"
Set-Content -Value $diff -Path $env:TEMP\diff -Encoding Ascii
- if ($WhatIf)
- {
+ if ($WhatIf) {
Write-Host -Foreground Green "Patch content"
cat $env:TEMP\diff
+ } else {
+ & $patchPath --binary -p1 $sdFilePath $env:TEMP\diff
}
- else
- {
- & $patchPath --binary -p1 $sdFilePath $env:TEMP\diff
- }
- }
- else
- {
+ } else {
Write-Host -Foreground Green "No changes in $file"
}
- }
- else
- {
+ } else {
Write-Host -Foreground Green "Ignore changes in $file, because there is no mapping for it"
}
- }
+ }
+}
+
+
+function script:log([string]$message) {
+ Write-Host -Foreground Green $message
+}
+
+
+function script:precheck([string]$command, [string]$missedMessage) {
+ $c = Get-Command $command -ErrorAction SilentlyContinue
+ if (-not $c) {
+ Write-Warning $missedMessage
+ return $false
+ } else {
+ return $true
+ }
+}
+
+
+function script:Get-InvertedOrderedMap {
+ param(
+ $h
+ )
+ $res = [ordered]@{}
+ foreach ($q in $h.GetEnumerator()) {
+ if ($res.Contains($q.Value)) {
+ throw "Cannot invert hashtable: duplicated key $($q.Value)"
+ }
+
+ $res[$q.Value] = $q.Key
+ }
+ return $res
+}
+
+
+## this function is from Dave Wyatt's answer on
+## http://stackoverflow.com/questions/22002748/hashtables-from-convertfrom-json-have-different-type-from-powershells-built-in-h
+function script:Convert-PSObjectToHashtable {
+ param (
+ [Parameter(ValueFromPipeline)]
+ $InputObject
+ )
+
+ process {
+ if ($null -eq $InputObject) { return $null }
+
+ if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]) {
+ $collection = @(
+ foreach ($object in $InputObject) { Convert-PSObjectToHashtable $object }
+ )
+
+ Write-Output -NoEnumerate $collection
+ } elseif ($InputObject -is [psobject]) {
+ $hash = @{}
+
+ foreach ($property in $InputObject.PSObject.Properties)
+ {
+ $hash[$property.Name] = Convert-PSObjectToHashtable $property.Value
+ }
+
+ $hash
+ } else {
+ $InputObject
+ }
+ }
}
diff --git a/appveyor.yml b/appveyor.yml
index e10ecacea6..6b01530a3e 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -6,9 +6,6 @@ environment:
priv_key:
secure:
-cache:
- - '%LocalAppData%\Microsoft\dotnet'
-
notifications:
- provider: Slack
incoming_webhook:
@@ -20,9 +17,9 @@ install:
- ps: $fileContent += "`n-----END RSA PRIVATE KEY-----`n"
- ps: Set-Content c:\users\appveyor\.ssh\id_rsa $fileContent
- git config --global url.git@github.com:.insteadOf https://github.com/
- - git submodule update --init --recursive -- src/windows-build src/Microsoft.PowerShell.Linux.Host/Modules/Pester
+ - git submodule update --init -- src/windows-build src/Modules/Pester
- ps: Invoke-WebRequest -Uri https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/install.ps1 -OutFile install.ps1
- - ps: ./install.ps1 -version 1.0.0.001888
+ - ps: ./install.ps1 -version 1.0.0-beta-002198
build_script:
- ps: |
@@ -38,15 +35,17 @@ test_script:
$ErrorActionPreference = 'Stop'
#
# CoreCLR
+ $env:CoreOutput = "$pwd\src\Microsoft.PowerShell.Host\bin\Debug\netstandardapp1.5\win81-x64"
Write-Host -Foreground Green 'Run CoreCLR tests'
$testResultsFile = "$pwd\TestsResults.xml"
- .\bin\powershell.exe --noprofile -c "Import-Module .\bin\Modules\Microsoft.PowerShell.Platform; Invoke-Pester test/powershell -OutputFormat NUnitXml -OutputFile $testResultsFile"
+ & ("$env:CoreOutput\powershell.exe") -c "Invoke-Pester test/powershell -OutputFormat NUnitXml -OutputFile $testResultsFile"
(New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path $testResultsFile))
#
# FullCLR
+ $env:FullOutput = "$pwd\src\Microsoft.PowerShell.ConsoleHost\bin\Debug\net451"
Write-Host -Foreground Green 'Run FullCLR tests'
$testResultsFileFullCLR = "$pwd\TestsResults.FullCLR.xml"
- Start-DevPSGitHub -binDir $pwd\binFull -NoNewWindow -ArgumentList '-command', "Import-Module .\src\Microsoft.PowerShell.Linux.Host\Modules\Pester; Import-Module .\bin\Modules\Microsoft.PowerShell.Platform; Invoke-Pester test/fullCLR -OutputFormat NUnitXml -OutputFile $testResultsFileFullCLR"
+ Start-DevPSGitHub -binDir $env:FullOutput -NoNewWindow -ArgumentList '-command', "Import-Module .\src\Modules\Pester; Import-Module .\bin\Modules\Microsoft.PowerShell.Platform; Invoke-Pester test/fullCLR -OutputFormat NUnitXml -OutputFile $testResultsFileFullCLR"
(New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path $testResultsFileFullCLR))
#
# Fail the build, if tests failed
@@ -71,8 +70,8 @@ on_finish:
$zipFilePath = Join-Path $pwd "$name.zip"
$zipFileFullPath = Join-Path $pwd "$name.FullCLR.zip"
Add-Type -assemblyname System.IO.Compression.FileSystem
- [System.IO.Compression.ZipFile]::CreateFromDirectory("$pwd\bin", $zipFilePath)
- [System.IO.Compression.ZipFile]::CreateFromDirectory("$pwd\binFull", $zipFileFullPath)
+ [System.IO.Compression.ZipFile]::CreateFromDirectory($env:CoreOutput, $zipFilePath)
+ [System.IO.Compression.ZipFile]::CreateFromDirectory($env:FullOutput, $zipFileFullPath)
@(
# You can add other artifacts here
diff --git a/bootstrap.sh b/bootstrap.sh
new file mode 100755
index 0000000000..599321730c
--- /dev/null
+++ b/bootstrap.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+echo "Installing build dependencies"
+
+curl http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
+echo "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.6 main" | sudo tee /etc/apt/sources.list.d/llvm.list
+sudo apt-get update -qq
+
+sudo apt-get install -y wget make g++ cmake \
+ libc6 libgcc1 libstdc++6 \
+ libcurl3 libgssapi-krb5-2 libicu52 liblldb-3.6 liblttng-ust0 libssl1.0.0 libunwind8 libuuid1 zlib1g clang-3.5
+
+wget -P /tmp https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-host-ubuntu-x64.latest.deb
+sudo dpkg -i /tmp/dotnet-host-ubuntu-x64.latest.deb
+
+wget -P /tmp https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-sharedframework-ubuntu-x64.latest.deb
+sudo dpkg -i /tmp/dotnet-sharedframework-ubuntu-x64.latest.deb
+
+wget -P /tmp https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-sdk-ubuntu-x64.latest.deb
+sudo dpkg -i /tmp/dotnet-sdk-ubuntu-x64.latest.deb
diff --git a/build.sh b/build.sh
index 5287ae1bb4..149910f03f 100755
--- a/build.sh
+++ b/build.sh
@@ -5,7 +5,7 @@ hash cmake 2>/dev/null || { echo >&2 "No cmake, please run 'sudo apt-get install
hash g++ 2>/dev/null || { echo >&2 "No g++, please run 'sudo apt-get install g++'"; exit 1; }
hash dotnet 2>/dev/null || { echo >&2 "No dotnet, please visit https://dotnet.github.io/getting-started/"; exit 1; }
-TOP="$(pwd)/src/Microsoft.PowerShell.Linux.Host"
+TOP="$(pwd)/src/Microsoft.PowerShell.Host"
# Test for lock file
test -r "$TOP/project.lock.json" || { echo >&2 "Please run 'dotnet restore' to download .NET Core packages"; exit 2; }
diff --git a/docs/debugging/README.md b/docs/debugging/README.md
index e1aaee6d71..2994048d17 100644
--- a/docs/debugging/README.md
+++ b/docs/debugging/README.md
@@ -42,3 +42,19 @@ provide a PID. (Please be careful not to commit such a change).
[vscode]: https://code.visualstudio.com/
[OmniSharp]: https://github.com/OmniSharp/omnisharp-vscode
[vscclrdebugger]: http://aka.ms/vscclrdebugger
+
+corehost
+--------
+
+The native executable prouduced by .NET CLI will produce trace output
+if launched with `COREHOST_TRACE=1 ./powershell`.
+
+CoreCLR PAL
+-----------
+
+The native code in the CLR has debug channels to selectively output
+information to the console. These are controlled by the
+`PAL_DBG_CHANNELS`, e.g., `export PAL_DBG_CHANNELS="+all.all"`, as
+detailed in the `dbgmsg.h` [header][].
+
+[header]: https://github.com/dotnet/coreclr/blob/release/1.0.0-rc2/src/pal/src/include/pal/dbgmsg.h
diff --git a/mapping.json b/mapping.json
index 8311b1361e..2f4ed00680 100644
--- a/mapping.json
+++ b/mapping.json
@@ -1180,5 +1180,26 @@
"src/monad/monad/nttargets/assemblies/nativemsh/pwrshcommon/WinSystemCallFacade.h": "src/powershell-native/nativemsh/pwrshcommon/WinSystemCallFacade.h",
"src/monad/monad/nttargets/assemblies/nativemsh/pwrshexe/MainEntry.cpp": "src/powershell-native/nativemsh/pwrshexe/MainEntry.cpp",
"src/monad/monad/nttargets/assemblies/nativemsh/pwrshexe/OutputWriter.h": "src/powershell-native/nativemsh/pwrshexe/OutputWriter.h",
- "src/monad/monad/src/graphicalhost/visualstudiopublic.snk": "src/signing/visualstudiopublic.snk"
+ "src/monad/monad/src/graphicalhost/visualstudiopublic.snk": "src/signing/visualstudiopublic.snk",
+ "src/monad/monad/miscfiles/modules/AppxProvider/AppxProvider.psd1": "src/Modules/AppxProvider/AppxProvider.psd1",
+ "src/monad/monad/miscfiles/modules/AppxProvider/AppxProvider.psm1": "src/Modules/AppxProvider/AppxProvider.psm1",
+ "src/monad/monad/miscfiles/modules/AppxProvider/AppxProvider.Resource.psd1": "src/Modules/AppxProvider/AppxProvider.Resource.psd1",
+ "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Archive/ArchiveResources.psd1": "src/Modules/Microsoft.PowerShell.Archive/ArchiveResources.psd1",
+ "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1": "src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1",
+ "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1": "src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1",
+ "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Diagnostics/CoreClr/Microsoft.PowerShell.Diagnostics.psd1": "src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1",
+ "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1": "src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1",
+ "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1": "src/Modules/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1",
+ "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1": "src/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1",
+ "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1": "src/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1",
+ "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Utility/CoreClr/Microsoft.PowerShell.Utility.psd1": "src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1",
+ "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1": "src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1",
+ "src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1": "src/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1",
+ "src/monad/monad/miscfiles/modules/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1": "src/Modules/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1",
+ "src/monad/monad/miscfiles/modules/PSDiagnostics/PSDiagnostics.psd1": "src/Modules/PSDiagnostics/PSDiagnostics.psd1",
+ "src/monad/monad/miscfiles/modules/PSDiagnostics/PSDiagnostics.psm1": "src/Modules/PSDiagnostics/PSDiagnostics.psm1",
+ "src/monad/monad/miscfiles/modules/PSGet/PSGet.Format.ps1xml": "src/Modules/PSGet/PSGet.Format.ps1xml",
+ "src/monad/monad/miscfiles/modules/PSGet/PSGet.psd1": "src/Modules/PSGet/PSGet.psd1",
+ "src/monad/monad/miscfiles/modules/PSGet/PSGet.Resource.psd1": "src/Modules/PSGet/PSGet.Resource.psd1",
+ "src/monad/monad/miscfiles/modules/PSGet/PSModule.psm1": "src/Modules/PSGet/PSModule.psm1"
}
diff --git a/pester.sh b/pester.sh
deleted file mode 100755
index 400b3c79a5..0000000000
--- a/pester.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-
-test -x bin/powershell || { echo >&2 "No bin/powershell, please run './build.sh'"; exit 1; }
-
-./bin/powershell --noprofile -c "Import-Module Microsoft.PowerShell.Platform; Invoke-Pester test/powershell/$1 -OutputFile pester-tests.xml -OutputFormat NUnitXml -EnableExit"
-failed_tests=$?
-
-# XML files are not executable
-chmod -x pester-tests.xml
-
-# Return number of failed tests as exit code (more than 0 will be an error)
-exit $failed_tests
diff --git a/src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 b/src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1
new file mode 100644
index 0000000000..d72eb9e283
--- /dev/null
+++ b/src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1
@@ -0,0 +1,16 @@
+@{
+GUID="CA046F10-CA64-4740-8FF9-2565DBA61A4F"
+Author="Microsoft Corporation"
+CompanyName="Microsoft Corporation"
+Copyright="© Microsoft Corporation. All rights reserved."
+ModuleVersion="3.0.0.0"
+PowerShellVersion="3.0"
+CLRVersion="4.0"
+AliasesToExport = @()
+FunctionsToExport = @()
+CmdletsToExport="Get-WinEvent", "Get-Counter", "Import-Counter", "Export-Counter", "New-WinEvent"
+NestedModules="Microsoft.PowerShell.Commands.Diagnostics.dll"
+TypesToProcess="GetEvent.types.ps1xml"
+FormatsToProcess="Event.format.ps1xml","Diagnostics.format.ps1xml"
+HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=390783'
+}
diff --git a/src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 b/src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
new file mode 100644
index 0000000000..618763603d
--- /dev/null
+++ b/src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
@@ -0,0 +1,33 @@
+@{
+GUID="1DA87E53-152B-403E-98DC-74D7B4D63D59"
+Author="Microsoft Corporation"
+CompanyName="Microsoft Corporation"
+Copyright="© Microsoft Corporation. All rights reserved."
+ModuleVersion="3.1.0.0"
+PowerShellVersion="3.0"
+CLRVersion="4.0"
+CmdletsToExport= "Format-List", "Format-Custom", "Format-Table", "Format-Wide",
+ "Out-File", "Out-Printer", "Out-String",
+ "Out-GridView", "Get-FormatData", "Export-FormatData", "ConvertFrom-Json", "ConvertTo-Json",
+ "Invoke-RestMethod", "Invoke-WebRequest", "Register-ObjectEvent", "Register-EngineEvent",
+ "Wait-Event", "Get-Event", "Remove-Event", "Get-EventSubscriber", "Unregister-Event",
+ "New-Event", "Add-Member", "Add-Type", "Compare-Object", "ConvertTo-Html", "ConvertFrom-StringData",
+ "Export-Csv", "Import-Csv", "ConvertTo-Csv", "ConvertFrom-Csv", "Export-Alias", "Invoke-Expression",
+ "Get-Alias", "Get-Culture", "Get-Date", "Get-Host", "Get-Member", "Get-Random", "Get-UICulture",
+ "Get-Unique", "Export-PSSession", "Import-PSSession", "Import-Alias", "Import-LocalizedData",
+ "Select-String", "Measure-Object", "New-Alias", "New-TimeSpan", "Read-Host", "Set-Alias", "Set-Date",
+ "Start-Sleep", "Tee-Object", "Measure-Command", "Update-List", "Update-TypeData", "Update-FormatData",
+ "Remove-TypeData", "Get-TypeData", "Write-Host", "Write-Progress", "New-Object", "Select-Object",
+ "Group-Object", "Sort-Object", "Get-Variable", "New-Variable", "Set-Variable", "Remove-Variable",
+ "Clear-Variable", "Export-Clixml", "Import-Clixml", "ConvertTo-Xml", "Select-Xml", "Write-Debug",
+ "Write-Verbose", "Write-Warning", "Write-Error", "Write-Information", "Write-Output", "Set-PSBreakpoint", "Get-PSBreakpoint",
+ "Remove-PSBreakpoint", "Enable-PSBreakpoint", "Disable-PSBreakpoint", "Get-PSCallStack",
+ "Send-MailMessage", "Get-TraceSource", "Set-TraceSource", "Trace-Command", "Show-Command", "Unblock-File",
+ "Get-Runspace", "Debug-Runspace", "Enable-RunspaceDebug", "Disable-RunspaceDebug", "Get-RunspaceDebug", "Wait-Debugger",
+ "ConvertFrom-String", "Convert-String"
+FunctionsToExport= "Get-FileHash", "New-TemporaryFile", "New-Guid", "Format-Hex", "Import-PowerShellDataFile",
+ "ConvertFrom-SddlString"
+AliasesToExport= "CFS", "fhx"
+NestedModules="Microsoft.PowerShell.Commands.Utility.dll","Microsoft.PowerShell.Utility.psm1"
+HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=390787'
+}
diff --git a/src/Microsoft.PowerShell.ConsoleHost/project.json b/src/Microsoft.PowerShell.ConsoleHost/project.json
index 0b99854b1d..999371d722 100644
--- a/src/Microsoft.PowerShell.ConsoleHost/project.json
+++ b/src/Microsoft.PowerShell.ConsoleHost/project.json
@@ -14,6 +14,12 @@
"Microsoft.PowerShell.Commands.Utility": "1.0.0-*"
},
+ "content": [
+ "Modules",
+ "../Modules",
+ "powershell.exe"
+ ],
+
"frameworks": {
"net451": {
}
diff --git a/src/Microsoft.PowerShell.Linux.Host/.gitignore b/src/Microsoft.PowerShell.Host/.gitignore
similarity index 100%
rename from src/Microsoft.PowerShell.Linux.Host/.gitignore
rename to src/Microsoft.PowerShell.Host/.gitignore
diff --git a/src/Microsoft.PowerShell.Linux.Host/AssemblyInfo.cs b/src/Microsoft.PowerShell.Host/AssemblyInfo.cs
similarity index 100%
rename from src/Microsoft.PowerShell.Linux.Host/AssemblyInfo.cs
rename to src/Microsoft.PowerShell.Host/AssemblyInfo.cs
diff --git a/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 b/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1
new file mode 100644
index 0000000000..dec59a24f7
--- /dev/null
+++ b/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1
@@ -0,0 +1,13 @@
+@{
+GUID="CA046F10-CA64-4740-8FF9-2565DBA61A4F"
+Author="Microsoft Corporation"
+CompanyName="Microsoft Corporation"
+Copyright="© Microsoft Corporation. All rights reserved."
+ModuleVersion="3.0.0.0"
+PowerShellVersion="3.0"
+CmdletsToExport="Get-WinEvent", "New-WinEvent"
+NestedModules="Microsoft.PowerShell.Commands.Diagnostics.dll"
+TypesToProcess="..\..\GetEvent.types.ps1xml"
+FormatsToProcess="..\..\Event.format.ps1xml"
+HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=390783'
+}
\ No newline at end of file
diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 b/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1
similarity index 100%
rename from src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1
rename to src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1
diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psd1 b/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psd1
similarity index 100%
rename from src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psd1
rename to src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psd1
diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psm1 b/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psm1
similarity index 100%
rename from src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psm1
rename to src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Platform/Microsoft.PowerShell.Platform.psm1
diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 b/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1
similarity index 100%
rename from src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1
rename to src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1
diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 b/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
similarity index 100%
rename from src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
rename to src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1 b/src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1
similarity index 100%
rename from src/Microsoft.PowerShell.Linux.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1
rename to src/Microsoft.PowerShell.Host/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1
diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/PSDiagnostics/PSDiagnostics.psd1 b/src/Microsoft.PowerShell.Host/Modules/PSDiagnostics/PSDiagnostics.psd1
similarity index 100%
rename from src/Microsoft.PowerShell.Linux.Host/Modules/PSDiagnostics/PSDiagnostics.psd1
rename to src/Microsoft.PowerShell.Host/Modules/PSDiagnostics/PSDiagnostics.psd1
diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/PSDiagnostics/PSDiagnostics.psm1 b/src/Microsoft.PowerShell.Host/Modules/PSDiagnostics/PSDiagnostics.psm1
similarity index 100%
rename from src/Microsoft.PowerShell.Linux.Host/Modules/PSDiagnostics/PSDiagnostics.psm1
rename to src/Microsoft.PowerShell.Host/Modules/PSDiagnostics/PSDiagnostics.psm1
diff --git a/src/Microsoft.PowerShell.Linux.Host/PSL_profile.ps1 b/src/Microsoft.PowerShell.Host/PSL_profile.ps1
similarity index 100%
rename from src/Microsoft.PowerShell.Linux.Host/PSL_profile.ps1
rename to src/Microsoft.PowerShell.Host/PSL_profile.ps1
diff --git a/src/Microsoft.PowerShell.Linux.Host/README.md b/src/Microsoft.PowerShell.Host/README.md
similarity index 100%
rename from src/Microsoft.PowerShell.Linux.Host/README.md
rename to src/Microsoft.PowerShell.Host/README.md
diff --git a/src/Microsoft.PowerShell.Linux.Host/host.cs b/src/Microsoft.PowerShell.Host/host.cs
similarity index 99%
rename from src/Microsoft.PowerShell.Linux.Host/host.cs
rename to src/Microsoft.PowerShell.Host/host.cs
index f4fa3e2538..5849c99c2f 100644
--- a/src/Microsoft.PowerShell.Linux.Host/host.cs
+++ b/src/Microsoft.PowerShell.Host/host.cs
@@ -1,4 +1,4 @@
-namespace Microsoft.PowerShell.Linux.Host
+namespace Microsoft.PowerShell.Host
{
using System;
using System.Globalization;
diff --git a/src/Microsoft.PowerShell.Linux.Host/main.cs b/src/Microsoft.PowerShell.Host/main.cs
similarity index 99%
rename from src/Microsoft.PowerShell.Linux.Host/main.cs
rename to src/Microsoft.PowerShell.Host/main.cs
index cef1bb1a28..133b0c4280 100644
--- a/src/Microsoft.PowerShell.Linux.Host/main.cs
+++ b/src/Microsoft.PowerShell.Host/main.cs
@@ -1,4 +1,4 @@
-namespace Microsoft.PowerShell.Linux.Host
+namespace Microsoft.PowerShell.Host
{
using System;
using System.Collections.Generic;
diff --git a/src/Microsoft.PowerShell.Linux.Host/project.json b/src/Microsoft.PowerShell.Host/project.json
similarity index 76%
rename from src/Microsoft.PowerShell.Linux.Host/project.json
rename to src/Microsoft.PowerShell.Host/project.json
index 0bdce2016b..1473ec4472 100644
--- a/src/Microsoft.PowerShell.Linux.Host/project.json
+++ b/src/Microsoft.PowerShell.Host/project.json
@@ -19,6 +19,7 @@
"content": [
"Modules",
+ "../Modules",
"*_profile.ps1",
"*.so",
"*.dylib"
@@ -28,5 +29,15 @@
"netstandardapp1.5": {
"imports": [ "dnxcore50", "portable-net45+win8" ]
}
+ },
+
+ "runtimes": {
+ "ubuntu.14.04-x64": { },
+ "centos.7.1-x64": { },
+ "win7-x64": { },
+ "win81-x64": { },
+ "win10-x64": { },
+ "osx.10.10-x64": { },
+ "osx.10.11-x64": { }
}
}
diff --git a/src/Microsoft.PowerShell.Linux.Host/rawui.cs b/src/Microsoft.PowerShell.Host/rawui.cs
similarity index 99%
rename from src/Microsoft.PowerShell.Linux.Host/rawui.cs
rename to src/Microsoft.PowerShell.Host/rawui.cs
index 9b359a2daa..e4b2214205 100644
--- a/src/Microsoft.PowerShell.Linux.Host/rawui.cs
+++ b/src/Microsoft.PowerShell.Host/rawui.cs
@@ -10,7 +10,7 @@ using System.Globalization;
using System.Reflection;
using System.Runtime.InteropServices;
-namespace Microsoft.PowerShell.Linux.Host
+namespace Microsoft.PowerShell.Host
{
// this is all from https://msdn.microsoft.com/en-us/library/ee706570%28v=vs.85%29.aspx
diff --git a/src/Microsoft.PowerShell.Linux.Host/readline.cs b/src/Microsoft.PowerShell.Host/readline.cs
similarity index 99%
rename from src/Microsoft.PowerShell.Linux.Host/readline.cs
rename to src/Microsoft.PowerShell.Host/readline.cs
index f44bdbb764..8d6c4bda8d 100644
--- a/src/Microsoft.PowerShell.Linux.Host/readline.cs
+++ b/src/Microsoft.PowerShell.Host/readline.cs
@@ -1,4 +1,4 @@
-namespace Microsoft.PowerShell.Linux.Host
+namespace Microsoft.PowerShell.Host
{
using System;
using System.Collections.ObjectModel;
diff --git a/src/Microsoft.PowerShell.Linux.Host/ui.cs b/src/Microsoft.PowerShell.Host/ui.cs
similarity index 99%
rename from src/Microsoft.PowerShell.Linux.Host/ui.cs
rename to src/Microsoft.PowerShell.Host/ui.cs
index 04aed71c5c..ad325690a8 100644
--- a/src/Microsoft.PowerShell.Linux.Host/ui.cs
+++ b/src/Microsoft.PowerShell.Host/ui.cs
@@ -1,4 +1,4 @@
-namespace Microsoft.PowerShell.Linux.Host
+namespace Microsoft.PowerShell.Host
{
using System;
using System.Collections.Generic;
diff --git a/src/Microsoft.PowerShell.Linux.Host/update-content.sh b/src/Microsoft.PowerShell.Linux.Host/update-content.sh
deleted file mode 100755
index 967d10f98e..0000000000
--- a/src/Microsoft.PowerShell.Linux.Host/update-content.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env bash
-
-# Types files
-cp ../monad/monad/miscfiles/types/CoreClr/types.ps1xml .
-cp ../monad/monad/miscfiles/types/CoreClr/typesv3.ps1xml .
-
-# Format files
-cp ../monad/monad/miscfiles/display/Certificate.format.ps1xml .
-cp ../monad/monad/miscfiles/display/Diagnostics.Format.ps1xml Diagnostics.format.ps1xml
-cp ../monad/monad/miscfiles/display/DotNetTypes.format.ps1xml .
-cp ../monad/monad/miscfiles/display/Event.format.ps1xml .
-cp ../monad/monad/miscfiles/display/FileSystem.format.ps1xml .
-cp ../monad/monad/miscfiles/display/Help.format.ps1xml .
-cp ../monad/monad/miscfiles/display/HelpV3.format.ps1xml .
-cp ../monad/monad/miscfiles/display/PowerShellCore.format.ps1xml .
-cp ../monad/monad/miscfiles/display/PowerShellTrace.format.ps1xml .
-cp ../monad/monad/miscfiles/display/Registry.format.ps1xml .
-cp ../monad/monad/miscfiles/display/WSMan.format.ps1xml .
-
-mkdir Modules
-cp -r ../monad/monad/miscfiles/modules/Microsoft.PowerShell.Utility Modules
-UTILSCLR=Modules/Microsoft.PowerShell.Utility/CoreClr
-mv $UTILSCLR/* Modules/Microsoft.PowerShell.Utility && rmdir $UTILSCLR
-cp -r ../monad/monad/miscfiles/modules/Microsoft.PowerShell.Security Modules
-cp -r ../monad/monad/miscfiles/modules/Microsoft.PowerShell.Management Modules
-cp -r ../monad/monad/miscfiles/modules/PSDiagnostics Modules
diff --git a/src/Modules/AppxProvider/AppxProvider.Resource.psd1 b/src/Modules/AppxProvider/AppxProvider.Resource.psd1
new file mode 100644
index 0000000000..f9c68ab194
Binary files /dev/null and b/src/Modules/AppxProvider/AppxProvider.Resource.psd1 differ
diff --git a/src/Modules/AppxProvider/AppxProvider.psd1 b/src/Modules/AppxProvider/AppxProvider.psd1
new file mode 100644
index 0000000000..b9f746d7e6
Binary files /dev/null and b/src/Modules/AppxProvider/AppxProvider.psd1 differ
diff --git a/src/Modules/AppxProvider/AppxProvider.psm1 b/src/Modules/AppxProvider/AppxProvider.psm1
new file mode 100644
index 0000000000..1c7a9f8ab1
--- /dev/null
+++ b/src/Modules/AppxProvider/AppxProvider.psm1
@@ -0,0 +1,956 @@
+#########################################################################################
+#
+# Copyright (c) Microsoft Corporation. All rights reserved.
+#
+# Appx Provider Module
+#
+#########################################################################################
+
+$script:ProviderName = "appx"
+$script:AppxPackageExtension = ".appx"
+$script:AppxManifestFile = "AppxManifest.xml"
+$script:Architecture = "Architecture"
+$script:ResourceId = "ResourceId"
+$script:AppxPackageSources = $null
+$script:AppxLocalPath="$env:LOCALAPPDATA\Microsoft\Windows\PowerShell\AppxProvider"
+$script:AppxPackageSourcesFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:AppxLocalPath -ChildPath "AppxPackageSources.xml"
+$Script:ResponseUri = "ResponseUri"
+$Script:StatusCode = "StatusCode"
+# Wildcard pattern matching configuration.
+$script:wildcardOptions = [System.Management.Automation.WildcardOptions]::CultureInvariant -bor `
+ [System.Management.Automation.WildcardOptions]::IgnoreCase
+#Localized Data
+Microsoft.PowerShell.Utility\Import-LocalizedData LocalizedData -filename AppxProvider.Resource.psd1
+
+#region Appx Provider APIs Implementation
+function Get-PackageProviderName
+{
+ return $script:ProviderName
+}
+
+function Initialize-Provider{
+ param(
+ )
+}
+
+function Get-DynamicOptions
+{
+ param
+ (
+ [Microsoft.PackageManagement.MetaProvider.PowerShell.OptionCategory]
+ $category
+ )
+
+ Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Get-DynamicOptions'))
+
+ switch($category)
+ {
+ Install {
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name Architecture -ExpectedType String -IsRequired $false)
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name ResourceId -ExpectedType String -IsRequired $false)
+ }
+ Package {
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name Architecture -ExpectedType String -IsRequired $false)
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name ResourceId -ExpectedType String -IsRequired $false)
+ }
+ }
+}
+
+function Find-Package
+{
+ [CmdletBinding()]
+ param
+ (
+ [string[]]
+ $names,
+
+ [string]
+ $requiredVersion,
+
+ [string]
+ $minimumVersion,
+
+ [string]
+ $maximumVersion
+ )
+
+ Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Find-Package'))
+
+ $ResourceId = $null
+ $Architecture = $null
+ $Sources = @()
+ $streamedResults = @()
+ $namesParameterEmpty = (-not $names) -or (($names.Count -eq 1) -and ($names[0] -eq ''))
+
+ Set-PackageSourcesVariable
+
+ if($RequiredVersion -and $MinimumVersion)
+ {
+
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $LocalizedData.VersionRangeAndRequiredVersionCannotBeSpecifiedTogether `
+ -ErrorId "VersionRangeAndRequiredVersionCannotBeSpecifiedTogether" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+ if($RequiredVersion -or $MinimumVersion)
+ {
+ if(-not $names -or $names.Count -ne 1 -or (Test-WildcardPattern -Name $names[0]))
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $LocalizedData.VersionParametersAreAllowedOnlyWithSinglePackage `
+ -ErrorId "VersionParametersAreAllowedOnlyWithSinglePackage" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+ }
+
+ $options = $request.Options
+ if($options)
+ {
+ foreach( $o in $options.Keys )
+ {
+ Write-Debug ( "OPTION: {0} => {1}" -f ($o, $options[$o]) )
+ }
+
+ if($options.ContainsKey('Source'))
+ {
+ $SourceNames = $($options['Source'])
+ Write-Verbose ($LocalizedData.SpecifiedSourceName -f ($SourceNames))
+ foreach($sourceName in $SourceNames)
+ {
+ if($script:AppxPackageSources.Contains($sourceName))
+ {
+ $Sources += $script:AppxPackageSources[$sourceName]
+ }
+ else
+ {
+ $sourceByLocation = Get-SourceName -Location $sourceName
+ if ($sourceByLocation -ne $null)
+ {
+ $Sources += $script:AppxPackageSources[$sourceByLocation]
+ }
+ else
+ {
+ $message = $LocalizedData.PackageSourceNotFound -f ($sourceName)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "PackageSourceNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $sourceName
+ }
+ }
+ }
+ }
+ else
+ {
+ Write-Verbose $LocalizedData.NoSourceNameIsSpecified
+ $script:AppxPackageSources.Values | Microsoft.PowerShell.Core\ForEach-Object { $Sources += $_ }
+ }
+
+ if($options.ContainsKey($script:Architecture))
+ {
+ $Architecture = $options[$script:Architecture]
+ }
+ if($options.ContainsKey($script:ResourceId))
+ {
+ $ResourceId = $options[$script:ResourceId]
+ }
+ }
+
+ foreach($source in $Sources)
+ {
+ $location = $source.SourceLocation
+ if($request.IsCanceled)
+ {
+ return
+ }
+ if(-not(Test-Path $location))
+ {
+ $message = $LocalizedData.PathNotFound -f ($Location)
+ Write-Verbose $message
+ continue
+ }
+
+ $packages = Get-AppxPackagesFromPath -path $location
+ foreach($pkg in $packages)
+ {
+ if($request.IsCanceled)
+ {
+ return
+ }
+
+ $pkgManifest = Get-PackageManfiestData -PackageFullPath $pkg.FullName
+ if(-not $pkgManifest)
+ {
+ continue
+ }
+
+ # $pkgManifest.Name has to match any of the supplied names, using PowerShell wildcards
+ if(-not($namesParameterEmpty))
+ {
+ if(-not(($names | Microsoft.PowerShell.Core\ForEach-Object { if ($pkgManifest.Name -like $_){return $true; break} } -End {return $false})))
+ {
+ continue
+ }
+ }
+
+ # Version
+ if($RequiredVersion)
+ {
+ if($RequiredVersion -ne $pkgManifest.Version)
+ {
+ continue
+ }
+ }
+ else
+ {
+ if(-not((-not $MinimumVersion -or ($MinimumVersion -le $pkgManifest.Version)) -and
+ (-not $MaximumVersion -or ($MaximumVersion -ge $pkgManifest.Version))))
+ {
+ continue
+ }
+ }
+
+
+ if($Architecture)
+ {
+ $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $Architecture, $script:wildcardOptions
+ if(-not($wildcardPattern.IsMatch($pkgManifest.Architecture)))
+ {
+ continue
+ }
+ }
+
+ if($ResourceId)
+ {
+ $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $ResourceId, $script:wildcardOptions
+ if(-not($wildcardPattern.IsMatch($pkgManifest.ResourceId)))
+ {
+ continue
+ }
+ }
+
+ $sid = New-SoftwareIdentityFromPackage -Package $pkgManifest -Source $source.Name
+ $fastPackageReference = $sid.fastPackageReference
+ if($streamedResults -notcontains $fastPackageReference)
+ {
+ $streamedResults += $fastPackageReference
+ Write-Output -InputObject $sid
+ }
+ }
+ }
+}
+
+function Get-InstalledPackage
+{
+ [CmdletBinding()]
+ param
+ (
+ [Parameter()]
+ [string]
+ $Name,
+
+ [Parameter()]
+ [string]
+ $RequiredVersion,
+
+ [Parameter()]
+ [string]
+ $MinimumVersion,
+
+ [Parameter()]
+ [string]
+ $MaximumVersion
+ )
+
+ Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Get-InstalledPackage'))
+
+ $Architecture = $null
+ $ResourceId = $null
+
+ $options = $request.Options
+ if($options)
+ {
+ if($options.ContainsKey($script:Architecture))
+ {
+ $Architecture = $options[$script:Architecture]
+ }
+ if($options.ContainsKey($script:ResourceId))
+ {
+ $ResourceId = $options[$script:ResourceId]
+ }
+ }
+
+ $params = @{}
+ if($Name)
+ {
+ $params.Add("Name", $Name)
+ }
+ $packages = Appx\Get-AppxPackage @params
+
+ foreach($package in $packages)
+ {
+ if($RequiredVersion)
+ {
+ if($RequiredVersion -ne $package.Version)
+ {
+ continue
+ }
+ }
+ else
+ {
+ if(-not((-not $MinimumVersion -or ($MinimumVersion -le $package.Version)) -and
+ (-not $MaximumVersion -or ($MaximumVersion -ge $package.Version))))
+ {
+ continue
+ }
+ }
+
+ if($Architecture)
+ {
+ $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $Architecture, $script:wildcardOptions
+ if(-not($wildcardPattern.IsMatch($package.Architecture)))
+ {
+ continue
+ }
+ }
+ if($ResourceId)
+ {
+ $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $ResourceId,$script:wildcardOptions
+ if(-not($wildcardPattern.IsMatch($package.ResourceId)))
+ {
+ continue
+ }
+ }
+
+ $sid = New-SoftwareIdentityFromPackage -Package $package
+ write-Output $sid
+ }
+}
+
+function Install-Package
+{
+ [CmdletBinding()]
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $fastPackageReference
+ )
+
+ Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Install-Package'))
+ Write-Debug -Message ($LocalizedData.FastPackageReference -f $fastPackageReference)
+
+ Appx\Add-AppxPackage -Path $fastPackageReference
+}
+
+function UnInstall-Package
+{
+ [CmdletBinding()]
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $fastPackageReference
+ )
+
+ Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Uninstall-Package'))
+ Write-Debug -Message ($LocalizedData.FastPackageReference -f $fastPackageReference)
+
+ Appx\Remove-AppxPackage -Package $fastPackageReference
+}
+
+function Add-PackageSource
+{
+ [CmdletBinding()]
+ param
+ (
+ [string]
+ $Name,
+
+ [string]
+ $Location,
+
+ [bool]
+ $Trusted
+ )
+
+ Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Add-PackageSource'))
+
+ Set-PackageSourcesVariable -Force
+
+ if(-not (Microsoft.PowerShell.Management\Test-Path $Location) -and
+ -not (Test-WebUri -uri $Location))
+ {
+ $LocationUri = [Uri]$Location
+ if($LocationUri.Scheme -eq 'file')
+ {
+ $message = $LocalizedData.PathNotFound -f ($Location)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Location
+ }
+ else
+ {
+ $message = $LocalizedData.InvalidWebUri -f ($Location, "Location")
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidWebUri" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Location
+ }
+ }
+
+ if(Test-WildcardPattern $Name)
+ {
+ $message = $LocalizedData.PackageSourceNameContainsWildCards -f ($Name)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "PackageSourceNameContainsWildCards" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Name
+ }
+
+ $LocationString = Get-ValidPackageLocation -LocationString $Location -ParameterName "Location"
+
+ # Check if Location is already registered with another Name
+ $existingSourceName = Get-SourceName -Location $LocationString
+
+ if($existingSourceName -and
+ ($Name -ne $existingSourceName))
+ {
+ $message = $LocalizedData.PackageSourceAlreadyRegistered -f ($existingSourceName, $Location, $Name)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "PackageSourceAlreadyRegistered" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+
+ # Check if Name is already registered
+ if($script:AppxPackageSources.Contains($Name))
+ {
+ $currentSourceObject = $script:AppxPackageSources[$Name]
+ $null = $script:AppxPackageSources.Remove($Name)
+ }
+
+ # Add new package source
+ $packageSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
+ Name = $Name
+ SourceLocation = $LocationString
+ Trusted=$Trusted
+ Registered= $true
+ })
+
+ $script:AppxPackageSources.Add($Name, $packageSource)
+ $message = $LocalizedData.SourceRegistered -f ($Name, $LocationString)
+ Write-Verbose $message
+
+ # Persist the package sources
+ Save-PackageSources
+
+ # return the package source object.
+ Write-Output -InputObject (New-PackageSourceFromSource -Source $packageSource)
+
+}
+
+function Resolve-PackageSource
+{
+ Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Resolve-PackageSource'))
+
+ Set-PackageSourcesVariable
+
+ $SourceName = $request.PackageSources
+
+ if(-not $SourceName)
+ {
+ $SourceName = "*"
+ }
+
+ foreach($src in $SourceName)
+ {
+ if($request.IsCanceled)
+ {
+ return
+ }
+
+ $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $src,$script:wildcardOptions
+ $sourceFound = $false
+
+ $script:AppxPackageSources.GetEnumerator() |
+ Microsoft.PowerShell.Core\Where-Object {$wildcardPattern.IsMatch($_.Key)} |
+ Microsoft.PowerShell.Core\ForEach-Object {
+ $source = $script:AppxPackageSources[$_.Key]
+ $packageSource = New-PackageSourceFromSource -Source $source
+ Write-Output -InputObject $packageSource
+ $sourceFound = $true
+ }
+
+ if(-not $sourceFound)
+ {
+ $sourceName = Get-SourceName -Location $src
+ if($sourceName)
+ {
+ $source = $script:AppxPackageSources[$sourceName]
+ $packageSource = New-PackageSourceFromSource -Source $source
+ Write-Output -InputObject $packageSource
+ }
+ elseif( -not (Test-WildcardPattern $src))
+ {
+ $message = $LocalizedData.PackageSourceNotFound -f ($src)
+ Write-Error -Message $message -ErrorId "PackageSourceNotFound" -Category InvalidOperation -TargetObject $src
+ }
+ }
+ }
+}
+
+function Remove-PackageSource
+{
+ param
+ (
+ [string]
+ $Name
+ )
+
+ Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Remove-PackageSource'))
+
+ Set-PackageSourcesVariable -Force
+
+ $SourcesToBeRemoved = @()
+
+ foreach ($sourceName in $Name)
+ {
+ if($request.IsCanceled)
+ {
+ return
+ }
+
+ # Check if $Name contains any wildcards
+ if(Test-WildcardPattern $sourceName)
+ {
+ $message = $LocalizedData.PackageSourceNameContainsWildCards -f ($sourceName)
+ Write-Error -Message $message -ErrorId "PackageSourceNameContainsWildCards" -Category InvalidOperation -TargetObject $sourceName
+ continue
+ }
+
+ # Check if the specified package source name is in the registered package sources
+ if(-not $script:AppxPackageSources.Contains($sourceName))
+ {
+ $message = $LocalizedData.PackageSourceNotFound -f ($sourceName)
+ Write-Error -Message $message -ErrorId "PackageSourceNotFound" -Category InvalidOperation -TargetObject $sourceName
+ continue
+ }
+
+ $SourcesToBeRemoved += $sourceName
+ $message = $LocalizedData.PackageSourceUnregistered -f ($sourceName)
+ Write-Verbose $message
+ }
+
+ # Remove the SourcesToBeRemoved
+ $SourcesToBeRemoved | Microsoft.PowerShell.Core\ForEach-Object { $null = $script:AppxPackageSources.Remove($_) }
+
+ # Persist the package sources
+ Save-PackageSources
+}
+#endregion
+
+#region Common functions
+
+function Get-AppxPackagesFromPath
+{
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ $Path
+ )
+
+ $filterAppxPackages = "*"+$script:AppxPackageExtension
+ $packages = Get-ChildItem -path $Path -filter $filterAppxPackages
+
+ return $packages
+
+}
+
+function Get-PackageManfiestData
+{
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ $PackageFullPath
+ )
+ $guid = [System.Guid]::NewGuid().toString()
+ try
+ {
+ [System.IO.Compression.ZipFile]::ExtractToDirectory($PackageFullPath, "$env:TEMP\$guid")
+ }
+ catch
+ {
+ Write-Verbose( $LocalizedData.MetaDataExtractionFailed -f ($PackageFullPath) )
+ return $null
+ }
+
+ [xml] $packageManifest = Get-Content "$env:TEMP\$guid\$script:AppxManifestFile" -ErrorAction SilentlyContinue
+ if($packageManifest)
+ {
+ $Identity = $packageManifest.Package.Identity
+ $manifestData = new-object psObject -Property @{Name=$Identity.Name; Architecture=$Identity.ProcessorArchitecture; Publisher=$Identity.Publisher; Version=$Identity.Version; ResourceId=$Identity.resourceId; PackageFullName=$PackageFullPath}
+ Remove-Item -Path "$env:TEMP\$guid" -Recurse -Force -ErrorAction SilentlyContinue
+ return $manifestData
+ }
+ else
+ {
+ Write-Verbose ($LocalizedData.MetaDataExtractionFailed -f ($PackageFullPath) )
+ }
+ return $null
+}
+
+function New-FastPackageReference
+{
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ [string]
+ $PackageFullName
+ )
+ return "$PackageFullName"
+}
+
+function New-SoftwareIdentityFromPackage
+{
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ $Package,
+
+ [string]
+ $Source
+
+ )
+
+ $fastPackageReference = New-FastPackageReference -PackageFullName $Package.PackageFullName
+
+ if(-not($Source))
+ {
+ $Source = $Package.Publisher
+ }
+ $details = @{
+ Publisher = $Package.Publisher
+ Architecture = $Package.Architecture
+ ResourceId = $Package.ResourceId
+ PackageFullName = $Package.PackageFullName
+ }
+
+ $params = @{
+ FastPackageReference = $fastPackageReference;
+ Name = $Package.Name;
+ Version = $Package.Version;
+ versionScheme = "MultiPartNumeric";
+ Source = $source;
+ Details = $details;
+ }
+
+ $sid = New-SoftwareIdentity @params
+ return $sid
+}
+
+function Test-WebUri
+{
+ [CmdletBinding()]
+ [OutputType([bool])]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $uri
+ )
+
+ return ($uri.AbsoluteURI -ne $null) -and ($uri.Scheme -match '[http|https]')
+}
+
+function Test-WildcardPattern
+{
+ [CmdletBinding()]
+ [OutputType([bool])]
+ param(
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNull()]
+ $Name
+ )
+
+ return [System.Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Name)
+}
+
+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)
+}
+
+function Get-SourceName
+{
+ [CmdletBinding()]
+ [OutputType("string")]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Location
+ )
+
+ Set-PackageSourcesVariable
+
+ foreach($source in $script:AppxPackageSources.Values)
+ {
+ if($source.SourceLocation -eq $Location)
+ {
+ return $source.Name
+ }
+ }
+}
+
+function WebRequestApisAvailable
+{
+ $webRequestApiAvailable = $false
+ try
+ {
+ [System.Net.WebRequest]
+ $webRequestApiAvailable = $true
+ }
+ catch
+ {
+ }
+ return $webRequestApiAvailable
+}
+
+function Ping-Endpoint
+{
+ param
+ (
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Endpoint
+ )
+
+ $results = @{}
+
+ if(WebRequestApisAvailable)
+ {
+ $iss = [System.Management.Automation.Runspaces.InitialSessionState]::Create()
+ $iss.types.clear()
+ $iss.formats.clear()
+ $iss.LanguageMode = "FullLanguage"
+
+ $WebRequestcmd = @'
+ try
+ {{
+ $request = [System.Net.WebRequest]::Create("{0}")
+ $request.Method = 'GET'
+ $request.Timeout = 30000
+ $response = [System.Net.HttpWebResponse]$request.GetResponse()
+ $response
+ $response.Close()
+ }}
+ catch [System.Net.WebException]
+ {{
+ "Error:System.Net.WebException"
+ }}
+'@ -f $EndPoint
+
+ $ps = [powershell]::Create($iss).AddScript($WebRequestcmd)
+ $response = $ps.Invoke()
+ $ps.dispose()
+
+ if ($response -ne "Error:System.Net.WebException")
+ {
+ $results.Add($Script:ResponseUri,$response.ResponseUri.ToString())
+ $results.Add($Script:StatusCode,$response.StatusCode.value__)
+ }
+ }
+ else
+ {
+ $response = $null
+ try
+ {
+ $httpClient = New-Object 'System.Net.Http.HttpClient'
+ $response = $httpclient.GetAsync($endpoint)
+ }
+ catch
+ {
+ }
+
+ if ($response -ne $null -and $response.result -ne $null)
+ {
+ $results.Add($Script:ResponseUri,$response.Result.RequestMessage.RequestUri.AbsoluteUri.ToString())
+ $results.Add($Script:StatusCode,$response.result.StatusCode.value__)
+ }
+ }
+ return $results
+}
+
+function Get-ValidPackageLocation
+{
+ [CmdletBinding()]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $LocationString,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $ParameterName
+ )
+
+ # Get the actual Uri from the Location
+ if(-not (Microsoft.PowerShell.Management\Test-Path $LocationString))
+ {
+ $results = Ping-Endpoint -Endpoint $LocationString
+
+ if ($results.ContainsKey("Exception"))
+ {
+ $Exception = $results["Exception"]
+ if($Exception)
+ {
+ $message = $LocalizedData.InvalidWebUri -f ($LocationString, $ParameterName)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidWebUri" `
+ -ExceptionObject $Exception `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+ }
+
+ if ($results.ContainsKey("ResponseUri"))
+ {
+ $LocationString = $results["ResponseUri"]
+ }
+ }
+
+ return $LocationString
+}
+
+function Set-PackageSourcesVariable
+{
+ param([switch]$Force)
+
+ if(-not $script:AppxPackageSources -or $Force)
+ {
+ if(Microsoft.PowerShell.Management\Test-Path $script:AppxPackageSourcesFilePath)
+ {
+ $script:AppxPackageSources = DeSerialize-PSObject -Path $script:AppxPackageSourcesFilePath
+ }
+ else
+ {
+ $script:AppxPackageSources = [ordered]@{}
+ }
+ }
+}
+
+function Save-PackageSources
+{
+ if($script:AppxPackageSources)
+ {
+ if(-not (Microsoft.PowerShell.Management\Test-Path $script:AppxLocalPath))
+ {
+ $null = Microsoft.PowerShell.Management\New-Item -Path $script:AppxLocalPath `
+ -ItemType Directory -Force `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue `
+ -Confirm:$false -WhatIf:$false
+ }
+ Microsoft.PowerShell.Utility\Out-File -FilePath $script:AppxPackageSourcesFilePath -Force -InputObject ([System.Management.Automation.PSSerializer]::Serialize($script:AppxPackageSources))
+ }
+}
+
+function New-PackageSourceFromSource
+{
+ param
+ (
+ [Parameter(Mandatory)]
+ $Source
+ )
+
+ # create a new package source
+ $src = New-PackageSource -Name $Source.Name `
+ -Location $Source.SourceLocation `
+ -Trusted $Source.Trusted `
+ -Registered $Source.Registered `
+
+ Write-Verbose ( $LocalizedData.PackageSourceDetails -f ($src.Name, $src.Location, $src.IsTrusted, $src.IsRegistered) )
+
+ # return the package source object.
+ Write-Output -InputObject $src
+}
+#endregion
+
+# Utility to throw an errorrecord
+function ThrowError
+{
+ param
+ (
+ [parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [System.Management.Automation.PSCmdlet]
+ $CallerPSCmdlet,
+
+ [parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [System.String]
+ $ExceptionName,
+
+ [parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [System.String]
+ $ExceptionMessage,
+
+ [System.Object]
+ $ExceptionObject,
+
+ [parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [System.String]
+ $ErrorId,
+
+ [parameter(Mandatory = $true)]
+ [ValidateNotNull()]
+ [System.Management.Automation.ErrorCategory]
+ $ErrorCategory
+ )
+
+ $exception = New-Object $ExceptionName $ExceptionMessage;
+ $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $ErrorId, $ErrorCategory, $ExceptionObject
+ $CallerPSCmdlet.ThrowTerminatingError($errorRecord)
+}
+#endregion
+
+Export-ModuleMember -Function Find-Package, `
+ Install-Package, `
+ Uninstall-Package, `
+ Get-InstalledPackage, `
+ Remove-PackageSource, `
+ Resolve-PackageSource, `
+ Add-PackageSource, `
+ Get-DynamicOptions, `
+ Initialize-Provider, `
+ Get-PackageProviderName
\ No newline at end of file
diff --git a/src/Modules/Microsoft.PowerShell.Archive/ArchiveResources.psd1 b/src/Modules/Microsoft.PowerShell.Archive/ArchiveResources.psd1
new file mode 100644
index 0000000000..914f951df0
Binary files /dev/null and b/src/Modules/Microsoft.PowerShell.Archive/ArchiveResources.psd1 differ
diff --git a/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1 b/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1
new file mode 100644
index 0000000000..859ea55124
--- /dev/null
+++ b/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1
@@ -0,0 +1,12 @@
+@{
+GUID="eb74e8da-9ae2-482a-a648-e96550fb8733"
+Author="Microsoft Corporation"
+CompanyName="Microsoft Corporation"
+Copyright="© Microsoft Corporation. All rights reserved."
+ModuleVersion="1.0.0.0"
+FunctionsToExport = @('Compress-Archive', 'Expand-Archive')
+CmdletsToExport = @()
+AliasesToExport = @()
+NestedModules="Microsoft.PowerShell.Archive.psm1"
+HelpInfoURI = 'http://go.microsoft.com/fwlink/?LinkId=393254'
+}
diff --git a/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1 b/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1
new file mode 100644
index 0000000000..b301646d6e
Binary files /dev/null and b/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1 differ
diff --git a/src/Modules/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1 b/src/Modules/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1
new file mode 100644
index 0000000000..9b3ecfc5f2
--- /dev/null
+++ b/src/Modules/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1
@@ -0,0 +1,14 @@
+@{
+GUID="56D66100-99A0-4FFC-A12D-EEE9A6718AEF"
+Author="Microsoft Corporation"
+CompanyName="Microsoft Corporation"
+Copyright="© Microsoft Corporation. All rights reserved."
+ModuleVersion="3.0.0.0"
+PowerShellVersion="3.0"
+CLRVersion="4.0"
+AliasesToExport = @()
+FunctionsToExport = @()
+CmdletsToExport="Start-Transcript", "Stop-Transcript"
+NestedModules="Microsoft.PowerShell.ConsoleHost.dll"
+HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=390784'
+}
diff --git a/src/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1 b/src/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1
new file mode 100644
index 0000000000..425e64b78b
--- /dev/null
+++ b/src/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1
@@ -0,0 +1,99 @@
+@{
+GUID="EEFCB906-B326-4E99-9F54-8B4BB6EF3C6D"
+Author="Microsoft Corporation"
+CompanyName="Microsoft Corporation"
+Copyright="© Microsoft Corporation. All rights reserved."
+ModuleVersion="3.1.0.0"
+PowerShellVersion="3.0"
+CLRVersion="4.0"
+NestedModules="Microsoft.PowerShell.Commands.Management.dll"
+HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=390785'
+AliasesToExport = @("gcb", "scb")
+FunctionsToExport = @()
+CmdletsToExport=@("Add-Content",
+ "Clear-Content",
+ "Clear-ItemProperty",
+ "Join-Path",
+ "Convert-Path",
+ "Copy-ItemProperty",
+ "Get-EventLog",
+ "Clear-EventLog",
+ "Write-EventLog",
+ "Limit-EventLog",
+ "Show-EventLog",
+ "New-EventLog",
+ "Remove-EventLog",
+ "Get-ChildItem",
+ "Get-Content",
+ "Get-ItemProperty",
+ "Get-ItemPropertyValue",
+ "Get-WmiObject",
+ "Invoke-WmiMethod",
+ "Move-ItemProperty",
+ "Get-Location",
+ "Set-Location",
+ "Push-Location",
+ "Pop-Location",
+ "New-PSDrive",
+ "Remove-PSDrive",
+ "Get-PSDrive",
+ "Get-Item",
+ "New-Item",
+ "Set-Item",
+ "Remove-Item",
+ "Move-Item",
+ "Rename-Item",
+ "Copy-Item",
+ "Clear-Item",
+ "Invoke-Item",
+ "Get-PSProvider",
+ "New-ItemProperty",
+ "Split-Path",
+ "Test-Path",
+ "Get-Process",
+ "Stop-Process",
+ "Wait-Process",
+ "Debug-Process",
+ "Start-Process",
+ "Remove-ItemProperty",
+ "Remove-WmiObject",
+ "Rename-ItemProperty",
+ "Register-WmiEvent",
+ "Resolve-Path",
+ "Get-Service",
+ "Stop-Service",
+ "Start-Service",
+ "Suspend-Service",
+ "Resume-Service",
+ "Restart-Service",
+ "Set-Service",
+ "New-Service",
+ "Set-Content",
+ "Set-ItemProperty",
+ "Set-WmiInstance",
+ "Get-Transaction",
+ "Start-Transaction",
+ "Complete-Transaction",
+ "Undo-Transaction",
+ "Use-Transaction",
+ "New-WebServiceProxy",
+ "Get-HotFix",
+ "Test-Connection",
+ "Enable-ComputerRestore",
+ "Disable-ComputerRestore",
+ "Checkpoint-Computer",
+ "Get-ComputerRestorePoint",
+ "Restart-Computer",
+ "Stop-Computer",
+ "Restore-Computer",
+ "Add-Computer",
+ "Remove-Computer",
+ "Test-ComputerSecureChannel",
+ "Reset-ComputerMachinePassword",
+ "Rename-Computer",
+ "Get-ControlPanelItem",
+ "Show-ControlPanelItem",
+ "Clear-Recyclebin",
+ "Get-Clipboard",
+ "Set-Clipboard")
+}
diff --git a/src/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 b/src/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1
new file mode 100644
index 0000000000..a5a678d7b8
--- /dev/null
+++ b/src/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1
@@ -0,0 +1,14 @@
+@{
+GUID="A94C8C7E-9810-47C0-B8AF-65089C13A35A"
+Author="Microsoft Corporation"
+CompanyName="Microsoft Corporation"
+Copyright="© Microsoft Corporation. All rights reserved."
+ModuleVersion="3.0.0.0"
+PowerShellVersion="3.0"
+CLRVersion="4.0"
+AliasesToExport = @()
+FunctionsToExport = @()
+CmdletsToExport="Get-Acl", "Set-Acl", "Get-PfxCertificate", "Get-Credential", "Get-ExecutionPolicy", "Set-ExecutionPolicy", "Get-AuthenticodeSignature", "Set-AuthenticodeSignature", "ConvertFrom-SecureString", "ConvertTo-SecureString", "Get-CmsMessage", "Unprotect-CmsMessage", "Protect-CmsMessage" , "New-FileCatalog" , "Test-FileCatalog"
+NestedModules="Microsoft.PowerShell.Security.dll"
+HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=390786'
+}
diff --git a/src/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1 b/src/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1
new file mode 100644
index 0000000000..85eaf15336
--- /dev/null
+++ b/src/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1
@@ -0,0 +1,709 @@
+function Get-FileHash
+{
+ [CmdletBinding(DefaultParameterSetName = "Path", HelpURI = "http://go.microsoft.com/fwlink/?LinkId=517145")]
+ param(
+ [Parameter(Mandatory, ParameterSetName="Path", Position = 0)]
+ [System.String[]]
+ $Path,
+
+ [Parameter(Mandatory, ParameterSetName="LiteralPath", ValueFromPipelineByPropertyName = $true)]
+ [Alias("PSPath")]
+ [System.String[]]
+ $LiteralPath,
+
+ [Parameter(Mandatory, ParameterSetName="Stream")]
+ [System.IO.Stream]
+ $InputStream,
+
+ [ValidateSet("SHA1", "SHA256", "SHA384", "SHA512", "MACTripleDES", "MD5", "RIPEMD160")]
+ [System.String]
+ $Algorithm="SHA256"
+ )
+
+ begin
+ {
+ # Construct the strongly-typed crypto object
+
+ # First see if it has a FIPS algorithm
+ $hasherType = "System.Security.Cryptography.${Algorithm}CryptoServiceProvider" -as [Type]
+ if ($hasherType)
+ {
+ $hasher = $hasherType::New()
+ }
+ else
+ {
+ # Check if the type is supported in the current system
+ $algorithmType = "System.Security.Cryptography.${Algorithm}" -as [Type]
+ if ($algorithmType)
+ {
+ if ($Algorithm -eq "MACTripleDES")
+ {
+ $hasher = $algorithmType::New()
+ }
+ else
+ {
+ $hasher = $algorithmType::Create()
+ }
+ }
+ else
+ {
+ $errorId = "AlgorithmTypeNotSupported"
+ $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidArgument
+ $errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::AlgorithmTypeNotSupported -f $Algorithm
+ $exception = [System.InvalidOperationException]::New($errorMessage)
+ $errorRecord = [System.Management.Automation.ErrorRecord]::New($exception, $errorId, $errorCategory, $null)
+ $PSCmdlet.ThrowTerminatingError($errorRecord)
+ }
+ }
+
+ function GetStreamHash
+ {
+ param(
+ [System.IO.Stream]
+ $InputStream,
+
+ [System.String]
+ $RelatedPath,
+
+ [System.Security.Cryptography.HashAlgorithm]
+ $Hasher)
+
+ # Compute file-hash using the crypto object
+ [Byte[]] $computedHash = $Hasher.ComputeHash($InputStream)
+ [string] $hash = [BitConverter]::ToString($computedHash) -replace '-',''
+
+ if ($RelatedPath -eq $null)
+ {
+ $retVal = [PSCustomObject] @{
+ Algorithm = $Algorithm.ToUpperInvariant()
+ Hash = $hash
+ }
+ }
+ else
+ {
+ $retVal = [PSCustomObject] @{
+ Algorithm = $Algorithm.ToUpperInvariant()
+ Hash = $hash
+ Path = $RelatedPath
+ }
+ }
+ $retVal.psobject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash")
+ $retVal
+ }
+ }
+
+ process
+ {
+ if($PSCmdlet.ParameterSetName -eq "Stream")
+ {
+ GetStreamHash -InputStream $InputStream -RelatedPath $null -Hasher $hasher
+ }
+ else
+ {
+ $pathsToProcess = @()
+ if($PSCmdlet.ParameterSetName -eq "LiteralPath")
+ {
+ $pathsToProcess += Resolve-Path -LiteralPath $LiteralPath | Foreach-Object ProviderPath
+ }
+ if($PSCmdlet.ParameterSetName -eq "Path")
+ {
+ $pathsToProcess += Resolve-Path $Path | Foreach-Object ProviderPath
+ }
+
+ foreach($filePath in $pathsToProcess)
+ {
+ if(Test-Path -LiteralPath $filePath -PathType Container)
+ {
+ continue
+ }
+
+ try
+ {
+ # Read the file specified in $FilePath as a Byte array
+ [system.io.stream]$stream = [system.io.file]::OpenRead($filePath)
+ GetStreamHash -InputStream $stream -RelatedPath $filePath -Hasher $hasher
+ }
+ catch [Exception]
+ {
+ $errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::FileReadError -f $FilePath, $_
+ Write-Error -Message $errorMessage -Category ReadError -ErrorId "FileReadError" -TargetObject $FilePath
+ return
+ }
+ finally
+ {
+ if($stream)
+ {
+ $stream.Dispose()
+ }
+ }
+ }
+ }
+ }
+}
+
+<# This cmdlet is used to create a new temporary file in $env:temp #>
+function New-TemporaryFile
+{
+ [CmdletBinding(
+ HelpURI='http://go.microsoft.com/fwlink/?LinkId=526726',
+ SupportsShouldProcess=$true)]
+ [OutputType([System.IO.FileInfo])]
+ Param()
+
+ Begin
+ {
+ try
+ {
+ if($PSCmdlet.ShouldProcess($env:TEMP))
+ {
+ $tempFilePath = [System.IO.Path]::GetTempFileName()
+ }
+ }
+ catch
+ {
+ $errorRecord = [System.Management.Automation.ErrorRecord]::new($_.Exception,"NewTemporaryFileWriteError", "WriteError", $env:TEMP)
+ Write-Error -ErrorRecord $errorRecord
+ return
+ }
+
+ if($tempFilePath)
+ {
+ Get-Item $tempFilePath
+ }
+ }
+}
+
+<# This cmdlet is used to generate a new guid #>
+function New-Guid
+{
+ [CmdletBinding(HelpURI='http://go.microsoft.com/fwlink/?LinkId=526920')]
+ [OutputType([System.Guid])]
+ Param()
+
+ Begin
+ {
+ [Guid]::NewGuid()
+ }
+}
+
+<############################################################################################
+# Format-Hex cmdlet helps in displaying the Hexadecimal equivalent of the input data.
+############################################################################################>
+function Format-Hex
+{
+ [CmdletBinding(
+ DefaultParameterSetName="Path",
+ HelpUri="http://go.microsoft.com/fwlink/?LinkId=526919")]
+ [Alias("fhx")]
+ [OutputType("Microsoft.PowerShell.Commands.ByteCollection")]
+ param
+ (
+ [Parameter (Mandatory=$true, Position=0, ParameterSetName="Path")]
+ [ValidateNotNullOrEmpty()]
+ [string[]] $Path,
+
+ [Parameter (Mandatory=$true, ParameterSetName="LiteralPath")]
+ [ValidateNotNullOrEmpty()]
+ [Alias("PSPath")]
+ [string[]] $LiteralPath,
+
+ [Parameter(Mandatory=$true, ParameterSetName="ByInputObject", ValueFromPipeline=$true)]
+ [Object] $InputObject,
+
+ [Parameter (ParameterSetName="ByInputObject")]
+ [ValidateSet("Ascii", "UTF32", "UTF7", "UTF8", "BigEndianUnicode", "Unicode")]
+ [string] $Encoding = "Ascii",
+
+ [Parameter(ParameterSetName="ByInputObject")]
+ [switch]$Raw
+ )
+
+ begin
+ {
+ $bufferSize = 16
+ $inputStreamArray = [System.Collections.ArrayList]::New()
+ <############################################################################################
+ # The ConvertToHexadecimalHelper is a helper method used to fetch unicode bytes from the
+ # input data and display the hexadecimial representaion of the of the input data in bytes.
+ ############################################################################################>
+ function ConvertToHexadecimalHelper
+ {
+ param
+ (
+ [Byte[]] $inputBytes,
+ [string] $path,
+ [Uint32] $offset
+ )
+
+ # This section is used to display the hexadecimal
+ # representaion of the of the input data in bytes.
+ if($inputBytes -ne $null)
+ {
+ $byteCollectionObject = [Microsoft.PowerShell.Commands.ByteCollection]::new($offset, $inputBytes, $path)
+ Write-Output -InputObject $byteCollectionObject
+ }
+ }
+
+ <############################################################################################
+ # The ProcessFileContent is a helper method used to fetch file contents in blocks and
+ # process it to support displaying hexadecimal formating of the fetched content.
+ ############################################################################################>
+ function ProcessFileContent
+ {
+ param
+ (
+ [string] $filePath,
+ [boolean] $isLiteralPath
+ )
+
+ if($isLiteralPath)
+ {
+ $resolvedPaths = Resolve-Path -LiteralPath $filePath
+ }
+ else
+ {
+ $resolvedPaths = Resolve-Path -Path $filePath
+ }
+
+ # If Path resolution has failed then a corresponding non-terminating error is
+ # written to the pipeline. We continue processing any remaining files.
+ if($resolvedPaths -eq $null)
+ {
+ return
+ }
+
+ if($resolvedPaths.Count -gt 1)
+ {
+ # write a non-terminating error message indicating that path specified is resolving to multiple file system paths.
+ $errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::FormatHexResolvePathError -f $filePath
+ Write-Error -Message $errorMessage -Category ([System.Management.Automation.ErrorCategory]::InvalidData) -ErrorId "FormatHexResolvePathError"
+ }
+
+ $targetFilePath = $resolvedPaths.ProviderPath
+
+
+ if($targetFilePath -ne $null)
+ {
+ $buffer = [byte[]]::new($bufferSize)
+
+ try
+ {
+ try
+ {
+ $currentFileStream = [System.IO.File]::Open($targetFilePath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read)
+ }
+ catch
+ {
+ # Failed to access the file. Write a non terminating error to the pipeline
+ # and move on with the remaining files.
+ $exception = $_.Exception
+ if($null -ne $_.Exception -and
+ $null -ne $_.Exception.InnerException)
+ {
+ $exception = $_.Exception.InnerException
+ }
+
+ $errorRecord = [System.Management.Automation.ErrorRecord]::new($exception,"FormatHexFileAccessError", ([System.Management.Automation.ErrorCategory]::ReadError), $targetFilePath)
+ $PSCmdlet.WriteError($errorRecord)
+ }
+
+ if($null -ne $currentFileStream)
+ {
+ $srcStream = [System.IO.BinaryReader]::new($currentFileStream)
+ $displayHeader = $true
+ $offset = 0
+ $blockCounter = 0
+ while($numberOfBytesRead = $srcStream.Read($buffer, 0, $bufferSize))
+ {
+ # send only the bytes that have been read
+ # if we send the whole buffer, we'll have extraneous bytes
+ # at the end of an incomplete group of 16 bytes
+ if ( $numberOfBytesRead -eq $bufferSize )
+ {
+ # under some circumstances if we don't copy the buffer
+ # and the results are stored to a variable, the results are not
+ # correct and one object replicated in all the output objects
+ ConvertToHexadecimalHelper ($buffer.Clone()) $targetFilePath $offset
+ }
+ else
+ {
+ # handle the case of the partial (and probably last) buffer
+ $bytesReadBuffer = [byte[]]::New($numberOfBytesRead)
+ [Array]::Copy($buffer,0, $bytesReadBuffer,0,$numberOfBytesRead)
+ ConvertToHexadecimalHelper $bytesReadBuffer $targetFilePath $offset
+ }
+ $displayHeader = $false
+ $blockCounter++;
+
+ # Updating the offset value.
+ $offset = $blockCounter*0x10
+ }
+ }
+ }
+ finally
+ {
+ If($null -ne $currentFileStream)
+ {
+ $currentFileStream.Dispose()
+ }
+ If($null -ne $srcStream)
+ {
+ $srcStream.Dispose()
+ }
+ }
+ }
+ }
+ }
+
+ process
+ {
+ switch($PSCmdlet.ParameterSetName)
+ {
+ "Path"
+ {
+ ProcessFileContent $Path $false
+ }
+ "LiteralPath"
+ {
+ ProcessFileContent $LiteralPath $true
+ }
+ "ByInputObject"
+ {
+ # If it's an actual byte array, then we directly use it for hexadecimal formatting.
+ if($InputObject -is [Byte[]])
+ {
+ ConvertToHexadecimalHelper $InputObject $null
+ return
+ }
+ # if it's a single byte, we'll assume streaming
+ elseif($InputObject -is [byte])
+ {
+ $null = $inputStreamArray.Add($InputObject)
+ }
+ # If the input data is of string type then directly get bytes out of it.
+ elseif($InputObject -is [string])
+ {
+ # The ValidateSet arribute on the Encoding paramter makes sure that only
+ # valid values (supported on all paltforms where Format-Hex is avaliable)
+ # are allowed through user input.
+ $inputBytes = [Text.Encoding]::$Encoding.GetBytes($InputObject)
+ ConvertToHexadecimalHelper $inputBytes $null
+ return
+ }
+ elseif($InputObject -is [System.IO.FileSystemInfo])
+ {
+ # If file path is provided as an input, use the file contents to show the hexadecimal format.
+ $filePath = ([System.IO.FileSystemInfo]$InputObject).FullName
+ ProcessFileContent $filePath $false
+ return
+ }
+ elseif($InputObject -is [int64])
+ {
+ $inputBytes = [BitConverter]::GetBytes($InputObject)
+ $null = $inputStreamArray.AddRange($inputBytes)
+ }
+ elseif($InputObject -is [int64[]])
+ {
+ foreach($i64 in $InputObject)
+ {
+ $inputBytes = [BitConverter]::GetBytes($i64)
+ $null = $inputStreamArray.AddRange($inputBytes)
+ }
+ }
+ elseif($InputObject -is [int])
+ {
+ # If we get what appears as ints, it may not be what the user really wants.
+ # for example, if the user types a small set of numbers just to get their
+ # character representations, as follows:
+ #
+ # 170..180 | format-hex
+ # Path:
+ # 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ #00000000 AA AB AC AD AE AF B0 B1 B2 B3 B4 ª«¬®¯°±²³´
+ #
+ # any integer padding is likely to be more confusing than this
+ # fairly compact representation.
+ #
+ # However, some might like to see the results with the raw data,
+ # -Raw exists to provide that behavior:
+ # PS# 170..180 | format-hex -Raw
+ #
+ # Path:
+ #
+ # 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ #
+ # 00000000 AA 00 00 00 AB 00 00 00 AC 00 00 00 AD 00 00 00 ª...«...¬......
+ # 00000010 AE 00 00 00 AF 00 00 00 B0 00 00 00 B1 00 00 00 ®...¯...°...±...
+ # 00000020 B2 00 00 00 B3 00 00 00 B4 00 00 00 ²...³...´...
+ #
+ # this provides a representation of the piped numbers which includes all
+ # of the bytes which are in an int32
+ if ( $Raw )
+ {
+ $inputBytes = [BitConverter]::GetBytes($InputObject)
+ $null = $inputStreamArray.AddRange($inputBytes)
+ }
+ else
+ {
+ # first determine whether we can represent this as a byte
+ $possibleByte = $InputObject -as [byte]
+ # first determine whether we can represent this as a int16
+ $possibleInt16 = $InputObject -as [int16]
+ if ( $possibleByte -ne $null )
+ {
+ $null = $inputStreamArray.Add($possibleByte)
+ }
+ elseif ( $possibleint16 -ne $null )
+ {
+ $inputBytes = [BitConverter]::GetBytes($possibleInt16)
+ $null = $inputStreamArray.AddRange($inputBytes)
+ }
+ else
+ {
+ # now int
+ $inputBytes = [BitConverter]::GetBytes($InputObject)
+ $null = $inputStreamArray.AddRange($inputBytes)
+ }
+ }
+ }
+ else
+ {
+ # Otherwise, write a non-terminating error message indicating that input object type is not supported.
+ $errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::FormatHexTypeNotSupported -f $InputObject.GetType()
+ Write-Error -Message $errorMessage -Category ([System.Management.Automation.ErrorCategory]::ParserError) -ErrorId "FormatHexFailureTypeNotSupported"
+ }
+ # Handle streaming case here
+ # during this process we may not have enough characters to create a ByteCollection
+ # if we do, create as many ByteCollections as necessary, each being 16 bytes in length
+ if ( $inputStreamArray.Count -ge $bufferSize )
+ {
+ $rowCount = [math]::Floor($inputStreamArray.Count/$bufferSize)
+ $arrayLength = $bufferSize * $rowCount
+ for($i = 0; $i -lt $rowCount; $i++)
+ {
+ $rowOffset = $i * $bufferSize
+ ConvertToHexadecimalHelper -inputBytes $inputStreamArray.GetRange($rowOffset, $bufferSize) -path ' ' -offset $offset
+ $offset += $bufferSize
+ }
+ # We use RemoveRange because of the pathological case of having
+ # streamed combination of bytes, int16, int32, int64 which are greater
+ # than 16 bytes. Consider the case:
+ # $i = [int16]::MaxValue + 3
+ # $i64=[int64]::MaxValue -5
+ # .{ $i;$i;$i;$i64 } | format-hex
+ # which create an arraylist 20 bytes
+ # we need to remove only the bytes from the array which we emitted
+ $inputStreamArray.RemoveRange(0,$arrayLength)
+ }
+ }
+ }
+ }
+ end
+ {
+ # now manage any left over bytes in the $inputStreamArray
+ if ( $PSCmdlet.ParameterSetName -eq "ByInputObject" )
+ {
+ ConvertToHexadecimalHelper $inputStreamArray $null -path ' ' -offset $offset
+ }
+ }
+
+}
+
+## Imports a PowerShell Data File - a PowerShell hashtable defined in
+## a file (such as a Module manifest, session configuration file)
+function Import-PowerShellDataFile
+{
+ [CmdletBinding(DefaultParameterSetName = "ByPath", HelpUri = "http://go.microsoft.com/fwlink/?LinkID=623621")]
+ [OutputType("System.Collections.Hashtable")]
+ param(
+ [Parameter(ParameterSetName = "ByPath", Position = 0)]
+ [String[]] $Path,
+
+ [Parameter(ParameterSetName = "ByLiteralPath", ValueFromPipelineByPropertyName = $true)]
+ [Alias("PSPath")]
+ [String[]] $LiteralPath
+ )
+
+ begin
+ {
+ function ThrowInvalidDataFile
+ {
+ param($resolvedPath, $extraError)
+
+ $errorId = "CouldNotParseAsPowerShellDataFile$extraError"
+ $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidData
+ $errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::CouldNotParseAsPowerShellDataFile -f $resolvedPath
+ $exception = [System.InvalidOperationException]::New($errorMessage)
+ $errorRecord = [System.Management.Automation.ErrorRecord]::New($exception, $errorId, $errorCategory, $null)
+ $PSCmdlet.WriteError($errorRecord)
+ }
+ }
+
+ process
+ {
+ foreach($resolvedPath in (Resolve-Path @PSBoundParameters))
+ {
+ $parseErrors = $null
+ $ast = [System.Management.Automation.Language.Parser]::ParseFile(($resolvedPath.ProviderPath), [ref] $null, [ref] $parseErrors)
+ if ($parseErrors.Length -gt 0)
+ {
+ ThrowInvalidDataFile $resolvedPath
+ }
+ else
+ {
+ $data = $ast.Find( { $args[0] -is [System.Management.Automation.Language.HashtableAst] }, $false )
+ if($data)
+ {
+ $data.SafeGetValue()
+ }
+ else
+ {
+ ThrowInvalidDataFile $resolvedPath "NoHashtableRoot"
+ }
+ }
+ }
+ }
+}
+
+## Converts a SDDL string into an object-based representation of a security
+## descriptor
+function ConvertFrom-SddlString
+{
+ [CmdletBinding(HelpUri = "http://go.microsoft.com/fwlink/?LinkId=623636")]
+ param(
+ ## The string representing the security descriptor in SDDL syntax
+ [Parameter(Mandatory, Position = 0)]
+ [String] $Sddl,
+
+ ## The type of rights that this SDDL string represents, if any.
+ [Parameter()]
+ [ValidateSet(
+ "FileSystemRights", "RegistryRights", "ActiveDirectoryRights",
+ "MutexRights", "SemaphoreRights", "CryptoKeyRights",
+ "EventWaitHandleRights")]
+ $Type
+ )
+
+ ## Translates a SID into a NT Account
+ function ConvertTo-NtAccount
+ {
+ param($Sid)
+
+ if($Sid)
+ {
+ $securityIdentifier = [System.Security.Principal.SecurityIdentifier] $Sid
+
+ try
+ {
+ $ntAccount = $securityIdentifier.Translate([System.Security.Principal.NTAccount]).ToString()
+ }
+ catch{}
+
+ $ntAccount
+ }
+ }
+
+ ## Gets the access rights that apply to an access mask, preferring right types
+ ## of 'Type' if specified.
+ function Get-AccessRights
+ {
+ param($AccessMask, $Type)
+
+ ## All the types of access rights understood by .NET
+ $rightTypes = [Ordered] @{
+ "FileSystemRights" = [System.Security.AccessControl.FileSystemRights]
+ "RegistryRights" = [System.Security.AccessControl.RegistryRights]
+ "ActiveDirectoryRights" = [System.DirectoryServices.ActiveDirectoryRights]
+ "MutexRights" = [System.Security.AccessControl.MutexRights]
+ "SemaphoreRights" = [System.Security.AccessControl.SemaphoreRights]
+ "CryptoKeyRights" = [System.Security.AccessControl.CryptoKeyRights]
+ "EventWaitHandleRights" = [System.Security.AccessControl.EventWaitHandleRights]
+ }
+ $typesToExamine = $rightTypes.Values
+
+ ## If they know the access mask represents a certain type, prefer its names
+ ## (i.e.: CreateLink for the registry over CreateDirectories for the filesystem)
+ if($Type)
+ {
+ $typesToExamine = @($rightTypes[$Type]) + $typesToExamine
+ }
+
+
+ ## Stores the access types we've found that apply
+ $foundAccess = @()
+
+ ## Store the access types we've already seen, so that we don't report access
+ ## flags that are essentially duplicate. Many of the access values in the different
+ ## enumerations have the same value but with different names.
+ $foundValues = @{}
+
+ ## Go through the entries in the different right types, and see if they apply to the
+ ## provided access mask. If they do, then add that to the result.
+ foreach($rightType in $typesToExamine)
+ {
+ foreach($accessFlag in [Enum]::GetNames($rightType))
+ {
+ $longKeyValue = [long] $rightType::$accessFlag
+ if(-not $foundValues.ContainsKey($longKeyValue))
+ {
+ $foundValues[$longKeyValue] = $true
+ if(($AccessMask -band $longKeyValue) -eq ($longKeyValue))
+ {
+ $foundAccess += $accessFlag
+ }
+ }
+ }
+ }
+
+ $foundAccess | Sort-Object
+ }
+
+ ## Converts an ACE into a string representation
+ function ConvertTo-AceString
+ {
+ param(
+ [Parameter(ValueFromPipeline)]
+ $Ace,
+ $Type
+ )
+
+ process
+ {
+ foreach($aceEntry in $Ace)
+ {
+ $AceString = (ConvertTo-NtAccount $aceEntry.SecurityIdentifier) + ": " + $aceEntry.AceQualifier
+ if($aceEntry.AceFlags -ne "None")
+ {
+ $AceString += " " + $aceEntry.AceFlags
+ }
+
+ if($aceEntry.AccessMask)
+ {
+ $foundAccess = Get-AccessRights $aceEntry.AccessMask $Type
+
+ if($foundAccess)
+ {
+ $AceString += " ({0})" -f ($foundAccess -join ", ")
+ }
+ }
+
+ $AceString
+ }
+ }
+ }
+
+ $rawSecurityDescriptor = [Security.AccessControl.CommonSecurityDescriptor]::new($false,$false,$Sddl)
+
+ $owner = ConvertTo-NtAccount $rawSecurityDescriptor.Owner
+ $group = ConvertTo-NtAccount $rawSecurityDescriptor.Group
+ $discretionaryAcl = ConvertTo-AceString $rawSecurityDescriptor.DiscretionaryAcl $Type
+ $systemAcl = ConvertTo-AceString $rawSecurityDescriptor.SystemAcl $Type
+
+ [PSCustomObject] @{
+ Owner = $owner
+ Group = $group
+ DiscretionaryAcl = @($discretionaryAcl)
+ SystemAcl = @($systemAcl)
+ RawDescriptor = $rawSecurityDescriptor
+ }
+}
diff --git a/src/Modules/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1 b/src/Modules/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1
new file mode 100644
index 0000000000..972d368861
--- /dev/null
+++ b/src/Modules/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1
@@ -0,0 +1,15 @@
+@{
+GUID="766204A6-330E-4263-A7AB-46C87AFC366C"
+Author="Microsoft Corporation"
+CompanyName="Microsoft Corporation"
+Copyright="© Microsoft Corporation. All rights reserved."
+ModuleVersion="3.0.0.0"
+PowerShellVersion="3.0"
+CLRVersion="4.0"
+AliasesToExport = @()
+FunctionsToExport = @()
+CmdletsToExport="Disable-WSManCredSSP", "Enable-WSManCredSSP", "Get-WSManCredSSP", "Set-WSManQuickConfig", "Test-WSMan", "Invoke-WSManAction", "Connect-WSMan", "Disconnect-WSMan", "Get-WSManInstance", "Set-WSManInstance", "Remove-WSManInstance", "New-WSManInstance", "New-WSManSessionOption"
+NestedModules="Microsoft.WSMan.Management.dll"
+FormatsToProcess="WSMan.format.ps1xml"
+HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=390788'
+}
diff --git a/src/Modules/PSDiagnostics/PSDiagnostics.psd1 b/src/Modules/PSDiagnostics/PSDiagnostics.psd1
new file mode 100644
index 0000000000..3d73330c0a
Binary files /dev/null and b/src/Modules/PSDiagnostics/PSDiagnostics.psd1 differ
diff --git a/src/Modules/PSDiagnostics/PSDiagnostics.psm1 b/src/Modules/PSDiagnostics/PSDiagnostics.psm1
new file mode 100644
index 0000000000..d36168f27d
Binary files /dev/null and b/src/Modules/PSDiagnostics/PSDiagnostics.psm1 differ
diff --git a/src/Modules/PSGet/PSGet.Format.ps1xml b/src/Modules/PSGet/PSGet.Format.ps1xml
new file mode 100644
index 0000000000..54ff00a1fe
--- /dev/null
+++ b/src/Modules/PSGet/PSGet.Format.ps1xml
@@ -0,0 +1,202 @@
+
+
+
+
+ PSRepositoryItemInfo
+
+ Microsoft.PowerShell.Commands.PSRepositoryItemInfo
+
+
+
+
+ 10
+
+
+ 35
+
+
+ 10
+
+
+ 20
+
+
+
+
+
+
+
+ Version
+
+
+ Name
+
+
+ Type
+
+
+ Repository
+
+
+ Description
+
+
+
+
+
+
+
+ PSRepository
+
+ Microsoft.PowerShell.Commands.PSRepository
+
+
+
+
+ 25
+
+
+ 25
+
+
+ 20
+
+
+
+
+
+
+
+ Name
+
+
+ PackageManagementProvider
+
+
+ InstallationPolicy
+
+
+ SourceLocation
+
+
+
+
+
+
+
+ PSScriptInfo
+
+ Microsoft.PowerShell.Commands.PSScriptInfo
+
+
+
+
+ 10
+
+
+ 25
+
+
+ 20
+
+
+
+
+
+
+
+ Version
+
+
+ Name
+
+
+ Author
+
+
+ Description
+
+
+
+
+
+
+
+ PSGetDscResourceInfo
+
+ Microsoft.PowerShell.Commands.PSGetCommandInfo
+ Microsoft.PowerShell.Commands.PSGetDscResourceInfo
+
+
+
+
+ 35
+
+
+ 10
+
+
+ 35
+
+
+
+
+
+
+
+ Name
+
+
+ Version
+
+
+ ModuleName
+
+
+ Repository
+
+
+
+
+
+
+
+ PSGetRoleCapabilityInfo
+
+ Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo
+
+
+
+
+ 35
+
+
+ 10
+
+
+ 35
+
+
+
+
+
+
+
+ Name
+
+
+ Version
+
+
+ ModuleName
+
+
+ Repository
+
+
+
+
+
+
+
+
diff --git a/src/Modules/PSGet/PSGet.Resource.psd1 b/src/Modules/PSGet/PSGet.Resource.psd1
new file mode 100644
index 0000000000..5177bec6b8
Binary files /dev/null and b/src/Modules/PSGet/PSGet.Resource.psd1 differ
diff --git a/src/Modules/PSGet/PSGet.psd1 b/src/Modules/PSGet/PSGet.psd1
new file mode 100644
index 0000000000..9fa416ac98
Binary files /dev/null and b/src/Modules/PSGet/PSGet.psd1 differ
diff --git a/src/Modules/PSGet/PSModule.psm1 b/src/Modules/PSGet/PSModule.psm1
new file mode 100644
index 0000000000..6ddcc4db7e
--- /dev/null
+++ b/src/Modules/PSGet/PSModule.psm1
@@ -0,0 +1,13064 @@
+
+#########################################################################################
+#
+# Copyright (c) Microsoft Corporation. All rights reserved.
+#
+# PowerShellGet Module
+#
+#########################################################################################
+
+Microsoft.PowerShell.Core\Set-StrictMode -Version Latest
+
+#region script variables
+
+# Check if this is nano server. [System.Runtime.Loader.AssemblyLoadContext] is only available on NanoServer
+$script:isNanoServer = $null -ne ('System.Runtime.Loader.AssemblyLoadContext' -as [Type])
+
+try
+{
+ $script:MyDocumentsFolderPath = [Environment]::GetFolderPath("MyDocuments")
+}
+catch
+{
+ $script:MyDocumentsFolderPath = $null
+}
+
+$script:ProgramFilesPSPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell"
+
+$script:MyDocumentsPSPath = if($script:MyDocumentsFolderPath)
+ {
+ Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsFolderPath -ChildPath "WindowsPowerShell"
+ }
+ else
+ {
+ Microsoft.PowerShell.Management\Join-Path -Path $env:USERPROFILE -ChildPath "Documents\WindowsPowerShell"
+ }
+
+$script:ProgramFilesModulesPath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesPSPath -ChildPath "Modules"
+$script:MyDocumentsModulesPath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsPSPath -ChildPath "Modules"
+
+$script:ProgramFilesScriptsPath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesPSPath -ChildPath "Scripts"
+
+$script:MyDocumentsScriptsPath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsPSPath -ChildPath "Scripts"
+
+$script:TempPath = ([System.IO.DirectoryInfo]$env:TEMP).FullName
+$script:PSGetItemInfoFileName = "PSGetModuleInfo.xml"
+$script:PSGetProgramDataPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramData -ChildPath 'Microsoft\Windows\PowerShell\PowerShellGet\'
+$script:PSGetAppLocalPath = Microsoft.PowerShell.Management\Join-Path -Path $env:LOCALAPPDATA -ChildPath 'Microsoft\Windows\PowerShell\PowerShellGet\'
+$script:PSGetModuleSourcesFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetAppLocalPath -ChildPath "PSRepositories.xml"
+$script:PSGetModuleSources = $null
+$script:PSGetInstalledModules = $null
+$script:PSGetSettingsFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetAppLocalPath -ChildPath "PowerShellGetSettings.xml"
+$script:PSGetSettings = $null
+
+$script:MyDocumentsInstalledScriptInfosPath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsScriptsPath -ChildPath 'InstalledScriptInfos'
+$script:ProgramFilesInstalledScriptInfosPath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesScriptsPath -ChildPath 'InstalledScriptInfos'
+
+$script:InstalledScriptInfoFileName = 'InstalledScriptInfo.xml'
+$script:PSGetInstalledScripts = $null
+
+# Public PSGallery module source name and location
+$Script:PSGalleryModuleSource="PSGallery"
+$Script:PSGallerySourceUri = 'https://go.microsoft.com/fwlink/?LinkID=397631&clcid=0x409'
+$Script:PSGalleryPublishUri = 'https://go.microsoft.com/fwlink/?LinkID=397527&clcid=0x409'
+$Script:PSGalleryScriptSourceUri = 'https://go.microsoft.com/fwlink/?LinkID=622995&clcid=0x409'
+
+# PSGallery V3 Source
+$Script:PSGalleryV3SourceUri = 'https://go.microsoft.com/fwlink/?LinkId=528403&clcid=0x409'
+
+$Script:PSGalleryV2ApiAvailable = $true
+$Script:PSGalleryV3ApiAvailable = $false
+$Script:PSGalleryApiChecked = $false
+
+$Script:ResponseUri = "ResponseUri"
+$Script:StatusCode = "StatusCode"
+$Script:Exception = "Exception"
+
+$script:PSModuleProviderName = 'PowerShellGet'
+$script:PackageManagementProviderParam = "PackageManagementProvider"
+$script:PublishLocation = "PublishLocation"
+$script:ScriptSourceLocation = 'ScriptSourceLocation'
+$script:ScriptPublishLocation = 'ScriptPublishLocation'
+
+$script:NuGetProviderName = "NuGet"
+$script:NuGetProviderVersion = [Version]'2.8.5.201'
+
+$script:SupportsPSModulesFeatureName="supports-powershell-modules"
+$script:FastPackRefHastable = @{}
+$script:NuGetBinaryProgramDataPath="$env:ProgramFiles\PackageManagement\ProviderAssemblies"
+$script:NuGetBinaryLocalAppDataPath="$env:LOCALAPPDATA\PackageManagement\ProviderAssemblies"
+# go fwlink for 'https://nuget.org/nuget.exe'
+$script:NuGetClientSourceURL = 'http://go.microsoft.com/fwlink/?LinkID=690216&clcid=0x409'
+$script:NuGetExeName = 'NuGet.exe'
+$script:NuGetExePath = $null
+$script:NuGetProvider = $null
+# PowerShellGetFormatVersion will be incremented when we change the .nupkg format structure.
+# PowerShellGetFormatVersion is in the form of Major.Minor.
+# Minor is incremented for the backward compatible format change.
+# Major is incremented for the breaking change.
+$script:CurrentPSGetFormatVersion = "1.0"
+$script:PSGetFormatVersion = "PowerShellGetFormatVersion"
+$script:SupportedPSGetFormatVersionMajors = @("1")
+$script:ModuleReferences = 'Module References'
+$script:AllVersions = "AllVersions"
+$script:Filter = "Filter"
+$script:IncludeValidSet = @('DscResource','Cmdlet','Function','Workflow','RoleCapability')
+$script:DscResource = "PSDscResource"
+$script:Command = "PSCommand"
+$script:Cmdlet = "PSCmdlet"
+$script:Function = "PSFunction"
+$script:Workflow = "PSWorkflow"
+$script:RoleCapability = 'PSRoleCapability'
+$script:Includes = "PSIncludes"
+$script:Tag = "Tag"
+$script:NotSpecified= '_NotSpecified_'
+$script:PSGetModuleName = 'PowerShellGet'
+$script:FindByCanonicalId = 'FindByCanonicalId'
+$script:InstalledLocation = 'InstalledLocation'
+$script:PSArtifactType = 'Type'
+$script:PSArtifactTypeModule = 'Module'
+$script:PSArtifactTypeScript = 'Script'
+$script:All = 'All'
+
+$script:Name = 'Name'
+$script:Version = 'Version'
+$script:Guid = 'Guid'
+$script:Path = 'Path'
+$script:ScriptBase = 'ScriptBase'
+$script:Description = 'Description'
+$script:Author = 'Author'
+$script:CompanyName = 'CompanyName'
+$script:Copyright = 'Copyright'
+$script:Tags = 'Tags'
+$script:LicenseUri = 'LicenseUri'
+$script:ProjectUri = 'ProjectUri'
+$script:IconUri = 'IconUri'
+$script:RequiredModules = 'RequiredModules'
+$script:ExternalModuleDependencies = 'ExternalModuleDependencies'
+$script:ReleaseNotes = 'ReleaseNotes'
+$script:RequiredScripts = 'RequiredScripts'
+$script:ExternalScriptDependencies = 'ExternalScriptDependencies'
+$script:DefinedCommands = 'DefinedCommands'
+$script:DefinedFunctions = 'DefinedFunctions'
+$script:DefinedWorkflows = 'DefinedWorkflows'
+$script:TextInfo = (Get-Culture).TextInfo
+
+$script:PSScriptInfoProperties = @($script:Name
+ $script:Version,
+ $script:Guid,
+ $script:Path,
+ $script:ScriptBase,
+ $script:Description,
+ $script:Author,
+ $script:CompanyName,
+ $script:Copyright,
+ $script:Tags,
+ $script:ReleaseNotes,
+ $script:RequiredModules,
+ $script:ExternalModuleDependencies,
+ $script:RequiredScripts,
+ $script:ExternalScriptDependencies,
+ $script:LicenseUri,
+ $script:ProjectUri,
+ $script:IconUri,
+ $script:DefinedCommands,
+ $script:DefinedFunctions,
+ $script:DefinedWorkflows
+ )
+
+$script:SystemEnvironmentKey = 'HKLM:\System\CurrentControlSet\Control\Session Manager\Environment'
+$script:UserEnvironmentKey = 'HKCU:\Environment'
+$script:SystemEnvironmentVariableMaximumLength = 1024
+$script:UserEnvironmentVariableMaximumLength = 255
+$script:EnvironmentVariableTarget = @{ Process = 0; User = 1; Machine = 2 }
+
+# Wildcard pattern matching configuration.
+$script:wildcardOptions = [System.Management.Automation.WildcardOptions]::CultureInvariant -bor `
+ [System.Management.Automation.WildcardOptions]::IgnoreCase
+
+$script:DynamicOptionTypeMap = @{
+ 0 = [string]; # String
+ 1 = [string[]]; # StringArray
+ 2 = [int]; # Int
+ 3 = [switch]; # Switch
+ 4 = [string]; # Folder
+ 5 = [string]; # File
+ 6 = [string]; # Path
+ 7 = [Uri]; # Uri
+ 8 = [SecureString]; #SecureString
+ }
+#endregion script variables
+
+#region Module message resolvers
+$script:PackageManagementMessageResolverScriptBlock = {
+ param($i, $Message)
+ return (PackageManagementMessageResolver -MsgId $i, -Message $Message)
+ }
+
+$script:PackageManagementSaveModuleMessageResolverScriptBlock = {
+ param($i, $Message)
+ $PackageTarget = $LocalizedData.InstallModulewhatIfMessage
+ $QuerySaveUntrustedPackage = $LocalizedData.QuerySaveUntrustedPackage
+
+ switch ($i)
+ {
+ 'ActionInstallPackage' { return "Save-Module" }
+ 'QueryInstallUntrustedPackage' {return $QuerySaveUntrustedPackage}
+ 'TargetPackage' { return $PackageTarget }
+ Default {
+ $Message = $Message -creplace "Install", "Download"
+ $Message = $Message -creplace "install", "download"
+ return (PackageManagementMessageResolver -MsgId $i, -Message $Message)
+ }
+ }
+ }
+
+$script:PackageManagementInstallModuleMessageResolverScriptBlock = {
+ param($i, $Message)
+ $PackageTarget = $LocalizedData.InstallModulewhatIfMessage
+
+ switch ($i)
+ {
+ 'ActionInstallPackage' { return "Install-Module" }
+ 'TargetPackage' { return $PackageTarget }
+ Default {
+ return (PackageManagementMessageResolver -MsgId $i, -Message $Message)
+ }
+ }
+ }
+
+$script:PackageManagementUnInstallModuleMessageResolverScriptBlock = {
+ param($i, $Message)
+ $PackageTarget = $LocalizedData.InstallModulewhatIfMessage
+ switch ($i)
+ {
+ 'ActionUninstallPackage' { return "Uninstall-Module" }
+ 'TargetPackageVersion' { return $PackageTarget }
+ Default {
+ return (PackageManagementMessageResolver -MsgId $i, -Message $Message)
+ }
+ }
+ }
+
+$script:PackageManagementUpdateModuleMessageResolverScriptBlock = {
+ param($i, $Message)
+ $PackageTarget = ($LocalizedData.UpdateModulewhatIfMessage -replace "__OLDVERSION__",$($psgetItemInfo.Version))
+ switch ($i)
+ {
+ 'ActionInstallPackage' { return "Update-Module" }
+ 'TargetPackage' { return $PackageTarget }
+ Default {
+ return (PackageManagementMessageResolver -MsgId $i, -Message $Message)
+ }
+ }
+ }
+
+function PackageManagementMessageResolver($MsgID, $Message) {
+ $NoMatchFound = $LocalizedData.NoMatchFound
+ $SourceNotFound = $LocalizedData.SourceNotFound
+ $ModuleIsNotTrusted = $LocalizedData.ModuleIsNotTrusted
+ $RepositoryIsNotTrusted = $LocalizedData.RepositoryIsNotTrusted
+ $QueryInstallUntrustedPackage = $LocalizedData.QueryInstallUntrustedPackage
+
+ switch ($MsgID)
+ {
+ 'NoMatchFound' { return $NoMatchFound }
+ 'SourceNotFound' { return $SourceNotFound }
+ 'CaptionPackageNotTrusted' { return $ModuleIsNotTrusted }
+ 'CaptionSourceNotTrusted' { return $RepositoryIsNotTrusted }
+ 'QueryInstallUntrustedPackage' {return $QueryInstallUntrustedPackage}
+ Default {
+ if($Message)
+ {
+ $tempMessage = $Message -creplace "PackageSource", "PSRepository"
+ $tempMessage = $Message -creplace "packagesource", "psrepository"
+ $tempMessage = $Message -creplace "Package", "Module"
+ $tempMessage = $tempMessage -creplace "package", "module"
+ $tempMessage = $tempMessage -creplace "Sources", "Repositories"
+ $tempMessage = $tempMessage -creplace "sources", "repositories"
+ $tempMessage = $tempMessage -creplace "Source", "Repository"
+ $tempMessage = $tempMessage -creplace "source", "repository"
+
+ return $tempMessage
+ }
+ }
+ }
+}
+
+#endregion Module message resolvers
+
+#region Script message resolvers
+$script:PackageManagementMessageResolverScriptBlockForScriptCmdlets = {
+ param($i, $Message)
+ return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message)
+ }
+
+$script:PackageManagementSaveScriptMessageResolverScriptBlock = {
+ param($i, $Message)
+ $PackageTarget = $LocalizedData.InstallScriptwhatIfMessage
+ $QuerySaveUntrustedPackage = $LocalizedData.QuerySaveUntrustedScriptPackage
+
+ switch ($i)
+ {
+ 'ActionInstallPackage' { return "Save-Script" }
+ 'QueryInstallUntrustedPackage' {return $QuerySaveUntrustedPackage}
+ 'TargetPackage' { return $PackageTarget }
+ Default {
+ $Message = $Message -creplace "Install", "Download"
+ $Message = $Message -creplace "install", "download"
+ return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message)
+ }
+ }
+ }
+
+$script:PackageManagementInstallScriptMessageResolverScriptBlock = {
+ param($i, $Message)
+ $PackageTarget = $LocalizedData.InstallScriptwhatIfMessage
+
+ switch ($i)
+ {
+ 'ActionInstallPackage' { return "Install-Script" }
+ 'TargetPackage' { return $PackageTarget }
+ Default {
+ return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message)
+ }
+ }
+ }
+
+$script:PackageManagementUnInstallScriptMessageResolverScriptBlock = {
+ param($i, $Message)
+ $PackageTarget = $LocalizedData.InstallScriptwhatIfMessage
+ switch ($i)
+ {
+ 'ActionUninstallPackage' { return "Uninstall-Script" }
+ 'TargetPackageVersion' { return $PackageTarget }
+ Default {
+ return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message)
+ }
+ }
+ }
+
+$script:PackageManagementUpdateScriptMessageResolverScriptBlock = {
+ param($i, $Message)
+ $PackageTarget = ($LocalizedData.UpdateScriptwhatIfMessage -replace "__OLDVERSION__",$($psgetItemInfo.Version))
+ switch ($i)
+ {
+ 'ActionInstallPackage' { return "Update-Script" }
+ 'TargetPackage' { return $PackageTarget }
+ Default {
+ return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message)
+ }
+ }
+ }
+
+function PackageManagementMessageResolverForScripts($MsgID, $Message) {
+ $NoMatchFound = $LocalizedData.NoMatchFoundForScriptName
+ $SourceNotFound = $LocalizedData.SourceNotFound
+ $ScriptIsNotTrusted = $LocalizedData.ScriptIsNotTrusted
+ $RepositoryIsNotTrusted = $LocalizedData.RepositoryIsNotTrusted
+ $QueryInstallUntrustedPackage = $LocalizedData.QueryInstallUntrustedScriptPackage
+
+ switch ($MsgID)
+ {
+ 'NoMatchFound' { return $NoMatchFound }
+ 'SourceNotFound' { return $SourceNotFound }
+ 'CaptionPackageNotTrusted' { return $ScriptIsNotTrusted }
+ 'CaptionSourceNotTrusted' { return $RepositoryIsNotTrusted }
+ 'QueryInstallUntrustedPackage' {return $QueryInstallUntrustedPackage}
+ Default {
+ if($Message)
+ {
+ $tempMessage = $Message -creplace "PackageSource", "PSRepository"
+ $tempMessage = $Message -creplace "packagesource", "psrepository"
+ $tempMessage = $Message -creplace "Package", "Script"
+ $tempMessage = $tempMessage -creplace "package", "script"
+ $tempMessage = $tempMessage -creplace "Sources", "Repositories"
+ $tempMessage = $tempMessage -creplace "sources", "repositories"
+ $tempMessage = $tempMessage -creplace "Source", "Repository"
+ $tempMessage = $tempMessage -creplace "source", "repository"
+
+ return $tempMessage
+ }
+ }
+ }
+}
+
+#endregion Script message resolvers
+
+Microsoft.PowerShell.Utility\Import-LocalizedData LocalizedData -filename PSGet.Resource.psd1
+
+#region Add .Net type for Telemetry APIs
+
+# This code is required to add a .Net type and call the Telemetry APIs
+# This is required since PowerShell does not support generation of .Net Anonymous types
+#
+$requiredAssembly = (
+ "system.management.automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
+ )
+
+$source = @"
+using System;
+using System.Management.Automation;
+
+namespace Microsoft.PowerShell.Get
+{
+ public static class Telemetry
+ {
+ public static void TraceMessageArtifactsNotFound(string[] artifactsNotFound, string operationName)
+ {
+ Microsoft.PowerShell.Telemetry.Internal.TelemetryAPI.TraceMessage(operationName, new { ArtifactsNotFound = artifactsNotFound });
+ }
+
+ public static void TraceMessageNonPSGalleryRegistration(string sourceLocationType, string sourceLocationHash, string installationPolicy, string packageManagementProvider, string publishLocationHash, string scriptSourceLocationHash, string scriptPublishLocationHash, string operationName)
+ {
+ Microsoft.PowerShell.Telemetry.Internal.TelemetryAPI.TraceMessage(operationName, new { SourceLocationType = sourceLocationType, SourceLocationHash = sourceLocationHash, InstallationPolicy = installationPolicy, PackageManagementProvider = packageManagementProvider, PublishLocationHash = publishLocationHash, ScriptSourceLocationHash = scriptSourceLocationHash, ScriptPublishLocationHash = scriptPublishLocationHash });
+ }
+
+ }
+}
+"@
+
+# Telemetry is turned off by default.
+$script:TelemetryEnabled = $false
+
+try
+{
+ Add-Type -ReferencedAssemblies $requiredAssembly -TypeDefinition $source -Language CSharp -ErrorAction SilentlyContinue
+
+ # If the telemetry namespace/methods are not found flow goes to the catch block where telemetry is disabled
+ $telemetryMethods = ([Microsoft.PowerShell.Get.Telemetry] | Get-Member -Static).Name
+
+ if ($telemetryMethods.Contains("TraceMessageArtifactsNotFound") -and $telemetryMethods.Contains("TraceMessageNonPSGalleryRegistration"))
+ {
+ # Turn ON Telemetry if the infrastructure is present on the machine
+ $script:TelemetryEnabled = $true
+ }
+}
+catch
+{
+ # Disable Telemetry if there are any issues finding/loading the Telemetry infrastructure
+ $script:TelemetryEnabled = $false
+}
+
+
+#endregion
+
+#region *-Module cmdlets
+function Publish-Module
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(SupportsShouldProcess=$true,
+ PositionalBinding=$false,
+ HelpUri='http://go.microsoft.com/fwlink/?LinkID=398575',
+ DefaultParameterSetName="ModuleNameParameterSet")]
+ Param
+ (
+ [Parameter(Mandatory=$true,
+ ParameterSetName="ModuleNameParameterSet",
+ ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Name,
+
+ [Parameter(Mandatory=$true,
+ ParameterSetName="ModulePathParameterSet",
+ ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Path,
+
+ [Parameter(ParameterSetName="ModuleNameParameterSet")]
+ [ValidateNotNullOrEmpty()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $NuGetApiKey,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Repository = $Script:PSGalleryModuleSource,
+
+ [Parameter()]
+ [ValidateSet("1.0")]
+ [Version]
+ $FormatVersion,
+
+ [Parameter()]
+ [string[]]
+ $ReleaseNotes,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Tags,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $LicenseUri,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $IconUri,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $ProjectUri
+ )
+
+ Begin
+ {
+ if($script:isNanoServer) {
+ $message = $LocalizedData.PublishPSArtifactUnsupportedOnNano -f "Module"
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "PublishModuleIsNotSupportedOnNanoServer" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $PSCmdlet `
+ -ErrorCategory InvalidOperation
+ }
+
+ Get-PSGalleryApiAvailability -Repository $Repository
+
+ if($LicenseUri -and -not (Test-WebUri -uri $LicenseUri))
+ {
+ $message = $LocalizedData.InvalidWebUri -f ($LicenseUri, "LicenseUri")
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidWebUri" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $LicenseUri
+ }
+
+ if($IconUri -and -not (Test-WebUri -uri $IconUri))
+ {
+ $message = $LocalizedData.InvalidWebUri -f ($IconUri, "IconUri")
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidWebUri" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $IconUri
+ }
+
+ if($ProjectUri -and -not (Test-WebUri -uri $ProjectUri))
+ {
+ $message = $LocalizedData.InvalidWebUri -f ($ProjectUri, "ProjectUri")
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidWebUri" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $ProjectUri
+ }
+
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe
+ }
+
+ Process
+ {
+ if($Repository -eq $Script:PSGalleryModuleSource)
+ {
+ $moduleSource = Get-PSRepository -Name $Repository -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
+ if(-not $moduleSource)
+ {
+ $message = $LocalizedData.PSGalleryNotFound -f ($Repository)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId 'PSGalleryNotFound' `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Repository
+ return
+ }
+ }
+ else
+ {
+ $ev = $null
+ $moduleSource = Get-PSRepository -Name $Repository -ErrorVariable ev
+ if($ev) { return }
+ }
+
+ $DestinationLocation = $moduleSource.PublishLocation
+
+ if(-not $DestinationLocation -or
+ (-not (Microsoft.PowerShell.Management\Test-Path $DestinationLocation) -and
+ -not (Test-WebUri -uri $DestinationLocation)))
+
+ {
+ $message = $LocalizedData.PSGalleryPublishLocationIsMissing -f ($Repository, $Repository)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "PSGalleryPublishLocationIsMissing" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Repository
+ }
+
+ $message = $LocalizedData.PublishLocation -f ($DestinationLocation)
+ Write-Verbose -Message $message
+
+ if(-not $NuGetApiKey.Trim())
+ {
+ if(Microsoft.PowerShell.Management\Test-Path -Path $DestinationLocation)
+ {
+ $NuGetApiKey = "$(Get-Random)"
+ }
+ else
+ {
+ $message = $LocalizedData.NuGetApiKeyIsRequiredForNuGetBasedGalleryService -f ($Repository, $DestinationLocation)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "NuGetApiKeyIsRequiredForNuGetBasedGalleryService" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+ }
+
+ $providerName = Get-ProviderName -PSCustomObject $moduleSource
+ if($providerName -ne $script:NuGetProviderName)
+ {
+ $message = $LocalizedData.PublishModuleSupportsOnlyNuGetBasedPublishLocations -f ($moduleSource.PublishLocation, $Repository, $Repository)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "PublishModuleSupportsOnlyNuGetBasedPublishLocations" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Repository
+ }
+
+ $moduleName = $null
+
+ if($Name)
+ {
+ $module = Microsoft.PowerShell.Core\Get-Module -ListAvailable -Name $Name -Verbose:$false |
+ Microsoft.PowerShell.Core\Where-Object {-not $RequiredVersion -or ($RequiredVersion -eq $_.Version)}
+
+ if(-not $module)
+ {
+ if($RequiredVersion)
+ {
+ $message = $LocalizedData.ModuleWithRequiredVersionNotAvailableLocally -f ($Name, $RequiredVersion)
+ }
+ else
+ {
+ $message = $LocalizedData.ModuleNotAvailableLocally -f ($Name)
+ }
+
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "ModuleNotAvailableLocallyToPublish" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Name
+
+ }
+ elseif($module.GetType().ToString() -ne "System.Management.Automation.PSModuleInfo")
+ {
+ $message = $LocalizedData.AmbiguousModuleName -f ($Name)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "AmbiguousModuleNameToPublish" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Name
+ }
+
+ $moduleName = $module.Name
+ $Path = $module.ModuleBase
+ }
+ else
+ {
+ $resolvedPath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1
+
+ if(-not $resolvedPath -or
+ -not (Microsoft.PowerShell.Management\Test-Path -Path $resolvedPath -PathType Container))
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage ($LocalizedData.PathIsNotADirectory -f ($Path)) `
+ -ErrorId "PathIsNotADirectory" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Path
+ return
+ }
+
+ $moduleName = Microsoft.PowerShell.Management\Split-Path -Path $resolvedPath -Leaf
+ $modulePathWithVersion = $false
+
+ # if the Leaf of the $resolvedPath is a version, use its parent folder name as the module name
+ $ModuleVersion = New-Object System.Version
+ if([System.Version]::TryParse($moduleName, ([ref]$ModuleVersion)))
+ {
+ $moduleName = Microsoft.PowerShell.Management\Split-Path -Path (Microsoft.PowerShell.Management\Split-Path $resolvedPath -Parent) -Leaf
+ $modulePathWithVersion = $true
+ }
+
+ $manifestPath = Join-Path -Path $resolvedPath -ChildPath "$moduleName.psd1"
+ $module = $null
+
+ if(Microsoft.PowerShell.Management\Test-Path -Path $manifestPath -PathType Leaf)
+ {
+ $ev = $null
+ $module = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $manifestPath `
+ -ErrorVariable ev `
+ -Verbose:$VerbosePreference
+ if($ev)
+ {
+ # Above Test-ModuleManifest cmdlet should write an errors to the Errors stream and Console.
+ return
+ }
+ }
+ elseif(-not $modulePathWithVersion -and ($PSVersionTable.PSVersion -ge [Version]'5.0'))
+ {
+ $module = Microsoft.PowerShell.Core\Get-Module -Name $resolvedPath -ListAvailable -ErrorAction SilentlyContinue -Verbose:$false
+ }
+
+ if(-not $module)
+ {
+ $message = $LocalizedData.InvalidModulePathToPublish -f ($Path)
+
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId 'InvalidModulePathToPublish' `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Path
+ }
+ elseif($module.GetType().ToString() -ne "System.Management.Automation.PSModuleInfo")
+ {
+ $message = $LocalizedData.AmbiguousModulePath -f ($Path)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId 'AmbiguousModulePathToPublish' `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Path
+ }
+
+ if($module -and (-not $module.Path.EndsWith('.psd1', [System.StringComparison]::OrdinalIgnoreCase)))
+ {
+ $message = $LocalizedData.InvalidModuleToPublish -f ($module.Name)
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidModuleToPublish" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation `
+ -ExceptionObject $module.Name
+ }
+
+ $moduleName = $module.Name
+ $Path = $module.ModuleBase
+ }
+
+ $message = $LocalizedData.PublishModuleLocation -f ($moduleName, $Path)
+ Write-Verbose -Message $message
+
+ #If users are providing tags using -Tags while running PS 5.0, will show warning messages
+ if($Tags)
+ {
+ $message = $LocalizedData.TagsShouldBeIncludedInManifestFile -f ($moduleName, $Path)
+ Write-Warning $message
+ }
+
+ if($ReleaseNotes)
+ {
+ $message = $LocalizedData.ReleaseNotesShouldBeIncludedInManifestFile -f ($moduleName, $Path)
+ Write-Warning $message
+ }
+
+ if($LicenseUri)
+ {
+ $message = $LocalizedData.LicenseUriShouldBeIncludedInManifestFile -f ($moduleName, $Path)
+ Write-Warning $message
+ }
+
+ if($IconUri)
+ {
+ $message = $LocalizedData.IconUriShouldBeIncludedInManifestFile -f ($moduleName, $Path)
+ Write-Warning $message
+ }
+
+ if($ProjectUri)
+ {
+ $message = $LocalizedData.ProjectUriShouldBeIncludedInManifestFile -f ($moduleName, $Path)
+ Write-Warning $message
+ }
+
+
+ # Copy the source module to temp location to publish
+ $tempModulePath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath `
+ -ChildPath "$(Microsoft.PowerShell.Utility\Get-Random)\$moduleName"
+
+ if(-not $FormatVersion)
+ {
+ $tempModulePathForFormatVersion = $tempModulePath
+ }
+ elseif ($FormatVersion -eq "1.0")
+ {
+ $tempModulePathForFormatVersion = Microsoft.PowerShell.Management\Join-Path $tempModulePath "Content\Deployment\$script:ModuleReferences\$moduleName"
+ }
+
+ $null = Microsoft.PowerShell.Management\New-Item -Path $tempModulePathForFormatVersion -ItemType Directory -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
+ Microsoft.PowerShell.Management\Copy-Item -Path "$Path\*" -Destination $tempModulePathForFormatVersion -Force -Recurse -Confirm:$false -WhatIf:$false
+
+ try
+ {
+ $manifestPath = Microsoft.PowerShell.Management\Join-Path $tempModulePathForFormatVersion "$moduleName.psd1"
+
+ if(-not (Microsoft.PowerShell.Management\Test-Path $manifestPath))
+ {
+ $message = $LocalizedData.InvalidModuleToPublish -f ($moduleName)
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidModuleToPublish" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation `
+ -ExceptionObject $moduleName
+ }
+
+ $ev = $null
+ $moduleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $manifestPath `
+ -ErrorVariable ev `
+ -Verbose:$VerbosePreference
+ if($ev)
+ {
+ # Above Test-ModuleManifest cmdlet should write an errors to the Errors stream and Console.
+ return
+ }
+
+ if(-not $moduleInfo -or
+ -not $moduleInfo.Author -or
+ -not $moduleInfo.Description)
+ {
+ $message = $LocalizedData.MissingRequiredManifestKeys -f ($moduleName)
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "MissingRequiredModuleManifestKeys" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation `
+ -ExceptionObject $moduleName
+ }
+
+ # Check if the specified module name is already used for a script on the specified repository
+ # Use Find-Script to check if that name is already used as scriptname
+ $scriptPSGetItemInfo = Find-Script -Name $moduleName `
+ -Repository $Repository `
+ -Tag 'PSScript' `
+ -Verbose:$VerbosePreference `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue `
+ -Debug:$DebugPreference |
+ Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $moduleName} |
+ Microsoft.PowerShell.Utility\Select-Object -Last 1
+ if($scriptPSGetItemInfo)
+ {
+ $message = $LocalizedData.SpecifiedNameIsAlearyUsed -f ($moduleName, $Repository, 'Find-Script')
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "SpecifiedNameIsAlearyUsed" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation `
+ -ExceptionObject $moduleName
+ }
+
+ $currentPSGetItemInfo = Find-Module -Name $moduleInfo.Name `
+ -Repository $Repository `
+ -Verbose:$VerbosePreference `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue `
+ -Debug:$DebugPreference |
+ Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $moduleInfo.Name} |
+ Microsoft.PowerShell.Utility\Select-Object -Last 1
+
+ if($currentPSGetItemInfo -and $currentPSGetItemInfo.Version -ge $moduleInfo.Version)
+ {
+ $message = $LocalizedData.ModuleVersionShouldBeGreaterThanGalleryVersion -f ($moduleInfo.Name, $moduleInfo.Version, $currentPSGetItemInfo.Version, $currentPSGetItemInfo.RepositorySourceLocation)
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "ModuleVersionShouldBeGreaterThanGalleryVersion" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation
+ }
+
+ $shouldProcessMessage = $LocalizedData.PublishModulewhatIfMessage -f ($moduleInfo.Version, $moduleInfo.Name)
+ if($PSCmdlet.ShouldProcess($shouldProcessMessage, "Publish-Module"))
+ {
+ Publish-PSArtifactUtility -PSModuleInfo $moduleInfo `
+ -ManifestPath $manifestPath `
+ -NugetApiKey $NuGetApiKey `
+ -Destination $DestinationLocation `
+ -Repository $Repository `
+ -NugetPackageRoot $tempModulePath `
+ -FormatVersion $FormatVersion `
+ -ReleaseNotes $($ReleaseNotes -join "`r`n") `
+ -Tags $Tags `
+ -LicenseUri $LicenseUri `
+ -IconUri $IconUri `
+ -ProjectUri $ProjectUri `
+ -Verbose:$VerbosePreference `
+ -WarningAction $WarningPreference `
+ -ErrorAction $ErrorActionPreference `
+ -Debug:$DebugPreference
+ }
+ }
+ finally
+ {
+ Microsoft.PowerShell.Management\Remove-Item $tempModulePath -Force -Recurse -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
+ }
+ }
+}
+
+function Find-Module
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=398574')]
+ [outputtype("PSCustomObject[]")]
+ Param
+ (
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ Position=0)]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Name,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNull()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNull()]
+ [Version]
+ $MaximumVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNull()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter()]
+ [switch]
+ $AllVersions,
+
+ [Parameter()]
+ [switch]
+ $IncludeDependencies,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [string]
+ $Filter,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [string[]]
+ $Tag,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [ValidateSet('DscResource','Cmdlet','Function','RoleCapability')]
+ [string[]]
+ $Includes,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [string[]]
+ $DscResource,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [string[]]
+ $RoleCapability,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [string[]]
+ $Command,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Repository
+ )
+
+ Begin
+ {
+ Get-PSGalleryApiAvailability -Repository $Repository
+
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+ }
+
+ Process
+ {
+ $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet `
+ -Name $Name `
+ -MinimumVersion $MinimumVersion `
+ -MaximumVersion $MaximumVersion `
+ -RequiredVersion $RequiredVersion `
+ -AllVersions:$AllVersions
+
+ if(-not $ValidationResult)
+ {
+ # Validate-VersionParameters throws the error.
+ # returning to avoid further execution when different values are specified for -ErrorAction parameter
+ return
+ }
+
+ $PSBoundParameters["Provider"] = $script:PSModuleProviderName
+ $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule
+
+ if($PSBoundParameters.ContainsKey("Repository"))
+ {
+ $PSBoundParameters["Source"] = $Repository
+ $null = $PSBoundParameters.Remove("Repository")
+
+ $ev = $null
+ $null = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false
+ if($ev) { return }
+ }
+
+ $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock
+
+ $modulesFoundInPSGallery = @()
+
+ # No Telemetry must be performed if PSGallery is not in the supplied list of Repositories
+ $isRepositoryNullOrPSGallerySpecified = $false
+ if ($Repository -and ($Repository -Contains $Script:PSGalleryModuleSource))
+ {
+ $isRepositoryNullOrPSGallerySpecified = $true
+ }
+ elseif(-not $Repository)
+ {
+ $psgalleryRepo = Get-PSRepository -Name $Script:PSGalleryModuleSource `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+ if($psgalleryRepo)
+ {
+ $isRepositoryNullOrPSGallerySpecified = $true
+ }
+ }
+
+ PackageManagement\Find-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object {
+
+ $psgetItemInfo = New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeModule
+
+ $psgetItemInfo
+
+ if ($psgetItemInfo -and
+ $isRepositoryNullOrPSGallerySpecified -and
+ $script:TelemetryEnabled -and
+ ($psgetItemInfo.Repository -eq $Script:PSGalleryModuleSource))
+ {
+ $modulesFoundInPSGallery += $psgetItemInfo.Name
+ }
+ }
+
+ # Perform Telemetry if Repository is not supplied or Repository contains PSGallery
+ # We are only interested in finding modules not in PSGallery
+ if ($isRepositoryNullOrPSGallerySpecified)
+ {
+ Log-ArtifactNotFoundInPSGallery -SearchedName $Name -FoundName $modulesFoundInPSGallery -operationName 'PSGET_FIND_MODULE'
+ }
+ }
+}
+
+function Save-Module
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(DefaultParameterSetName='NameAndPathParameterSet',
+ HelpUri='http://go.microsoft.com/fwlink/?LinkId=531351',
+ SupportsShouldProcess=$true)]
+ Param
+ (
+ [Parameter(Mandatory=$true,
+ ValueFromPipelineByPropertyName=$true,
+ Position=0,
+ ParameterSetName='NameAndPathParameterSet')]
+ [Parameter(Mandatory=$true,
+ ValueFromPipelineByPropertyName=$true,
+ Position=0,
+ ParameterSetName='NameAndLiteralPathParameterSet')]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Name,
+
+ [Parameter(Mandatory=$true,
+ ValueFromPipeline=$true,
+ ValueFromPipelineByPropertyName=$true,
+ Position=0,
+ ParameterSetName='InputOjectAndPathParameterSet')]
+ [Parameter(Mandatory=$true,
+ ValueFromPipeline=$true,
+ ValueFromPipelineByPropertyName=$true,
+ Position=0,
+ ParameterSetName='InputOjectAndLiteralPathParameterSet')]
+ [ValidateNotNull()]
+ [PSCustomObject[]]
+ $InputObject,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndPathParameterSet')]
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndLiteralPathParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndPathParameterSet')]
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndLiteralPathParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $MaximumVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndPathParameterSet')]
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndLiteralPathParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndPathParameterSet')]
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndLiteralPathParameterSet')]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Repository,
+
+ [Parameter(Mandatory=$true, ParameterSetName='NameAndPathParameterSet')]
+ [Parameter(Mandatory=$true, ParameterSetName='InputOjectAndPathParameterSet')]
+ [string]
+ $Path,
+
+ [Parameter(Mandatory=$true, ParameterSetName='NameAndLiteralPathParameterSet')]
+ [Parameter(Mandatory=$true, ParameterSetName='InputOjectAndLiteralPathParameterSet')]
+ [string]
+ $LiteralPath,
+
+ [Parameter()]
+ [switch]
+ $Force
+ )
+
+ Begin
+ {
+ Get-PSGalleryApiAvailability -Repository $Repository
+
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+
+ # Module names already tried in the current pipeline for InputObject parameterset
+ $moduleNamesInPipeline = @()
+ }
+
+ Process
+ {
+ $PSBoundParameters["Provider"] = $script:PSModuleProviderName
+ $PSBoundParameters["MessageResolver"] = $script:PackageManagementSaveModuleMessageResolverScriptBlock
+ $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule
+
+ # When -Force is specified, Path will be created if not available.
+ if(-not $Force)
+ {
+ if($Path)
+ {
+ $destinationPath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1
+
+ if(-not $destinationPath -or -not (Microsoft.PowerShell.Management\Test-path $destinationPath))
+ {
+ $errorMessage = ($LocalizedData.PathNotFound -f $Path)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $Path `
+ -ErrorCategory InvalidArgument
+ }
+
+ $PSBoundParameters['Path'] = $destinationPath
+ }
+ else
+ {
+ $destinationPath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1
+
+ if(-not $destinationPath -or -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $destinationPath))
+ {
+ $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $LiteralPath `
+ -ErrorCategory InvalidArgument
+ }
+
+ $PSBoundParameters['LiteralPath'] = $destinationPath
+ }
+ }
+
+ if($Name)
+ {
+ $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet `
+ -Name $Name `
+ -TestWildcardsInName `
+ -MinimumVersion $MinimumVersion `
+ -MaximumVersion $MaximumVersion `
+ -RequiredVersion $RequiredVersion
+
+ if(-not $ValidationResult)
+ {
+ # Validate-VersionParameters throws the error.
+ # returning to avoid further execution when different values are specified for -ErrorAction parameter
+ return
+ }
+
+ if($PSBoundParameters.ContainsKey("Repository"))
+ {
+ $PSBoundParameters["Source"] = $Repository
+ $null = $PSBoundParameters.Remove("Repository")
+
+ $ev = $null
+ $null = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false
+ if($ev) { return }
+ }
+
+ $null = PackageManagement\Save-Package @PSBoundParameters
+ }
+ elseif($InputObject)
+ {
+ $null = $PSBoundParameters.Remove("InputObject")
+
+ foreach($inputValue in $InputObject)
+ {
+ if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetCommandInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetCommandInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo"))
+
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $LocalizedData.InvalidInputObjectValue `
+ -ErrorId "InvalidInputObjectValue" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $inputValue
+ }
+
+ if( ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -or
+ ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -or
+ ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetCommandInfo") -or
+ ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetCommandInfo") -or
+ ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo") -or
+ ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo"))
+ {
+ $psgetModuleInfo = $inputValue.PSGetModuleInfo
+ }
+ else
+ {
+ $psgetModuleInfo = $inputValue
+ }
+
+ # Skip the module name if it is already tried in the current pipeline
+ if($moduleNamesInPipeline -contains $psgetModuleInfo.Name)
+ {
+ continue
+ }
+
+ $moduleNamesInPipeline += $psgetModuleInfo.Name
+
+ if ($psgetModuleInfo.PowerShellGetFormatVersion -and
+ ($script:SupportedPSGetFormatVersionMajors -notcontains $psgetModuleInfo.PowerShellGetFormatVersion.Major))
+ {
+ $message = $LocalizedData.NotSupportedPowerShellGetFormatVersion -f ($psgetModuleInfo.Name, $psgetModuleInfo.PowerShellGetFormatVersion, $psgetModuleInfo.Name)
+ Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation
+ continue
+ }
+
+ $PSBoundParameters["Name"] = $psgetModuleInfo.Name
+ $PSBoundParameters["RequiredVersion"] = $psgetModuleInfo.Version
+ $PSBoundParameters['Source'] = $psgetModuleInfo.Repository
+ $PSBoundParameters["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $psgetModuleInfo)
+
+ $null = PackageManagement\Save-Package @PSBoundParameters
+ }
+ }
+ }
+}
+
+function Install-Module
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(DefaultParameterSetName='NameParameterSet',
+ HelpUri='http://go.microsoft.com/fwlink/?LinkID=398573',
+ SupportsShouldProcess=$true)]
+ Param
+ (
+ [Parameter(Mandatory=$true,
+ ValueFromPipelineByPropertyName=$true,
+ Position=0,
+ ParameterSetName='NameParameterSet')]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Name,
+
+ [Parameter(Mandatory=$true,
+ ValueFromPipeline=$true,
+ ValueFromPipelineByPropertyName=$true,
+ Position=0,
+ ParameterSetName='InputObject')]
+ [ValidateNotNull()]
+ [PSCustomObject[]]
+ $InputObject,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $MaximumVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter(ParameterSetName='NameParameterSet')]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Repository,
+
+ [Parameter()]
+ [ValidateSet("CurrentUser","AllUsers")]
+ [string]
+ $Scope = "AllUsers",
+
+ [Parameter()]
+ [switch]
+ $Force
+ )
+
+ Begin
+ {
+ Get-PSGalleryApiAvailability -Repository $Repository
+
+ if(-not (Test-RunningAsElevated) -and ($Scope -ne "CurrentUser"))
+ {
+ # Throw an error when Install-Module is used as a non-admin user and '-Scope CurrentUser' is not specified
+ $message = $LocalizedData.InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser -f @($script:programFilesModulesPath, $script:MyDocumentsModulesPath)
+
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+
+ # Module names already tried in the current pipeline for InputObject parameterset
+ $moduleNamesInPipeline = @()
+ $YesToAll = $false
+ $NoToAll = $false
+ $SourceSGrantedTrust = @()
+ $SourcesDeniedTrust = @()
+ }
+
+ Process
+ {
+ $RepositoryIsNotTrusted = $LocalizedData.RepositoryIsNotTrusted
+ $QueryInstallUntrustedPackage = $LocalizedData.QueryInstallUntrustedPackage
+ $PackageTarget = $LocalizedData.InstallModulewhatIfMessage
+
+ $PSBoundParameters["Provider"] = $script:PSModuleProviderName
+ $PSBoundParameters["MessageResolver"] = $script:PackageManagementInstallModuleMessageResolverScriptBlock
+ $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule
+ $PSBoundParameters['Scope'] = $Scope
+
+ if($PSCmdlet.ParameterSetName -eq "NameParameterSet")
+ {
+ $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet `
+ -Name $Name `
+ -TestWildcardsInName `
+ -MinimumVersion $MinimumVersion `
+ -MaximumVersion $MaximumVersion `
+ -RequiredVersion $RequiredVersion
+
+ if(-not $ValidationResult)
+ {
+ # Validate-VersionParameters throws the error.
+ # returning to avoid further execution when different values are specified for -ErrorAction parameter
+ return
+ }
+
+ if($PSBoundParameters.ContainsKey("Repository"))
+ {
+ $PSBoundParameters["Source"] = $Repository
+ $null = $PSBoundParameters.Remove("Repository")
+
+ $ev = $null
+ $null = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false
+ if($ev) { return }
+ }
+
+ $null = PackageManagement\Install-Package @PSBoundParameters
+ }
+ elseif($PSCmdlet.ParameterSetName -eq "InputObject")
+ {
+ $null = $PSBoundParameters.Remove("InputObject")
+
+ foreach($inputValue in $InputObject)
+ {
+ if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetCommandInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetCommandInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo"))
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $LocalizedData.InvalidInputObjectValue `
+ -ErrorId "InvalidInputObjectValue" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $inputValue
+ }
+
+ if( ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -or
+ ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -or
+ ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetCommandInfo") -or
+ ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetCommandInfo") -or
+ ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo") -or
+ ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo"))
+ {
+ $psgetModuleInfo = $inputValue.PSGetModuleInfo
+ }
+ else
+ {
+ $psgetModuleInfo = $inputValue
+ }
+
+ # Skip the module name if it is already tried in the current pipeline
+ if($moduleNamesInPipeline -contains $psgetModuleInfo.Name)
+ {
+ continue
+ }
+
+ $moduleNamesInPipeline += $psgetModuleInfo.Name
+
+ if ($psgetModuleInfo.PowerShellGetFormatVersion -and
+ ($script:SupportedPSGetFormatVersionMajors -notcontains $psgetModuleInfo.PowerShellGetFormatVersion.Major))
+ {
+ $message = $LocalizedData.NotSupportedPowerShellGetFormatVersion -f ($psgetModuleInfo.Name, $psgetModuleInfo.PowerShellGetFormatVersion, $psgetModuleInfo.Name)
+ Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation
+ continue
+ }
+
+ $PSBoundParameters["Name"] = $psgetModuleInfo.Name
+ $PSBoundParameters["RequiredVersion"] = $psgetModuleInfo.Version
+ $PSBoundParameters['Source'] = $psgetModuleInfo.Repository
+ $PSBoundParameters["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $psgetModuleInfo)
+
+ #Check if module is already installed
+ $InstalledModuleInfo = Test-ModuleInstalled -Name $psgetModuleInfo.Name -RequiredVersion $psgetModuleInfo.Version
+ if(-not $Force -and $InstalledModuleInfo -ne $null)
+ {
+ $message = $LocalizedData.ModuleAlreadyInstalledVerbose -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase)
+ Write-Verbose -Message $message
+ }
+ else
+ {
+ $source = $psgetModuleInfo.Repository
+ $installationPolicy = (Get-PSRepository -Name $source).InstallationPolicy
+ $ShouldProcessMessage = $PackageTarget -f ($psgetModuleInfo.Name, $psgetModuleInfo.Version)
+
+ if($psCmdlet.ShouldProcess($ShouldProcessMessage))
+ {
+ if($installationPolicy.Equals("Untrusted", [StringComparison]::OrdinalIgnoreCase))
+ {
+ if(-not($YesToAll -or $NoToAll -or $SourceSGrantedTrust.Contains($source) -or $sourcesDeniedTrust.Contains($source) -or $Force))
+ {
+ $message = $QueryInstallUntrustedPackage -f ($psgetModuleInfo.Name, $psgetModuleInfo.RepositorySourceLocation)
+ if($PSVersionTable.PSVersion -ge [Version]"5.0")
+ {
+ $sourceTrusted = $psCmdlet.ShouldContinue("$message", "$RepositoryIsNotTrusted",$true, [ref]$YesToAll, [ref]$NoToAll)
+ }
+ else
+ {
+ $sourceTrusted = $psCmdlet.ShouldContinue("$message", "$RepositoryIsNotTrusted", [ref]$YesToAll, [ref]$NoToAll)
+ }
+
+ if($sourceTrusted)
+ {
+ $SourceSGrantedTrust+=$source
+ }
+ else
+ {
+ $SourcesDeniedTrust+=$source
+ }
+ }
+ }
+
+ if($installationPolicy.Equals("trusted", [StringComparison]::OrdinalIgnoreCase) -or $SourceSGrantedTrust.Contains($source) -or $YesToAll -or $Force)
+ {
+ $PSBoundParameters["Force"] = $true
+ $null = PackageManagement\Install-Package @PSBoundParameters
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+function Update-Module
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(SupportsShouldProcess=$true,
+ HelpUri='http://go.microsoft.com/fwlink/?LinkID=398576')]
+ Param
+ (
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ Position=0)]
+ [ValidateNotNullOrEmpty()]
+ [String[]]
+ $Name,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNull()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNull()]
+ [Version]
+ $MaximumVersion,
+
+ [Parameter()]
+ [Switch]
+ $Force
+ )
+
+ Begin
+ {
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+
+ # Module names already tried in the current pipeline
+ $moduleNamesInPipeline = @()
+ }
+
+ Process
+ {
+ $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet `
+ -Name $Name `
+ -MaximumVersion $MaximumVersion `
+ -RequiredVersion $RequiredVersion
+
+ if(-not $ValidationResult)
+ {
+ # Validate-VersionParameters throws the error.
+ # returning to avoid further execution when different values are specified for -ErrorAction parameter
+ return
+ }
+
+ $GetPackageParameters = @{}
+ $GetPackageParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule
+ $GetPackageParameters["Provider"] = $script:PSModuleProviderName
+ $GetPackageParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock
+ $GetPackageParameters['ErrorAction'] = 'SilentlyContinue'
+ $GetPackageParameters['WarningAction'] = 'SilentlyContinue'
+
+ $PSGetItemInfos = @()
+
+ if($Name)
+ {
+ foreach($moduleName in $Name)
+ {
+ $GetPackageParameters['Name'] = $moduleName
+ $installedPackages = PackageManagement\Get-Package @GetPackageParameters
+
+ if(-not $installedPackages -and -not (Test-WildcardPattern -Name $moduleName))
+ {
+ $availableModules = Get-Module -ListAvailable $moduleName -Verbose:$false | Microsoft.PowerShell.Utility\Select-Object -Unique
+
+ if(-not $availableModules)
+ {
+ $message = $LocalizedData.ModuleNotInstalledOnThisMachine -f ($moduleName)
+ Write-Error -Message $message -ErrorId 'ModuleNotInstalledOnThisMachine' -Category InvalidOperation -TargetObject $moduleName
+ }
+ else
+ {
+ $message = $LocalizedData.ModuleNotInstalledUsingPowerShellGet -f ($moduleName)
+ Write-Error -Message $message -ErrorId 'ModuleNotInstalledUsingInstallModuleCmdlet' -Category InvalidOperation -TargetObject $moduleName
+ }
+
+ continue
+ }
+
+ $installedPackages |
+ Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeModule} |
+ Microsoft.PowerShell.Core\ForEach-Object {
+ if(-not (Test-RunningAsElevated) -and $_.InstalledLocation.StartsWith($script:programFilesModulesPath, [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ if(-not (Test-WildcardPattern -Name $moduleName))
+ {
+ $message = $LocalizedData.AdminPrivilegesRequiredForUpdate -f ($_.Name, $_.InstalledLocation)
+ Write-Error -Message $message -ErrorId "AdminPrivilegesAreRequiredForUpdate" -Category InvalidOperation -TargetObject $moduleName
+ }
+ continue
+ }
+
+ $PSGetItemInfos += $_
+ }
+ }
+ }
+ else
+ {
+
+ $PSGetItemInfos = PackageManagement\Get-Package @GetPackageParameters |
+ Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeModule} |
+ Microsoft.PowerShell.Core\Where-Object {
+ (Test-RunningAsElevated) -or
+ $_.InstalledLocation.StartsWith($script:MyDocumentsModulesPath, [System.StringComparison]::OrdinalIgnoreCase)
+ }
+ }
+
+
+ $PSBoundParameters["Provider"] = $script:PSModuleProviderName
+ $PSBoundParameters["MessageResolver"] = $script:PackageManagementUpdateModuleMessageResolverScriptBlock
+ $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule
+
+ foreach($psgetItemInfo in $PSGetItemInfos)
+ {
+ # Skip the module name if it is already tried in the current pipeline
+ if($moduleNamesInPipeline -contains $psgetItemInfo.Name)
+ {
+ continue
+ }
+
+ $moduleNamesInPipeline += $psgetItemInfo.Name
+
+ $message = $LocalizedData.CheckingForModuleUpdate -f ($psgetItemInfo.Name)
+ Write-Verbose -Message $message
+
+ $providerName = Get-ProviderName -PSCustomObject $psgetItemInfo
+ if(-not $providerName)
+ {
+ $providerName = $script:NuGetProviderName
+ }
+
+ $PSBoundParameters["Name"] = $psgetItemInfo.Name
+ $PSBoundParameters['Source'] = $psgetItemInfo.Repository
+
+ Get-PSGalleryApiAvailability -Repository (Get-SourceName -Location $psgetItemInfo.RepositorySourceLocation)
+
+ $PSBoundParameters["PackageManagementProvider"] = $providerName
+ $PSBoundParameters["InstallUpdate"] = $true
+
+ if($psgetItemInfo.InstalledLocation.ToString().StartsWith($script:MyDocumentsModulesPath, [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $PSBoundParameters["Scope"] = "CurrentUser"
+ }
+ else
+ {
+ $PSBoundParameters['Scope'] = 'AllUsers'
+ }
+
+ $sid = PackageManagement\Install-Package @PSBoundParameters
+ }
+ }
+}
+
+function Uninstall-Module
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(DefaultParameterSetName='NameParameterSet',
+ SupportsShouldProcess=$true,
+ HelpUri='http://go.microsoft.com/fwlink/?LinkId=526864')]
+ Param
+ (
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ Mandatory=$true,
+ Position=0,
+ ParameterSetName='NameParameterSet')]
+ [ValidateNotNullOrEmpty()]
+ [String[]]
+ $Name,
+
+ [Parameter(Mandatory=$true,
+ ValueFromPipeline=$true,
+ ValueFromPipelineByPropertyName=$true,
+ Position=0,
+ ParameterSetName='InputObject')]
+ [ValidateNotNull()]
+ [PSCustomObject[]]
+ $InputObject,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $MaximumVersion,
+
+ [Parameter(ParameterSetName='NameParameterSet')]
+ [switch]
+ $AllVersions,
+
+ [Parameter()]
+ [Switch]
+ $Force
+ )
+
+ Process
+ {
+ $PSBoundParameters["Provider"] = $script:PSModuleProviderName
+ $PSBoundParameters["MessageResolver"] = $script:PackageManagementUnInstallModuleMessageResolverScriptBlock
+ $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule
+
+ if($PSCmdlet.ParameterSetName -eq "InputObject")
+ {
+ $null = $PSBoundParameters.Remove("InputObject")
+
+ foreach($inputValue in $InputObject)
+ {
+ if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo"))
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $LocalizedData.InvalidInputObjectValue `
+ -ErrorId "InvalidInputObjectValue" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $inputValue
+ }
+
+ $PSBoundParameters["Name"] = $inputValue.Name
+ $PSBoundParameters["RequiredVersion"] = $inputValue.Version
+
+ $null = PackageManagement\Uninstall-Package @PSBoundParameters
+ }
+ }
+ else
+ {
+ $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet `
+ -Name $Name `
+ -TestWildcardsInName `
+ -MinimumVersion $MinimumVersion `
+ -MaximumVersion $MaximumVersion `
+ -RequiredVersion $RequiredVersion `
+ -AllVersions:$AllVersions
+
+ if(-not $ValidationResult)
+ {
+ # Validate-VersionParameters throws the error.
+ # returning to avoid further execution when different values are specified for -ErrorAction parameter
+ return
+ }
+
+ $null = PackageManagement\Uninstall-Package @PSBoundParameters
+ }
+ }
+}
+
+function Get-InstalledModule
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkId=526863')]
+ Param
+ (
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ Position=0)]
+ [ValidateNotNullOrEmpty()]
+ [String[]]
+ $Name,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNull()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNull()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNull()]
+ [Version]
+ $MaximumVersion,
+
+ [Parameter()]
+ [switch]
+ $AllVersions
+ )
+
+ Process
+ {
+ $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet `
+ -Name $Name `
+ -MinimumVersion $MinimumVersion `
+ -MaximumVersion $MaximumVersion `
+ -RequiredVersion $RequiredVersion `
+ -AllVersions:$AllVersions
+
+ if(-not $ValidationResult)
+ {
+ # Validate-VersionParameters throws the error.
+ # returning to avoid further execution when different values are specified for -ErrorAction parameter
+ return
+ }
+
+ $PSBoundParameters["Provider"] = $script:PSModuleProviderName
+ $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock
+ $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule
+
+ PackageManagement\Get-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeModule}
+ }
+}
+
+#endregion *-Module cmdlets
+
+#region Find-DscResouce cmdlet
+
+function Find-DscResource
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(HelpUri = 'http://go.microsoft.com/fwlink/?LinkId=517196')]
+ [outputtype('PSCustomObject[]')]
+ Param
+ (
+ [Parameter(Position = 0)]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Name,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $ModuleName,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter()]
+ [switch]
+ $AllVersions,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [string[]]
+ $Tag,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [string]
+ $Filter,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Repository
+ )
+
+
+ Process
+ {
+ $PSBoundParameters['Includes'] = 'DscResource'
+
+ if($PSBoundParameters.ContainsKey('Name'))
+ {
+ $PSBoundParameters['DscResource'] = $Name
+ $null = $PSBoundParameters.Remove('Name')
+ }
+
+ if($PSBoundParameters.ContainsKey('ModuleName'))
+ {
+ $PSBoundParameters['Name'] = $ModuleName
+ $null = $PSBoundParameters.Remove('ModuleName')
+ }
+
+ PowerShellGet\Find-Module @PSBoundParameters |
+ Microsoft.PowerShell.Core\ForEach-Object {
+ $psgetModuleInfo = $_
+ $psgetModuleInfo.Includes.DscResource | Microsoft.PowerShell.Core\ForEach-Object {
+ if($Name -and ($Name -notcontains $_))
+ {
+ return
+ }
+
+ $psgetDscResourceInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
+ Name = $_
+ Version = $psgetModuleInfo.Version
+ ModuleName = $psgetModuleInfo.Name
+ Repository = $psgetModuleInfo.Repository
+ PSGetModuleInfo = $psgetModuleInfo
+ })
+
+ $psgetDscResourceInfo.PSTypeNames.Insert(0, 'Microsoft.PowerShell.Commands.PSGetDscResourceInfo')
+ $psgetDscResourceInfo
+ }
+ }
+ }
+}
+
+#endregion Find-DscResouce cmdlet
+
+#region Find-Command cmdlet
+
+function Find-Command
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(HelpUri = 'http://go.microsoft.com/fwlink/?LinkId=733636')]
+ [outputtype('PSCustomObject[]')]
+ Param
+ (
+ [Parameter(Position = 0)]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Name,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $ModuleName,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter()]
+ [switch]
+ $AllVersions,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [string[]]
+ $Tag,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [string]
+ $Filter,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Repository
+ )
+
+
+ Process
+ {
+ if($PSBoundParameters.ContainsKey('Name'))
+ {
+ $PSBoundParameters['Command'] = $Name
+ $null = $PSBoundParameters.Remove('Name')
+ }
+ else
+ {
+ $PSBoundParameters['Includes'] = @('Cmdlet','Function')
+ }
+
+ if($PSBoundParameters.ContainsKey('ModuleName'))
+ {
+ $PSBoundParameters['Name'] = $ModuleName
+ $null = $PSBoundParameters.Remove('ModuleName')
+ }
+
+ PowerShellGet\Find-Module @PSBoundParameters |
+ Microsoft.PowerShell.Core\ForEach-Object {
+ $psgetModuleInfo = $_
+ $psgetModuleInfo.Includes.Command | Microsoft.PowerShell.Core\ForEach-Object {
+ if(($_ -eq "*") -or ($Name -and ($Name -notcontains $_)))
+ {
+ return
+ }
+
+ $psgetCommandInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
+ Name = $_
+ Version = $psgetModuleInfo.Version
+ ModuleName = $psgetModuleInfo.Name
+ Repository = $psgetModuleInfo.Repository
+ PSGetModuleInfo = $psgetModuleInfo
+ })
+
+ $psgetCommandInfo.PSTypeNames.Insert(0, 'Microsoft.PowerShell.Commands.PSGetCommandInfo')
+ $psgetCommandInfo
+ }
+ }
+ }
+}
+
+#endregion Find-Command cmdlet
+
+#region Find-RoleCapability cmdlet
+
+function Find-RoleCapability
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(HelpUri = 'http://go.microsoft.com/fwlink/?LinkId=718029')]
+ [outputtype('PSCustomObject[]')]
+ Param
+ (
+ [Parameter(Position = 0)]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Name,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $ModuleName,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter()]
+ [switch]
+ $AllVersions,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [string[]]
+ $Tag,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [string]
+ $Filter,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Repository
+ )
+
+
+ Process
+ {
+ $PSBoundParameters['Includes'] = 'RoleCapability'
+
+ if($PSBoundParameters.ContainsKey('Name'))
+ {
+ $PSBoundParameters['RoleCapability'] = $Name
+ $null = $PSBoundParameters.Remove('Name')
+ }
+
+ if($PSBoundParameters.ContainsKey('ModuleName'))
+ {
+ $PSBoundParameters['Name'] = $ModuleName
+ $null = $PSBoundParameters.Remove('ModuleName')
+ }
+
+ PowerShellGet\Find-Module @PSBoundParameters |
+ Microsoft.PowerShell.Core\ForEach-Object {
+ $psgetModuleInfo = $_
+ $psgetModuleInfo.Includes.RoleCapability | Microsoft.PowerShell.Core\ForEach-Object {
+ if($Name -and ($Name -notcontains $_))
+ {
+ return
+ }
+
+ $psgetRoleCapabilityInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
+ Name = $_
+ Version = $psgetModuleInfo.Version
+ ModuleName = $psgetModuleInfo.Name
+ Repository = $psgetModuleInfo.Repository
+ PSGetModuleInfo = $psgetModuleInfo
+ })
+
+ $psgetRoleCapabilityInfo.PSTypeNames.Insert(0, 'Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo')
+ $psgetRoleCapabilityInfo
+ }
+ }
+ }
+}
+
+#endregion Find-RoleCapability cmdlet
+
+#region *-Script cmdlets
+function Publish-Script
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(SupportsShouldProcess=$true,
+ PositionalBinding=$false,
+ DefaultParameterSetName='PathParameterSet',
+ HelpUri='http://go.microsoft.com/fwlink/?LinkId=619788')]
+ Param
+ (
+ [Parameter(Mandatory=$true,
+ ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='PathParameterSet')]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Path,
+
+ [Parameter(Mandatory=$true,
+ ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='LiteralPathParameterSet')]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $LiteralPath,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $NuGetApiKey,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Repository = $Script:PSGalleryModuleSource
+ )
+
+ Begin
+ {
+ if($script:isNanoServer) {
+ $message = $LocalizedData.PublishPSArtifactUnsupportedOnNano -f "Script"
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "PublishScriptIsNotSupportedOnNanoServer" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $PSCmdlet `
+ -ErrorCategory InvalidOperation
+ }
+
+ Get-PSGalleryApiAvailability -Repository $Repository
+
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe
+ }
+
+ Process
+ {
+ $scriptFilePath = $null
+ if($Path)
+ {
+ $scriptFilePath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet |
+ Microsoft.PowerShell.Utility\Select-Object -First 1
+
+ if(-not $scriptFilePath -or
+ -not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf))
+ {
+ $errorMessage = ($LocalizedData.PathNotFound -f $Path)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $Path `
+ -ErrorCategory InvalidArgument
+ }
+ }
+ else
+ {
+ $scriptFilePath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet |
+ Microsoft.PowerShell.Utility\Select-Object -First 1
+
+ if(-not $scriptFilePath -or
+ -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $scriptFilePath -PathType Leaf))
+ {
+ $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $LiteralPath `
+ -ErrorCategory InvalidArgument
+ }
+ }
+
+ if(-not $scriptFilePath.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $errorMessage = ($LocalizedData.InvalidScriptFilePath -f $scriptFilePath)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "InvalidScriptFilePath" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $scriptFilePath `
+ -ErrorCategory InvalidArgument
+ return
+ }
+
+ if($Repository -eq $Script:PSGalleryModuleSource)
+ {
+ $repo = Get-PSRepository -Name $Repository -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
+ if(-not $repo)
+ {
+ $message = $LocalizedData.PSGalleryNotFound -f ($Repository)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId 'PSGalleryNotFound' `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Repository
+ return
+ }
+ }
+ else
+ {
+ $ev = $null
+ $repo = Get-PSRepository -Name $Repository -ErrorVariable ev
+ if($ev) { return }
+ }
+
+ $DestinationLocation = $null
+
+ if(Get-Member -InputObject $repo -Name $script:ScriptPublishLocation)
+ {
+ $DestinationLocation = $repo.ScriptPublishLocation
+ }
+
+ if(-not $DestinationLocation -or
+ (-not (Microsoft.PowerShell.Management\Test-Path -Path $DestinationLocation) -and
+ -not (Test-WebUri -uri $DestinationLocation)))
+
+ {
+ $message = $LocalizedData.PSRepositoryScriptPublishLocationIsMissing -f ($Repository, $Repository)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "PSRepositoryScriptPublishLocationIsMissing" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Repository
+ }
+
+ $message = $LocalizedData.PublishLocation -f ($DestinationLocation)
+ Write-Verbose -Message $message
+
+ if(-not $NuGetApiKey.Trim())
+ {
+ if(Microsoft.PowerShell.Management\Test-Path -Path $DestinationLocation)
+ {
+ $NuGetApiKey = "$(Get-Random)"
+ }
+ else
+ {
+ $message = $LocalizedData.NuGetApiKeyIsRequiredForNuGetBasedGalleryService -f ($Repository, $DestinationLocation)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "NuGetApiKeyIsRequiredForNuGetBasedGalleryService" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+ }
+
+ $providerName = Get-ProviderName -PSCustomObject $repo
+ if($providerName -ne $script:NuGetProviderName)
+ {
+ $message = $LocalizedData.PublishScriptSupportsOnlyNuGetBasedPublishLocations -f ($DestinationLocation, $Repository, $Repository)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "PublishScriptSupportsOnlyNuGetBasedPublishLocations" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Repository
+ }
+
+ if($Path)
+ {
+ $PSScriptInfo = Test-ScriptFileInfo -Path $scriptFilePath
+ }
+ else
+ {
+ $PSScriptInfo = Test-ScriptFileInfo -LiteralPath $scriptFilePath
+ }
+
+ if(-not $PSScriptInfo)
+ {
+ # Test-ScriptFileInfo throws the actual error
+ return
+ }
+
+ $scriptName = $PSScriptInfo.Name
+
+ # Copy the source script file to temp location to publish
+ $tempScriptPath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath `
+ -ChildPath "$(Microsoft.PowerShell.Utility\Get-Random)\$scriptName"
+
+ $null = Microsoft.PowerShell.Management\New-Item -Path $tempScriptPath -ItemType Directory -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
+ if($Path)
+ {
+ Microsoft.PowerShell.Management\Copy-Item -Path $scriptFilePath -Destination $tempScriptPath -Force -Recurse -Confirm:$false -WhatIf:$false
+ }
+ else
+ {
+ Microsoft.PowerShell.Management\Copy-Item -LiteralPath $scriptFilePath -Destination $tempScriptPath -Force -Recurse -Confirm:$false -WhatIf:$false
+ }
+
+ try
+ {
+ # Check if the specified script name is already used for a module on the specified repository
+ # Use Find-Module to check if that name is already used as module name
+ $modulePSGetItemInfo = Find-Module -Name $scriptName `
+ -Repository $Repository `
+ -Tag 'PSModule' `
+ -Verbose:$VerbosePreference `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue `
+ -Debug:$DebugPreference |
+ Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $scriptName} |
+ Microsoft.PowerShell.Utility\Select-Object -Last 1
+ if($modulePSGetItemInfo)
+ {
+ $message = $LocalizedData.SpecifiedNameIsAlearyUsed -f ($scriptName, $Repository, 'Find-Module')
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "SpecifiedNameIsAlearyUsed" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation `
+ -ExceptionObject $scriptName
+ }
+
+ $currentPSGetItemInfo = $null
+ $currentPSGetItemInfo = Find-Script -Name $scriptName `
+ -Repository $Repository `
+ -Verbose:$VerbosePreference `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue `
+ -Debug:$DebugPreference |
+ Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $scriptName} |
+ Microsoft.PowerShell.Utility\Select-Object -Last 1
+
+ if($currentPSGetItemInfo -and $currentPSGetItemInfo.Version -ge $PSScriptInfo.Version)
+ {
+ $message = $LocalizedData.ScriptVersionShouldBeGreaterThanGalleryVersion -f ($scriptName,
+ $PSScriptInfo.Version,
+ $currentPSGetItemInfo.Version,
+ $currentPSGetItemInfo.RepositorySourceLocation)
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "ScriptVersionShouldBeGreaterThanGalleryVersion" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation
+ }
+
+ $shouldProcessMessage = $LocalizedData.PublishScriptwhatIfMessage -f ($PSScriptInfo.Version, $scriptName)
+ if($PSCmdlet.ShouldProcess($shouldProcessMessage, "Publish-Script"))
+ {
+ Publish-PSArtifactUtility -PSScriptInfo $PSScriptInfo `
+ -NugetApiKey $NuGetApiKey `
+ -Destination $DestinationLocation `
+ -Repository $Repository `
+ -NugetPackageRoot $tempScriptPath `
+ -Verbose:$VerbosePreference `
+ -WarningAction $WarningPreference `
+ -ErrorAction $ErrorActionPreference `
+ -Debug:$DebugPreference
+ }
+ }
+ finally
+ {
+ Microsoft.PowerShell.Management\Remove-Item $tempScriptPath -Force -Recurse -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
+ }
+ }
+}
+
+function Find-Script
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkId=619785')]
+ [outputtype("PSCustomObject[]")]
+ Param
+ (
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ Position=0)]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Name,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNull()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNull()]
+ [Version]
+ $MaximumVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNull()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter()]
+ [switch]
+ $AllVersions,
+
+ [Parameter()]
+ [switch]
+ $IncludeDependencies,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [string]
+ $Filter,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [string[]]
+ $Tag,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [ValidateSet('Function','Workflow')]
+ [string[]]
+ $Includes,
+
+ [Parameter()]
+ [ValidateNotNull()]
+ [string[]]
+ $Command,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Repository
+ )
+
+ Begin
+ {
+ Get-PSGalleryApiAvailability -Repository $Repository
+
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+ }
+
+ Process
+ {
+ $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet `
+ -Name $Name `
+ -MinimumVersion $MinimumVersion `
+ -MaximumVersion $MaximumVersion `
+ -RequiredVersion $RequiredVersion `
+ -AllVersions:$AllVersions
+
+ if(-not $ValidationResult)
+ {
+ # Validate-VersionParameters throws the error.
+ # returning to avoid further execution when different values are specified for -ErrorAction parameter
+ return
+ }
+
+ $PSBoundParameters['Provider'] = $script:PSModuleProviderName
+ $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript
+
+ if($PSBoundParameters.ContainsKey("Repository"))
+ {
+ $PSBoundParameters["Source"] = $Repository
+ $null = $PSBoundParameters.Remove("Repository")
+
+ $ev = $null
+ $repositories = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false
+ if($ev) { return }
+
+ $RepositoriesWithoutScriptSourceLocation = $false
+ foreach($repo in $repositories)
+ {
+ if(-not $repo.ScriptSourceLocation)
+ {
+ $message = $LocalizedData.ScriptSourceLocationIsMissing -f ($repo.Name)
+ Write-Error -Message $message `
+ -ErrorId 'ScriptSourceLocationIsMissing' `
+ -Category InvalidArgument `
+ -TargetObject $repo.Name `
+ -Exception 'System.ArgumentException'
+
+ $RepositoriesWithoutScriptSourceLocation = $true
+ }
+ }
+
+ if($RepositoriesWithoutScriptSourceLocation)
+ {
+ return
+ }
+ }
+
+ $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlockForScriptCmdlets
+
+ $scriptsFoundInPSGallery = @()
+
+ # No Telemetry must be performed if PSGallery is not in the supplied list of Repositories
+ $isRepositoryNullOrPSGallerySpecified = $false
+ if ($Repository -and ($Repository -Contains $Script:PSGalleryModuleSource))
+ {
+ $isRepositoryNullOrPSGallerySpecified = $true
+ }
+ elseif(-not $Repository)
+ {
+ $psgalleryRepo = Get-PSRepository -Name $Script:PSGalleryModuleSource `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+ # And check for IsDeafult?
+ if($psgalleryRepo)
+ {
+ $isRepositoryNullOrPSGallerySpecified = $true
+ }
+ }
+
+ PackageManagement\Find-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object {
+ $psgetItemInfo = New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeScript
+
+ $psgetItemInfo
+
+ if ($psgetItemInfo -and
+ $isRepositoryNullOrPSGallerySpecified -and
+ $script:TelemetryEnabled -and
+ ($psgetItemInfo.Repository -eq $Script:PSGalleryModuleSource))
+ {
+ $scriptsFoundInPSGallery += $psgetItemInfo.Name
+ }
+ }
+
+ # Perform Telemetry if Repository is not supplied or Repository contains PSGallery
+ # We are only interested in finding artifacts not in PSGallery
+ if ($isRepositoryNullOrPSGallerySpecified)
+ {
+ Log-ArtifactNotFoundInPSGallery -SearchedName $Name -FoundName $scriptsFoundInPSGallery -operationName PSGET_FIND_SCRIPT
+ }
+ }
+}
+
+function Save-Script
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(DefaultParameterSetName='NameAndPathParameterSet',
+ HelpUri='http://go.microsoft.com/fwlink/?LinkId=619786',
+ SupportsShouldProcess=$true)]
+ Param
+ (
+ [Parameter(Mandatory=$true,
+ ValueFromPipelineByPropertyName=$true,
+ Position=0,
+ ParameterSetName='NameAndPathParameterSet')]
+ [Parameter(Mandatory=$true,
+ ValueFromPipelineByPropertyName=$true,
+ Position=0,
+ ParameterSetName='NameAndLiteralPathParameterSet')]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Name,
+
+ [Parameter(Mandatory=$true,
+ ValueFromPipeline=$true,
+ ValueFromPipelineByPropertyName=$true,
+ Position=0,
+ ParameterSetName='InputOjectAndPathParameterSet')]
+ [Parameter(Mandatory=$true,
+ ValueFromPipeline=$true,
+ ValueFromPipelineByPropertyName=$true,
+ Position=0,
+ ParameterSetName='InputOjectAndLiteralPathParameterSet')]
+ [ValidateNotNull()]
+ [PSCustomObject[]]
+ $InputObject,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndPathParameterSet')]
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndLiteralPathParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndPathParameterSet')]
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndLiteralPathParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $MaximumVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndPathParameterSet')]
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndLiteralPathParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndPathParameterSet')]
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndLiteralPathParameterSet')]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Repository,
+
+ [Parameter(Mandatory=$true,
+ ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndPathParameterSet')]
+
+ [Parameter(Mandatory=$true,
+ ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='InputOjectAndPathParameterSet')]
+ [string]
+ $Path,
+
+ [Parameter(Mandatory=$true,
+ ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameAndLiteralPathParameterSet')]
+
+ [Parameter(Mandatory=$true,
+ ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='InputOjectAndLiteralPathParameterSet')]
+ [string]
+ $LiteralPath,
+
+ [Parameter()]
+ [switch]
+ $Force
+ )
+
+ Begin
+ {
+ Get-PSGalleryApiAvailability -Repository $Repository
+
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+
+ # Script names already tried in the current pipeline for InputObject parameterset
+ $scriptNamesInPipeline = @()
+ }
+
+ Process
+ {
+ $PSBoundParameters["Provider"] = $script:PSModuleProviderName
+ $PSBoundParameters["MessageResolver"] = $script:PackageManagementSaveScriptMessageResolverScriptBlock
+ $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript
+
+ # When -Force is specified, Path will be created if not available.
+ if(-not $Force)
+ {
+ if($Path)
+ {
+ $destinationPath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet |
+ Microsoft.PowerShell.Utility\Select-Object -First 1
+
+ if(-not $destinationPath -or -not (Microsoft.PowerShell.Management\Test-path $destinationPath))
+ {
+ $errorMessage = ($LocalizedData.PathNotFound -f $Path)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $Path `
+ -ErrorCategory InvalidArgument
+ }
+
+ $PSBoundParameters['Path'] = $destinationPath
+ }
+ else
+ {
+ $destinationPath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet |
+ Microsoft.PowerShell.Utility\Select-Object -First 1
+
+ if(-not $destinationPath -or -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $destinationPath))
+ {
+ $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $LiteralPath `
+ -ErrorCategory InvalidArgument
+ }
+
+ $PSBoundParameters['LiteralPath'] = $destinationPath
+ }
+ }
+
+ if($Name)
+ {
+ $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet `
+ -Name $Name `
+ -TestWildcardsInName `
+ -MinimumVersion $MinimumVersion `
+ -MaximumVersion $MaximumVersion `
+ -RequiredVersion $RequiredVersion
+
+ if(-not $ValidationResult)
+ {
+ # Validate-VersionParameters throws the error.
+ # returning to avoid further execution when different values are specified for -ErrorAction parameter
+ return
+ }
+
+ if($PSBoundParameters.ContainsKey("Repository"))
+ {
+ $PSBoundParameters["Source"] = $Repository
+ $null = $PSBoundParameters.Remove("Repository")
+
+ $ev = $null
+ $repositories = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false
+ if($ev) { return }
+
+ $RepositoriesWithoutScriptSourceLocation = $false
+ foreach($repo in $repositories)
+ {
+ if(-not $repo.ScriptSourceLocation)
+ {
+ $message = $LocalizedData.ScriptSourceLocationIsMissing -f ($repo.Name)
+ Write-Error -Message $message `
+ -ErrorId 'ScriptSourceLocationIsMissing' `
+ -Category InvalidArgument `
+ -TargetObject $repo.Name `
+ -Exception 'System.ArgumentException'
+
+ $RepositoriesWithoutScriptSourceLocation = $true
+ }
+ }
+
+ if($RepositoriesWithoutScriptSourceLocation)
+ {
+ return
+ }
+ }
+
+ $null = PackageManagement\Save-Package @PSBoundParameters
+ }
+ elseif($InputObject)
+ {
+ $null = $PSBoundParameters.Remove("InputObject")
+
+ foreach($inputValue in $InputObject)
+ {
+ if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo"))
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $LocalizedData.InvalidInputObjectValue `
+ -ErrorId "InvalidInputObjectValue" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $inputValue
+ }
+
+ $psRepositoryItemInfo = $inputValue
+
+ # Skip the script name if it is already tried in the current pipeline
+ if($scriptNamesInPipeline -contains $psRepositoryItemInfo.Name)
+ {
+ continue
+ }
+
+ $scriptNamesInPipeline += $psRepositoryItemInfo.Name
+
+ if ($psRepositoryItemInfo.PowerShellGetFormatVersion -and
+ ($script:SupportedPSGetFormatVersionMajors -notcontains $psRepositoryItemInfo.PowerShellGetFormatVersion.Major))
+ {
+ $message = $LocalizedData.NotSupportedPowerShellGetFormatVersionScripts -f ($psRepositoryItemInfo.Name, $psRepositoryItemInfo.PowerShellGetFormatVersion, $psRepositoryItemInfo.Name)
+ Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation
+ continue
+ }
+
+ $PSBoundParameters["Name"] = $psRepositoryItemInfo.Name
+ $PSBoundParameters["RequiredVersion"] = $psRepositoryItemInfo.Version
+ $PSBoundParameters['Source'] = $psRepositoryItemInfo.Repository
+ $PSBoundParameters["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $psRepositoryItemInfo)
+
+ $null = PackageManagement\Save-Package @PSBoundParameters
+ }
+ }
+ }
+}
+
+function Install-Script
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(DefaultParameterSetName='NameParameterSet',
+ HelpUri='http://go.microsoft.com/fwlink/?LinkId=619784',
+ SupportsShouldProcess=$true)]
+ Param
+ (
+ [Parameter(Mandatory=$true,
+ ValueFromPipelineByPropertyName=$true,
+ Position=0,
+ ParameterSetName='NameParameterSet')]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Name,
+
+ [Parameter(Mandatory=$true,
+ ValueFromPipeline=$true,
+ ValueFromPipelineByPropertyName=$true,
+ Position=0,
+ ParameterSetName='InputObject')]
+ [ValidateNotNull()]
+ [PSCustomObject[]]
+ $InputObject,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $MaximumVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter(ParameterSetName='NameParameterSet')]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Repository,
+
+ [Parameter()]
+ [ValidateSet("CurrentUser","AllUsers")]
+ [string]
+ $Scope = 'AllUsers',
+
+ [Parameter()]
+ [Switch]
+ $NoPathUpdate,
+
+ [Parameter()]
+ [switch]
+ $Force
+ )
+
+ Begin
+ {
+ Get-PSGalleryApiAvailability -Repository $Repository
+
+ if(-not (Test-RunningAsElevated) -and ($Scope -ne "CurrentUser"))
+ {
+ # Throw an error when Install-Script is used as a non-admin user and '-Scope CurrentUser' is not specified
+ $AdminPreviligeErrorMessage = $LocalizedData.InstallScriptNeedsCurrentUserScopeParameterForNonAdminUser -f @($script:ProgramFilesScriptsPath, $script:MyDocumentsScriptsPath)
+ $AdminPreviligeErrorId = 'InstallScriptNeedsCurrentUserScopeParameterForNonAdminUser'
+
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $AdminPreviligeErrorMessage `
+ -ErrorId $AdminPreviligeErrorId `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+
+ # Check and add the scope path to PATH environment variable
+ if($Scope -eq 'AllUsers')
+ {
+ $scopePath = $script:ProgramFilesScriptsPath
+ }
+ else
+ {
+ $scopePath = $script:MyDocumentsScriptsPath
+ }
+
+ ValidateAndSet-PATHVariableIfUserAccepts -Scope $Scope `
+ -ScopePath $scopePath `
+ -NoPathUpdate:$NoPathUpdate `
+ -Force:$Force
+
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+
+ # Script names already tried in the current pipeline for InputObject parameterset
+ $scriptNamesInPipeline = @()
+
+ $YesToAll = $false
+ $NoToAll = $false
+ $SourceSGrantedTrust = @()
+ $SourcesDeniedTrust = @()
+ }
+
+ Process
+ {
+ $RepositoryIsNotTrusted = $LocalizedData.RepositoryIsNotTrusted
+ $QueryInstallUntrustedPackage = $LocalizedData.QueryInstallUntrustedScriptPackage
+ $PackageTarget = $LocalizedData.InstallScriptwhatIfMessage
+
+ $PSBoundParameters["Provider"] = $script:PSModuleProviderName
+ $PSBoundParameters["MessageResolver"] = $script:PackageManagementInstallScriptMessageResolverScriptBlock
+ $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript
+ $PSBoundParameters['Scope'] = $Scope
+
+ if($PSCmdlet.ParameterSetName -eq "NameParameterSet")
+ {
+ $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet `
+ -Name $Name `
+ -TestWildcardsInName `
+ -MinimumVersion $MinimumVersion `
+ -MaximumVersion $MaximumVersion `
+ -RequiredVersion $RequiredVersion
+
+ if(-not $ValidationResult)
+ {
+ # Validate-VersionParameters throws the error.
+ # returning to avoid further execution when different values are specified for -ErrorAction parameter
+ return
+ }
+
+ if($PSBoundParameters.ContainsKey("Repository"))
+ {
+ $PSBoundParameters["Source"] = $Repository
+ $null = $PSBoundParameters.Remove("Repository")
+
+ $ev = $null
+ $repositories = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false
+ if($ev) { return }
+
+ $RepositoriesWithoutScriptSourceLocation = $false
+ foreach($repo in $repositories)
+ {
+ if(-not $repo.ScriptSourceLocation)
+ {
+ $message = $LocalizedData.ScriptSourceLocationIsMissing -f ($repo.Name)
+ Write-Error -Message $message `
+ -ErrorId 'ScriptSourceLocationIsMissing' `
+ -Category InvalidArgument `
+ -TargetObject $repo.Name `
+ -Exception 'System.ArgumentException'
+
+ $RepositoriesWithoutScriptSourceLocation = $true
+ }
+ }
+
+ if($RepositoriesWithoutScriptSourceLocation)
+ {
+ return
+ }
+ }
+
+ if(-not $Force)
+ {
+ foreach($scriptName in $Name)
+ {
+ # Throw an error if there is a command with the same name and -force is not specified.
+ $cmd = Microsoft.PowerShell.Core\Get-Command -Name $scriptName `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+ if($cmd)
+ {
+ # Check if this script was already installed, may be with -Force
+ $InstalledScriptInfo = Test-ScriptInstalled -Name $scriptName `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+ if(-not $InstalledScriptInfo)
+ {
+ $message = $LocalizedData.CommandAlreadyAvailable -f ($scriptName)
+ Write-Error -Message $message -ErrorId CommandAlreadyAvailableWitScriptName -Category InvalidOperation
+
+ # return if only single name is specified
+ if($scriptName -eq $Name)
+ {
+ return
+ }
+ }
+ }
+ }
+ }
+
+ $null = PackageManagement\Install-Package @PSBoundParameters
+ }
+ elseif($PSCmdlet.ParameterSetName -eq "InputObject")
+ {
+ $null = $PSBoundParameters.Remove("InputObject")
+
+ foreach($inputValue in $InputObject)
+ {
+
+ if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo"))
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $LocalizedData.InvalidInputObjectValue `
+ -ErrorId "InvalidInputObjectValue" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $inputValue
+ }
+
+ $psRepositoryItemInfo = $inputValue
+
+ # Skip the script name if it is already tried in the current pipeline
+ if($scriptNamesInPipeline -contains $psRepositoryItemInfo.Name)
+ {
+ continue
+ }
+
+ $scriptNamesInPipeline += $psRepositoryItemInfo.Name
+
+ if ($psRepositoryItemInfo.PowerShellGetFormatVersion -and
+ ($script:SupportedPSGetFormatVersionMajors -notcontains $psRepositoryItemInfo.PowerShellGetFormatVersion.Major))
+ {
+ $message = $LocalizedData.NotSupportedPowerShellGetFormatVersionScripts -f ($psRepositoryItemInfo.Name, $psRepositoryItemInfo.PowerShellGetFormatVersion, $psRepositoryItemInfo.Name)
+ Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation
+ continue
+ }
+
+ $PSBoundParameters["Name"] = $psRepositoryItemInfo.Name
+ $PSBoundParameters["RequiredVersion"] = $psRepositoryItemInfo.Version
+ $PSBoundParameters['Source'] = $psRepositoryItemInfo.Repository
+ $PSBoundParameters["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $psRepositoryItemInfo)
+
+ $InstalledScriptInfo = Test-ScriptInstalled -Name $psRepositoryItemInfo.Name
+ if(-not $Force -and $InstalledScriptInfo)
+ {
+ $message = $LocalizedData.ScriptAlreadyInstalledVerbose -f ($InstalledScriptInfo.Version, $InstalledScriptInfo.Name, $InstalledScriptInfo.ScriptBase)
+ Write-Verbose -Message $message
+ }
+ else
+ {
+ # Throw an error if there is a command with the same name and -force is not specified.
+ if(-not $Force)
+ {
+ $cmd = Microsoft.PowerShell.Core\Get-Command -Name $psRepositoryItemInfo.Name `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+ if($cmd)
+ {
+ $message = $LocalizedData.CommandAlreadyAvailable -f ($psRepositoryItemInfo.Name)
+ Write-Error -Message $message -ErrorId CommandAlreadyAvailableWitScriptName -Category InvalidOperation
+
+ continue
+ }
+ }
+
+ $source = $psRepositoryItemInfo.Repository
+ $installationPolicy = (Get-PSRepository -Name $source).InstallationPolicy
+ $ShouldProcessMessage = $PackageTarget -f ($psRepositoryItemInfo.Name, $psRepositoryItemInfo.Version)
+
+ if($psCmdlet.ShouldProcess($ShouldProcessMessage))
+ {
+ if($installationPolicy.Equals("Untrusted", [StringComparison]::OrdinalIgnoreCase))
+ {
+ if(-not($YesToAll -or $NoToAll -or $SourceSGrantedTrust.Contains($source) -or $sourcesDeniedTrust.Contains($source) -or $Force))
+ {
+ $message = $QueryInstallUntrustedPackage -f ($psRepositoryItemInfo.Name, $psRepositoryItemInfo.RepositorySourceLocation)
+
+ if($PSVersionTable.PSVersion -ge [Version]"5.0")
+ {
+ $sourceTrusted = $psCmdlet.ShouldContinue("$message", "$RepositoryIsNotTrusted",$true, [ref]$YesToAll, [ref]$NoToAll)
+ }
+ else
+ {
+ $sourceTrusted = $psCmdlet.ShouldContinue("$message", "$RepositoryIsNotTrusted", [ref]$YesToAll, [ref]$NoToAll)
+ }
+
+ if($sourceTrusted)
+ {
+ $SourcesGrantedTrust+=$source
+ }
+ else
+ {
+ $SourcesDeniedTrust+=$source
+ }
+ }
+ }
+ }
+ if($installationPolicy.Equals("trusted", [StringComparison]::OrdinalIgnoreCase) -or $SourcesGrantedTrust.Contains($source) -or $YesToAll -or $Force)
+ {
+ $PSBoundParameters["Force"] = $true
+ $null = PackageManagement\Install-Package @PSBoundParameters
+ }
+ }
+ }
+ }
+ }
+}
+
+function Update-Script
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(SupportsShouldProcess=$true,
+ HelpUri='http://go.microsoft.com/fwlink/?LinkId=619787')]
+ Param
+ (
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ Position=0)]
+ [ValidateNotNullOrEmpty()]
+ [String[]]
+ $Name,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNull()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNull()]
+ [Version]
+ $MaximumVersion,
+
+ [Parameter()]
+ [Switch]
+ $Force
+ )
+
+ Begin
+ {
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+
+ # Script names already tried in the current pipeline
+ $scriptNamesInPipeline = @()
+ }
+
+ Process
+ {
+ $scriptFilePathsToUpdate = @()
+
+ $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet `
+ -Name $Name `
+ -MaximumVersion $MaximumVersion `
+ -RequiredVersion $RequiredVersion
+
+ if(-not $ValidationResult)
+ {
+ # Validate-VersionParameters throws the error.
+ # returning to avoid further execution when different values are specified for -ErrorAction parameter
+ return
+ }
+
+ if($Name)
+ {
+ foreach($scriptName in $Name)
+ {
+ $availableScriptPaths = Get-AvailableScriptFilePath -Name $scriptName -Verbose:$false
+
+ if(-not $availableScriptPaths -and -not (Test-WildcardPattern -Name $scriptName))
+ {
+ $message = $LocalizedData.ScriptNotInstalledOnThisMachine -f ($scriptName, $script:MyDocumentsScriptsPath, $script:ProgramFilesScriptsPath)
+ Write-Error -Message $message -ErrorId "ScriptNotInstalledOnThisMachine" -Category InvalidOperation -TargetObject $scriptName
+ continue
+ }
+
+ foreach($scriptFilePath in $availableScriptPaths)
+ {
+ $installedScriptFilePath = Get-InstalledScriptFilePath -Name ([System.IO.Path]::GetFileNameWithoutExtension($scriptFilePath)) |
+ Microsoft.PowerShell.Core\Where-Object {$_ -eq $scriptFilePath }
+
+ # Check if this script got installed with PowerShellGet and user has required permissions
+ if ($installedScriptFilePath)
+ {
+ if(-not (Test-RunningAsElevated) -and $installedScriptFilePath.StartsWith($script:ProgramFilesScriptsPath, [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ if(-not (Test-WildcardPattern -Name $scriptName))
+ {
+ $message = $LocalizedData.AdminPrivilegesRequiredForScriptUpdate -f ($scriptName, $installedScriptFilePath)
+ Write-Error -Message $message -ErrorId "AdminPrivilegesAreRequiredForUpdate" -Category InvalidOperation -TargetObject $scriptName
+ }
+ continue
+ }
+
+ $scriptFilePathsToUpdate += $installedScriptFilePath
+ }
+ else
+ {
+ if(-not (Test-WildcardPattern -Name $scriptName))
+ {
+ $message = $LocalizedData.ScriptNotInstalledUsingPowerShellGet -f ($scriptName)
+ Write-Error -Message $message -ErrorId "ScriptNotInstalledUsingPowerShellGet" -Category InvalidOperation -TargetObject $scriptName
+ }
+ continue
+ }
+ }
+ }
+ }
+ else
+ {
+ $isRunningAsElevated = Test-RunningAsElevated
+ $installedScriptFilePaths = Get-InstalledScriptFilePath
+
+ if($isRunningAsElevated)
+ {
+ $scriptFilePathsToUpdate = $installedScriptFilePaths
+ }
+ else
+ {
+ # Update the scripts installed under
+ $scriptFilePathsToUpdate = $installedScriptFilePaths | Microsoft.PowerShell.Core\Where-Object {
+ $_.StartsWith($script:MyDocumentsScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)}
+ }
+ }
+
+ $PSBoundParameters["Provider"] = $script:PSModuleProviderName
+ $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript
+ $PSBoundParameters["MessageResolver"] = $script:PackageManagementUpdateScriptMessageResolverScriptBlock
+ $PSBoundParameters["InstallUpdate"] = $true
+
+ foreach($scriptFilePath in $scriptFilePathsToUpdate)
+ {
+ $scriptName = [System.IO.Path]::GetFileNameWithoutExtension($scriptFilePath)
+
+ $installedScriptInfoFilePath = $null
+ $installedScriptInfoFileName = "$($scriptName)_$script:InstalledScriptInfoFileName"
+
+ if($scriptFilePath.ToString().StartsWith($script:MyDocumentsScriptsPath, [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $PSBoundParameters["Scope"] = "CurrentUser"
+ $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsInstalledScriptInfosPath `
+ -ChildPath $installedScriptInfoFileName
+ }
+ elseif($scriptFilePath.ToString().StartsWith($script:ProgramFilesScriptsPath, [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $PSBoundParameters["Scope"] = "AllUsers"
+ $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesInstalledScriptInfosPath `
+ -ChildPath $installedScriptInfoFileName
+
+ }
+
+ $psgetItemInfo = $null
+ if($installedScriptInfoFilePath -and (Microsoft.PowerShell.Management\Test-Path -Path $installedScriptInfoFilePath -PathType Leaf))
+ {
+ $psgetItemInfo = DeSerialize-PSObject -Path $installedScriptInfoFilePath
+ }
+
+ # Skip the script name if it is already tried in the current pipeline
+ if(-not $psgetItemInfo -or ($scriptNamesInPipeline -contains $psgetItemInfo.Name))
+ {
+ continue
+ }
+
+
+ $scriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $psgetItemInfo.InstalledLocation `
+ -ChildPath "$($psgetItemInfo.Name).ps1"
+
+ # Remove the InstalledScriptInfo.xml file if the actual script file was manually uninstalled by the user
+ if(-not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf))
+ {
+ Microsoft.PowerShell.Management\Remove-Item -Path $installedScriptInfoFilePath -Force -ErrorAction SilentlyContinue
+
+ continue
+ }
+
+ $scriptNamesInPipeline += $psgetItemInfo.Name
+
+ $message = $LocalizedData.CheckingForScriptUpdate -f ($psgetItemInfo.Name)
+ Write-Verbose -Message $message
+
+ $providerName = Get-ProviderName -PSCustomObject $psgetItemInfo
+ if(-not $providerName)
+ {
+ $providerName = $script:NuGetProviderName
+ }
+
+ $PSBoundParameters["PackageManagementProvider"] = $providerName
+ $PSBoundParameters["Name"] = $psgetItemInfo.Name
+ $PSBoundParameters['Source'] = $psgetItemInfo.Repository
+
+ Get-PSGalleryApiAvailability -Repository (Get-SourceName -Location $psgetItemInfo.RepositorySourceLocation)
+
+ $sid = PackageManagement\Install-Package @PSBoundParameters
+ }
+ }
+}
+
+function Uninstall-Script
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(DefaultParameterSetName='NameParameterSet',
+ SupportsShouldProcess=$true,
+ HelpUri='http://go.microsoft.com/fwlink/?LinkId=619789')]
+ Param
+ (
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ Mandatory=$true,
+ Position=0,
+ ParameterSetName='NameParameterSet')]
+ [ValidateNotNullOrEmpty()]
+ [String[]]
+ $Name,
+
+ [Parameter(Mandatory=$true,
+ ValueFromPipeline=$true,
+ ValueFromPipelineByPropertyName=$true,
+ Position=0,
+ ParameterSetName='InputObject')]
+ [ValidateNotNull()]
+ [PSCustomObject[]]
+ $InputObject,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='NameParameterSet')]
+ [ValidateNotNull()]
+ [Version]
+ $MaximumVersion,
+
+ [Parameter()]
+ [Switch]
+ $Force
+ )
+
+ Process
+ {
+ $PSBoundParameters["Provider"] = $script:PSModuleProviderName
+ $PSBoundParameters["MessageResolver"] = $script:PackageManagementUnInstallScriptMessageResolverScriptBlock
+ $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript
+
+ if($PSCmdlet.ParameterSetName -eq "InputObject")
+ {
+ $null = $PSBoundParameters.Remove("InputObject")
+
+ foreach($inputValue in $InputObject)
+ {
+ if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and
+ ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo"))
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $LocalizedData.InvalidInputObjectValue `
+ -ErrorId "InvalidInputObjectValue" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $inputValue
+ }
+
+ $PSBoundParameters["Name"] = $inputValue.Name
+ $PSBoundParameters["RequiredVersion"] = $inputValue.Version
+
+ $null = PackageManagement\Uninstall-Package @PSBoundParameters
+ }
+ }
+ else
+ {
+ $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet `
+ -Name $Name `
+ -TestWildcardsInName `
+ -MinimumVersion $MinimumVersion `
+ -MaximumVersion $MaximumVersion `
+ -RequiredVersion $RequiredVersion
+
+ if(-not $ValidationResult)
+ {
+ # Validate-VersionParameters throws the error.
+ # returning to avoid further execution when different values are specified for -ErrorAction parameter
+ return
+ }
+
+ $null = PackageManagement\Uninstall-Package @PSBoundParameters
+ }
+ }
+}
+
+function Get-InstalledScript
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkId=619790')]
+ Param
+ (
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ Position=0)]
+ [ValidateNotNullOrEmpty()]
+ [String[]]
+ $Name,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNull()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNull()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNull()]
+ [Version]
+ $MaximumVersion
+ )
+
+ Process
+ {
+ $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet `
+ -Name $Name `
+ -MinimumVersion $MinimumVersion `
+ -MaximumVersion $MaximumVersion `
+ -RequiredVersion $RequiredVersion
+
+ if(-not $ValidationResult)
+ {
+ # Validate-VersionParameters throws the error.
+ # returning to avoid further execution when different values are specified for -ErrorAction parameter
+ return
+ }
+
+ $PSBoundParameters["Provider"] = $script:PSModuleProviderName
+ $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlockForScriptCmdlets
+ $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript
+
+ PackageManagement\Get-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeScript}
+ }
+}
+
+#endregion *-Script cmdlets
+
+#region *-PSRepository cmdlets
+
+function Register-PSRepository
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(PositionalBinding=$false,
+ HelpUri='http://go.microsoft.com/fwlink/?LinkID=517129')]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Name,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $SourceLocation,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $PublishLocation,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $ScriptSourceLocation,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $ScriptPublishLocation,
+
+ [Parameter()]
+ [ValidateSet('Trusted','Untrusted')]
+ [string]
+ $InstallationPolicy = 'Untrusted',
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $PackageManagementProvider
+ )
+
+ DynamicParam
+ {
+ if (Get-Variable -Name SourceLocation -ErrorAction SilentlyContinue)
+ {
+ Set-Variable -Name selctedProviderName -value $null -Scope 1
+
+ if(Get-Variable -Name PackageManagementProvider -ErrorAction SilentlyContinue)
+ {
+ $selctedProviderName = $PackageManagementProvider
+ $null = Get-DynamicParameters -Location $SourceLocation -PackageManagementProvider ([REF]$selctedProviderName)
+ }
+ else
+ {
+ $dynamicParameters = Get-DynamicParameters -Location $SourceLocation -PackageManagementProvider ([REF]$selctedProviderName)
+ Set-Variable -Name PackageManagementProvider -Value $selctedProviderName -Scope 1
+ $null = $dynamicParameters
+ }
+ }
+ }
+
+ Begin
+ {
+ Get-PSGalleryApiAvailability -Repository $Name
+
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+
+ if($PackageManagementProvider)
+ {
+ $providers = PackageManagement\Get-PackageProvider | Where-Object { $_.Name -ne $script:PSModuleProviderName -and $_.Features.ContainsKey($script:SupportsPSModulesFeatureName) }
+
+ if (-not $providers -or $providers.Name -notcontains $PackageManagementProvider)
+ {
+ $possibleProviderNames = $script:NuGetProviderName
+
+ if($providers)
+ {
+ $possibleProviderNames = ($providers.Name -join ',')
+ }
+
+ $message = $LocalizedData.InvalidPackageManagementProviderValue -f ($PackageManagementProvider, $possibleProviderNames, $script:NuGetProviderName)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidPackageManagementProviderValue" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $PackageManagementProvider
+ return
+ }
+ }
+ }
+
+ Process
+ {
+ # Ping and resolve the specified location
+ $SourceLocation = Resolve-Location -Location (Get-LocationString -LocationUri $SourceLocation) `
+ -LocationParameterName 'SourceLocation' `
+ -CallerPSCmdlet $PSCmdlet
+ if(-not $SourceLocation)
+ {
+ # Above Resolve-Location function throws an error when it is not able to resolve a location
+ return
+ }
+
+ if($InstallationPolicy -eq "Trusted")
+ {
+ $PSBoundParameters.Add("Trusted", $true)
+ }
+
+ $providerName = $null
+
+ if($PackageManagementProvider)
+ {
+ $providerName = $PackageManagementProvider
+ }
+ elseif($selctedProviderName)
+ {
+ $providerName = $selctedProviderName
+ }
+ else
+ {
+ $providerName = Get-PackageManagementProviderName -Location $SourceLocation
+ }
+
+ if($providerName)
+ {
+ $PSBoundParameters[$script:PackageManagementProviderParam] = $providerName
+ }
+
+ if($PublishLocation)
+ {
+ $PSBoundParameters[$script:PublishLocation] = Get-LocationString -LocationUri $PublishLocation
+ }
+
+ if($ScriptPublishLocation)
+ {
+ $PSBoundParameters[$script:ScriptPublishLocation] = Get-LocationString -LocationUri $ScriptPublishLocation
+ }
+
+ if($ScriptSourceLocation)
+ {
+ $PSBoundParameters[$script:ScriptSourceLocation] = Get-LocationString -LocationUri $ScriptSourceLocation
+ }
+
+ $PSBoundParameters["Provider"] = $script:PSModuleProviderName
+
+ $PSBoundParameters["Location"] = Get-LocationString -LocationUri $SourceLocation
+ $null = $PSBoundParameters.Remove("SourceLocation")
+ $null = $PSBoundParameters.Remove("InstallationPolicy")
+
+ $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock
+
+ $null = PackageManagement\Register-PackageSource @PSBoundParameters
+ }
+}
+
+function Set-PSRepository
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(PositionalBinding=$false,
+ HelpUri='http://go.microsoft.com/fwlink/?LinkID=517128')]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Name,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $SourceLocation,
+
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $PublishLocation,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $ScriptSourceLocation,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $ScriptPublishLocation,
+
+ [Parameter()]
+ [ValidateSet('Trusted','Untrusted')]
+ [string]
+ $InstallationPolicy,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $PackageManagementProvider
+ )
+
+ DynamicParam
+ {
+ if (Get-Variable -Name Name -ErrorAction SilentlyContinue)
+ {
+ $moduleSource = Get-PSRepository -Name $Name -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
+
+ if($moduleSource)
+ {
+ $providerName = (Get-ProviderName -PSCustomObject $moduleSource)
+
+ $loc = $moduleSource.SourceLocation
+
+ if(Get-Variable -Name SourceLocation -ErrorAction SilentlyContinue)
+ {
+ $loc = $SourceLocation
+ }
+
+ if(Get-Variable -Name PackageManagementProvider -ErrorAction SilentlyContinue)
+ {
+ $providerName = $PackageManagementProvider
+ }
+
+ $null = Get-DynamicParameters -Location $loc -PackageManagementProvider ([REF]$providerName)
+ }
+ }
+ }
+
+ Begin
+ {
+ Get-PSGalleryApiAvailability -Repository $Name
+
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+
+ if($PackageManagementProvider)
+ {
+ $providers = PackageManagement\Get-PackageProvider | Where-Object { $_.Name -ne $script:PSModuleProviderName -and $_.Features.ContainsKey($script:SupportsPSModulesFeatureName) }
+
+ if (-not $providers -or $providers.Name -notcontains $PackageManagementProvider)
+ {
+ $possibleProviderNames = $script:NuGetProviderName
+
+ if($providers)
+ {
+ $possibleProviderNames = ($providers.Name -join ',')
+ }
+
+ $message = $LocalizedData.InvalidPackageManagementProviderValue -f ($PackageManagementProvider, $possibleProviderNames, $script:NuGetProviderName)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidPackageManagementProviderValue" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $PackageManagementProvider
+ return
+ }
+ }
+ }
+
+ Process
+ {
+ # Ping and resolve the specified location
+ if($SourceLocation)
+ {
+ # Ping and resolve the specified location
+ $SourceLocation = Resolve-Location -Location (Get-LocationString -LocationUri $SourceLocation) `
+ -LocationParameterName 'SourceLocation' `
+ -CallerPSCmdlet $PSCmdlet
+ if(-not $SourceLocation)
+ {
+ # Above Resolve-Location function throws an error when it is not able to resolve a location
+ return
+ }
+ }
+
+ $ModuleSource = Get-PSRepository -Name $Name -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
+
+ if(-not $ModuleSource)
+ {
+ $message = $LocalizedData.RepositoryNotFound -f ($Name)
+
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "RepositoryNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation `
+ -ExceptionObject $Name
+ }
+
+ if (-not $PackageManagementProvider)
+ {
+ $PackageManagementProvider = (Get-ProviderName -PSCustomObject $ModuleSource)
+ }
+
+ $Trusted = $ModuleSource.Trusted
+ if($InstallationPolicy)
+ {
+ if($InstallationPolicy -eq "Trusted")
+ {
+ $Trusted = $true
+ }
+ else
+ {
+ $Trusted = $false
+ }
+
+ $null = $PSBoundParameters.Remove("InstallationPolicy")
+ }
+
+ if($PublishLocation)
+ {
+ $PSBoundParameters[$script:PublishLocation] = Get-LocationString -LocationUri $PublishLocation
+ }
+
+ if($ScriptPublishLocation)
+ {
+ $PSBoundParameters[$script:ScriptPublishLocation] = Get-LocationString -LocationUri $ScriptPublishLocation
+ }
+
+ if($ScriptSourceLocation)
+ {
+ $PSBoundParameters[$script:ScriptSourceLocation] = Get-LocationString -LocationUri $ScriptSourceLocation
+ }
+
+ if($SourceLocation)
+ {
+ $PSBoundParameters["NewLocation"] = Get-LocationString -LocationUri $SourceLocation
+
+ $null = $PSBoundParameters.Remove("SourceLocation")
+ }
+
+ $PSBoundParameters[$script:PackageManagementProviderParam] = $PackageManagementProvider
+ $PSBoundParameters.Add("Trusted", $Trusted)
+ $PSBoundParameters["Provider"] = $script:PSModuleProviderName
+ $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock
+
+ $null = PackageManagement\Set-PackageSource @PSBoundParameters
+ }
+}
+
+function Unregister-PSRepository
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=517130')]
+ Param
+ (
+ [Parameter(ValueFromPipelineByPropertyName=$true,
+ Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Name
+ )
+
+ Begin
+ {
+ Get-PSGalleryApiAvailability -Repository $Name
+ }
+
+ Process
+ {
+ $PSBoundParameters["Provider"] = $script:PSModuleProviderName
+ $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock
+
+ $null = $PSBoundParameters.Remove("Name")
+
+ foreach ($moduleSourceName in $Name)
+ {
+ # Check if $moduleSourceName contains any wildcards
+ if(Test-WildcardPattern $moduleSourceName)
+ {
+ $message = $LocalizedData.RepositoryNameContainsWildCards -f ($moduleSourceName)
+ Write-Error -Message $message -ErrorId "RepositoryNameContainsWildCards" -Category InvalidOperation
+ continue
+ }
+
+ $PSBoundParameters["Source"] = $moduleSourceName
+
+ $null = PackageManagement\Unregister-PackageSource @PSBoundParameters
+ }
+ }
+}
+
+function Get-PSRepository
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=517127')]
+ Param
+ (
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Name
+ )
+
+ Begin
+ {
+ Get-PSGalleryApiAvailability -Repository $Name
+ }
+
+ Process
+ {
+ $PSBoundParameters["Provider"] = $script:PSModuleProviderName
+ $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock
+
+ if($Name)
+ {
+ foreach($sourceName in $Name)
+ {
+ $PSBoundParameters["Name"] = $sourceName
+
+ $packageSources = PackageManagement\Get-PackageSource @PSBoundParameters
+
+ $packageSources | Microsoft.PowerShell.Core\ForEach-Object { New-ModuleSourceFromPackageSource -PackageSource $_ }
+ }
+ }
+ else
+ {
+ $packageSources = PackageManagement\Get-PackageSource @PSBoundParameters
+
+ $packageSources | Microsoft.PowerShell.Core\ForEach-Object { New-ModuleSourceFromPackageSource -PackageSource $_ }
+ }
+ }
+}
+
+#endregion *-PSRepository cmdlets
+
+#region *-ScriptFileInfo cmdlets
+
+# Below is the sample PSScriptInfo in a script file.
+<#PSScriptInfo
+
+.VERSION 1.0
+
+.GUID 544238e3-1751-4065-9227-be105ff11636
+
+.AUTHOR manikb
+
+.COMPANYNAME Microsoft Corporation
+
+.COPYRIGHT (c) 2015 Microsoft Corporation. All rights reserved.
+
+.TAGS Tag1 Tag2 Tag3
+
+.LICENSEURI https://contoso.com/License
+
+.PROJECTURI https://contoso.com/
+
+.ICONURI https://contoso.com/Icon
+
+.EXTERNALMODULEDEPENDENCIES ExternalModule1
+
+.REQUIREDSCRIPTS Start-WFContosoServer,Stop-ContosoServerScript
+
+.EXTERNALSCRIPTDEPENDENCIES Stop-ContosoServerScript
+
+.RELEASENOTES
+contoso script now supports following features
+Feature 1
+Feature 2
+Feature 3
+Feature 4
+Feature 5
+
+#>
+
+<# #Requires -Module statements #>
+
+<#
+
+.DESCRIPTION
+ Description goes here.
+
+#>
+
+
+#
+function Test-ScriptFileInfo
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(PositionalBinding=$false,
+ DefaultParameterSetName='PathParameterSet',
+ HelpUri='http://go.microsoft.com/fwlink/?LinkId=619791')]
+ Param
+ (
+ [Parameter(Mandatory=$true,
+ Position=0,
+ ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='PathParameterSet')]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Path,
+
+ [Parameter(Mandatory=$true,
+ ValueFromPipelineByPropertyName=$true,
+ ParameterSetName='LiteralPathParameterSet')]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $LiteralPath
+ )
+
+ Process
+ {
+ $scriptFilePath = $null
+ if($Path)
+ {
+ $scriptFilePath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1
+
+ if(-not $scriptFilePath -or -not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf))
+ {
+ $errorMessage = ($LocalizedData.PathNotFound -f $Path)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $Path `
+ -ErrorCategory InvalidArgument
+ return
+ }
+ }
+ else
+ {
+ $scriptFilePath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1
+
+ if(-not $scriptFilePath -or -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $scriptFilePath -PathType Leaf))
+ {
+ $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $LiteralPath `
+ -ErrorCategory InvalidArgument
+ return
+ }
+ }
+
+ if(-not $scriptFilePath.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $errorMessage = ($LocalizedData.InvalidScriptFilePath -f $scriptFilePath)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "InvalidScriptFilePath" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $scriptFilePath `
+ -ErrorCategory InvalidArgument
+ return
+ }
+
+ $PSScriptInfo = New-PSScriptInfoObject -Path $scriptFilePath
+
+ [System.Management.Automation.Language.Token[]]$tokens = $null;
+ [System.Management.Automation.Language.ParseError[]]$errors = $null;
+ $ast = [System.Management.Automation.Language.Parser]::ParseFile($scriptFilePath, ([ref]$tokens), ([ref]$errors))
+
+
+ $notSupportedOnNanoErrorIds = @('WorkflowNotSupportedInPowerShellCore',
+ 'ConfigurationNotSupportedInPowerShellCore')
+ $errosAfterSkippingOneCoreErrors = $errors | Microsoft.PowerShell.Core\Where-Object { $notSupportedOnNanoErrorIds -notcontains $_.ErrorId}
+
+ if($errosAfterSkippingOneCoreErrors)
+ {
+ $errorMessage = ($LocalizedData.ScriptParseError -f $scriptFilePath)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "ScriptParseError" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $errosAfterSkippingOneCoreErrors `
+ -ErrorCategory InvalidArgument
+ return
+ }
+
+ if($ast)
+ {
+ # Get the block/group comment begining with <#PSScriptInfo
+ $CommentTokens = $tokens | Microsoft.PowerShell.Core\Where-Object {$_.Kind -eq 'Comment'}
+
+ $psscriptInfoComments = $CommentTokens |
+ Microsoft.PowerShell.Core\Where-Object { $_.Extent.Text -match "<#PSScriptInfo" } |
+ Microsoft.PowerShell.Utility\Select-Object -First 1
+
+ if(-not $psscriptInfoComments)
+ {
+ $errorMessage = ($LocalizedData.MissingPSScriptInfo -f $scriptFilePath)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "MissingPSScriptInfo" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $scriptFilePath `
+ -ErrorCategory InvalidArgument
+ return
+ }
+
+ # $psscriptInfoComments.Text will have the multiline PSScriptInfo comment,
+ # split them into multiple lines to parse for the PSScriptInfo metadata properties.
+ $commentLines = $psscriptInfoComments.Text -split "`r`n"
+
+ $KeyName = $null
+ $Value = ""
+
+ # PSScriptInfo comment will be in following format:
+ <#PSScriptInfo
+
+ .VERSION 1.0
+
+ .GUID 544238e3-1751-4065-9227-be105ff11636
+
+ .AUTHOR manikb
+
+ .COMPANYNAME Microsoft Corporation
+
+ .COPYRIGHT (c) 2015 Microsoft Corporation. All rights reserved.
+
+ .TAGS Tag1 Tag2 Tag3
+
+ .LICENSEURI https://contoso.com/License
+
+ .PROJECTURI https://contoso.com/
+
+ .ICONURI https://contoso.com/Icon
+
+ .EXTERNALMODULEDEPENDENCIES ExternalModule1
+
+ .REQUIREDSCRIPTS Start-WFContosoServer,Stop-ContosoServerScript
+
+ .EXTERNALSCRIPTDEPENDENCIES Stop-ContosoServerScript
+
+ .RELEASENOTES
+ contoso script now supports following features
+ Feature 1
+ Feature 2
+ Feature 3
+ Feature 4
+ Feature 5
+
+ #>
+ # If comment line count is not more than two, it doesn't have the any metadata property
+ # First line is <#PSScriptInfo
+ # Last line #>
+ #
+ if($commentLines.Count -gt 2)
+ {
+ for($i = 1; $i -lt ($commentLines.count - 1); $i++)
+ {
+ $line = $commentLines[$i]
+
+ if(-not $line)
+ {
+ continue
+ }
+
+ # A line is starting with . conveys a new metadata property
+ # __NEWLINE__ is used for replacing the value lines while adding the value to $PSScriptInfo object
+ #
+ if($line.trim().StartsWith('.'))
+ {
+ $parts = $line.trim() -split '[.\s+]',3 | Microsoft.PowerShell.Core\Where-Object {$_}
+
+ if($KeyName -and $Value)
+ {
+ if($keyName -eq $script:ReleaseNotes)
+ {
+ $Value = $Value.Trim() -split '__NEWLINE__'
+ }
+ elseif($keyName -eq $script:DESCRIPTION)
+ {
+ $Value = $Value -split '__NEWLINE__'
+ $Value = ($Value -join "`r`n").Trim()
+ }
+ else
+ {
+ $Value = $Value -split '__NEWLINE__' | Microsoft.PowerShell.Core\Where-Object { $_ }
+
+ if($Value -and $Value.GetType().ToString() -eq "System.String")
+ {
+ $Value = $Value.Trim()
+ }
+ }
+
+ ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo `
+ -PropertyName $KeyName `
+ -PropertyValue $Value `
+ -CallerPSCmdlet $PSCmdlet
+ }
+
+ $KeyName = $null
+ $Value = ""
+
+ if($parts.GetType().ToString() -eq "System.String")
+ {
+ $KeyName = $parts
+ }
+ else
+ {
+ $KeyName = $parts[0];
+ $Value = $parts[1]
+ }
+ }
+ else
+ {
+ if($Value)
+ {
+ # __NEWLINE__ is used for replacing the value lines while adding the value to $PSScriptInfo object
+ $Value += '__NEWLINE__'
+ }
+
+ $Value += $line
+ }
+ }
+
+ if($KeyName -and $Value)
+ {
+ if($keyName -eq $script:ReleaseNotes)
+ {
+ $Value = $Value.Trim() -split '__NEWLINE__'
+ }
+ elseif($keyName -eq $script:DESCRIPTION)
+ {
+ $Value = $Value -split '__NEWLINE__'
+ $Value = ($Value -join "`r`n").Trim()
+ }
+ else
+ {
+ $Value = $Value -split '__NEWLINE__' | Microsoft.PowerShell.Core\Where-Object { $_ }
+
+ if($Value -and $Value.GetType().ToString() -eq "System.String")
+ {
+ $Value = $Value.Trim()
+ }
+ }
+
+ ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo `
+ -PropertyName $KeyName `
+ -PropertyValue $Value `
+ -CallerPSCmdlet $PSCmdlet
+
+ $KeyName = $null
+ $Value = ""
+ }
+ }
+
+ $helpContent = $ast.GetHelpContent()
+ if($helpContent -and $helpContent.Description)
+ {
+ ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo `
+ -PropertyName $script:DESCRIPTION `
+ -PropertyValue $helpContent.Description.Trim() `
+ -CallerPSCmdlet $PSCmdlet
+
+ }
+
+ # Handle RequiredModules
+ if((Microsoft.PowerShell.Utility\Get-Member -InputObject $ast -Name 'ScriptRequirements') -and
+ $ast.ScriptRequirements -and
+ (Microsoft.PowerShell.Utility\Get-Member -InputObject $ast.ScriptRequirements -Name 'RequiredModules') -and
+ $ast.ScriptRequirements.RequiredModules)
+ {
+ ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo `
+ -PropertyName $script:RequiredModules `
+ -PropertyValue $ast.ScriptRequirements.RequiredModules `
+ -CallerPSCmdlet $PSCmdlet
+ }
+
+ # Get all defined functions and populate DefinedCommands, DefinedFunctions and DefinedWorkflows
+ $allCommands = $ast.FindAll({param($i) return ($i.GetType().Name -eq 'FunctionDefinitionAst')}, $true)
+
+ if($allCommands)
+ {
+ $allCommandNames = $allCommands | ForEach-Object {$_.Name} | Select-Object -Unique
+ ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo `
+ -PropertyName $script:DefinedCommands `
+ -PropertyValue $allCommandNames `
+ -CallerPSCmdlet $PSCmdlet
+
+ $allFunctionNames = $allCommands | Where-Object {-not $_.IsWorkflow} | ForEach-Object {$_.Name} | Select-Object -Unique
+ ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo `
+ -PropertyName $script:DefinedFunctions `
+ -PropertyValue $allFunctionNames `
+ -CallerPSCmdlet $PSCmdlet
+
+
+ $allWorkflowNames = $allCommands | Where-Object {$_.IsWorkflow} | ForEach-Object {$_.Name} | Select-Object -Unique
+ ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo `
+ -PropertyName $script:DefinedWorkflows `
+ -PropertyValue $allWorkflowNames `
+ -CallerPSCmdlet $PSCmdlet
+ }
+ }
+
+ # Ensure that the script file has the required metadata properties.
+ if(-not $PSScriptInfo.Version -or -not $PSScriptInfo.Guid -or -not $PSScriptInfo.Author -or -not $PSScriptInfo.Description)
+ {
+ $errorMessage = ($LocalizedData.MissingRequiredPSScriptInfoProperties -f $scriptFilePath)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "MissingRequiredPSScriptInfoProperties" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $Path `
+ -ErrorCategory InvalidArgument
+ return
+ }
+
+ $PSScriptInfo = Get-OrderedPSScriptInfoObject -PSScriptInfo $PSScriptInfo
+
+ return $PSScriptInfo
+ }
+}
+
+function New-ScriptFileInfo
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(PositionalBinding=$false,
+ SupportsShouldProcess=$true,
+ HelpUri='http://go.microsoft.com/fwlink/?LinkId=619792')]
+ Param
+ (
+ [Parameter(Mandatory=$false,
+ Position=0,
+ ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Path,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Version]
+ $Version,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Author,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Description,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Guid]
+ $Guid,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [String]
+ $CompanyName,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Copyright,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Object[]]
+ $RequiredModules,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [String[]]
+ $ExternalModuleDependencies,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $RequiredScripts,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [String[]]
+ $ExternalScriptDependencies,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Tags,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $ProjectUri,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $LicenseUri,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $IconUri,
+
+ [Parameter()]
+ [string[]]
+ $ReleaseNotes,
+
+ [Parameter()]
+ [switch]
+ $PassThru,
+
+ [Parameter()]
+ [switch]
+ $Force
+ )
+
+ Process
+ {
+ if($Path)
+ {
+ if(-not $Path.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $errorMessage = ($LocalizedData.InvalidScriptFilePath -f $Path)
+ ThrowError -ExceptionName 'System.ArgumentException' `
+ -ExceptionMessage $errorMessage `
+ -ErrorId 'InvalidScriptFilePath' `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $Path `
+ -ErrorCategory InvalidArgument
+ return
+ }
+
+ if(-not $Force -and (Microsoft.PowerShell.Management\Test-Path -Path $Path))
+ {
+ $errorMessage = ($LocalizedData.ScriptFileExist -f $Path)
+ ThrowError -ExceptionName 'System.ArgumentException' `
+ -ExceptionMessage $errorMessage `
+ -ErrorId 'ScriptFileExist' `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $Path `
+ -ErrorCategory InvalidArgument
+ return
+ }
+ }
+ elseif(-not $PassThru)
+ {
+ ThrowError -ExceptionName 'System.ArgumentException' `
+ -ExceptionMessage $LocalizedData.MissingTheRequiredPathOrPassThruParameter `
+ -ErrorId 'MissingTheRequiredPathOrPassThruParameter' `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ return
+ }
+
+ if(-not $Version)
+ {
+ $Version = [Version]'1.0'
+ }
+
+ if(-not $Author)
+ {
+ $Author = (Get-EnvironmentVariable -Name 'USERNAME' -Target $script:EnvironmentVariableTarget.Process -ErrorAction SilentlyContinue)
+ }
+
+ if(-not $Guid)
+ {
+ $Guid = [System.Guid]::NewGuid()
+ }
+
+ $params = @{
+ Version = $Version
+ Author = $Author
+ Guid = $Guid
+ CompanyName = $CompanyName
+ Copyright = $Copyright
+ ExternalModuleDependencies = $ExternalModuleDependencies
+ RequiredScripts = $RequiredScripts
+ ExternalScriptDependencies = $ExternalScriptDependencies
+ Tags = $Tags
+ ProjectUri = $ProjectUri
+ LicenseUri = $LicenseUri
+ IconUri = $IconUri
+ ReleaseNotes = $ReleaseNotes
+ }
+
+ if(-not (Validate-ScriptFileInfoParameters -parameters $params))
+ {
+ return
+ }
+
+ if("$Description" -match '<#' -or "$Description" -match '#>')
+ {
+ $message = $LocalizedData.InvalidParameterValue -f ($Description, 'Description')
+ Write-Error -Message $message -ErrorId 'InvalidParameterValue' -Category InvalidArgument
+
+ return
+ }
+
+ $PSScriptInfoString = Get-PSScriptInfoString @params
+
+ $requiresStrings = Get-RequiresString -RequiredModules $RequiredModules
+
+ $ScriptCommentHelpInfoString = Get-ScriptCommentHelpInfoString -Description $Description
+
+ $ScriptMetadataString = $PSScriptInfoString
+ $ScriptMetadataString += "`r`n"
+
+ if("$requiresStrings".Trim())
+ {
+ $ScriptMetadataString += "`r`n"
+ $ScriptMetadataString += $requiresStrings -join "`r`n"
+ $ScriptMetadataString += "`r`n"
+ }
+
+ $ScriptMetadataString += "`r`n"
+ $ScriptMetadataString += $ScriptCommentHelpInfoString
+ $ScriptMetadataString += "Param()`r`n`r`n"
+
+ $tempScriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $env:TEMP -ChildPath "$(Get-Random).ps1"
+
+ try
+ {
+ Microsoft.PowerShell.Management\Set-Content -Value $ScriptMetadataString -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false
+
+ $scriptInfo = Test-ScriptFileInfo -Path $tempScriptFilePath
+
+ if(-not $scriptInfo)
+ {
+ # Above Test-ScriptFileInfo cmdlet writes the errors
+ return
+ }
+
+ if($Path -and ($Force -or $PSCmdlet.ShouldProcess($Path, ($LocalizedData.NewScriptFileInfowhatIfMessage -f $Path) )))
+ {
+ Microsoft.PowerShell.Management\Copy-Item -Path $tempScriptFilePath -Destination $Path -Force -WhatIf:$false -Confirm:$false
+ }
+
+ if($PassThru)
+ {
+ Write-Output -InputObject $ScriptMetadataString
+ }
+ }
+ finally
+ {
+ Microsoft.PowerShell.Management\Remove-Item -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
+ }
+ }
+}
+
+function Update-ScriptFileInfo
+{
+ <#
+ .ExternalHelp PSGet.psm1-help.xml
+ #>
+ [CmdletBinding(PositionalBinding=$false,
+ DefaultParameterSetName='PathParameterSet',
+ SupportsShouldProcess=$true,
+ HelpUri='http://go.microsoft.com/fwlink/?LinkId=619793')]
+ Param
+ (
+ [Parameter(Mandatory=$true,
+ Position=0,
+ ParameterSetName='PathParameterSet',
+ ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Path,
+
+ [Parameter(Mandatory=$true,
+ Position=0,
+ ParameterSetName='LiteralPathParameterSet',
+ ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $LiteralPath,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Version]
+ $Version,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Author,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Guid]
+ $Guid,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Description,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [String]
+ $CompanyName,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Copyright,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Object[]]
+ $RequiredModules,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [String[]]
+ $ExternalModuleDependencies,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $RequiredScripts,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [String[]]
+ $ExternalScriptDependencies,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Tags,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $ProjectUri,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $LicenseUri,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $IconUri,
+
+ [Parameter()]
+ [string[]]
+ $ReleaseNotes,
+
+ [Parameter()]
+ [switch]
+ $PassThru,
+
+ [Parameter()]
+ [switch]
+ $Force
+ )
+
+ Process
+ {
+ $scriptFilePath = $null
+ if($Path)
+ {
+ $scriptFilePath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet |
+ Microsoft.PowerShell.Utility\Select-Object -First 1
+
+ if(-not $scriptFilePath -or
+ -not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf))
+ {
+ $errorMessage = ($LocalizedData.PathNotFound -f $Path)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $Path `
+ -ErrorCategory InvalidArgument
+ }
+ }
+ else
+ {
+ $scriptFilePath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet |
+ Microsoft.PowerShell.Utility\Select-Object -First 1
+
+ if(-not $scriptFilePath -or
+ -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $scriptFilePath -PathType Leaf))
+ {
+ $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $LiteralPath `
+ -ErrorCategory InvalidArgument
+ }
+ }
+
+ if(-not $scriptFilePath.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $errorMessage = ($LocalizedData.InvalidScriptFilePath -f $scriptFilePath)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "InvalidScriptFilePath" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $scriptFilePath `
+ -ErrorCategory InvalidArgument
+ return
+ }
+
+ $psscriptInfo = $null
+ try
+ {
+ $psscriptInfo = Test-ScriptFileInfo -LiteralPath $scriptFilePath
+ }
+ catch
+ {
+ if(-not $Force)
+ {
+ throw $_
+ return
+ }
+ }
+
+ if(-not $psscriptInfo)
+ {
+ if(-not $Description)
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $LocalizedData.DescriptionParameterIsMissingForAddingTheScriptFileInfo `
+ -ErrorId 'DescriptionParameterIsMissingForAddingTheScriptFileInfo' `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ return
+ }
+
+ if(-not $Version)
+ {
+ $Version = [Version]'1.0'
+ }
+
+ if(-not $Author)
+ {
+ $Author = (Get-EnvironmentVariable -Name 'USERNAME' -Target $script:EnvironmentVariableTarget.Process -ErrorAction SilentlyContinue)
+ }
+
+ if(-not $Guid)
+ {
+ $Guid = [System.Guid]::NewGuid()
+ }
+ }
+ else
+ {
+ # Use existing values if any of the parameters are not specified during Update-ScriptFileInfo
+ if(-not $Version -and $psscriptInfo.Version)
+ {
+ $Version = $psscriptInfo.Version
+ }
+
+ if(-not $Guid -and $psscriptInfo.Guid)
+ {
+ $Guid = $psscriptInfo.Guid
+ }
+
+ if(-not $Author -and $psscriptInfo.Author)
+ {
+ $Author = $psscriptInfo.Author
+ }
+
+ if(-not $CompanyName -and $psscriptInfo.CompanyName)
+ {
+ $CompanyName = $psscriptInfo.CompanyName
+ }
+
+ if(-not $Copyright -and $psscriptInfo.Copyright)
+ {
+ $Copyright = $psscriptInfo.Copyright
+ }
+
+ if(-not $RequiredModules -and $psscriptInfo.RequiredModules)
+ {
+ $RequiredModules = $psscriptInfo.RequiredModules
+ }
+
+ if(-not $ExternalModuleDependencies -and $psscriptInfo.ExternalModuleDependencies)
+ {
+ $ExternalModuleDependencies = $psscriptInfo.ExternalModuleDependencies
+ }
+
+ if(-not $RequiredScripts -and $psscriptInfo.RequiredScripts)
+ {
+ $RequiredScripts = $psscriptInfo.RequiredScripts
+ }
+
+ if(-not $ExternalScriptDependencies -and $psscriptInfo.ExternalScriptDependencies)
+ {
+ $ExternalScriptDependencies = $psscriptInfo.ExternalScriptDependencies
+ }
+
+ if(-not $Tags -and $psscriptInfo.Tags)
+ {
+ $Tags = $psscriptInfo.Tags
+ }
+
+ if(-not $ProjectUri -and $psscriptInfo.ProjectUri)
+ {
+ $ProjectUri = $psscriptInfo.ProjectUri
+ }
+
+ if(-not $LicenseUri -and $psscriptInfo.LicenseUri)
+ {
+ $LicenseUri = $psscriptInfo.LicenseUri
+ }
+
+ if(-not $IconUri -and $psscriptInfo.IconUri)
+ {
+ $IconUri = $psscriptInfo.IconUri
+ }
+
+ if(-not $ReleaseNotes -and $psscriptInfo.ReleaseNotes)
+ {
+ $ReleaseNotes = $psscriptInfo.ReleaseNotes
+ }
+ }
+
+ $params = @{
+ Version = $Version
+ Author = $Author
+ Guid = $Guid
+ CompanyName = $CompanyName
+ Copyright = $Copyright
+ ExternalModuleDependencies = $ExternalModuleDependencies
+ RequiredScripts = $RequiredScripts
+ ExternalScriptDependencies = $ExternalScriptDependencies
+ Tags = $Tags
+ ProjectUri = $ProjectUri
+ LicenseUri = $LicenseUri
+ IconUri = $IconUri
+ ReleaseNotes = $ReleaseNotes
+ }
+
+ if(-not (Validate-ScriptFileInfoParameters -parameters $params))
+ {
+ return
+ }
+
+ if("$Description" -match '<#' -or "$Description" -match '#>')
+ {
+ $message = $LocalizedData.InvalidParameterValue -f ($Description, 'Description')
+ Write-Error -Message $message -ErrorId 'InvalidParameterValue' -Category InvalidArgument
+
+ return
+ }
+
+ $PSScriptInfoString = Get-PSScriptInfoString @params
+
+ $requiresStrings = ""
+ $requiresStrings = Get-RequiresString -RequiredModules $RequiredModules
+
+ $DescriptionValue = if($Description) {$Description} else {$psscriptInfo.Description}
+ $ScriptCommentHelpInfoString = Get-ScriptCommentHelpInfoString -Description $DescriptionValue
+
+ $ScriptMetadataString = $PSScriptInfoString
+ $ScriptMetadataString += "`r`n"
+
+ if("$requiresStrings".Trim())
+ {
+ $ScriptMetadataString += "`r`n"
+ $ScriptMetadataString += $requiresStrings -join "`r`n"
+ $ScriptMetadataString += "`r`n"
+ }
+
+ $ScriptMetadataString += "`r`n"
+ $ScriptMetadataString += $ScriptCommentHelpInfoString
+ $ScriptMetadataString += "`r`nParam()`r`n`r`n"
+ if(-not $ScriptMetadataString)
+ {
+ return
+ }
+
+ $tempScriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $env:TEMP -ChildPath "$(Get-Random).ps1"
+
+ try
+ {
+ # First create a new script file with new script metadata to ensure that updated values are valid.
+ Microsoft.PowerShell.Management\Set-Content -Value $ScriptMetadataString -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false
+
+ $scriptInfo = Test-ScriptFileInfo -Path $tempScriptFilePath
+
+ if(-not $scriptInfo)
+ {
+ # Above Test-ScriptFileInfo cmdlet writes the error
+ return
+ }
+
+ $scriptFileContents = Microsoft.PowerShell.Management\Get-Content -LiteralPath $scriptFilePath
+
+ # If -Force is specified and script file doesnt have a valid PSScriptInfo
+ # Prepend the PSScriptInfo and Check if the Test-ScriptFileInfo returns a valid script info without any errors
+ if($Force -and -not $psscriptInfo)
+ {
+ # Add the script file contents to the temp file with script metadata
+ Microsoft.PowerShell.Management\Set-Content -LiteralPath $tempScriptFilePath `
+ -Value $ScriptMetadataString,$scriptFileContents `
+ -Force `
+ -WhatIf:$false `
+ -Confirm:$false
+
+ $tempScriptInfo = $null
+ try
+ {
+ $tempScriptInfo = Test-ScriptFileInfo -LiteralPath $tempScriptFilePath
+ }
+ catch
+ {
+ $errorMessage = ($LocalizedData.UnableToAddPSScriptInfo -f $scriptFilePath)
+ ThrowError -ExceptionName 'System.InvalidOperationException' `
+ -ExceptionMessage $errorMessage `
+ -ErrorId 'UnableToAddPSScriptInfo' `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $scriptFilePath `
+ -ErrorCategory InvalidOperation
+ return
+ }
+ }
+ else
+ {
+ [System.Management.Automation.Language.Token[]]$tokens = $null;
+ [System.Management.Automation.Language.ParseError[]]$errors = $null;
+ $ast = [System.Management.Automation.Language.Parser]::ParseFile($scriptFilePath, ([ref]$tokens), ([ref]$errors))
+
+ # Update PSScriptInfo and #Requires
+ $CommentTokens = $tokens | Microsoft.PowerShell.Core\Where-Object {$_.Kind -eq 'Comment'}
+
+ $psscriptInfoComments = $CommentTokens |
+ Microsoft.PowerShell.Core\Where-Object { $_.Extent.Text -match "<#PSScriptInfo" } |
+ Microsoft.PowerShell.Utility\Select-Object -First 1
+
+ if(-not $psscriptInfoComments)
+ {
+ $errorMessage = ($LocalizedData.MissingPSScriptInfo -f $scriptFilePath)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "MissingPSScriptInfo" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ExceptionObject $scriptFilePath `
+ -ErrorCategory InvalidArgument
+ return
+ }
+
+ # Ensure that metadata is replaced at the correct location and should not corrupt the existing script file.
+
+ # Remove the lines between below lines and add the new PSScriptInfo and new #Requires statements
+ # ($psscriptInfoComments.Extent.StartLineNumber - 1)
+ # ($psscriptInfoComments.Extent.EndLineNumber - 1)
+ $tempContents = @()
+ $IsNewPScriptInfoAdded = $false
+
+ for($i = 0; $i -lt $scriptFileContents.Count; $i++)
+ {
+ $line = $scriptFileContents[$i]
+ if(($i -ge ($psscriptInfoComments.Extent.StartLineNumber - 1)) -and
+ ($i -le ($psscriptInfoComments.Extent.EndLineNumber - 1)))
+ {
+ if(-not $IsNewPScriptInfoAdded)
+ {
+ $PSScriptInfoString = $PSScriptInfoString.TrimStart()
+ $requiresStrings = $requiresStrings.TrimEnd()
+
+ $tempContents += "$PSScriptInfoString `r`n`r`n$($requiresStrings -join "`r`n")"
+ $IsNewPScriptInfoAdded = $true
+ }
+ }
+ elseif($line -notmatch "\s*#Requires\s+-Module")
+ {
+ # Add the existing lines if they are not part of PSScriptInfo comment or not containing #Requires -Module statements.
+ $tempContents += $line
+ }
+ }
+
+ Microsoft.PowerShell.Management\Set-Content -Value $tempContents -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false
+
+ $scriptInfo = Test-ScriptFileInfo -Path $tempScriptFilePath
+
+ if(-not $scriptInfo)
+ {
+ # Above Test-ScriptFileInfo cmdlet writes the error
+ return
+ }
+
+ # Now update the Description value if a new is specified.
+ if($Description)
+ {
+ $tempContents = @()
+ $IsDescriptionAdded = $false
+
+ $IsDescriptionBeginFound = $false
+ $scriptFileContents = Microsoft.PowerShell.Management\Get-Content -Path $tempScriptFilePath
+
+ for($i = 0; $i -lt $scriptFileContents.Count; $i++)
+ {
+ $line = $scriptFileContents[$i]
+
+ if(-not $IsDescriptionAdded)
+ {
+ if(-not $IsDescriptionBeginFound)
+ {
+ if($line.Trim().StartsWith(".DESCRIPTION", [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $IsDescriptionBeginFound = $true
+ }
+ else
+ {
+ $tempContents += $line
+ }
+ }
+ else
+ {
+ # Description begin has found
+ # Skip the old description lines until description end is found
+
+ if($line.Trim().StartsWith("#>", [System.StringComparison]::OrdinalIgnoreCase) -or
+ $line.Trim().StartsWith(".", [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $tempContents += ".DESCRIPTION `r`n$($Description -join "`r`n")`r`n"
+ $IsDescriptionAdded = $true
+ $tempContents += $line
+ }
+ }
+ }
+ else
+ {
+ $tempContents += $line
+ }
+ }
+
+ Microsoft.PowerShell.Management\Set-Content -Value $tempContents -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false
+
+ $scriptInfo = Test-ScriptFileInfo -Path $tempScriptFilePath
+
+ if(-not $scriptInfo)
+ {
+ # Above Test-ScriptFileInfo cmdlet writes the error
+ return
+ }
+ }
+ }
+
+ if($Force -or $PSCmdlet.ShouldProcess($scriptFilePath, ($LocalizedData.UpdateScriptFileInfowhatIfMessage -f $Path) ))
+ {
+ Microsoft.PowerShell.Management\Copy-Item -Path $tempScriptFilePath -Destination $scriptFilePath -Force -WhatIf:$false -Confirm:$false
+
+ if($PassThru)
+ {
+ $ScriptMetadataString
+ }
+ }
+ }
+ finally
+ {
+ Microsoft.PowerShell.Management\Remove-Item -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
+ }
+ }
+}
+
+function Get-RequiresString
+{
+ [CmdletBinding()]
+ Param
+ (
+ [Parameter()]
+ [Object[]]
+ $RequiredModules
+ )
+
+ Process
+ {
+ if($RequiredModules)
+ {
+ $RequiredModuleStrings = @()
+
+ foreach($requiredModuleObject in $RequiredModules)
+ {
+ if($requiredModuleObject.GetType().ToString() -eq 'System.Collections.Hashtable')
+ {
+ if(($requiredModuleObject.Keys.Count -eq 1) -and
+ (Microsoft.PowerShell.Utility\Get-Member -InputObject $requiredModuleObject -Name 'ModuleName'))
+ {
+ $RequiredModuleStrings += $requiredModuleObject['ModuleName'].ToString()
+ }
+ else
+ {
+ $moduleSpec = New-Object Microsoft.PowerShell.Commands.ModuleSpecification -ArgumentList $requiredModuleObject
+ if (-not (Microsoft.PowerShell.Utility\Get-Variable -Name moduleSpec -ErrorAction SilentlyContinue))
+ {
+ return
+ }
+
+ $keyvalueStrings = $requiredModuleObject.Keys | Microsoft.PowerShell.Core\ForEach-Object {"$_ = '$( $requiredModuleObject[$_])'"}
+ $RequiredModuleStrings += "@{$($keyvalueStrings -join '; ')}"
+ }
+ }
+ elseif(($PSVersionTable.PSVersion -eq [Version]'3.0') -and
+ ($requiredModuleObject.GetType().ToString() -eq 'Microsoft.PowerShell.Commands.ModuleSpecification'))
+ {
+ # ModuleSpecification.ToString() is not implemented on PowerShell 3.0.
+
+ $optionalString = " "
+
+ if($requiredModuleObject.Version)
+ {
+ $optionalString += "ModuleVersion = '$($requiredModuleObject.Version.ToString())'; "
+ }
+
+ if($requiredModuleObject.Guid)
+ {
+ $optionalString += "Guid = '$($requiredModuleObject.Guid.ToString())'; "
+ }
+
+ if($optionalString.Trim())
+ {
+ $moduleSpecString = "@{ ModuleName = '$($requiredModuleObject.Name.ToString())';$optionalString}"
+ }
+ else
+ {
+ $moduleSpecString = $requiredModuleObject.Name.ToString()
+ }
+
+ $RequiredModuleStrings += $moduleSpecString
+ }
+ else
+ {
+ $RequiredModuleStrings += $requiredModuleObject.ToString()
+ }
+ }
+
+ $hashRequiresStrings = $RequiredModuleStrings |
+ Microsoft.PowerShell.Core\ForEach-Object { "#Requires -Module $_" }
+
+ return $hashRequiresStrings
+ }
+ else
+ {
+ return ""
+ }
+ }
+}
+
+function Get-PSScriptInfoString
+{
+ [CmdletBinding(PositionalBinding=$false)]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Version]
+ $Version,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Guid]
+ $Guid,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Author,
+
+ [Parameter()]
+ [String]
+ $CompanyName,
+
+ [Parameter()]
+ [string]
+ $Copyright,
+
+ [Parameter()]
+ [String[]]
+ $ExternalModuleDependencies,
+
+ [Parameter()]
+ [string[]]
+ $RequiredScripts,
+
+ [Parameter()]
+ [String[]]
+ $ExternalScriptDependencies,
+
+ [Parameter()]
+ [string[]]
+ $Tags,
+
+ [Parameter()]
+ [Uri]
+ $ProjectUri,
+
+ [Parameter()]
+ [Uri]
+ $LicenseUri,
+
+ [Parameter()]
+ [Uri]
+ $IconUri,
+
+ [Parameter()]
+ [string[]]
+ $ReleaseNotes
+ )
+
+ Process
+ {
+ $PSScriptInfoString = @"
+
+<#PSScriptInfo
+
+.VERSION $Version
+
+.GUID $Guid
+
+.AUTHOR $Author
+
+.COMPANYNAME $CompanyName
+
+.COPYRIGHT $Copyright
+
+.TAGS $Tags
+
+.LICENSEURI $LicenseUri
+
+.PROJECTURI $ProjectUri
+
+.ICONURI $IconUri
+
+.EXTERNALMODULEDEPENDENCIES $($ExternalModuleDependencies -join ',')
+
+.REQUIREDSCRIPTS $($RequiredScripts -join ',')
+
+.EXTERNALSCRIPTDEPENDENCIES $($ExternalScriptDependencies -join ',')
+
+.RELEASENOTES
+$($ReleaseNotes -join "`r`n")
+
+#>
+"@
+ return $PSScriptInfoString
+ }
+}
+
+function Validate-ScriptFileInfoParameters
+{
+ [CmdletBinding(PositionalBinding=$false)]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [PSCustomObject]
+ $Parameters
+ )
+
+ $hasErrors = $false
+
+ $Parameters.Keys | ForEach-Object {
+
+ $parameterName = $_
+
+ $parameterValue = $($Parameters[$parameterName])
+
+ if("$parameterValue" -match '<#' -or "$parameterValue" -match '#>')
+ {
+ $message = $LocalizedData.InvalidParameterValue -f ($parameterValue, $parameterName)
+ Write-Error -Message $message -ErrorId 'InvalidParameterValue' -Category InvalidArgument
+
+ $hasErrors = $true
+ }
+ }
+
+ return (-not $hasErrors)
+}
+
+function Get-ScriptCommentHelpInfoString
+{
+ [CmdletBinding(PositionalBinding=$false)]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Description,
+
+ [Parameter()]
+ [string]
+ $Synopsis,
+
+ [Parameter()]
+ [string[]]
+ $Example,
+
+ [Parameter()]
+ [string[]]
+ $Inputs,
+
+ [Parameter()]
+ [string[]]
+ $Outputs,
+
+ [Parameter()]
+ [string[]]
+ $Notes,
+
+ [Parameter()]
+ [string[]]
+ $Link,
+
+ [Parameter()]
+ [string]
+ $Component,
+
+ [Parameter()]
+ [string]
+ $Role,
+
+ [Parameter()]
+ [string]
+ $Functionality
+ )
+
+ Process
+ {
+ $ScriptCommentHelpInfoString = "<# `r`n`r`n.DESCRIPTION `r`n $Description `r`n`r`n"
+
+ if("$Synopsis".Trim())
+ {
+ $ScriptCommentHelpInfoString += ".SYNOPSIS `r`n$Synopsis `r`n`r`n"
+ }
+
+ if("$Example".Trim())
+ {
+ $Example | ForEach-Object {
+ if($_)
+ {
+ $ScriptCommentHelpInfoString += ".EXAMPLE `r`n$_ `r`n`r`n"
+ }
+ }
+ }
+
+ if("$Inputs".Trim())
+ {
+ $Inputs | ForEach-Object {
+ if($_)
+ {
+ $ScriptCommentHelpInfoString += ".INPUTS `r`n$_ `r`n`r`n"
+ }
+ }
+ }
+
+ if("$Outputs".Trim())
+ {
+ $Outputs | ForEach-Object {
+ if($_)
+ {
+ $ScriptCommentHelpInfoString += ".OUTPUTS `r`n$_ `r`n`r`n"
+ }
+ }
+ }
+
+ if("$Notes".Trim())
+ {
+ $ScriptCommentHelpInfoString += ".NOTES `r`n$($Notes -join "`r`n") `r`n`r`n"
+ }
+
+ if("$Link".Trim())
+ {
+ $Link | ForEach-Object {
+ if($_)
+ {
+ $ScriptCommentHelpInfoString += ".LINK `r`n$_ `r`n`r`n"
+ }
+ }
+ }
+
+ if("$Component".Trim())
+ {
+ $ScriptCommentHelpInfoString += ".COMPONENT `r`n$($Component -join "`r`n") `r`n`r`n"
+ }
+
+ if("$Role".Trim())
+ {
+ $ScriptCommentHelpInfoString += ".ROLE `r`n$($Role -join "`r`n") `r`n`r`n"
+ }
+
+ if("$Functionality".Trim())
+ {
+ $ScriptCommentHelpInfoString += ".FUNCTIONALITY `r`n$($Functionality -join "`r`n") `r`n`r`n"
+ }
+
+ $ScriptCommentHelpInfoString += "#> `r`n"
+
+ return $ScriptCommentHelpInfoString
+ }
+}
+
+#endregion *-ScriptFileInfo cmdlets
+
+#region Utility functions
+function ToUpper
+{
+ param([string]$str)
+ return $script:TextInfo.ToUpper($str)
+}
+
+function Resolve-PathHelper
+{
+ param
+ (
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $path,
+
+ [Parameter()]
+ [switch]
+ $isLiteralPath,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [System.Management.Automation.PSCmdlet]
+ $callerPSCmdlet
+ )
+
+ $resolvedPaths =@()
+
+ foreach($currentPath in $path)
+ {
+ try
+ {
+ if($isLiteralPath)
+ {
+ $currentResolvedPaths = Microsoft.PowerShell.Management\Resolve-Path -LiteralPath $currentPath -ErrorAction Stop
+ }
+ else
+ {
+ $currentResolvedPaths = Microsoft.PowerShell.Management\Resolve-Path -Path $currentPath -ErrorAction Stop
+ }
+ }
+ catch
+ {
+ $errorMessage = ($LocalizedData.PathNotFound -f $currentPath)
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $errorMessage `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $callerPSCmdlet `
+ -ErrorCategory InvalidOperation
+ }
+
+ foreach($currentResolvedPath in $currentResolvedPaths)
+ {
+ $resolvedPaths += $currentResolvedPath.ProviderPath
+ }
+ }
+
+ $resolvedPaths
+}
+
+function Check-PSGalleryApiAvailability
+{
+ param
+ (
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $PSGalleryV2ApiUri,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $PSGalleryV3ApiUri
+ )
+
+ # check internet availability first
+ $connected = $false
+ if(Get-Command Microsoft.PowerShell.Management\Test-Connection -ErrorAction SilentlyContinue)
+ {
+ $connected = Microsoft.PowerShell.Management\Test-Connection -ComputerName "www.microsoft.com" -Count 1 -Quiet
+ }
+ else
+ {
+ $connected = NetTCPIP\Test-NetConnection -ComputerName "www.microsoft.com" -InformationLevel Quiet
+ }
+ if ( -not $connected)
+ {
+ return
+ }
+
+ $statusCode_v2 = $null
+ $resolvedUri_v2 = $null
+ $statusCode_v3 = $null
+ $resolvedUri_v3 = $null
+
+ # ping V2
+ $res_v2 = Ping-Endpoint -Endpoint $PSGalleryV2ApiUri
+ if ($res_v2.ContainsKey($Script:ResponseUri))
+ {
+ $resolvedUri_v2 = $res_v2[$Script:ResponseUri]
+ }
+ if ($res_v2.ContainsKey($Script:StatusCode))
+ {
+ $statusCode_v2 = $res_v2[$Script:StatusCode]
+ }
+
+
+ # ping V3
+ $res_v3 = Ping-Endpoint -Endpoint $PSGalleryV3ApiUri
+ if ($res_v3.ContainsKey($Script:ResponseUri))
+ {
+ $resolvedUri_v3 = $res_v3[$Script:ResponseUri]
+ }
+ if ($res_v3.ContainsKey($Script:StatusCode))
+ {
+ $statusCode_v3 = $res_v3[$Script:StatusCode]
+ }
+
+
+ $Script:PSGalleryV2ApiAvailable = (($statusCode_v2 -eq 200) -and ($resolvedUri_v2))
+ $Script:PSGalleryV3ApiAvailable = (($statusCode_v3 -eq 200) -and ($resolvedUri_v3))
+ $Script:PSGalleryApiChecked = $true
+}
+
+function Get-PSGalleryApiAvailability
+{
+ param
+ (
+ [Parameter()]
+ [string[]]
+ $Repository
+ )
+
+ # skip if repository is null or not PSGallery
+ if ( -not $Repository)
+ {
+ return
+ }
+
+ if ($Repository -notcontains $Script:PSGalleryModuleSource )
+ {
+ return
+ }
+
+ # run check only once
+ if( -not $Script:PSGalleryApiChecked)
+ {
+ $null = Check-PSGalleryApiAvailability -PSGalleryV2ApiUri $Script:PSGallerySourceUri -PSGalleryV3ApiUri $Script:PSGalleryV3SourceUri
+ }
+
+ if ( -not $Script:PSGalleryV2ApiAvailable )
+ {
+ if ($Script:PSGalleryV3ApiAvailable)
+ {
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $LocalizedData.PSGalleryApiV2Discontinued `
+ -ErrorId "PSGalleryApiV2Discontinued" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation
+ }
+ else
+ {
+ # both APIs are down, throw error
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $LocalizedData.PowerShellGalleryUnavailable `
+ -ErrorId "PowerShellGalleryUnavailable" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation
+ }
+
+ }
+ else
+ {
+ if ($Script:PSGalleryV3ApiAvailable)
+ {
+ Write-Warning -Message $LocalizedData.PSGalleryApiV2Deprecated
+ return
+ }
+ }
+
+ # if V2 is available and V3 is not available, do nothing
+}
+
+function HttpClientApisAvailable
+{
+ $HttpClientApisAvailable = $false
+ try
+ {
+ [System.Net.Http.HttpClient]
+ $HttpClientApisAvailable = $true
+ }
+ catch
+ {
+ }
+ return $HttpClientApisAvailable
+}
+
+function Ping-Endpoint
+{
+ param
+ (
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Endpoint,
+
+ [Parameter()]
+ [switch]
+ $AllowAutoRedirect = $true
+ )
+
+ $results = @{}
+
+ if(HttpClientApisAvailable)
+ {
+ $response = $null
+ try
+ {
+ $handler = New-Object System.Net.Http.HttpClientHandler
+ $handler.UseDefaultCredentials = $true
+ $httpClient = New-Object System.Net.Http.HttpClient -ArgumentList $handler
+ $response = $httpclient.GetAsync($endpoint)
+ }
+ catch
+ {
+ }
+
+ if ($response -ne $null -and $response.result -ne $null)
+ {
+ $results.Add($Script:ResponseUri,$response.Result.RequestMessage.RequestUri.AbsoluteUri.ToString())
+ $results.Add($Script:StatusCode,$response.result.StatusCode.value__)
+ }
+ }
+ else
+ {
+ $iss = [System.Management.Automation.Runspaces.InitialSessionState]::Create()
+ $iss.types.clear()
+ $iss.formats.clear()
+ $iss.LanguageMode = "FullLanguage"
+
+ $WebRequestcmd = @'
+ try
+ {{
+ $request = [System.Net.WebRequest]::Create("{0}")
+ $request.Method = 'GET'
+ $request.Timeout = 30000
+ $request.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
+ $request.AllowAutoRedirect = ${1}
+ $response = [System.Net.HttpWebResponse]$request.GetResponse()
+ if($response.StatusCode.value__ -eq 302)
+ {{
+ $response.Headers["Location"].ToString()
+ }}
+ else
+ {{
+ $response
+ }}
+ $response.Close()
+ }}
+ catch [System.Net.WebException]
+ {{
+ "Error:System.Net.WebException"
+ }}
+'@ -f $EndPoint, $AllowAutoRedirect
+
+ $ps = [powershell]::Create($iss).AddScript($WebRequestcmd)
+ $response = $ps.Invoke()
+ $ps.dispose()
+ if ($response -ne "Error:System.Net.WebException")
+ {
+ if($AllowAutoRedirect)
+ {
+ $results.Add($Script:ResponseUri,$response.ResponseUri.ToString())
+ $results.Add($Script:StatusCode,$response.StatusCode.value__)
+ }
+ else
+ {
+ $results.Add($Script:ResponseUri,[String]$response)
+ }
+ }
+ }
+ return $results
+}
+
+function Validate-VersionParameters
+{
+ Param(
+ [parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [System.Management.Automation.PSCmdlet]
+ $CallerPSCmdlet,
+
+ [Parameter()]
+ [String[]]
+ $Name,
+
+ [Parameter()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter()]
+ [Version]
+ $MaximumVersion,
+
+ [Parameter()]
+ [Switch]
+ $AllVersions,
+
+ [Parameter()]
+ [Switch]
+ $TestWildcardsInName
+ )
+
+ if($TestWildcardsInName -and $Name -and (Test-WildcardPattern -Name "$Name"))
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage ($LocalizedData.NameShouldNotContainWildcardCharacters -f "$($Name -join ',')") `
+ -ErrorId 'NameShouldNotContainWildcardCharacters' `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Name
+ }
+ elseif($AllVersions -and ($RequiredVersion -or $MinimumVersion -or $MaximumVersion))
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $LocalizedData.AllVersionsCannotBeUsedWithOtherVersionParameters `
+ -ErrorId 'AllVersionsCannotBeUsedWithOtherVersionParameters' `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+ elseif($RequiredVersion -and ($MinimumVersion -or $MaximumVersion))
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $LocalizedData.VersionRangeAndRequiredVersionCannotBeSpecifiedTogether `
+ -ErrorId "VersionRangeAndRequiredVersionCannotBeSpecifiedTogether" `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+ elseif($MinimumVersion -and $MaximumVersion -and ($MinimumVersion -gt $MaximumVersion))
+ {
+ $Message = $LocalizedData.MinimumVersionIsGreaterThanMaximumVersion -f ($MinimumVersion, $MaximumVersion)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $Message `
+ -ErrorId "MinimumVersionIsGreaterThanMaximumVersion" `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+ elseif($AllVersions -or $RequiredVersion -or $MinimumVersion -or $MaximumVersion)
+ {
+ if(-not $Name -or $Name.Count -ne 1 -or (Test-WildcardPattern -Name $Name[0]))
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $LocalizedData.VersionParametersAreAllowedOnlyWithSingleName `
+ -ErrorId "VersionParametersAreAllowedOnlyWithSingleName" `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+ }
+
+ return $true
+}
+
+function ValidateAndSet-PATHVariableIfUserAccepts
+{
+ [CmdletBinding()]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [string]
+ $Scope,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $ScopePath,
+
+ [Parameter()]
+ [Switch]
+ $NoPathUpdate,
+
+ [Parameter()]
+ [Switch]
+ $Force,
+
+ [Parameter()]
+ $Request
+ )
+
+ Set-PSGetSettingsVariable
+
+ # Check and add the scope path to PATH environment variable if USER accepts the prompt.
+ if($Scope -eq 'AllUsers')
+ {
+ $envVariableTarget = $script:EnvironmentVariableTarget.Machine
+ $scriptPATHPromptQuery=$LocalizedData.ScriptPATHPromptQuery -f $ScopePath
+ $scopeSpecificKey = 'AllUsersScope_AllowPATHChangeForScripts'
+ }
+ else
+ {
+ $envVariableTarget = $script:EnvironmentVariableTarget.User
+ $scriptPATHPromptQuery=$LocalizedData.ScriptPATHPromptQuery -f $ScopePath
+ $scopeSpecificKey = 'CurrentUserScope_AllowPATHChangeForScripts'
+ }
+
+ $AlreadyPromptedForScope = $script:PSGetSettings.Contains($scopeSpecificKey)
+ Write-Debug "Already prompted for the current scope:$AlreadyPromptedForScope"
+
+ if(-not $AlreadyPromptedForScope)
+ {
+ # Read the file contents once again to ensure that it was not set in another PowerShell Session
+ Set-PSGetSettingsVariable -Force
+
+ $AlreadyPromptedForScope = $script:PSGetSettings.Contains($scopeSpecificKey)
+ Write-Debug "After reading contents of PowerShellGetSettings.xml file, the Already prompted for the current scope:$AlreadyPromptedForScope"
+
+ if($AlreadyPromptedForScope)
+ {
+ return
+ }
+
+ $userResponse = $false
+
+ if(-not $NoPathUpdate)
+ {
+ $scopePathEndingWithBackSlash = "$scopePath\"
+
+ # Check and add the $scopePath to $env:Path value
+ if( (($env:PATH -split ';') -notcontains $scopePath) -and
+ (($env:PATH -split ';') -notcontains $scopePathEndingWithBackSlash))
+ {
+ if($Force)
+ {
+ $userResponse = $true
+ }
+ else
+ {
+ $scriptPATHPromptCaption = $LocalizedData.ScriptPATHPromptCaption
+
+ if($Request)
+ {
+ $userResponse = $Request.ShouldContinue($scriptPATHPromptQuery, $scriptPATHPromptCaption)
+ }
+ else
+ {
+ $userResponse = $PSCmdlet.ShouldContinue($scriptPATHPromptQuery, $scriptPATHPromptCaption)
+ }
+ }
+
+ if($userResponse)
+ {
+ $currentPATHValue = Get-EnvironmentVariable -Name 'PATH' -Target $envVariableTarget
+
+ if((($currentPATHValue -split ';') -notcontains $scopePath) -and
+ (($currentPATHValue -split ';') -notcontains $scopePathEndingWithBackSlash))
+ {
+ # To ensure that the installed script is immediately usable,
+ # we need to add the scope path to the PATH enviroment variable.
+ Set-EnvironmentVariable -Name 'PATH' `
+ -Value "$currentPATHValue;$scopePath" `
+ -Target $envVariableTarget
+
+ Write-Verbose ($LocalizedData.AddedScopePathToPATHVariable -f ($scopePath,$Scope))
+ }
+
+ # Process specific PATH
+ # Check and add the $scopePath to $env:Path value of current process
+ # so that installed scripts can be used in the current process.
+ $target = $script:EnvironmentVariableTarget.Process
+ $currentPATHValue = Get-EnvironmentVariable -Name 'PATH' -Target $target
+
+ if((($currentPATHValue -split ';') -notcontains $scopePath) -and
+ (($currentPATHValue -split ';') -notcontains $scopePathEndingWithBackSlash))
+ {
+ # To ensure that the installed script is immediately usable,
+ # we need to add the scope path to the PATH enviroment variable.
+ Set-EnvironmentVariable -Name 'PATH' `
+ -Value "$currentPATHValue;$scopePath" `
+ -Target $target
+
+ Write-Verbose ($LocalizedData.AddedScopePathToProcessSpecificPATHVariable -f ($scopePath,$Scope))
+ }
+ }
+ }
+ }
+
+ # Add user's response to the PowerShellGet.settings file
+ $script:PSGetSettings[$scopeSpecificKey] = $userResponse
+
+ Save-PSGetSettings
+ }
+}
+
+function Save-PSGetSettings
+{
+ if($script:PSGetSettings)
+ {
+ if(-not (Microsoft.PowerShell.Management\Test-Path -Path $script:PSGetAppLocalPath))
+ {
+ $null = Microsoft.PowerShell.Management\New-Item -Path $script:PSGetAppLocalPath `
+ -ItemType Directory `
+ -Force `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue `
+ -Confirm:$false `
+ -WhatIf:$false
+ }
+
+ Microsoft.PowerShell.Utility\Out-File -FilePath $script:PSGetSettingsFilePath -Force `
+ -InputObject ([System.Management.Automation.PSSerializer]::Serialize($script:PSGetSettings))
+
+ Write-Debug "In Save-PSGetSettings, persisted the $script:PSGetSettingsFilePath file"
+ }
+}
+
+function Set-PSGetSettingsVariable
+{
+ [CmdletBinding()]
+ param([switch]$Force)
+
+ if(-not $script:PSGetSettings -or $Force)
+ {
+ if(Microsoft.PowerShell.Management\Test-Path -Path $script:PSGetSettingsFilePath)
+ {
+ $script:PSGetSettings = DeSerialize-PSObject -Path $script:PSGetSettingsFilePath
+ }
+ else
+ {
+ $script:PSGetSettings = [ordered]@{}
+ }
+ }
+}
+
+function Set-ModuleSourcesVariable
+{
+ [CmdletBinding()]
+ param([switch]$Force)
+
+ if(-not $script:PSGetModuleSources -or $Force)
+ {
+ $isPersistRequired = $false
+ if(Microsoft.PowerShell.Management\Test-Path $script:PSGetModuleSourcesFilePath)
+ {
+ $script:PSGetModuleSources = DeSerialize-PSObject -Path $script:PSGetModuleSourcesFilePath
+ }
+ else
+ {
+ $script:PSGetModuleSources = [ordered]@{}
+
+ if(-not $script:PSGetModuleSources.Contains($Script:PSGalleryModuleSource))
+ {
+ $isPersistRequired = $true
+ $psgalleryLocation = Resolve-Location -Location $Script:PSGallerySourceUri `
+ -LocationParameterName 'SourceLocation' `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+
+ $scriptSourceLocation = Resolve-Location -Location $Script:PSGalleryScriptSourceUri `
+ -LocationParameterName 'ScriptSourceLocation' `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+ if($psgalleryLocation)
+ {
+ $result = Ping-Endpoint -Endpoint $Script:PSGalleryPublishUri -AllowAutoRedirect:$false
+ if ($result.ContainsKey($Script:ResponseUri) -and $result[$Script:ResponseUri])
+ {
+ $script:PSGalleryPublishUri = $result[$Script:ResponseUri]
+ }
+ $moduleSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
+ Name = $Script:PSGalleryModuleSource
+ SourceLocation = $psgalleryLocation
+ PublishLocation = $Script:PSGalleryPublishUri
+ ScriptSourceLocation = $scriptSourceLocation
+ ScriptPublishLocation = $Script:PSGalleryPublishUri
+ Trusted=$false
+ Registered=$true
+ InstallationPolicy = 'Untrusted'
+ PackageManagementProvider=$script:NuGetProviderName
+ ProviderOptions = @{}
+ })
+
+ $moduleSource.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepository")
+ $script:PSGetModuleSources.Add($Script:PSGalleryModuleSource, $moduleSource)
+ }
+ }
+ }
+
+ # Already registed repositories may not have the ScriptSourceLocation property, try to populate it from the existing SourceLocation
+ # Also populate the PublishLocation and ScriptPublishLocation from the SourceLocation if PublishLocation is empty/null.
+ #
+ $script:PSGetModuleSources.Keys | Microsoft.PowerShell.Core\ForEach-Object {
+ $moduleSource = $script:PSGetModuleSources[$_]
+
+ if(-not (Get-Member -InputObject $moduleSource -Name $script:ScriptSourceLocation))
+ {
+ $scriptSourceLocation = Get-ScriptSourceLocation -Location $moduleSource.SourceLocation
+
+ Microsoft.PowerShell.Utility\Add-Member -InputObject $script:PSGetModuleSources[$_] `
+ -MemberType NoteProperty `
+ -Name $script:ScriptSourceLocation `
+ -Value $scriptSourceLocation
+
+ if(Get-Member -InputObject $moduleSource -Name $script:PublishLocation)
+ {
+ if(-not $moduleSource.PublishLocation)
+ {
+ $script:PSGetModuleSources[$_].PublishLocation = Get-PublishLocation -Location $moduleSource.SourceLocation
+ }
+
+ Microsoft.PowerShell.Utility\Add-Member -InputObject $script:PSGetModuleSources[$_] `
+ -MemberType NoteProperty `
+ -Name $script:ScriptPublishLocation `
+ -Value $moduleSource.PublishLocation
+ }
+
+ $isPersistRequired = $true
+ }
+ }
+
+ if($isPersistRequired)
+ {
+ Save-ModuleSources
+ }
+ }
+}
+
+function Get-PackageManagementProviderName
+{
+ [CmdletBinding()]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $Location
+ )
+
+ $PackageManagementProviderName = $null
+ $loc = Get-LocationString -LocationUri $Location
+
+ $providers = PackageManagement\Get-PackageProvider | Where-Object { $_.Features.ContainsKey($script:SupportsPSModulesFeatureName) }
+
+ foreach($provider in $providers)
+ {
+ # Skip the PowerShellGet provider
+ if($provider.ProviderName -eq $script:PSModuleProviderName)
+ {
+ continue
+ }
+
+ $packageSource = Get-PackageSource -Location $loc -Provider $provider.ProviderName -ErrorAction SilentlyContinue
+
+ if($packageSource)
+ {
+ $PackageManagementProviderName = $provider.ProviderName
+ break
+ }
+ }
+
+ return $PackageManagementProviderName
+}
+
+function Get-ProviderName
+{
+ [CmdletBinding()]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [PSCustomObject]
+ $PSCustomObject
+ )
+
+ $providerName = $script:NuGetProviderName
+
+ if((Get-Member -InputObject $PSCustomObject -Name PackageManagementProvider))
+ {
+ $providerName = $PSCustomObject.PackageManagementProvider
+ }
+
+ return $providerName
+}
+
+function Get-DynamicParameters
+{
+ [CmdletBinding()]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $Location,
+
+ [Parameter(Mandatory=$true)]
+ [REF]
+ $PackageManagementProvider
+ )
+
+ $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
+ $dynamicOptions = $null
+
+ $loc = Get-LocationString -LocationUri $Location
+
+ if(-not $loc)
+ {
+ return $paramDictionary
+ }
+
+ # Ping and resolve the specified location
+ $loc = Resolve-Location -Location $loc `
+ -LocationParameterName 'Location' `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+ if(-not $loc)
+ {
+ return $paramDictionary
+ }
+
+ $providers = PackageManagement\Get-PackageProvider | Where-Object { $_.Features.ContainsKey($script:SupportsPSModulesFeatureName) }
+
+ if ($PackageManagementProvider.Value)
+ {
+ # Skip the PowerShellGet provider
+ if($PackageManagementProvider.Value -ne $script:PSModuleProviderName)
+ {
+ $SelectedProvider = $providers | Where-Object {$_.ProviderName -eq $PackageManagementProvider.Value}
+
+ if($SelectedProvider)
+ {
+ $res = Get-PackageSource -Location $loc -Provider $PackageManagementProvider.Value -ErrorAction SilentlyContinue
+
+ if($res)
+ {
+ $dynamicOptions = $SelectedProvider.DynamicOptions
+ }
+ }
+ }
+ }
+ else
+ {
+ $PackageManagementProvider.Value = Get-PackageManagementProviderName -Location $Location
+ if($PackageManagementProvider.Value)
+ {
+ $provider = $providers | Where-Object {$_.ProviderName -eq $PackageManagementProvider.Value}
+ $dynamicOptions = $provider.DynamicOptions
+ }
+ }
+
+ foreach ($option in $dynamicOptions)
+ {
+ # Skip the Destination parameter
+ if( $option.IsRequired -and
+ ($option.Name -eq "Destination") )
+ {
+ continue
+ }
+
+ $paramAttribute = New-Object System.Management.Automation.ParameterAttribute
+ $paramAttribute.Mandatory = $option.IsRequired
+
+ $message = $LocalizedData.DynamicParameterHelpMessage -f ($option.Name, $PackageManagementProvider.Value, $loc, $option.Name)
+ $paramAttribute.HelpMessage = $message
+
+ $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]
+ $attributeCollection.Add($paramAttribute)
+
+ $ageParam = New-Object System.Management.Automation.RuntimeDefinedParameter($option.Name,
+ $script:DynamicOptionTypeMap[$option.Type.value__],
+ $attributeCollection)
+ $paramDictionary.Add($option.Name, $ageParam)
+ }
+
+ return $paramDictionary
+}
+
+function New-PSGetItemInfo
+{
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ $SoftwareIdentity,
+
+ [Parameter()]
+ $PackageManagementProviderName,
+
+ [Parameter()]
+ [string]
+ $SourceLocation,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $Type,
+
+ [Parameter()]
+ [string]
+ $InstalledLocation,
+
+ [Parameter()]
+ [System.DateTime]
+ $InstalledDate,
+
+ [Parameter()]
+ [System.DateTime]
+ $UpdatedDate
+ )
+
+ foreach($swid in $SoftwareIdentity)
+ {
+
+ if($SourceLocation)
+ {
+ $sourceName = (Get-SourceName -Location $SourceLocation)
+ }
+ else
+ {
+ # First get the source name from the Metadata
+ # if not exists, get the source name from $swid.Source
+ # otherwise default to $swid.Source
+ $sourceName = (Get-First $swid.Metadata["SourceName"])
+
+ if(-not $sourceName)
+ {
+ $sourceName = (Get-SourceName -Location $swid.Source)
+ }
+
+ if(-not $sourceName)
+ {
+ $sourceName = $swid.Source
+ }
+
+ $SourceLocation = Get-SourceLocation -SourceName $sourceName
+ }
+
+ $published = (Get-First $swid.Metadata["published"])
+ $PublishedDate = New-Object System.DateTime
+
+ $InstalledDateString = (Get-First $swid.Metadata['installeddate'])
+ if(-not $InstalledDate -and $InstalledDateString)
+ {
+ $InstalledDate = New-Object System.DateTime
+ if(-not ([System.DateTime]::TryParse($InstalledDateString, ([ref]$InstalledDate))))
+ {
+ $InstalledDate = $null
+ }
+ }
+
+ $UpdatedDateString = (Get-First $swid.Metadata['updateddate'])
+ if(-not $UpdatedDate -and $UpdatedDateString)
+ {
+ $UpdatedDate = New-Object System.DateTime
+ if(-not ([System.DateTime]::TryParse($UpdatedDateString, ([ref]$UpdatedDate))))
+ {
+ $UpdatedDate = $null
+ }
+ }
+
+ $tags = (Get-First $swid.Metadata["tags"]) -split " "
+ $userTags = @()
+
+ $exportedDscResources = @()
+ $exportedRoleCapabilities = @()
+ $exportedCmdlets = @()
+ $exportedFunctions = @()
+ $exportedWorkflows = @()
+ $exportedCommands = @()
+
+ $exportedRoleCapabilities += (Get-First $swid.Metadata['RoleCapabilities']) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() }
+ $exportedDscResources += (Get-First $swid.Metadata["DscResources"]) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() }
+ $exportedCmdlets += (Get-First $swid.Metadata["Cmdlets"]) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() }
+ $exportedFunctions += (Get-First $swid.Metadata["Functions"]) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() }
+ $exportedWorkflows += (Get-First $swid.Metadata["Workflows"]) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() }
+ $exportedCommands += $exportedCmdlets + $exportedFunctions + $exportedWorkflows
+ $PSGetFormatVersion = $null
+
+ ForEach($tag in $tags)
+ {
+ if(-not $tag.Trim())
+ {
+ continue
+ }
+
+ $parts = $tag -split "_",2
+ if($parts.Count -ne 2)
+ {
+ $userTags += $tag
+ continue
+ }
+
+ Switch($parts[0])
+ {
+ $script:Command { $exportedCommands += $parts[1]; break }
+ $script:DscResource { $exportedDscResources += $parts[1]; break }
+ $script:Cmdlet { $exportedCmdlets += $parts[1]; break }
+ $script:Function { $exportedFunctions += $parts[1]; break }
+ $script:Workflow { $exportedWorkflows += $parts[1]; break }
+ $script:RoleCapability { $exportedRoleCapabilities += $parts[1]; break }
+ $script:PSGetFormatVersion { $PSGetFormatVersion = $parts[1]; break }
+ $script:Includes { break }
+ Default { $userTags += $tag; break }
+ }
+ }
+
+ $ArtifactDependencies = @()
+ Foreach ($dependencyString in $swid.Dependencies)
+ {
+ [Uri]$packageId = $null
+ if([Uri]::TryCreate($dependencyString, [System.UriKind]::Absolute, ([ref]$packageId)))
+ {
+ $segments = $packageId.Segments
+ $Version = $null
+ $DependencyName = $null
+ if ($segments)
+ {
+ $DependencyName = [Uri]::UnescapeDataString($segments[0].Trim('/', '\'))
+ $Version = if($segments.Count -gt 1){[Uri]::UnescapeDataString($segments[1])}
+ }
+
+ $dep = [ordered]@{
+ Name=$DependencyName
+ }
+
+ if($Version)
+ {
+ # Required/exact version is represented in NuGet as "[2.0]"
+ if ($Version -match "\[+[0-9.]+\]")
+ {
+ $dep["RequiredVersion"] = $Version.Trim('[', ']')
+ }
+ elseif ($Version -match "\[+[0-9., ]+\]")
+ {
+ # Minimum and Maximum version range is represented in NuGet as "[1.0, 2.0]"
+ $versionRange = $Version.Trim('[', ']') -split ',' | Microsoft.PowerShell.Core\Where-Object {$_}
+ if($versionRange -and $versionRange.count -eq 2)
+ {
+ $dep["MinimumVersion"] = $versionRange[0].Trim()
+ $dep["MaximumVersion"] = $versionRange[1].Trim()
+ }
+ }
+ elseif ($Version -match "\(+[0-9., ]+\]")
+ {
+ # Maximum version is represented in NuGet as "(, 2.0]"
+ $maximumVersion = $Version.Trim('(', ']') -split ',' | Microsoft.PowerShell.Core\Where-Object {$_}
+
+ if($maximumVersion)
+ {
+ $dep["MaximumVersion"] = $maximumVersion.Trim()
+ }
+ }
+ else
+ {
+ $dep['MinimumVersion'] = $Version
+ }
+ }
+
+ $dep["CanonicalId"]=$dependencyString
+
+ $ArtifactDependencies += $dep
+ }
+ }
+
+ $additionalMetadata = New-Object -TypeName System.Collections.Hashtable
+ foreach ( $key in $swid.Metadata.Keys.LocalName)
+ {
+ if (!$additionalMetadata.ContainsKey($key))
+ {
+ $additionalMetadata.Add($key, (Get-First $swid.Metadata[$key]) )
+ }
+ }
+
+ if($additionalMetadata.ContainsKey('ItemType'))
+ {
+ $Type = $additionalMetadata['ItemType']
+ }
+ elseif($userTags -contains 'PSModule')
+ {
+ $Type = $script:PSArtifactTypeModule
+ }
+ elseif($userTags -contains 'PSScript')
+ {
+ $Type = $script:PSArtifactTypeScript
+ }
+
+ $PSGetItemInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
+ Name = $swid.Name
+ Version = [Version]$swid.Version
+ Type = $Type
+ Description = (Get-First $swid.Metadata["description"])
+ Author = (Get-EntityName -SoftwareIdentity $swid -Role "author")
+ CompanyName = (Get-EntityName -SoftwareIdentity $swid -Role "owner")
+ Copyright = (Get-First $swid.Metadata["copyright"])
+ PublishedDate = if([System.DateTime]::TryParse($published, ([ref]$PublishedDate))){$PublishedDate};
+ InstalledDate = $InstalledDate;
+ UpdatedDate = $UpdatedDate;
+ LicenseUri = (Get-UrlFromSwid -SoftwareIdentity $swid -UrlName "license")
+ ProjectUri = (Get-UrlFromSwid -SoftwareIdentity $swid -UrlName "project")
+ IconUri = (Get-UrlFromSwid -SoftwareIdentity $swid -UrlName "icon")
+ Tags = $userTags
+
+ Includes = @{
+ DscResource = $exportedDscResources
+ Command = $exportedCommands
+ Cmdlet = $exportedCmdlets
+ Function = $exportedFunctions
+ Workflow = $exportedWorkflows
+ RoleCapability = $exportedRoleCapabilities
+ }
+
+ PowerShellGetFormatVersion=[Version]$PSGetFormatVersion
+
+ ReleaseNotes = (Get-First $swid.Metadata["releaseNotes"])
+
+ Dependencies = $ArtifactDependencies
+
+ RepositorySourceLocation = $SourceLocation
+ Repository = $sourceName
+ PackageManagementProvider = if($PackageManagementProviderName) { $PackageManagementProviderName } else { (Get-First $swid.Metadata["PackageManagementProvider"]) }
+
+ AdditionalMetadata = $additionalMetadata
+ })
+
+ if(-not $InstalledLocation)
+ {
+ $InstalledLocation = (Get-First $swid.Metadata[$script:InstalledLocation])
+ }
+
+ if($InstalledLocation)
+ {
+ Microsoft.PowerShell.Utility\Add-Member -InputObject $PSGetItemInfo -MemberType NoteProperty -Name $script:InstalledLocation -Value $InstalledLocation
+ }
+
+ $PSGetItemInfo.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepositoryItemInfo")
+ $PSGetItemInfo
+ }
+}
+
+function Get-SourceName
+{
+ [CmdletBinding()]
+ [OutputType("string")]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Location
+ )
+
+ Set-ModuleSourcesVariable
+
+ foreach($psModuleSource in $script:PSGetModuleSources.Values)
+ {
+ if(($psModuleSource.Name -eq $Location) -or
+ ($psModuleSource.SourceLocation -eq $Location) -or
+ ((Get-Member -InputObject $psModuleSource -Name $script:ScriptSourceLocation) -and
+ ($psModuleSource.ScriptSourceLocation -eq $Location)))
+ {
+ return $psModuleSource.Name
+ }
+ }
+}
+
+function Get-SourceLocation
+{
+ [CmdletBinding()]
+ [OutputType("string")]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $SourceName
+ )
+
+ Set-ModuleSourcesVariable
+
+ if($script:PSGetModuleSources.Contains($SourceName))
+ {
+ return $script:PSGetModuleSources[$SourceName].SourceLocation
+ }
+ else
+ {
+ return $SourceName
+ }
+}
+
+function Get-UrlFromSwid
+{
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ $SoftwareIdentity,
+
+ [Parameter(Mandatory=$true)]
+ $UrlName
+ )
+
+ foreach($link in $SoftwareIdentity.Links)
+ {
+ if( $link.Relationship -eq $UrlName)
+ {
+ return $link.HRef
+ }
+ }
+
+ return $null
+}
+
+function Get-EntityName
+{
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ $SoftwareIdentity,
+
+ [Parameter(Mandatory=$true)]
+ $Role
+ )
+
+ foreach( $entity in $SoftwareIdentity.Entities )
+ {
+ if( $entity.Role -eq $Role)
+ {
+ $entity.Name
+ }
+ }
+}
+
+function Install-NuGetClientBinaries
+{
+ [CmdletBinding()]
+ param
+ (
+ [parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [System.Management.Automation.PSCmdlet]
+ $CallerPSCmdlet,
+
+ [parameter()]
+ [switch]
+ $BootstrapNuGetExe,
+
+ [parameter()]
+ [switch]
+ $Force
+ )
+
+ if($script:NuGetProvider -and
+ (-not $BootstrapNuGetExe -or
+ ($script:NuGetExePath -and (Microsoft.PowerShell.Management\Test-Path -Path $script:NuGetExePath))))
+ {
+ return
+ }
+
+ $bootstrapNuGetProvider = (-not $script:NuGetProvider)
+
+ if($bootstrapNuGetProvider)
+ {
+ # Bootstrap the NuGet provider only if it is not available.
+ # By default PackageManagement loads the latest version of the NuGet provider.
+ $nugetProvider = PackageManagement\Get-PackageProvider -ErrorAction SilentlyContinue -WarningAction SilentlyContinue |
+ Microsoft.PowerShell.Core\Where-Object {
+ $_.Name -eq $script:NuGetProviderName -and
+ $_.Version -ge $script:NuGetProviderVersion
+ }
+ if($nugetProvider)
+ {
+ $script:NuGetProvider = $nugetProvider
+
+ $bootstrapNuGetProvider = $false
+ }
+ else
+ {
+ # User might have installed it in an another console or in the same process, check available NuGet providers and import the required provider.
+ $availableNugetProviders = PackageManagement\Get-PackageProvider -Name $script:NuGetProviderName `
+ -ListAvailable `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue |
+ Microsoft.PowerShell.Core\Where-Object {
+ $_.Name -eq $script:NuGetProviderName -and
+ $_.Version -ge $script:NuGetProviderVersion
+ }
+ if($availableNugetProviders)
+ {
+ # Force import ensures that nuget provider with minimum version got loaded.
+ $null = PackageManagement\Import-PackageProvider -Name $script:NuGetProviderName `
+ -MinimumVersion $script:NuGetProviderVersion `
+ -Force
+
+ $nugetProvider = PackageManagement\Get-PackageProvider -ErrorAction SilentlyContinue -WarningAction SilentlyContinue |
+ Microsoft.PowerShell.Core\Where-Object {
+ $_.Name -eq $script:NuGetProviderName -and
+ $_.Version -ge $script:NuGetProviderVersion
+ }
+ if($nugetProvider)
+ {
+ $script:NuGetProvider = $nugetProvider
+
+ $bootstrapNuGetProvider = $false
+ }
+ }
+ }
+ }
+
+ if($BootstrapNuGetExe -and
+ (-not $script:NuGetExePath -or
+ -not (Microsoft.PowerShell.Management\Test-Path -Path $script:NuGetExePath)))
+ {
+ $programDataExePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetProgramDataPath -ChildPath $script:NuGetExeName
+ $applocalDataExePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetAppLocalPath -ChildPath $script:NuGetExeName
+
+ # Check if NuGet.exe is available under one of the predefined PowerShellGet locations under ProgramData or LocalAppData
+ if(Microsoft.PowerShell.Management\Test-Path -Path $programDataExePath)
+ {
+ $script:NuGetExePath = $programDataExePath
+ $BootstrapNuGetExe = $false
+ }
+ elseif(Microsoft.PowerShell.Management\Test-Path -Path $applocalDataExePath)
+ {
+ $script:NuGetExePath = $applocalDataExePath
+ $BootstrapNuGetExe = $false
+ }
+ else
+ {
+ # Using Get-Command cmdlet, get the location of NuGet.exe if it is available under $env:PATH.
+ # NuGet.exe does not work if it is under $env:WINDIR, so skip it from the Get-Command results.
+ $nugetCmd = Microsoft.PowerShell.Core\Get-Command -Name $script:NuGetExeName `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue |
+ Microsoft.PowerShell.Core\Where-Object {
+ $_.Path -and
+ ((Microsoft.PowerShell.Management\Split-Path -Path $_.Path -Leaf) -eq $script:NuGetExeName) -and
+ (-not $_.Path.StartsWith($env:windir, [System.StringComparison]::OrdinalIgnoreCase))
+ } | Microsoft.PowerShell.Utility\Select-Object -First 1
+
+ if($nugetCmd -and $nugetCmd.Path)
+ {
+ $script:NuGetExePath = $nugetCmd.Path
+ $BootstrapNuGetExe = $false
+ }
+ }
+ }
+ else
+ {
+ # No need to bootstrap the NuGet.exe when $BootstrapNuGetExe is false or NuGet.exe path is already assigned.
+ $BootstrapNuGetExe = $false
+ }
+
+ # On Nano server we don't need NuGet.exe
+ if(-not $bootstrapNuGetProvider -and ($script:isNanoServer -or -not $BootstrapNuGetExe))
+ {
+ return
+ }
+
+ # We should prompt only once for bootstrapping the NuGet provider and/or NuGet.exe
+
+ # Should continue message for bootstrapping only NuGet provider
+ $shouldContinueQueryMessage = $LocalizedData.InstallNuGetProviderShouldContinueQuery -f @($script:NuGetProviderVersion,$script:NuGetBinaryProgramDataPath,$script:NuGetBinaryLocalAppDataPath)
+ $shouldContinueCaption = $LocalizedData.InstallNuGetProviderShouldContinueCaption
+
+ # Should continue message for bootstrapping both NuGet provider and NuGet.exe
+ if($bootstrapNuGetProvider -and $BootstrapNuGetExe)
+ {
+ $shouldContinueQueryMessage = $LocalizedData.InstallNuGetBinariesShouldContinueQuery2 -f @($script:NuGetProviderVersion,$script:NuGetBinaryProgramDataPath,$script:NuGetBinaryLocalAppDataPath, $script:PSGetProgramDataPath, $script:PSGetAppLocalPath)
+ $shouldContinueCaption = $LocalizedData.InstallNuGetBinariesShouldContinueCaption2
+ }
+ elseif($BootstrapNuGetExe)
+ {
+ # Should continue message for bootstrapping only NuGet.exe
+ $shouldContinueQueryMessage = $LocalizedData.InstallNuGetExeShouldContinueQuery -f ($script:PSGetProgramDataPath, $script:PSGetAppLocalPath)
+ $shouldContinueCaption = $LocalizedData.InstallNuGetExeShouldContinueCaption
+ }
+
+ if($Force -or $psCmdlet.ShouldContinue($shouldContinueQueryMessage, $shouldContinueCaption))
+ {
+ if($bootstrapNuGetProvider)
+ {
+ Write-Verbose -Message $LocalizedData.DownloadingNugetProvider
+
+ $scope = 'CurrentUser'
+ if(Test-RunningAsElevated)
+ {
+ $scope = 'AllUsers'
+ }
+
+ # Bootstrap the NuGet provider
+ $null = PackageManagement\Install-PackageProvider -Name $script:NuGetProviderName `
+ -MinimumVersion $script:NuGetProviderVersion `
+ -Scope $scope `
+ -Force
+
+ # Force import ensures that nuget provider with minimum version got loaded.
+ $null = PackageManagement\Import-PackageProvider -Name $script:NuGetProviderName `
+ -MinimumVersion $script:NuGetProviderVersion `
+ -Force
+
+ $nugetProvider = PackageManagement\Get-PackageProvider -Name $script:NuGetProviderName
+
+ if ($nugetProvider)
+ {
+ $script:NuGetProvider = $nugetProvider
+ }
+ }
+
+ if($BootstrapNuGetExe -and -not $script:isNanoServer)
+ {
+ Write-Verbose -Message $LocalizedData.DownloadingNugetExe
+
+ $nugetExeBasePath = $script:PSGetAppLocalPath
+
+ # if the current process is running with elevated privileges,
+ # install NuGet.exe to $script:PSGetProgramDataPath
+ if(Test-RunningAsElevated)
+ {
+ $nugetExeBasePath = $script:PSGetProgramDataPath
+ }
+
+ if(-not (Microsoft.PowerShell.Management\Test-Path -Path $nugetExeBasePath))
+ {
+ $null = Microsoft.PowerShell.Management\New-Item -Path $nugetExeBasePath `
+ -ItemType Directory -Force `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue `
+ -Confirm:$false -WhatIf:$false
+ }
+
+ $nugetExeFilePath = Microsoft.PowerShell.Management\Join-Path -Path $nugetExeBasePath -ChildPath $script:NuGetExeName
+
+ # Download the NuGet.exe from http://nuget.org/NuGet.exe
+ $null = Microsoft.PowerShell.Utility\Invoke-WebRequest -Uri $script:NuGetClientSourceURL `
+ -OutFile $nugetExeFilePath
+
+ if (Microsoft.PowerShell.Management\Test-Path -Path $nugetExeFilePath)
+ {
+ $script:NuGetExePath = $nugetExeFilePath
+ }
+ }
+ }
+
+ $message = $null
+ $errorId = $null
+ $failedToBootstrapNuGetProvider = $false
+ $failedToBootstrapNuGetExe = $false
+
+ if($bootstrapNuGetProvider -and -not $script:NuGetProvider)
+ {
+ $failedToBootstrapNuGetProvider = $true
+
+ $message = $LocalizedData.CouldNotInstallNuGetProvider -f @($script:NuGetProviderVersion)
+ $errorId = 'CouldNotInstallNuGetProvider'
+ }
+
+ if($BootstrapNuGetExe -and
+ (-not $script:NuGetExePath -or
+ -not (Microsoft.PowerShell.Management\Test-Path -Path $script:NuGetExePath)))
+ {
+ $failedToBootstrapNuGetExe = $true
+
+ $message = $LocalizedData.CouldNotInstallNuGetExe -f @($script:NuGetProviderVersion)
+ $errorId = 'CouldNotInstallNuGetExe'
+ }
+
+ # Change the error id and message if both NuGet provider and NuGet.exe are not installed.
+ if($failedToBootstrapNuGetProvider -and $failedToBootstrapNuGetExe)
+ {
+ $message = $LocalizedData.CouldNotInstallNuGetBinaries2 -f @($script:NuGetProviderVersion)
+ $errorId = 'CouldNotInstallNuGetBinaries'
+ }
+
+ # Throw the error message if one of the above conditions are met
+ if($message -and $errorId)
+ {
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId $errorId `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -ErrorCategory InvalidOperation
+ }
+}
+
+# Check if current user is running with elevated privileges
+function Test-RunningAsElevated
+{
+ [CmdletBinding()]
+ [OutputType([bool])]
+ Param()
+
+ $wid=[System.Security.Principal.WindowsIdentity]::GetCurrent()
+ $prp=new-object System.Security.Principal.WindowsPrincipal($wid)
+ $adm=[System.Security.Principal.WindowsBuiltInRole]::Administrator
+ return $prp.IsInRole($adm)
+}
+
+function Get-EscapedString
+{
+ [CmdletBinding()]
+ [OutputType([String])]
+ Param
+ (
+ [Parameter()]
+ [string]
+ $ElementValue
+ )
+
+ return [System.Security.SecurityElement]::Escape($ElementValue)
+}
+
+function ValidateAndGet-ScriptDependencies
+{
+ param(
+ [Parameter(Mandatory=$true)]
+ [string]
+ $Repository,
+
+ [Parameter(Mandatory=$true)]
+ [PSCustomObject]
+ $DependentScriptInfo,
+
+ [parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [System.Management.Automation.PSCmdlet]
+ $CallerPSCmdlet
+ )
+
+ $DependenciesDetails = @()
+
+ # Validate dependent modules
+ $RequiredModuleSpecification = $DependentScriptInfo.RequiredModules
+ if($RequiredModuleSpecification)
+ {
+ ForEach($moduleSpecification in $RequiredModuleSpecification)
+ {
+ $ModuleName = $moduleSpecification.Name
+
+ $FindModuleArguments = @{
+ Repository = $Repository
+ Verbose = $VerbosePreference
+ ErrorAction = 'SilentlyContinue'
+ WarningAction = 'SilentlyContinue'
+ Debug = $DebugPreference
+ }
+
+ if($DependentScriptInfo.ExternalModuleDependencies -contains $ModuleName)
+ {
+ Write-Verbose -Message ($LocalizedData.SkippedModuleDependency -f $ModuleName)
+
+ continue
+ }
+
+ $FindModuleArguments['Name'] = $ModuleName
+ $ReqModuleInfo = @{}
+ $ReqModuleInfo['Name'] = $ModuleName
+
+ if($moduleSpecification.Version)
+ {
+ $FindModuleArguments['MinimumVersion'] = $moduleSpecification.Version
+ $ReqModuleInfo['MinimumVersion'] = $moduleSpecification.Version
+ }
+ elseif((Get-Member -InputObject $moduleSpecification -Name RequiredVersion) -and $moduleSpecification.RequiredVersion)
+ {
+ $FindModuleArguments['RequiredVersion'] = $moduleSpecification.RequiredVersion
+ $ReqModuleInfo['RequiredVersion'] = $moduleSpecification.RequiredVersion
+ }
+
+ if((Get-Member -InputObject $moduleSpecification -Name MaximumVersion) -and $moduleSpecification.MaximumVersion)
+ {
+ # * can be specified in the MaximumVersion of a ModuleSpecification to convey that maximum possible value of that version part.
+ # like 1.0.0.* --> 1.0.0.99999999
+ # replace * with 99999999, PowerShell core takes care validating the * to be the last character in the version string.
+ $maximumVersion = $moduleSpecification.MaximumVersion -replace '\*','99999999'
+ $FindModuleArguments['MaximumVersion'] = $maximumVersion
+ $ReqModuleInfo['MaximumVersion'] = $maximumVersion
+ }
+
+ $psgetItemInfo = Find-Module @FindModuleArguments |
+ Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $ModuleName} |
+ Microsoft.PowerShell.Utility\Select-Object -Last 1
+
+ if(-not $psgetItemInfo)
+ {
+ $message = $LocalizedData.UnableToResolveScriptDependency -f ('module', $ModuleName, $DependentScriptInfo.Name, $Repository, 'ExternalModuleDependencies')
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "UnableToResolveScriptDependency" `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -ErrorCategory InvalidOperation
+ }
+
+ $DependenciesDetails += $ReqModuleInfo
+ }
+ }
+
+ # Validate dependent scrips
+ $RequiredScripts = $DependentScriptInfo.RequiredScripts
+ if($RequiredScripts)
+ {
+ ForEach($requiredScript in $RequiredScripts)
+ {
+ $FindScriptArguments = @{
+ Repository = $Repository
+ Verbose = $VerbosePreference
+ ErrorAction = 'SilentlyContinue'
+ WarningAction = 'SilentlyContinue'
+ Debug = $DebugPreference
+ }
+
+ if($DependentScriptInfo.ExternalScriptDependencies -contains $requiredScript)
+ {
+ Write-Verbose -Message ($LocalizedData.SkippedScriptDependency -f $requiredScript)
+
+ continue
+ }
+
+ $FindScriptArguments['Name'] = $requiredScript
+ $ReqScriptInfo = @{}
+ $ReqScriptInfo['Name'] = $requiredScript
+
+ $psgetItemInfo = Find-Script @FindScriptArguments |
+ Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $requiredScript} |
+ Microsoft.PowerShell.Utility\Select-Object -Last 1
+
+ if(-not $psgetItemInfo)
+ {
+ $message = $LocalizedData.UnableToResolveScriptDependency -f ('script', $requiredScript, $DependentScriptInfo.Name, $Repository, 'ExternalScriptDependencies')
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "UnableToResolveScriptDependency" `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -ErrorCategory InvalidOperation
+ }
+
+ $DependenciesDetails += $ReqScriptInfo
+ }
+ }
+
+ return $DependenciesDetails
+}
+
+function ValidateAndGet-RequiredModuleDetails
+{
+ param(
+ [Parameter()]
+ $ModuleManifestRequiredModules,
+
+ [Parameter()]
+ [PSModuleInfo[]]
+ $RequiredPSModuleInfos,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $Repository,
+
+ [Parameter(Mandatory=$true)]
+ [PSModuleInfo]
+ $DependentModuleInfo,
+
+ [parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [System.Management.Automation.PSCmdlet]
+ $CallerPSCmdlet
+ )
+
+ $RequiredModuleDetails = @()
+
+ if(-not $RequiredPSModuleInfos)
+ {
+ return $RequiredModuleDetails
+ }
+
+ if($ModuleManifestRequiredModules)
+ {
+ ForEach($RequiredModule in $ModuleManifestRequiredModules)
+ {
+ $ModuleName = $null
+ $VersionString = $null
+
+ $ReqModuleInfo = @{}
+
+ $FindModuleArguments = @{
+ Repository = $Repository
+ Verbose = $VerbosePreference
+ ErrorAction = 'SilentlyContinue'
+ WarningAction = 'SilentlyContinue'
+ Debug = $DebugPreference
+ }
+
+ # ModuleSpecification case
+ if($RequiredModule.GetType().ToString() -eq 'System.Collections.Hashtable')
+ {
+ $ModuleName = $RequiredModule.ModuleName
+
+ # Version format in NuSpec:
+ # "[2.0]" --> (== 2.0) Required Version
+ # "2.0" --> (>= 2.0) Minimum Version
+ if($RequiredModule.Keys -Contains "RequiredVersion")
+ {
+ $FindModuleArguments['RequiredVersion'] = $RequiredModule.RequiredVersion
+ $ReqModuleInfo['RequiredVersion'] = $RequiredModule.RequiredVersion
+ }
+ elseif($RequiredModule.Keys -Contains "ModuleVersion")
+ {
+ $FindModuleArguments['MinimumVersion'] = $RequiredModule.ModuleVersion
+ $ReqModuleInfo['MinimumVersion'] = $RequiredModule.ModuleVersion
+ }
+
+ if($RequiredModule.Keys -Contains 'MaximumVersion' -and $RequiredModule.MaximumVersion)
+ {
+ # * can be specified in the MaximumVersion of a ModuleSpecification to convey that maximum possible value of that version part.
+ # like 1.0.0.* --> 1.0.0.99999999
+ # replace * with 99999999, PowerShell core takes care validating the * to be the last character in the version string.
+ $maximumVersion = $RequiredModule.MaximumVersion -replace '\*','99999999'
+
+ $FindModuleArguments['MaximumVersion'] = $maximumVersion
+ $ReqModuleInfo['MaximumVersion'] = $maximumVersion
+ }
+ }
+ else
+ {
+ # Just module name was specified
+ $ModuleName = $RequiredModule.ToString()
+ }
+
+ if((Get-ExternalModuleDependencies -PSModuleInfo $DependentModuleInfo) -contains $ModuleName)
+ {
+ Write-Verbose -Message ($LocalizedData.SkippedModuleDependency -f $ModuleName)
+
+ continue
+ }
+
+ # Skip this module name if it's name is not in $RequiredPSModuleInfos.
+ # This is required when a ModuleName is part of the NestedModules list of the actual module.
+ # $ModuleName is packaged as part of the actual module When $RequiredPSModuleInfos doesn't contain it's name.
+ if($RequiredPSModuleInfos.Name -notcontains $ModuleName)
+ {
+ continue
+ }
+
+ $ReqModuleInfo['Name'] = $ModuleName
+
+ # Add the dependency only if the module is available on the gallery
+ # Otherwise Module installation will fail as all required modules need to be available on
+ # the same Repository
+ $FindModuleArguments['Name'] = $ModuleName
+
+ $psgetItemInfo = Find-Module @FindModuleArguments |
+ Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $ModuleName} |
+ Microsoft.PowerShell.Utility\Select-Object -Last 1
+
+ if(-not $psgetItemInfo)
+ {
+ $message = $LocalizedData.UnableToResolveModuleDependency -f ($ModuleName, $DependentModuleInfo.Name, $Repository, $ModuleName, $Repository, $ModuleName, $ModuleName)
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "UnableToResolveModuleDependency" `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -ErrorCategory InvalidOperation
+ }
+
+ $RequiredModuleDetails += $ReqModuleInfo
+ }
+ }
+ else
+ {
+ # If Import-LocalizedData cmdlet was failed to read the .psd1 contents
+ # use provided $RequiredPSModuleInfos (PSModuleInfo.RequiredModules or PSModuleInfo.NestedModules of the actual dependent module)
+
+ $FindModuleArguments = @{
+ Repository = $Repository
+ Verbose = $VerbosePreference
+ ErrorAction = 'SilentlyContinue'
+ WarningAction = 'SilentlyContinue'
+ Debug = $DebugPreference
+ }
+
+ ForEach($RequiredModuleInfo in $RequiredPSModuleInfos)
+ {
+ $ModuleName = $requiredModuleInfo.Name
+
+ if((Get-ExternalModuleDependencies -PSModuleInfo $DependentModuleInfo) -contains $ModuleName)
+ {
+ Write-Verbose -Message ($LocalizedData.SkippedModuleDependency -f $ModuleName)
+
+ continue
+ }
+
+ $FindModuleArguments['Name'] = $ModuleName
+ $FindModuleArguments['MinimumVersion'] = $requiredModuleInfo.Version
+
+ $psgetItemInfo = Find-Module @FindModuleArguments |
+ Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $ModuleName} |
+ Microsoft.PowerShell.Utility\Select-Object -Last 1
+
+ if(-not $psgetItemInfo)
+ {
+ $message = $LocalizedData.UnableToResolveModuleDependency -f ($ModuleName, $DependentModuleInfo.Name, $Repository, $ModuleName, $Repository, $ModuleName, $ModuleName)
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "UnableToResolveModuleDependency" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation
+ }
+
+ $RequiredModuleDetails += @{
+ Name=$_.Name
+ MinimumVersion=$_.Version
+ }
+ }
+ }
+
+ return $RequiredModuleDetails
+}
+
+function Get-ExternalModuleDependencies
+{
+ Param (
+ [Parameter(Mandatory=$true)]
+ [PSModuleInfo]
+ $PSModuleInfo
+ )
+
+ if($PSModuleInfo.PrivateData -and
+ ($PSModuleInfo.PrivateData.GetType().ToString() -eq "System.Collections.Hashtable") -and
+ $PSModuleInfo.PrivateData["PSData"] -and
+ ($PSModuleInfo.PrivateData["PSData"].GetType().ToString() -eq "System.Collections.Hashtable") -and
+ $PSModuleInfo.PrivateData.PSData['ExternalModuleDependencies'] -and
+ ($PSModuleInfo.PrivateData.PSData['ExternalModuleDependencies'].GetType().ToString() -eq "System.Object[]")
+ )
+ {
+ return $PSModuleInfo.PrivateData.PSData.ExternalModuleDependencies
+ }
+}
+
+function Get-ModuleDependencies
+{
+ Param (
+ [Parameter(Mandatory=$true)]
+ [PSModuleInfo]
+ $PSModuleInfo,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $Repository,
+
+ [parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [System.Management.Automation.PSCmdlet]
+ $CallerPSCmdlet
+ )
+
+ $DependentModuleDetails = @()
+
+ if($PSModuleInfo.RequiredModules -or $PSModuleInfo.NestedModules)
+ {
+ # PSModuleInfo.RequiredModules doesn't provide the RequiredVersion info from the ModuleSpecification
+ # Reading the contents of module manifest file using Import-LocalizedData cmdlet
+ # to get the RequiredVersion details.
+ Import-LocalizedData -BindingVariable ModuleManifestHashTable `
+ -FileName (Microsoft.PowerShell.Management\Split-Path $PSModuleInfo.Path -Leaf) `
+ -BaseDirectory $PSModuleInfo.ModuleBase `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+
+ if($PSModuleInfo.RequiredModules)
+ {
+ $ModuleManifestRequiredModules = $null
+
+ if($ModuleManifestHashTable)
+ {
+ $ModuleManifestRequiredModules = $ModuleManifestHashTable.RequiredModules
+ }
+
+
+ $DependentModuleDetails += ValidateAndGet-RequiredModuleDetails -ModuleManifestRequiredModules $ModuleManifestRequiredModules `
+ -RequiredPSModuleInfos $PSModuleInfo.RequiredModules `
+ -Repository $Repository `
+ -DependentModuleInfo $PSModuleInfo `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -Verbose:$VerbosePreference `
+ -Debug:$DebugPreference
+ }
+
+ if($PSModuleInfo.NestedModules)
+ {
+ $ModuleManifestRequiredModules = $null
+
+ if($ModuleManifestHashTable)
+ {
+ $ModuleManifestRequiredModules = $ModuleManifestHashTable.NestedModules
+ }
+
+ # A nested module is be considered as a dependency
+ # 1) whose module base is not under the specified module base OR
+ # 2) whose module base is under the specified module base and it's path doesn't exists
+ #
+ $RequiredPSModuleInfos = $PSModuleInfo.NestedModules | Microsoft.PowerShell.Core\Where-Object {
+ -not $_.ModuleBase.StartsWith($PSModuleInfo.ModuleBase, [System.StringComparison]::OrdinalIgnoreCase) -or
+ -not $_.Path -or
+ -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $_.Path)
+ }
+
+ $DependentModuleDetails += ValidateAndGet-RequiredModuleDetails -ModuleManifestRequiredModules $ModuleManifestRequiredModules `
+ -RequiredPSModuleInfos $RequiredPSModuleInfos `
+ -Repository $Repository `
+ -DependentModuleInfo $PSModuleInfo `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -Verbose:$VerbosePreference `
+ -Debug:$DebugPreference
+ }
+ }
+
+ return $DependentModuleDetails
+}
+
+function Publish-PSArtifactUtility
+{
+ [CmdletBinding(PositionalBinding=$false)]
+ Param
+ (
+ [Parameter(Mandatory=$true, ParameterSetName='PublishModule')]
+ [ValidateNotNullOrEmpty()]
+ [PSModuleInfo]
+ $PSModuleInfo,
+
+ [Parameter(Mandatory=$true, ParameterSetName='PublishScript')]
+ [ValidateNotNullOrEmpty()]
+ [PSCustomObject]
+ $PSScriptInfo,
+
+ [Parameter(Mandatory=$true, ParameterSetName='PublishModule')]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $ManifestPath,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Destination,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Repository,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $NugetApiKey,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $NugetPackageRoot,
+
+ [Parameter(ParameterSetName='PublishModule')]
+ [Version]
+ $FormatVersion,
+
+ [Parameter(ParameterSetName='PublishModule')]
+ [string]
+ $ReleaseNotes,
+
+ [Parameter(ParameterSetName='PublishModule')]
+ [string[]]
+ $Tags,
+
+ [Parameter(ParameterSetName='PublishModule')]
+ [Uri]
+ $LicenseUri,
+
+ [Parameter(ParameterSetName='PublishModule')]
+ [Uri]
+ $IconUri,
+
+ [Parameter(ParameterSetName='PublishModule')]
+ [Uri]
+ $ProjectUri
+ )
+
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe
+
+ $PSArtifactType = $script:PSArtifactTypeModule
+ $Name = $null
+ $Description = $null
+ $Version = $null
+ $Author = $null
+ $CompanyName = $null
+ $Copyright = $null
+
+ if($PSModuleInfo)
+ {
+ $Name = $PSModuleInfo.Name
+ $Description = $PSModuleInfo.Description
+ $Version = $PSModuleInfo.Version
+ $Author = $PSModuleInfo.Author
+ $CompanyName = $PSModuleInfo.CompanyName
+ $Copyright = $PSModuleInfo.Copyright
+
+ if($PSModuleInfo.PrivateData -and
+ ($PSModuleInfo.PrivateData.GetType().ToString() -eq "System.Collections.Hashtable") -and
+ $PSModuleInfo.PrivateData["PSData"] -and
+ ($PSModuleInfo.PrivateData["PSData"].GetType().ToString() -eq "System.Collections.Hashtable")
+ )
+ {
+ if( -not $Tags -and $PSModuleInfo.PrivateData.PSData["Tags"])
+ {
+ $Tags = $PSModuleInfo.PrivateData.PSData.Tags
+ }
+
+ if( -not $ReleaseNotes -and $PSModuleInfo.PrivateData.PSData["ReleaseNotes"])
+ {
+ $ReleaseNotes = $PSModuleInfo.PrivateData.PSData.ReleaseNotes
+ }
+
+ if( -not $LicenseUri -and $PSModuleInfo.PrivateData.PSData["LicenseUri"])
+ {
+ $LicenseUri = $PSModuleInfo.PrivateData.PSData.LicenseUri
+ }
+
+ if( -not $IconUri -and $PSModuleInfo.PrivateData.PSData["IconUri"])
+ {
+ $IconUri = $PSModuleInfo.PrivateData.PSData.IconUri
+ }
+
+ if( -not $ProjectUri -and $PSModuleInfo.PrivateData.PSData["ProjectUri"])
+ {
+ $ProjectUri = $PSModuleInfo.PrivateData.PSData.ProjectUri
+ }
+ }
+ }
+ else
+ {
+ $PSArtifactType = $script:PSArtifactTypeScript
+
+ $Name = $PSScriptInfo.Name
+ $Description = $PSScriptInfo.Description
+ $Version = $PSScriptInfo.Version
+ $Author = $PSScriptInfo.Author
+ $CompanyName = $PSScriptInfo.CompanyName
+ $Copyright = $PSScriptInfo.Copyright
+
+ if($PSScriptInfo.'Tags')
+ {
+ $Tags = $PSScriptInfo.Tags
+ }
+
+ if($PSScriptInfo.'ReleaseNotes')
+ {
+ $ReleaseNotes = $PSScriptInfo.ReleaseNotes
+ }
+
+ if($PSScriptInfo.'LicenseUri')
+ {
+ $LicenseUri = $PSScriptInfo.LicenseUri
+ }
+
+ if($PSScriptInfo.'IconUri')
+ {
+ $IconUri = $PSScriptInfo.IconUri
+ }
+
+ if($PSScriptInfo.'ProjectUri')
+ {
+ $ProjectUri = $PSScriptInfo.ProjectUri
+ }
+ }
+
+
+ # Add PSModule and PSGet format version tags
+ if(-not $Tags)
+ {
+ $Tags = @()
+ }
+
+ if($FormatVersion)
+ {
+ $Tags += "$($script:PSGetFormatVersion)_$FormatVersion"
+ }
+
+ $DependentModuleDetails = @()
+
+ if($PSScriptInfo)
+ {
+ $Tags += "PSScript"
+
+ if($PSScriptInfo.DefinedCommands)
+ {
+ if($PSScriptInfo.DefinedFunctions)
+ {
+ $Tags += "$($script:Includes)_Function"
+ $Tags += $PSScriptInfo.DefinedFunctions | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" }
+ }
+
+ if($PSScriptInfo.DefinedWorkflows)
+ {
+ $Tags += "$($script:Includes)_Workflow"
+ $Tags += $PSScriptInfo.DefinedWorkflows | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Workflow)_$_" }
+ }
+
+ $Tags += $PSScriptInfo.DefinedCommands | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" }
+ }
+
+ # Populate the dependencies elements from RequiredModules and RequiredScripts
+ #
+ $DependentModuleDetails += ValidateAndGet-ScriptDependencies -Repository $Repository `
+ -DependentScriptInfo $PSScriptInfo `
+ -CallerPSCmdlet $PSCmdlet `
+ -Verbose:$VerbosePreference `
+ -Debug:$DebugPreference
+ }
+ else
+ {
+ $Tags += "PSModule"
+
+ Import-LocalizedData -BindingVariable ModuleManifestHashTable `
+ -FileName (Microsoft.PowerShell.Management\Split-Path $ManifestPath -Leaf) `
+ -BaseDirectory (Microsoft.PowerShell.Management\Split-Path $ManifestPath -Parent) `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+
+
+ if($PSModuleInfo.ExportedCommands.Count)
+ {
+ if($PSModuleInfo.ExportedCmdlets.Count)
+ {
+ $Tags += "$($script:Includes)_Cmdlet"
+ $Tags += $PSModuleInfo.ExportedCmdlets.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Cmdlet)_$_" }
+
+ #if CmdletsToExport field in manifest file is "*", we suggest the user to include all those cmdlets for best practice
+ if($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('CmdletsToExport') -and ($ModuleManifestHashTable.CmdletsToExport -eq "*"))
+ {
+ $WarningMessage = $LocalizedData.ShouldIncludeCmdletsToExport -f ($ManifestPath)
+ Write-Warning -Message $WarningMessage
+ }
+ }
+
+ if($PSModuleInfo.ExportedFunctions.Count)
+ {
+ $Tags += "$($script:Includes)_Function"
+ $Tags += $PSModuleInfo.ExportedFunctions.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" }
+
+ if($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('FunctionsToExport') -and ($ModuleManifestHashTable.FunctionsToExport -eq "*"))
+ {
+ $WarningMessage = $LocalizedData.ShouldIncludeFunctionsToExport -f ($ManifestPath)
+ Write-Warning -Message $WarningMessage
+ }
+ }
+
+ $Tags += $PSModuleInfo.ExportedCommands.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" }
+ }
+
+ $dscResourceNames = Get-ExportedDscResources -PSModuleInfo $PSModuleInfo
+ if($dscResourceNames)
+ {
+ $Tags += "$($script:Includes)_DscResource"
+
+ $Tags += $dscResourceNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:DscResource)_$_" }
+
+ #If DscResourcesToExport is commented out or "*" is used, we will write-warning
+ if($ModuleManifestHashTable -and
+ ($ModuleManifestHashTable.ContainsKey("DscResourcesToExport") -and
+ $ModuleManifestHashTable.DscResourcesToExport -eq "*") -or
+ -not $ModuleManifestHashTable.ContainsKey("DscResourcesToExport"))
+ {
+ $WarningMessage = $LocalizedData.ShouldIncludeDscResourcesToExport -f ($ManifestPath)
+ Write-Warning -Message $WarningMessage
+ }
+ }
+
+ $RoleCapabilityNames = Get-AvailableRoleCapabilityName -PSModuleInfo $PSModuleInfo
+ if($RoleCapabilityNames)
+ {
+ $Tags += "$($script:Includes)_RoleCapability"
+
+ $Tags += $RoleCapabilityNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:RoleCapability)_$_" }
+ }
+
+ # Populate the module dependencies elements from RequiredModules and
+ # NestedModules properties of the current PSModuleInfo
+ $DependentModuleDetails = Get-ModuleDependencies -PSModuleInfo $PSModuleInfo `
+ -Repository $Repository `
+ -CallerPSCmdlet $PSCmdlet `
+ -Verbose:$VerbosePreference `
+ -Debug:$DebugPreference
+ }
+
+ $dependencies = @()
+ ForEach($Dependency in $DependentModuleDetails)
+ {
+ $ModuleName = $Dependency.Name
+ $VersionString = $null
+
+ # Version format in NuSpec:
+ # "[2.0]" --> (== 2.0) Required Version
+ # "2.0" --> (>= 2.0) Minimum Version
+ #
+ # When only MaximumVersion is specified in the ModuleSpecification
+ # (,1.0] = x <= 1.0
+ #
+ # When both Minimum and Maximum versions are specified in the ModuleSpecification
+ # [1.0,2.0] = 1.0 <= x <= 2.0
+
+ if($Dependency.Keys -Contains "RequiredVersion")
+ {
+ $VersionString = "[$($Dependency.RequiredVersion)]"
+ }
+ elseif($Dependency.Keys -Contains 'MinimumVersion' -and $Dependency.Keys -Contains 'MaximumVersion')
+ {
+ $VersionString = "[$($Dependency.MinimumVersion),$($Dependency.MaximumVersion)]"
+ }
+ elseif($Dependency.Keys -Contains 'MaximumVersion')
+ {
+ $VersionString = "(,$($Dependency.MaximumVersion)]"
+ }
+ elseif($Dependency.Keys -Contains 'MinimumVersion')
+ {
+ $VersionString = "$($Dependency.MinimumVersion)"
+ }
+
+ $dependencies += ""
+ }
+
+ # Populate the nuspec elements
+ $nuspec = @"
+
+
+
+ $(Get-EscapedString -ElementValue "$Name")
+ $($Version)
+ $(Get-EscapedString -ElementValue "$Author")
+ $(Get-EscapedString -ElementValue "$CompanyName")
+ $(Get-EscapedString -ElementValue "$Description")
+ $(Get-EscapedString -ElementValue "$ReleaseNotes")
+ $(Get-EscapedString -ElementValue "$Copyright")
+ $(if($Tags){ Get-EscapedString -ElementValue ($Tags -join ' ')})
+ $(if($LicenseUri){
+ "$(Get-EscapedString -ElementValue "$LicenseUri")
+ true"
+ })
+ $(if($ProjectUri){
+ "$(Get-EscapedString -ElementValue "$ProjectUri")"
+ })
+ $(if($IconUri){
+ "$(Get-EscapedString -ElementValue "$IconUri")"
+ })
+
+ $dependencies
+
+
+
+"@
+
+ $NupkgPath = "$NugetPackageRoot\$Name.$($Version.ToString()).nupkg"
+ $NuspecPath = "$NugetPackageRoot\$Name.nuspec"
+ $tempErrorFile = $null
+ $tempOutputFile = $null
+
+ try
+ {
+ # Remove existing nuspec and nupkg files
+ Microsoft.PowerShell.Management\Remove-Item $NupkgPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
+ Microsoft.PowerShell.Management\Remove-Item $NuspecPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
+
+ Microsoft.PowerShell.Management\Set-Content -Value $nuspec -Path $NuspecPath
+
+ # Create .nupkg file
+ $output = & $script:NuGetExePath pack $NuspecPath -OutputDirectory $NugetPackageRoot
+ if($LASTEXITCODE)
+ {
+ if($PSArtifactType -eq $script:PSArtifactTypeModule)
+ {
+ $message = $LocalizedData.FailedToCreateCompressedModule -f ($output)
+ $errorId = "FailedToCreateCompressedModule"
+ }
+ else
+ {
+ $message = $LocalizedData.FailedToCreateCompressedScript -f ($output)
+ $errorId = "FailedToCreateCompressedScript"
+ }
+
+ Write-Error -Message $message -ErrorId $errorId -Category InvalidOperation
+ return
+ }
+
+ # Publish the .nupkg to gallery
+ $tempErrorFile = Microsoft.PowerShell.Management\Join-Path -Path $nugetPackageRoot -ChildPath "TempPublishError.txt"
+ $tempOutputFile = Microsoft.PowerShell.Management\Join-Path -Path $nugetPackageRoot -ChildPath "TempPublishOutput.txt"
+
+ Microsoft.PowerShell.Management\Start-Process -FilePath "$script:NuGetExePath" `
+ -ArgumentList @('push', $NupkgPath, '-source', $Destination, '-NonInteractive', '-ApiKey', $NugetApiKey) `
+ -RedirectStandardError $tempErrorFile `
+ -RedirectStandardOutput $tempOutputFile `
+ -NoNewWindow `
+ -Wait
+
+ $errorMsg = Microsoft.PowerShell.Management\Get-Content -Path $tempErrorFile -Raw
+
+ if($errorMsg)
+ {
+ if($PSArtifactType -eq $script:PSArtifactTypeModule)
+ {
+ $message = $LocalizedData.FailedToPublish -f ($Name,$errorMsg)
+ $errorId = "FailedToPublishTheModule"
+ }
+ else
+ {
+ $message = $LocalizedData.FailedToPublishScript -f ($Name,$errorMsg)
+ $errorId = "FailedToPublishTheScript"
+ }
+
+ Write-Error -Message $message -ErrorId $errorId -Category InvalidOperation
+ }
+ else
+ {
+ if($PSArtifactType -eq $script:PSArtifactTypeModule)
+ {
+ $message = $LocalizedData.PublishedSuccessfully -f ($Name, $Destination, $Name)
+ }
+ else
+ {
+ $message = $LocalizedData.PublishedScriptSuccessfully -f ($Name, $Destination, $Name)
+ }
+
+ Write-Verbose -Message $message
+ }
+ }
+ finally
+ {
+ if($NupkgPath -and (Test-Path -Path $NupkgPath -PathType Leaf))
+ {
+ Microsoft.PowerShell.Management\Remove-Item $NupkgPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
+ }
+
+ if($NuspecPath -and (Test-Path -Path $NuspecPath -PathType Leaf))
+ {
+ Microsoft.PowerShell.Management\Remove-Item $NuspecPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
+ }
+
+ if($tempErrorFile -and (Test-Path -Path $tempErrorFile -PathType Leaf))
+ {
+ Microsoft.PowerShell.Management\Remove-Item $tempErrorFile -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
+ }
+
+ if($tempOutputFile -and (Test-Path -Path $tempOutputFile -PathType Leaf))
+ {
+ Microsoft.PowerShell.Management\Remove-Item $tempOutputFile -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
+ }
+ }
+}
+
+function ValidateAndAdd-PSScriptInfoEntry
+{
+ [CmdletBinding()]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [PSCustomObject]
+ $PSScriptInfo,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $PropertyName,
+
+ [Parameter()]
+ $PropertyValue,
+
+ [parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [System.Management.Automation.PSCmdlet]
+ $CallerPSCmdlet
+ )
+
+ $Value = $PropertyValue
+ $KeyName = $PropertyName
+
+ # return if $KeyName value is not null in $PSScriptInfo
+ if(-not $value -or -not $KeyName -or (Get-Member -InputObject $PSScriptInfo -Name $KeyName) -and $PSScriptInfo."$KeyName")
+ {
+ return
+ }
+
+ switch($PropertyName)
+ {
+ # Validate the property value and also use proper key name as users can specify the property name in any case.
+ $script:Version {
+ $KeyName = $script:Version
+
+ [Version]$Version = $null
+
+ if([System.Version]::TryParse($Value, ([ref]$Version)))
+ {
+ $Value = $Version
+ }
+ else
+ {
+ $message = $LocalizedData.InvalidVersion -f ($Value)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidVersion" `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Value
+ return
+ }
+ break
+ }
+
+ $script:Author { $KeyName = $script:Author }
+
+ $script:Guid {
+ $KeyName = $script:Guid
+
+ [Guid]$guid = [System.Guid]::Empty
+ if([System.Guid]::TryParse($Value, ([ref]$guid)))
+ {
+ $Value = $guid
+ }
+ else
+ {
+ $message = $LocalizedData.InvalidGuid -f ($Value)
+ ThrowError -ExceptionName 'System.ArgumentException' `
+ -ExceptionMessage $message `
+ -ErrorId 'InvalidGuid' `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Value
+ return
+ }
+
+ break
+ }
+
+ $script:Description { $KeyName = $script:Description }
+
+ $script:CompanyName { $KeyName = $script:CompanyName }
+
+ $script:Copyright { $KeyName = $script:Copyright }
+
+ $script:Tags {
+ $KeyName = $script:Tags
+ $Value = $Value -split '[,\s+]' | Microsoft.PowerShell.Core\Where-Object {$_}
+ break
+ }
+
+ $script:LicenseUri {
+ $KeyName = $script:LicenseUri
+ if(-not (Test-WebUri -Uri $Value))
+ {
+ $message = $LocalizedData.InvalidWebUri -f ($LicenseUri, "LicenseUri")
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidWebUri" `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Value
+ return
+ }
+
+ $Value = [Uri]$Value
+ }
+
+ $script:ProjectUri {
+ $KeyName = $script:ProjectUri
+ if(-not (Test-WebUri -Uri $Value))
+ {
+ $message = $LocalizedData.InvalidWebUri -f ($ProjectUri, "ProjectUri")
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidWebUri" `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Value
+ return
+ }
+
+ $Value = [Uri]$Value
+ }
+
+ $script:IconUri {
+ $KeyName = $script:IconUri
+ if(-not (Test-WebUri -Uri $Value))
+ {
+ $message = $LocalizedData.InvalidWebUri -f ($IconUri, "IconUri")
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidWebUri" `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Value
+ return
+ }
+
+ $Value = [Uri]$Value
+ }
+
+ $script:ExternalModuleDependencies {
+ $KeyName = $script:ExternalModuleDependencies
+ $Value = $Value -split '[,\s+]' | Microsoft.PowerShell.Core\Where-Object {$_}
+ }
+
+ $script:ReleaseNotes { $KeyName = $script:ReleaseNotes }
+
+ $script:RequiredModules { $KeyName = $script:RequiredModules }
+
+ $script:RequiredScripts {
+ $KeyName = $script:RequiredScripts
+ $Value = $Value -split '[,\s+]' | Microsoft.PowerShell.Core\Where-Object {$_}
+ }
+
+ $script:ExternalScriptDependencies {
+ $KeyName = $script:ExternalScriptDependencies
+ $Value = $Value -split '[,\s+]' | Microsoft.PowerShell.Core\Where-Object {$_}
+ }
+
+ $script:DefinedCommands { $KeyName = $script:DefinedCommands }
+
+ $script:DefinedFunctions { $KeyName = $script:DefinedFunctions }
+
+ $script:DefinedWorkflows { $KeyName = $script:DefinedWorkflows }
+ }
+
+ Microsoft.PowerShell.Utility\Add-Member -InputObject $PSScriptInfo `
+ -MemberType NoteProperty `
+ -Name $KeyName `
+ -Value $Value `
+ -Force
+}
+
+function Get-ExportedDscResources
+{
+ [CmdletBinding(PositionalBinding=$false)]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [PSModuleInfo]
+ $PSModuleInfo
+ )
+
+ $dscResources = @()
+
+ if(Get-Command -Name Get-DscResource -Module PSDesiredStateConfiguration -ErrorAction SilentlyContinue)
+ {
+ $OldPSModulePath = $env:PSModulePath
+
+ try
+ {
+ $env:PSModulePath = Join-Path -Path $PSHOME -ChildPath "Modules"
+ $env:PSModulePath = "$env:PSModulePath;$(Split-Path -Path $PSModuleInfo.ModuleBase -Parent)"
+
+ $dscResources = PSDesiredStateConfiguration\Get-DscResource -ErrorAction SilentlyContinue -WarningAction SilentlyContinue |
+ Microsoft.PowerShell.Core\ForEach-Object {
+ if($_.Module -and ($_.Module.Name -eq $PSModuleInfo.Name))
+ {
+ $_.Name
+ }
+ }
+ }
+ finally
+ {
+ $env:PSModulePath = $OldPSModulePath
+ }
+ }
+ else
+ {
+ $dscResourcesDir = Microsoft.PowerShell.Management\Join-Path -Path $PSModuleInfo.ModuleBase -ChildPath "DscResources"
+ if(Microsoft.PowerShell.Management\Test-Path $dscResourcesDir)
+ {
+ $dscResources = Microsoft.PowerShell.Management\Get-ChildItem -Path $dscResourcesDir -Directory -Name
+ }
+ }
+
+ return $dscResources
+}
+
+function Get-AvailableRoleCapabilityName
+{
+ [CmdletBinding(PositionalBinding=$false)]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [PSModuleInfo]
+ $PSModuleInfo
+ )
+
+ $RoleCapabilityNames = @()
+
+ $RoleCapabilitiesDir = Microsoft.PowerShell.Management\Join-Path -Path $PSModuleInfo.ModuleBase -ChildPath 'RoleCapabilities'
+ if(Microsoft.PowerShell.Management\Test-Path -Path $RoleCapabilitiesDir -PathType Container)
+ {
+ $RoleCapabilityNames = Microsoft.PowerShell.Management\Get-ChildItem -Path $RoleCapabilitiesDir `
+ -Name -Filter *.psrc |
+ ForEach-Object {[System.IO.Path]::GetFileNameWithoutExtension($_)}
+ }
+
+ return $RoleCapabilityNames
+}
+
+function Get-LocationString
+{
+ [CmdletBinding(PositionalBinding=$false)]
+ Param
+ (
+ [Parameter()]
+ [Uri]
+ $LocationUri
+ )
+
+ $LocationString = $null
+
+ if($LocationUri)
+ {
+ if($LocationUri.Scheme -eq 'file')
+ {
+ $LocationString = $LocationUri.OriginalString
+ }
+ elseif($LocationUri.AbsoluteUri)
+ {
+ $LocationString = $LocationUri.AbsoluteUri
+ }
+ else
+ {
+ $LocationString = $LocationUri.ToString()
+ }
+ }
+
+ return $LocationString
+}
+
+#endregion Utility functions
+
+#region PowerShellGet Provider APIs Implementation
+function Get-PackageProviderName
+{
+ return $script:PSModuleProviderName
+}
+
+function Get-Feature
+{
+ Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Get-Feature'))
+ Write-Output -InputObject (New-Feature $script:SupportsPSModulesFeatureName )
+}
+
+function Initialize-Provider
+{
+ Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Initialize-Provider'))
+}
+
+function Get-DynamicOptions
+{
+ param
+ (
+ [Microsoft.PackageManagement.MetaProvider.PowerShell.OptionCategory]
+ $category
+ )
+
+ Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Get-DynamicOptions'))
+
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:PackageManagementProviderParam -ExpectedType String -IsRequired $false)
+
+ Write-Output -InputObject (New-DynamicOption -Category $category `
+ -Name $script:PSArtifactType `
+ -ExpectedType String `
+ -IsRequired $false `
+ -PermittedValues @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript, $script:All))
+
+ switch($category)
+ {
+ Package {
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:Filter -ExpectedType String -IsRequired $false)
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:Tag -ExpectedType StringArray -IsRequired $false)
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name Includes -ExpectedType StringArray -IsRequired $false -PermittedValues $script:IncludeValidSet)
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name DscResource -ExpectedType StringArray -IsRequired $false)
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name RoleCapability -ExpectedType StringArray -IsRequired $false)
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name Command -ExpectedType StringArray -IsRequired $false)
+ }
+
+ Source {
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:PublishLocation -ExpectedType String -IsRequired $false)
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:ScriptSourceLocation -ExpectedType String -IsRequired $false)
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:ScriptPublishLocation -ExpectedType String -IsRequired $false)
+ }
+
+ Install
+ {
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name "Scope" -ExpectedType String -IsRequired $false -PermittedValues @("CurrentUser","AllUsers"))
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name "InstallUpdate" -ExpectedType Switch -IsRequired $false)
+ Write-Output -InputObject (New-DynamicOption -Category $category -Name 'NoPathUpdate' -ExpectedType Switch -IsRequired $false)
+ }
+ }
+}
+
+function Add-PackageSource
+{
+ [CmdletBinding()]
+ param
+ (
+ [string]
+ $Name,
+
+ [string]
+ $Location,
+
+ [bool]
+ $Trusted
+ )
+
+ Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Add-PackageSource'))
+
+ Set-ModuleSourcesVariable -Force
+
+ $IsNewModuleSource = $false
+ $Options = $request.Options
+
+ foreach( $o in $Options.Keys )
+ {
+ Write-Debug ( "OPTION: {0} => {1}" -f ($o, $Options[$o]) )
+ }
+
+ if($Options.ContainsKey('IsNewModuleSource'))
+ {
+ $IsNewModuleSource = $Options['IsNewModuleSource']
+
+ if($IsNewModuleSource.GetType().ToString() -eq 'System.String')
+ {
+ if($IsNewModuleSource -eq 'false')
+ {
+ $IsNewModuleSource = $false
+ }
+ elseif($IsNewModuleSource -eq 'true')
+ {
+ $IsNewModuleSource = $true
+ }
+ }
+ }
+
+ $IsUpdatePackageSource = $false
+ if($Options.ContainsKey('IsUpdatePackageSource'))
+ {
+ $IsUpdatePackageSource = $Options['IsUpdatePackageSource']
+
+ if($IsUpdatePackageSource.GetType().ToString() -eq 'System.String')
+ {
+ if($IsUpdatePackageSource -eq 'false')
+ {
+ $IsUpdatePackageSource = $false
+ }
+ elseif($IsUpdatePackageSource -eq 'true')
+ {
+ $IsUpdatePackageSource = $true
+ }
+ }
+ }
+
+ $PublishLocation = $null
+ if($Options.ContainsKey($script:PublishLocation))
+ {
+ $PublishLocation = $Options[$script:PublishLocation]
+
+ if(-not (Microsoft.PowerShell.Management\Test-Path $PublishLocation) -and
+ -not (Test-WebUri -uri $PublishLocation))
+ {
+ $PublishLocationUri = [Uri]$PublishLocation
+ if($PublishLocationUri.Scheme -eq 'file')
+ {
+ $message = $LocalizedData.PathNotFound -f ($PublishLocation)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $PublishLocation
+ }
+ else
+ {
+ $message = $LocalizedData.InvalidWebUri -f ($PublishLocation, "PublishLocation")
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidWebUri" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $PublishLocation
+ }
+ }
+ }
+
+ $ScriptSourceLocation = $null
+ if($Options.ContainsKey($script:ScriptSourceLocation))
+ {
+ $ScriptSourceLocation = $Options[$script:ScriptSourceLocation]
+
+ if(-not (Microsoft.PowerShell.Management\Test-Path $ScriptSourceLocation) -and
+ -not (Test-WebUri -uri $ScriptSourceLocation))
+ {
+ $ScriptSourceLocationUri = [Uri]$ScriptSourceLocation
+ if($ScriptSourceLocationUri.Scheme -eq 'file')
+ {
+ $message = $LocalizedData.PathNotFound -f ($ScriptSourceLocation)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $ScriptSourceLocation
+ }
+ else
+ {
+ $message = $LocalizedData.InvalidWebUri -f ($ScriptSourceLocation, "ScriptSourceLocation")
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidWebUri" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $ScriptSourceLocation
+ }
+ }
+ }
+
+ $ScriptPublishLocation = $null
+ if($Options.ContainsKey($script:ScriptPublishLocation))
+ {
+ $ScriptPublishLocation = $Options[$script:ScriptPublishLocation]
+
+ if(-not (Microsoft.PowerShell.Management\Test-Path $ScriptPublishLocation) -and
+ -not (Test-WebUri -uri $ScriptPublishLocation))
+ {
+ $ScriptPublishLocationUri = [Uri]$ScriptPublishLocation
+ if($ScriptPublishLocationUri.Scheme -eq 'file')
+ {
+ $message = $LocalizedData.PathNotFound -f ($ScriptPublishLocation)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $ScriptPublishLocation
+ }
+ else
+ {
+ $message = $LocalizedData.InvalidWebUri -f ($ScriptPublishLocation, "ScriptPublishLocation")
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidWebUri" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $ScriptPublishLocation
+ }
+ }
+ }
+
+ # Ping and resolve the specified location
+ $Location = Resolve-Location -Location $Location `
+ -LocationParameterName 'Location' `
+ -CallerPSCmdlet $PSCmdlet
+ if(-not $Location)
+ {
+ # Above Resolve-Location function throws an error when it is not able to resolve a location
+ return
+ }
+
+ if(-not (Microsoft.PowerShell.Management\Test-Path -Path $Location) -and
+ -not (Test-WebUri -uri $Location) )
+ {
+ $LocationUri = [Uri]$Location
+ if($LocationUri.Scheme -eq 'file')
+ {
+ $message = $LocalizedData.PathNotFound -f ($Location)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Location
+ }
+ else
+ {
+ $message = $LocalizedData.InvalidWebUri -f ($Location, "Location")
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidWebUri" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Location
+ }
+ }
+
+ if(Test-WildcardPattern $Name)
+ {
+ $message = $LocalizedData.RepositoryNameContainsWildCards -f ($Name)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "RepositoryNameContainsWildCards" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Name
+ }
+
+ $LocationString = Get-ValidModuleLocation -LocationString $Location -ParameterName "Location"
+
+ # Check if Location is already registered with another Name
+ $existingSourceName = Get-SourceName -Location $LocationString
+
+ if($existingSourceName -and
+ ($Name -ne $existingSourceName) -and
+ -not $IsNewModuleSource)
+ {
+ $message = $LocalizedData.RepositoryAlreadyRegistered -f ($existingSourceName, $Location, $Name)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "RepositoryAlreadyRegistered" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+
+ $currentSourceObject = $null
+
+ # Check if Name is already registered
+ if($script:PSGetModuleSources.Contains($Name))
+ {
+ $currentSourceObject = $script:PSGetModuleSources[$Name]
+ }
+
+ if(-not $PublishLocation -and $currentSourceObject -and $currentSourceObject.PublishLocation)
+ {
+ $PublishLocation = $currentSourceObject.PublishLocation
+ }
+
+ if((-not $ScriptPublishLocation) -and
+ $currentSourceObject -and
+ (Get-Member -InputObject $currentSourceObject -Name $script:ScriptPublishLocation) -and
+ $currentSourceObject.ScriptPublishLocation)
+ {
+ $ScriptPublishLocation = $currentSourceObject.ScriptPublishLocation
+ }
+
+ if((-not $ScriptSourceLocation) -and
+ $currentSourceObject -and
+ (Get-Member -InputObject $currentSourceObject -Name $script:ScriptSourceLocation) -and
+ $currentSourceObject.ScriptSourceLocation)
+ {
+ $ScriptSourceLocation = $currentSourceObject.ScriptSourceLocation
+ }
+
+ $IsProviderSpecified = $false;
+ if ($Options.ContainsKey($script:PackageManagementProviderParam))
+ {
+ $SpecifiedProviderName = $Options[$script:PackageManagementProviderParam]
+
+ $IsProviderSpecified = $true
+
+ Write-Verbose ($LocalizedData.SpecifiedProviderName -f $SpecifiedProviderName)
+ if ($SpecifiedProviderName -eq $script:PSModuleProviderName)
+ {
+ $message = $LocalizedData.InvalidPackageManagementProviderValue -f ($SpecifiedProviderName, $script:NuGetProviderName, $script:NuGetProviderName)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidPackageManagementProviderValue" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $SpecifiedProviderName
+ return
+ }
+ }
+ else
+ {
+ $SpecifiedProviderName = $script:NuGetProviderName
+ Write-Verbose ($LocalizedData.ProviderNameNotSpecified -f $SpecifiedProviderName)
+ }
+
+ $packageSource = $null
+
+ $selProviders = $request.SelectProvider($SpecifiedProviderName)
+
+ if(-not $selProviders -and $IsProviderSpecified)
+ {
+ $message = $LocalizedData.SpecifiedProviderNotAvailable -f $SpecifiedProviderName
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "SpecifiedProviderNotAvailable" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation `
+ -ExceptionObject $SpecifiedProviderName
+ }
+
+ # Try with user specified provider or NuGet provider
+ foreach($SelectedProvider in $selProviders)
+ {
+ if($request.IsCanceled)
+ {
+ return
+ }
+
+ if($SelectedProvider -and $SelectedProvider.Features.ContainsKey($script:SupportsPSModulesFeatureName))
+ {
+ $packageSource = $SelectedProvider.ResolvePackageSources( (New-Request -Sources @($LocationString)) )
+ }
+ else
+ {
+ $message = $LocalizedData.SpecifiedProviderDoesnotSupportPSModules -f $SelectedProvider.ProviderName
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "SpecifiedProviderDoesnotSupportPSModules" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation `
+ -ExceptionObject $SelectedProvider.ProviderName
+ }
+
+ if($packageSource)
+ {
+ break
+ }
+ }
+
+ # Poll other package provider when NuGet provider doesn't resolves the specified location
+ if(-not $packageSource -and -not $IsProviderSpecified)
+ {
+ Write-Verbose ($LocalizedData.PollingPackageManagementProvidersForLocation -f $LocationString)
+
+ $moduleProviders = $request.SelectProvidersWithFeature($script:SupportsPSModulesFeatureName)
+
+ foreach($provider in $moduleProviders)
+ {
+ if($request.IsCanceled)
+ {
+ return
+ }
+
+ # Skip already tried $SpecifiedProviderName and PowerShellGet provider
+ if($provider.ProviderName -eq $SpecifiedProviderName -or
+ $provider.ProviderName -eq $script:PSModuleProviderName)
+ {
+ continue
+ }
+
+ Write-Verbose ($LocalizedData.PollingSingleProviderForLocation -f ($LocationString, $provider.ProviderName))
+ $packageSource = $provider.ResolvePackageSources((New-Request -Option @{} -Sources @($LocationString)))
+
+ if($packageSource)
+ {
+ Write-Verbose ($LocalizedData.FoundProviderForLocation -f ($provider.ProviderName, $Location))
+ $SelectedProvider = $provider
+ break
+ }
+ }
+ }
+
+ if(-not $packageSource)
+ {
+ $message = $LocalizedData.SpecifiedLocationCannotBeRegistered -f $Location
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "SpecifiedLocationCannotBeRegistered" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation `
+ -ExceptionObject $Location
+ }
+
+ $ProviderOptions = @{}
+
+ $SelectedProvider.DynamicOptions | Microsoft.PowerShell.Core\ForEach-Object {
+ if($options.ContainsKey($_.Name) )
+ {
+ $ProviderOptions[$_.Name] = $options[$_.Name]
+ }
+ }
+
+ # Keep the existing provider options if not specified in Set-PSRepository
+ if($currentSourceObject)
+ {
+ $currentSourceObject.ProviderOptions.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object {
+ if (-not $ProviderOptions.ContainsKey($_.Key) )
+ {
+ $ProviderOptions[$_.Key] = $_.Value
+ }
+ }
+ }
+
+ if(-not $PublishLocation)
+ {
+ $PublishLocation = Get-PublishLocation -Location $LocationString
+ }
+
+ # Use the PublishLocation for the scripts when ScriptPublishLocation is not specified by the user
+ if(-not $ScriptPublishLocation)
+ {
+ $ScriptPublishLocation = $PublishLocation
+
+ # ScriptPublishLocation and PublishLocation should be equal in case of SMB Share or Local directory paths
+ if($Options.ContainsKey($script:ScriptPublishLocation) -and
+ (Microsoft.PowerShell.Management\Test-Path -Path $ScriptPublishLocation))
+ {
+ if($ScriptPublishLocation -ne $PublishLocation)
+ {
+ $message = $LocalizedData.PublishLocationPathsForModulesAndScriptsShouldBeEqual -f ($LocationString, $ScriptSourceLocation)
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "PublishLocationPathsForModulesAndScriptsShouldBeEqual" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation `
+ -ExceptionObject $Location
+ }
+ }
+ }
+
+ if(-not $ScriptSourceLocation)
+ {
+ $ScriptSourceLocation = Get-ScriptSourceLocation -Location $LocationString
+ }
+ elseif($Options.ContainsKey($script:ScriptSourceLocation))
+ {
+ # ScriptSourceLocation and SourceLocation cannot be same for they are URLs
+ # Both should be equal in case of SMB Share or Local directory paths
+ if(Microsoft.PowerShell.Management\Test-Path -Path $ScriptSourceLocation)
+ {
+ if($ScriptSourceLocation -ne $LocationString)
+ {
+ $message = $LocalizedData.SourceLocationPathsForModulesAndScriptsShouldBeEqual -f ($LocationString, $ScriptSourceLocation)
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "SourceLocationPathsForModulesAndScriptsShouldBeEqual" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation `
+ -ExceptionObject $Location
+ }
+ }
+ else
+ {
+ if($ScriptSourceLocation -eq $LocationString)
+ {
+ $message = $LocalizedData.SourceLocationUrisForModulesAndScriptsShouldBeDifferent -f ($LocationString, $ScriptSourceLocation)
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "SourceLocationUrisForModulesAndScriptsShouldBeDifferent" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation `
+ -ExceptionObject $Location
+ }
+ }
+ }
+
+ # no error so we can safely remove the source
+ if($script:PSGetModuleSources.Contains($Name))
+ {
+ $null = $script:PSGetModuleSources.Remove($Name)
+ }
+
+ # Add new module source
+ $moduleSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
+ Name = $Name
+ SourceLocation = $LocationString
+ PublishLocation = $PublishLocation
+ ScriptSourceLocation = $ScriptSourceLocation
+ ScriptPublishLocation = $ScriptPublishLocation
+ Trusted=$Trusted
+ Registered= (-not $IsNewModuleSource)
+ InstallationPolicy = if($Trusted) {'Trusted'} else {'Untrusted'}
+ PackageManagementProvider = $SelectedProvider.ProviderName
+ ProviderOptions = $ProviderOptions
+ })
+
+ #region telemetry - Capture non-PSGallery registrations as telemetry events
+ if ($script:TelemetryEnabled)
+ {
+
+ Log-NonPSGalleryRegistration -sourceLocation $moduleSource.SourceLocation `
+ -installationPolicy $moduleSource.InstallationPolicy `
+ -packageManagementProvider $moduleSource.PackageManagementProvider `
+ -publishLocation $moduleSource.PublishLocation `
+ -scriptSourceLocation $moduleSource.ScriptSourceLocation `
+ -scriptPublishLocation $moduleSource.ScriptPublishLocation `
+ -operationName PSGET_NONPSGALLERY_REGISTRATION `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+
+ }
+ #endregion
+
+ $moduleSource.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepository")
+
+ # Persist the repositories only when Register-PSRepository cmdlet is used
+ if(-not $IsNewModuleSource)
+ {
+ $script:PSGetModuleSources.Add($Name, $moduleSource)
+
+ $message = $LocalizedData.RepositoryRegistered -f ($Name, $LocationString)
+ Write-Verbose $message
+
+ # Persist the module sources
+ Save-ModuleSources
+ }
+
+ # return the package source object.
+ Write-Output -InputObject (New-PackageSourceFromModuleSource -ModuleSource $moduleSource)
+}
+
+function Resolve-PackageSource
+{
+ Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('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:PSGetModuleSources.GetEnumerator() |
+ Microsoft.PowerShell.Core\Where-Object {$wildcardPattern.IsMatch($_.Key)} |
+ Microsoft.PowerShell.Core\ForEach-Object {
+
+ $moduleSource = $script:PSGetModuleSources[$_.Key]
+
+ $packageSource = New-PackageSourceFromModuleSource -ModuleSource $moduleSource
+
+ Write-Output -InputObject $packageSource
+
+ $moduleSourceFound = $true
+ }
+
+ if(-not $moduleSourceFound)
+ {
+ $sourceName = Get-SourceName -Location $moduleSourceName
+
+ if($sourceName)
+ {
+ $moduleSource = $script:PSGetModuleSources[$sourceName]
+
+ $packageSource = New-PackageSourceFromModuleSource -ModuleSource $moduleSource
+
+ Write-Output -InputObject $packageSource
+ }
+ elseif( -not (Test-WildcardPattern $moduleSourceName))
+ {
+ $message = $LocalizedData.RepositoryNotFound -f ($moduleSourceName)
+
+ Write-Error -Message $message -ErrorId "RepositoryNotFound" -Category InvalidOperation -TargetObject $moduleSourceName
+ }
+ }
+ }
+}
+
+function Remove-PackageSource
+{
+ param
+ (
+ [string]
+ $Name
+ )
+
+ Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Remove-PackageSource'))
+
+ Set-ModuleSourcesVariable -Force
+
+ $ModuleSourcesToBeRemoved = @()
+
+ foreach ($moduleSourceName in $Name)
+ {
+ if($request.IsCanceled)
+ {
+ return
+ }
+
+ # Check if $Name contains any wildcards
+ if(Test-WildcardPattern $moduleSourceName)
+ {
+ $message = $LocalizedData.RepositoryNameContainsWildCards -f ($moduleSourceName)
+ Write-Error -Message $message -ErrorId "RepositoryNameContainsWildCards" -Category InvalidOperation -TargetObject $moduleSourceName
+ continue
+ }
+
+ # Check if the specified module source name is in the registered module sources
+ if(-not $script:PSGetModuleSources.Contains($moduleSourceName))
+ {
+ $message = $LocalizedData.RepositoryNotFound -f ($moduleSourceName)
+ Write-Error -Message $message -ErrorId "RepositoryNotFound" -Category InvalidOperation -TargetObject $moduleSourceName
+ continue
+ }
+
+ $ModuleSourcesToBeRemoved += $moduleSourceName
+ $message = $LocalizedData.RepositoryUnregistered -f ($moduleSourceName)
+ Write-Verbose $message
+ }
+
+ # Remove the module source
+ $ModuleSourcesToBeRemoved | Microsoft.PowerShell.Core\ForEach-Object { $null = $script:PSGetModuleSources.Remove($_) }
+
+ # Persist the module sources
+ Save-ModuleSources
+}
+
+function Find-Package
+{
+ [CmdletBinding()]
+ param
+ (
+ [string[]]
+ $names,
+
+ [string]
+ $requiredVersion,
+
+ [string]
+ $minimumVersion,
+
+ [string]
+ $maximumVersion
+ )
+
+ Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Find-Package'))
+
+ Set-ModuleSourcesVariable
+
+ if($RequiredVersion -and $MinimumVersion)
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $LocalizedData.VersionRangeAndRequiredVersionCannotBeSpecifiedTogether `
+ -ErrorId "VersionRangeAndRequiredVersionCannotBeSpecifiedTogether" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+
+ if($RequiredVersion -or $MinimumVersion)
+ {
+ if(-not $names -or $names.Count -ne 1 -or (Test-WildcardPattern -Name $names[0]))
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $LocalizedData.VersionParametersAreAllowedOnlyWithSingleName `
+ -ErrorId "VersionParametersAreAllowedOnlyWithSingleName" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+ }
+
+ $options = $request.Options
+
+ foreach( $o in $options.Keys )
+ {
+ Write-Debug ( "OPTION: {0} => {1}" -f ($o, $options[$o]) )
+ }
+
+ # When using -Name, we don't send PSGet-specific properties to the server - we will filter it ourselves
+ $postFilter = New-Object -TypeName System.Collections.Hashtable
+ if($options.ContainsKey("Name"))
+ {
+ if($options.ContainsKey("Includes"))
+ {
+ $postFilter["Includes"] = $options["Includes"]
+ $null = $options.Remove("Includes")
+ }
+
+ if($options.ContainsKey("DscResource"))
+ {
+ $postFilter["DscResource"] = $options["DscResource"]
+ $null = $options.Remove("DscResource")
+ }
+
+ if($options.ContainsKey('RoleCapability'))
+ {
+ $postFilter['RoleCapability'] = $options['RoleCapability']
+ $null = $options.Remove('RoleCapability')
+ }
+
+ if($options.ContainsKey("Command"))
+ {
+ $postFilter["Command"] = $options["Command"]
+ $null = $options.Remove("Command")
+ }
+ }
+
+ $LocationOGPHashtable = [ordered]@{}
+ if($options -and $options.ContainsKey('Source'))
+ {
+ $SourceNames = $($options['Source'])
+
+ Write-Verbose ($LocalizedData.SpecifiedSourceName -f ($SourceNames))
+
+ foreach($sourceName in $SourceNames)
+ {
+ if($script:PSGetModuleSources.Contains($sourceName))
+ {
+ $ModuleSource = $script:PSGetModuleSources[$sourceName]
+ $LocationOGPHashtable[$ModuleSource.SourceLocation] = (Get-ProviderName -PSCustomObject $ModuleSource)
+ }
+ else
+ {
+ $sourceByLocation = Get-SourceName -Location $sourceName
+
+ if ($sourceByLocation)
+ {
+ $ModuleSource = $script:PSGetModuleSources[$sourceByLocation]
+ $LocationOGPHashtable[$ModuleSource.SourceLocation] = (Get-ProviderName -PSCustomObject $ModuleSource)
+ }
+ else
+ {
+ $message = $LocalizedData.RepositoryNotFound -f ($sourceName)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "RepositoryNotFound" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $sourceName
+ }
+ }
+ }
+ }
+ elseif($options -and
+ $options.ContainsKey($script:PackageManagementProviderParam) -and
+ $options.ContainsKey('Location'))
+ {
+ $Location = $options['Location']
+ $PackageManagementProvider = $options['PackageManagementProvider']
+
+ Write-Verbose ($LocalizedData.SpecifiedLocationAndOGP -f ($Location, $PackageManagementProvider))
+
+ $LocationOGPHashtable[$Location] = $PackageManagementProvider
+ }
+ else
+ {
+ Write-Verbose $LocalizedData.NoSourceNameIsSpecified
+
+ $script:PSGetModuleSources.Values | Microsoft.PowerShell.Core\ForEach-Object { $LocationOGPHashtable[$_.SourceLocation] = (Get-ProviderName -PSCustomObject $_) }
+ }
+
+ $artifactTypes = $script:PSArtifactTypeModule
+ if($options.ContainsKey($script:PSArtifactType))
+ {
+ $artifactTypes = $options[$script:PSArtifactType]
+ }
+
+ if($artifactTypes -eq $script:All)
+ {
+ $artifactTypes = @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript)
+ }
+
+ $providerOptions = @{}
+
+ if($options.ContainsKey($script:AllVersions))
+ {
+ $providerOptions[$script:AllVersions] = $options[$script:AllVersions]
+ }
+
+ if($options.ContainsKey($script:Filter))
+ {
+ $Filter = $options[$script:Filter]
+ $providerOptions['Contains'] = $Filter
+ }
+
+ if($options.ContainsKey($script:Tag))
+ {
+ $userSpecifiedTags = $options[$script:Tag] | Microsoft.PowerShell.Utility\Select-Object -Unique
+ }
+ else
+ {
+ $userSpecifiedTags = @($script:NotSpecified)
+ }
+
+ $specifiedDscResources = @()
+ if($options.ContainsKey('DscResource'))
+ {
+ $specifiedDscResources = $options['DscResource'] |
+ Microsoft.PowerShell.Utility\Select-Object -Unique |
+ Microsoft.PowerShell.Core\ForEach-Object {"$($script:DscResource)_$_"}
+ }
+
+ $specifiedRoleCapabilities = @()
+ if($options.ContainsKey('RoleCapability'))
+ {
+ $specifiedRoleCapabilities = $options['RoleCapability'] |
+ Microsoft.PowerShell.Utility\Select-Object -Unique |
+ Microsoft.PowerShell.Core\ForEach-Object {"$($script:RoleCapability)_$_"}
+ }
+
+ $specifiedCommands = @()
+ if($options.ContainsKey('Command'))
+ {
+ $specifiedCommands = $options['Command'] |
+ Microsoft.PowerShell.Utility\Select-Object -Unique |
+ Microsoft.PowerShell.Core\ForEach-Object {"$($script:Command)_$_"}
+ }
+
+ $specifiedIncludes = @()
+ if($options.ContainsKey('Includes'))
+ {
+ $includes = $options['Includes'] |
+ Microsoft.PowerShell.Utility\Select-Object -Unique |
+ Microsoft.PowerShell.Core\ForEach-Object {"$($script:Includes)_$_"}
+
+ # Add PSIncludes_DscResource to $specifiedIncludes iff -DscResource names are not specified
+ # Add PSIncludes_RoleCapability to $specifiedIncludes iff -RoleCapability names are not specified
+ # Add PSIncludes_Cmdlet or PSIncludes_Function to $specifiedIncludes iff -Command names are not specified
+ # otherwise $script:NotSpecified will be added to $specifiedIncludes
+ if($includes)
+ {
+ if(-not $specifiedDscResources -and ($includes -contains "$($script:Includes)_DscResource") )
+ {
+ $specifiedIncludes += "$($script:Includes)_DscResource"
+ }
+
+ if(-not $specifiedRoleCapabilities -and ($includes -contains "$($script:Includes)_RoleCapability") )
+ {
+ $specifiedIncludes += "$($script:Includes)_RoleCapability"
+ }
+
+ if(-not $specifiedCommands)
+ {
+ if($includes -contains "$($script:Includes)_Cmdlet")
+ {
+ $specifiedIncludes += "$($script:Includes)_Cmdlet"
+ }
+
+ if($includes -contains "$($script:Includes)_Function")
+ {
+ $specifiedIncludes += "$($script:Includes)_Function"
+ }
+
+ if($includes -contains "$($script:Includes)_Workflow")
+ {
+ $specifiedIncludes += "$($script:Includes)_Workflow"
+ }
+ }
+ }
+ }
+
+ if(-not $specifiedDscResources)
+ {
+ $specifiedDscResources += $script:NotSpecified
+ }
+
+ if(-not $specifiedRoleCapabilities)
+ {
+ $specifiedRoleCapabilities += $script:NotSpecified
+ }
+
+ if(-not $specifiedCommands)
+ {
+ $specifiedCommands += $script:NotSpecified
+ }
+
+ if(-not $specifiedIncludes)
+ {
+ $specifiedIncludes += $script:NotSpecified
+ }
+
+ $providerSearchTags = @{}
+
+ foreach($tag in $userSpecifiedTags)
+ {
+ foreach($include in $specifiedIncludes)
+ {
+ foreach($command in $specifiedCommands)
+ {
+ foreach($resource in $specifiedDscResources)
+ {
+ foreach($roleCapability in $specifiedRoleCapabilities)
+ {
+ $providerTags = @()
+ if($resource -ne $script:NotSpecified)
+ {
+ $providerTags += $resource
+ }
+
+ if($roleCapability -ne $script:NotSpecified)
+ {
+ $providerTags += $roleCapability
+ }
+
+ if($command -ne $script:NotSpecified)
+ {
+ $providerTags += $command
+ }
+
+ if($include -ne $script:NotSpecified)
+ {
+ $providerTags += $include
+ }
+
+ if($tag -ne $script:NotSpecified)
+ {
+ $providerTags += $tag
+ }
+
+ if($providerTags)
+ {
+ $providerSearchTags["$tag $resource $roleCapability $command $include"] = $providerTags
+ }
+ }
+ }
+ }
+ }
+ }
+
+ $InstallationPolicy = "Untrusted"
+ if($options.ContainsKey('InstallationPolicy'))
+ {
+ $InstallationPolicy = $options['InstallationPolicy']
+ }
+
+ $streamedResults = @()
+
+ foreach($artifactType in $artifactTypes)
+ {
+ foreach($kvPair in $LocationOGPHashtable.GetEnumerator())
+ {
+ if($request.IsCanceled)
+ {
+ return
+ }
+
+ $Location = $kvPair.Key
+ if($artifactType -eq $script:PSArtifactTypeScript)
+ {
+ $sourceName = Get-SourceName -Location $Location
+
+ if($SourceName)
+ {
+ $ModuleSource = $script:PSGetModuleSources[$SourceName]
+
+ # Skip source if no ScriptSourceLocation is available.
+ if(-not $ModuleSource.ScriptSourceLocation)
+ {
+ if($options.ContainsKey('Source'))
+ {
+ $message = $LocalizedData.ScriptSourceLocationIsMissing -f ($ModuleSource.Name)
+ Write-Error -Message $message `
+ -ErrorId 'ScriptSourceLocationIsMissing' `
+ -Category InvalidArgument `
+ -TargetObject $ModuleSource.Name
+ }
+
+ continue
+ }
+
+ $Location = $ModuleSource.ScriptSourceLocation
+ }
+ }
+
+ $ProviderName = $kvPair.Value
+
+ Write-Verbose ($LocalizedData.GettingPackageManagementProviderObject -f ($ProviderName))
+
+ $provider = $request.SelectProvider($ProviderName)
+
+ if(-not $provider)
+ {
+ Write-Error -Message ($LocalizedData.PackageManagementProviderIsNotAvailable -f $ProviderName)
+
+ Continue
+ }
+
+ Write-Verbose ($LocalizedData.SpecifiedLocationAndOGP -f ($Location, $provider.ProviderName))
+
+ if($providerSearchTags.Values.Count)
+ {
+ $tagList = $providerSearchTags.Values
+ }
+ else
+ {
+ $tagList = @($script:NotSpecified)
+ }
+
+ $namesParameterEmpty = ($names.Count -eq 1) -and ($names[0] -eq '')
+
+ foreach($providerTag in $tagList)
+ {
+ if($request.IsCanceled)
+ {
+ return
+ }
+
+ $FilterOnTag = @()
+
+ if($providerTag -ne $script:NotSpecified)
+ {
+ $FilterOnTag = $providerTag
+ }
+
+ if(Microsoft.PowerShell.Management\Test-Path -Path $Location)
+ {
+ if($artifactType -eq $script:PSArtifactTypeScript)
+ {
+ $FilterOnTag += 'PSScript'
+ }
+ elseif($artifactType -eq $script:PSArtifactTypeModule)
+ {
+ $FilterOnTag += 'PSModule'
+ }
+ }
+
+ if($FilterOnTag)
+ {
+ $providerOptions["FilterOnTag"] = $FilterOnTag
+ }
+ elseif($providerOptions.ContainsKey('FilterOnTag'))
+ {
+ $null = $providerOptions.Remove('FilterOnTag')
+ }
+
+ if($request.Options.ContainsKey($script:FindByCanonicalId))
+ {
+ $providerOptions[$script:FindByCanonicalId] = $request.Options[$script:FindByCanonicalId]
+ }
+
+ $providerOptions["Headers"] = 'PSGalleryClientVersion=1.1'
+
+ $pkgs = $provider.FindPackages($names,
+ $requiredVersion,
+ $minimumVersion,
+ $maximumVersion,
+ (New-Request -Sources @($Location) -Options $providerOptions) )
+
+ foreach($pkg in $pkgs)
+ {
+ if($request.IsCanceled)
+ {
+ return
+ }
+
+ # $pkg.Name has to match any of the supplied names, using PowerShell wildcards
+ if ($namesParameterEmpty -or ($names | % { if ($pkg.Name -like $_){return $true; break} } -End {return $false}))
+ {
+ $includePackage = $true
+
+ # If -Name was provided, we need to post-filter
+ # Filtering has AND semantics between different parameters and OR within a parameter (each parameter is potentially an array)
+ if($options.ContainsKey("Name") -and $postFilter.Count -gt 0)
+ {
+ if ($pkg.Metadata["DscResources"].Count -gt 0)
+ {
+ $pkgDscResources = $pkg.Metadata["DscResources"] -Split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() }
+ }
+ else
+ {
+ $pkgDscResources = $pkg.Metadata["tags"] -Split " " `
+ | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } `
+ | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:DscResource, [System.StringComparison]::OrdinalIgnoreCase) } `
+ | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:DscResource.Length + 1) }
+ }
+
+ if ($pkg.Metadata['RoleCapabilities'].Count -gt 0)
+ {
+ $pkgRoleCapabilities = $pkg.Metadata['RoleCapabilities'] -Split ' ' | Microsoft.PowerShell.Core\Where-Object { $_.Trim() }
+ }
+ else
+ {
+ $pkgRoleCapabilities = $pkg.Metadata["tags"] -Split ' ' `
+ | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } `
+ | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:RoleCapability, [System.StringComparison]::OrdinalIgnoreCase) } `
+ | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:RoleCapability.Length + 1) }
+ }
+
+ if ($pkg.Metadata["Functions"].Count -gt 0)
+ {
+ $pkgFunctions = $pkg.Metadata["Functions"] -Split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() }
+ }
+ else
+ {
+ $pkgFunctions = $pkg.Metadata["tags"] -Split " " `
+ | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } `
+ | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:Function, [System.StringComparison]::OrdinalIgnoreCase) } `
+ | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:Function.Length + 1) }
+ }
+
+ if ($pkg.Metadata["Cmdlets"].Count -gt 0)
+ {
+ $pkgCmdlets = $pkg.Metadata["Cmdlets"] -Split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() }
+ }
+ else
+ {
+ $pkgCmdlets = $pkg.Metadata["tags"] -Split " " `
+ | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } `
+ | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:Cmdlet, [System.StringComparison]::OrdinalIgnoreCase) } `
+ | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:Cmdlet.Length + 1) }
+ }
+
+ if ($pkg.Metadata["Workflows"].Count -gt 0)
+ {
+ $pkgWorkflows = $pkg.Metadata["Workflows"] -Split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() }
+ }
+ else
+ {
+ $pkgWorkflows = $pkg.Metadata["tags"] -Split " " `
+ | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } `
+ | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:Workflow, [System.StringComparison]::OrdinalIgnoreCase) } `
+ | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:Workflow.Length + 1) }
+ }
+
+ foreach ($key in $postFilter.Keys)
+ {
+ switch ($key)
+ {
+ "DscResource" {
+ $values = $postFilter[$key]
+
+ $includePackage = $false
+
+ foreach ($value in $values)
+ {
+ $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $value,$script:wildcardOptions
+
+ $pkgDscResources | Microsoft.PowerShell.Core\ForEach-Object {
+ if ($wildcardPattern.IsMatch($_))
+ {
+ $includePackage = $true
+ break
+ }
+ }
+ }
+
+ if (-not $includePackage)
+ {
+ break
+ }
+ }
+
+ 'RoleCapability' {
+ $values = $postFilter[$key]
+
+ $includePackage = $false
+
+ foreach ($value in $values)
+ {
+ $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $value,$script:wildcardOptions
+
+ $pkgRoleCapabilities | Microsoft.PowerShell.Core\ForEach-Object {
+ if ($wildcardPattern.IsMatch($_))
+ {
+ $includePackage = $true
+ break
+ }
+ }
+ }
+
+ if (-not $includePackage)
+ {
+ break
+ }
+ }
+
+ "Command" {
+ $values = $postFilter[$key]
+
+ $includePackage = $false
+
+ foreach ($value in $values)
+ {
+ $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $value,$script:wildcardOptions
+
+ $pkgFunctions | Microsoft.PowerShell.Core\ForEach-Object {
+ if ($wildcardPattern.IsMatch($_))
+ {
+ $includePackage = $true
+ break
+ }
+ }
+
+ $pkgCmdlets | Microsoft.PowerShell.Core\ForEach-Object {
+ if ($wildcardPattern.IsMatch($_))
+ {
+ $includePackage = $true
+ break
+ }
+ }
+
+ $pkgWorkflows | Microsoft.PowerShell.Core\ForEach-Object {
+ if ($wildcardPattern.IsMatch($_))
+ {
+ $includePackage = $true
+ break
+ }
+ }
+ }
+
+ if (-not $includePackage)
+ {
+ break
+ }
+ }
+
+ "Includes" {
+ $values = $postFilter[$key]
+
+ $includePackage = $false
+
+ foreach ($value in $values)
+ {
+ switch ($value)
+ {
+ "Cmdlet" { if ($pkgCmdlets ) { $includePackage = $true } }
+ "Function" { if ($pkgFunctions ) { $includePackage = $true } }
+ "DscResource" { if ($pkgDscResources ) { $includePackage = $true } }
+ "RoleCapability" { if ($pkgRoleCapabilities ) { $includePackage = $true } }
+ "Workflow" { if ($pkgWorkflows ) { $includePackage = $true } }
+ }
+ }
+
+ if (-not $includePackage)
+ {
+ break
+ }
+ }
+ }
+ }
+ }
+
+ if ($includePackage)
+ {
+ $fastPackageReference = New-FastPackageReference -ProviderName $provider.ProviderName `
+ -PackageName $pkg.Name `
+ -Version $pkg.Version `
+ -Source $Location `
+ -ArtifactType $artifactType
+
+ if($streamedResults -notcontains $fastPackageReference)
+ {
+ $streamedResults += $fastPackageReference
+
+ $FromTrustedSource = $false
+
+ $ModuleSourceName = Get-SourceName -Location $Location
+
+ if($ModuleSourceName)
+ {
+ $FromTrustedSource = $script:PSGetModuleSources[$ModuleSourceName].Trusted
+ }
+ elseif($InstallationPolicy -eq "Trusted")
+ {
+ $FromTrustedSource = $true
+ }
+
+ $sid = New-SoftwareIdentityFromPackage -Package $pkg `
+ -PackageManagementProviderName $provider.ProviderName `
+ -SourceLocation $Location `
+ -IsFromTrustedSource:$FromTrustedSource `
+ -Type $artifactType `
+ -request $request
+
+ $script:FastPackRefHastable[$fastPackageReference] = $pkg
+
+ Write-Output -InputObject $sid
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+function Download-Package
+{
+ [CmdletBinding()]
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $FastPackageReference,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Location
+ )
+
+ Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Download-Package'))
+
+ Install-PackageUtility -FastPackageReference $FastPackageReference -Request $Request -Location $Location
+}
+
+function Install-Package
+{
+ [CmdletBinding()]
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $FastPackageReference
+ )
+
+ Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Install-Package'))
+
+ Install-PackageUtility -FastPackageReference $FastPackageReference -Request $Request
+}
+
+function Install-PackageUtility
+{
+ [CmdletBinding()]
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $FastPackageReference,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Location,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ $request
+ )
+
+ Set-ModuleSourcesVariable
+
+ Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Install-PackageUtility'))
+
+ Write-Debug ($LocalizedData.FastPackageReference -f $fastPackageReference)
+
+ $Force = $false
+ $MinimumVersion = $null
+ $RequiredVersion = $null
+ $IsSavePackage = $false
+ $Scope = $null
+ $NoPathUpdate = $false
+
+ # take the fastPackageReference and get the package object again.
+ $parts = $fastPackageReference -Split '[|]'
+
+ if( $parts.Length -eq 5 )
+ {
+ $providerName = $parts[0]
+ $packageName = $parts[1]
+ $version = $parts[2]
+ $sourceLocation= $parts[3]
+ $artfactType = $parts[4]
+
+ # The default destination location for Modules and Scripts is ProgramFiles path
+ $scriptDestination = $script:ProgramFilesScriptsPath
+ $moduleDestination = $script:programFilesModulesPath
+ $Scope = 'AllUsers'
+
+ if($artfactType -eq $script:PSArtifactTypeScript)
+ {
+ $AdminPreviligeErrorMessage = $LocalizedData.InstallScriptNeedsCurrentUserScopeParameterForNonAdminUser -f @($script:ProgramFilesScriptsPath, $script:MyDocumentsScriptsPath)
+ $AdminPreviligeErrorId = 'InstallScriptNeedsCurrentUserScopeParameterForNonAdminUser'
+ }
+ else
+ {
+ $AdminPreviligeErrorMessage = $LocalizedData.InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser -f @($script:programFilesModulesPath, $script:MyDocumentsModulesPath)
+ $AdminPreviligeErrorId = 'InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser'
+ }
+
+ $installUpdate = $false
+
+ $options = $request.Options
+
+ if($options)
+ {
+ foreach( $o in $options.Keys )
+ {
+ Write-Debug ("OPTION: {0} => {1}" -f ($o, $request.Options[$o]) )
+ }
+
+ if($options.ContainsKey('Scope'))
+ {
+ $Scope = $options['Scope']
+ Write-Verbose ($LocalizedData.SpecifiedInstallationScope -f $Scope)
+
+ if($Scope -eq "CurrentUser")
+ {
+ $scriptDestination = $script:MyDocumentsScriptsPath
+ $moduleDestination = $script:MyDocumentsModulesPath
+ }
+ elseif($Scope -eq "AllUsers")
+ {
+ $scriptDestination = $script:ProgramFilesScriptsPath
+ $moduleDestination = $script:programFilesModulesPath
+
+ if(-not (Test-RunningAsElevated))
+ {
+ # Throw an error when Install-Module/Script is used as a non-admin user and '-Scope CurrentUser' is not specified
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $AdminPreviligeErrorMessage `
+ -ErrorId $AdminPreviligeErrorId `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+ }
+ }
+ elseif($Location)
+ {
+ $IsSavePackage = $true
+ $Scope = $null
+
+ $moduleDestination = $Location
+ $scriptDestination = $Location
+ }
+ # if no scope and no destination path and not elevated, then raise an error
+ elseif(-not (Test-RunningAsElevated))
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $AdminPreviligeErrorMessage `
+ -ErrorId $AdminPreviligeErrorId `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+
+ if($options.ContainsKey('Force'))
+ {
+ $Force = $options['Force']
+
+ if($Force.GetType().ToString() -eq 'System.String')
+ {
+ if($Force -eq 'false')
+ {
+ $Force = $false
+ }
+ elseif($Force -eq 'true')
+ {
+ $Force = $true
+ }
+ }
+ }
+
+ if($options.ContainsKey('NoPathUpdate'))
+ {
+ $NoPathUpdate = $options['NoPathUpdate']
+
+ if($NoPathUpdate.GetType().ToString() -eq 'System.String')
+ {
+ if($NoPathUpdate -eq 'false')
+ {
+ $NoPathUpdate = $false
+ }
+ elseif($NoPathUpdate -eq 'true')
+ {
+ $NoPathUpdate = $true
+ }
+ }
+ }
+
+ if($options.ContainsKey('MinimumVersion'))
+ {
+ $MinimumVersion = $options['MinimumVersion']
+ }
+
+ if($options.ContainsKey('RequiredVersion'))
+ {
+ $RequiredVersion = $options['RequiredVersion']
+ }
+
+ if($options.ContainsKey('InstallUpdate'))
+ {
+ $installUpdate = $options['InstallUpdate']
+
+ if($installUpdate.GetType().ToString() -eq 'System.String')
+ {
+ if($installUpdate -eq 'false')
+ {
+ $installUpdate = $false
+ }
+ elseif($installUpdate -eq 'true')
+ {
+ $installUpdate = $true
+ }
+ }
+ }
+
+ if($Scope -and ($artfactType -eq $script:PSArtifactTypeScript) -and (-not $installUpdate))
+ {
+ ValidateAndSet-PATHVariableIfUserAccepts -Scope $Scope `
+ -ScopePath $scriptDestination `
+ -Request $request `
+ -NoPathUpdate:$NoPathUpdate `
+ -Force:$Force
+ }
+
+ if($artfactType -eq $script:PSArtifactTypeModule)
+ {
+ $message = $LocalizedData.ModuleDestination -f @($moduleDestination)
+ }
+ else
+ {
+ $message = $LocalizedData.ScriptDestination -f @($scriptDestination, $moduleDestination)
+ }
+ Write-Verbose $message
+ }
+
+ Write-Debug "ArtfactType is $artfactType"
+
+ if($artfactType -eq $script:PSArtifactTypeModule)
+ {
+ # Test if module is already installed
+ $InstalledModuleInfo = if(-not $IsSavePackage){ Test-ModuleInstalled -Name $packageName -RequiredVersion $RequiredVersion }
+
+ if(-not $Force -and $InstalledModuleInfo)
+ {
+ if($RequiredVersion -and (Test-ModuleSxSVersionSupport))
+ {
+ # Check if the module with the required version is already installed otherwise proceed to install/update.
+ if($InstalledModuleInfo)
+ {
+ $message = $LocalizedData.ModuleWithRequiredVersionAlreadyInstalled -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase, $InstalledModuleInfo.Version)
+ Write-Error -Message $message -ErrorId "ModuleWithRequiredVersionAlreadyInstalled" -Category InvalidOperation
+
+ return
+ }
+ }
+ else
+ {
+ if(-not $installUpdate)
+ {
+ if( (-not $MinimumVersion -and ($version -ne $InstalledModuleInfo.Version)) -or
+ ($MinimumVersion -and ($MinimumVersion -gt $InstalledModuleInfo.Version)))
+ {
+ if($PSVersionTable.PSVersion -ge [Version]"5.0")
+ {
+ $message = $LocalizedData.ModuleAlreadyInstalledSxS -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase, $version, $InstalledModuleInfo.Version, $version)
+ }
+ else
+ {
+ $message = $LocalizedData.ModuleAlreadyInstalled -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase, $InstalledModuleInfo.Version, $version)
+ }
+ Write-Error -Message $message -ErrorId "ModuleAlreadyInstalled" -Category InvalidOperation
+ }
+ else
+ {
+ $message = $LocalizedData.ModuleAlreadyInstalledVerbose -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase)
+ Write-Verbose $message
+ }
+
+ return
+ }
+ else
+ {
+ if($InstalledModuleInfo.Version -lt $version)
+ {
+ $message = $LocalizedData.FoundModuleUpdate -f ($InstalledModuleInfo.Name, $version)
+ Write-Verbose $message
+ }
+ else
+ {
+ $message = $LocalizedData.NoUpdateAvailable -f ($InstalledModuleInfo.Name)
+ Write-Verbose $message
+ return
+ }
+ }
+ }
+ }
+ }
+
+ if($artfactType -eq $script:PSArtifactTypeScript)
+ {
+ # Test if script is already installed
+ $InstalledScriptInfo = if(-not $IsSavePackage){ Test-ScriptInstalled -Name $packageName }
+
+ Write-Debug "InstalledScriptInfo is $InstalledScriptInfo"
+
+ if(-not $Force -and $InstalledScriptInfo)
+ {
+ if(-not $installUpdate)
+ {
+ if( (-not $MinimumVersion -and ($version -ne $InstalledScriptInfo.Version)) -or
+ ($MinimumVersion -and ($MinimumVersion -gt $InstalledScriptInfo.Version)))
+ {
+ $message = $LocalizedData.ScriptAlreadyInstalled -f ($InstalledScriptInfo.Version, $InstalledScriptInfo.Name, $InstalledScriptInfo.ScriptBase, $InstalledScriptInfo.Version, $version)
+ Write-Error -Message $message -ErrorId "ScriptAlreadyInstalled" -Category InvalidOperation
+ }
+ else
+ {
+ $message = $LocalizedData.ScriptAlreadyInstalledVerbose -f ($InstalledScriptInfo.Version, $InstalledScriptInfo.Name, $InstalledScriptInfo.ScriptBase)
+ Write-Verbose $message
+ }
+
+ return
+ }
+ else
+ {
+ if($InstalledScriptInfo.Version -lt $version)
+ {
+ $message = $LocalizedData.FoundScriptUpdate -f ($InstalledScriptInfo.Name, $version)
+ Write-Verbose $message
+ }
+ else
+ {
+ $message = $LocalizedData.NoScriptUpdateAvailable -f ($InstalledScriptInfo.Name)
+ Write-Verbose $message
+ return
+ }
+ }
+ }
+
+ # Throw an error if there is a command with the same name and -force is not specified.
+ if(-not $installUpdate -and
+ -not $IsSavePackage -and
+ -not $Force)
+ {
+ $cmd = Microsoft.PowerShell.Core\Get-Command -Name $packageName `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+ if($cmd)
+ {
+ $message = $LocalizedData.CommandAlreadyAvailable -f ($packageName)
+ Write-Error -Message $message -ErrorId CommandAlreadyAvailableWitScriptName -Category InvalidOperation
+ return
+ }
+ }
+ }
+
+ # create a temp folder and download the module
+ $tempDestination = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath -ChildPath "$(Microsoft.PowerShell.Utility\Get-Random)"
+ $null = Microsoft.PowerShell.Management\New-Item -Path $tempDestination -ItemType Directory -Force -Confirm:$false -WhatIf:$false
+
+ try
+ {
+ $provider = $request.SelectProvider($providerName)
+ if(-not $provider)
+ {
+ Write-Error -Message ($LocalizedData.PackageManagementProviderIsNotAvailable -f $providerName)
+
+ return
+ }
+
+ if($request.IsCanceled)
+ {
+ return
+ }
+
+ Write-Verbose ($LocalizedData.SpecifiedLocationAndOGP -f ($provider.ProviderName, $providerName))
+
+ $newRequest = New-Request -Options @{Destination=$tempDestination;
+ ExcludeVersion=$true} `
+ -Sources @($SourceLocation)
+
+ if($artfactType -eq $script:PSArtifactTypeModule)
+ {
+ $message = $LocalizedData.DownloadingModuleFromGallery -f ($packageName, $version, $sourceLocation)
+ }
+ else
+ {
+ $message = $LocalizedData.DownloadingScriptFromGallery -f ($packageName, $version, $sourceLocation)
+ }
+ Write-Verbose $message
+
+ $installedPkgs = $provider.InstallPackage($script:FastPackRefHastable[$fastPackageReference], $newRequest)
+
+ foreach($pkg in $installedPkgs)
+ {
+ if($request.IsCanceled)
+ {
+ return
+ }
+
+ $destinationModulePath = Microsoft.PowerShell.Management\Join-Path -Path $moduleDestination -ChildPath $pkg.Name
+
+ # Side-by-Side module version is avialable on PowerShell 5.0 or later versions only
+ # By default, PowerShell module versions will be installed/updated Side-by-Side.
+ if(Test-ModuleSxSVersionSupport)
+ {
+ $destinationModulePath = Microsoft.PowerShell.Management\Join-Path -Path $destinationModulePath -ChildPath $pkg.Version
+ }
+
+ $destinationscriptPath = $scriptDestination
+
+ # Get actual artifact type from the package
+ $packageType = $script:PSArtifactTypeModule
+ $installLocation = $destinationModulePath
+ $tempPackagePath = Microsoft.PowerShell.Management\Join-Path -Path $tempDestination -ChildPath $pkg.Name
+ if(Microsoft.PowerShell.Management\Test-Path -Path $tempPackagePath)
+ {
+ $packageFiles = Microsoft.PowerShell.Management\Get-ChildItem -Path $tempPackagePath -Recurse -Exclude "*.nupkg","*.nuspec"
+
+ if($packageFiles -and $packageFiles.GetType().ToString() -eq 'System.IO.FileInfo' -and $packageFiles.Name -eq "$($pkg.Name).ps1")
+ {
+ $packageType = $script:PSArtifactTypeScript
+ $installLocation = $destinationscriptPath
+ }
+ }
+
+ $AdditionalParams = @{}
+
+ if(-not $IsSavePackage)
+ {
+ # During the install operation:
+ # InstalledDate should be the current Get-Date value
+ # UpdatedDate should be null
+ #
+ # During the update operation:
+ # InstalledDate should be from the previous version's InstalledDate otherwise current Get-Date value
+ # UpdatedDate should be the current Get-Date value
+ #
+ $InstalledDate = Microsoft.PowerShell.Utility\Get-Date
+
+ if($installUpdate)
+ {
+ $AdditionalParams['UpdatedDate'] = Microsoft.PowerShell.Utility\Get-Date
+
+ $InstalledItemDetails = $null
+ if($packageType -eq $script:PSArtifactTypeModule)
+ {
+ $InstalledItemDetails = Get-InstalledModuleDetails -Name $pkg.Name | Select-Object -Last 1
+ }
+ elseif($packageType -eq $script:PSArtifactTypeScript)
+ {
+ $InstalledItemDetails = Get-InstalledScriptDetails -Name $pkg.Name | Select-Object -Last 1
+ }
+
+ if($InstalledItemDetails -and
+ $InstalledItemDetails.PSGetItemInfo -and
+ (Get-Member -InputObject $InstalledItemDetails.PSGetItemInfo -Name 'InstalledDate') -and
+ $InstalledItemDetails.PSGetItemInfo.InstalledDate)
+ {
+ $InstalledDate = $InstalledItemDetails.PSGetItemInfo.InstalledDate
+ }
+ }
+
+ $AdditionalParams['InstalledDate'] = $InstalledDate
+ }
+
+ $sid = New-SoftwareIdentityFromPackage -Package $pkg `
+ -SourceLocation $sourceLocation `
+ -PackageManagementProviderName $provider.ProviderName `
+ -Request $request `
+ -Type $packageType `
+ -InstalledLocation $installLocation `
+ @AdditionalParams
+
+ # construct the PSGetItemInfo from SoftwareIdentity and persist it
+ $psgItemInfo = New-PSGetItemInfo -SoftwareIdentity $pkg `
+ -PackageManagementProviderName $provider.ProviderName `
+ -SourceLocation $sourceLocation `
+ -Type $packageType `
+ -InstalledLocation $installLocation `
+ @AdditionalParams
+
+ if($packageType -eq $script:PSArtifactTypeModule)
+ {
+ if ($psgItemInfo.PowerShellGetFormatVersion -and
+ ($script:SupportedPSGetFormatVersionMajors -notcontains $psgItemInfo.PowerShellGetFormatVersion.Major))
+ {
+ $message = $LocalizedData.NotSupportedPowerShellGetFormatVersion -f ($psgItemInfo.Name, $psgItemInfo.PowerShellGetFormatVersion, $psgItemInfo.Name)
+ Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation
+ continue
+ }
+
+ if(-not $psgItemInfo.PowerShellGetFormatVersion)
+ {
+ $sourceModulePath = Microsoft.PowerShell.Management\Join-Path $tempDestination $pkg.Name
+ }
+ else
+ {
+ $sourceModulePath = Microsoft.PowerShell.Management\Join-Path $tempDestination "$($pkg.Name)\Content\*\$script:ModuleReferences\$($pkg.Name)"
+ }
+
+ $CurrentModuleInfo = $null
+
+ # Validate the module
+ if(-not $IsSavePackage)
+ {
+ $CurrentModuleInfo = Test-ValidManifestModule -ModuleBasePath $sourceModulePath
+
+ if(-not $CurrentModuleInfo)
+ {
+ $message = $LocalizedData.InvalidPSModule -f ($pkg.Name)
+ Write-Error -Message $message -ErrorId "InvalidManifestModule" -Category InvalidOperation
+ continue
+ }
+ }
+
+ # Test if module is already installed
+ $InstalledModuleInfo2 = if(-not $IsSavePackage){ Test-ModuleInstalled -Name $pkg.Name -RequiredVersion $pkg.Version }
+
+ if($pkg.Name -ne $packageName)
+ {
+ if(-not $Force -and $InstalledModuleInfo2)
+ {
+ if(Test-ModuleSxSVersionSupport)
+ {
+ if($pkg.version -eq $InstalledModuleInfo2.Version)
+ {
+ if(-not $installUpdate)
+ {
+ $message = $LocalizedData.ModuleWithRequiredVersionAlreadyInstalled -f ($InstalledModuleInfo2.Version, $InstalledModuleInfo2.Name, $InstalledModuleInfo2.ModuleBase, $InstalledModuleInfo2.Version)
+ }
+ else
+ {
+ $message = $LocalizedData.NoUpdateAvailable -f ($pkg.Name)
+ }
+
+ Write-Verbose $message
+ Continue
+ }
+ }
+ else
+ {
+ if(-not $installUpdate)
+ {
+ $message = $LocalizedData.ModuleAlreadyInstalledVerbose -f ($InstalledModuleInfo2.Version, $InstalledModuleInfo2.Name, $InstalledModuleInfo2.ModuleBase)
+ Write-Verbose $message
+ Continue
+ }
+ else
+ {
+ if($pkg.version -gt $InstalledModuleInfo2.Version)
+ {
+ $message = $LocalizedData.FoundModuleUpdate -f ($pkg.Name, $pkg.Version)
+ Write-Verbose $message
+ }
+ else
+ {
+ $message = $LocalizedData.NoUpdateAvailable -f ($pkg.Name)
+ Write-Verbose $message
+ Continue
+ }
+ }
+ }
+ }
+
+ if($IsSavePackage)
+ {
+ $DependencyInstallMessage = $LocalizedData.SavingDependencyModule -f ($pkg.Name, $pkg.Version, $packageName)
+ }
+ else
+ {
+ $DependencyInstallMessage = $LocalizedData.InstallingDependencyModule -f ($pkg.Name, $pkg.Version, $packageName)
+ }
+
+ Write-Verbose $DependencyInstallMessage
+ }
+
+ # check if module is in use
+ if($InstalledModuleInfo2)
+ {
+ $moduleInUse = Test-ModuleInUse -ModuleBasePath $InstalledModuleInfo2.ModuleBase `
+ -ModuleName $InstalledModuleInfo2.Name `
+ -ModuleVersion $InstalledModuleInfo2.Version `
+ -Verbose:$VerbosePreference `
+ -WarningAction $WarningPreference `
+ -ErrorAction $ErrorActionPreference `
+ -Debug:$DebugPreference
+
+ if($moduleInUse)
+ {
+ $message = $LocalizedData.ModuleIsInUse -f ($psgItemInfo.Name)
+ Write-Verbose $message
+ continue
+ }
+ }
+
+ Copy-Module -SourcePath $sourceModulePath -DestinationPath $destinationModulePath -PSGetItemInfo $psgItemInfo
+
+ if(-not $IsSavePackage)
+ {
+ # Write warning messages if externally managed module dependencies are not installed.
+ $ExternalModuleDependencies = Get-ExternalModuleDependencies -PSModuleInfo $CurrentModuleInfo
+ foreach($ExternalDependency in $ExternalModuleDependencies)
+ {
+ $depModuleInfo = Test-ModuleInstalled -Name $ExternalDependency
+
+ if(-not $depModuleInfo)
+ {
+ Write-Warning -Message ($LocalizedData.MissingExternallyManagedModuleDependency -f $ExternalDependency,$pkg.Name,$ExternalDependency)
+ }
+ else
+ {
+ Write-Verbose -Message ($LocalizedData.ExternallyManagedModuleDependencyIsInstalled -f $ExternalDependency)
+ }
+ }
+ }
+
+ # Remove the old module base folder if it is different from the required destination module path when -Force is specified
+ if($Force -and
+ $InstalledModuleInfo2 -and
+ -not $destinationModulePath.StartsWith($InstalledModuleInfo2.ModuleBase, [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ Microsoft.PowerShell.Management\Remove-Item -Path $InstalledModuleInfo2.ModuleBase `
+ -Force -Recurse `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue `
+ -Confirm:$false -WhatIf:$false
+ }
+
+ if($IsSavePackage)
+ {
+ $message = $LocalizedData.ModuleSavedSuccessfully -f ($psgItemInfo.Name)
+ }
+ else
+ {
+ $message = $LocalizedData.ModuleInstalledSuccessfully -f ($psgItemInfo.Name)
+ }
+ Write-Verbose $message
+ }
+
+
+ if($packageType -eq $script:PSArtifactTypeScript)
+ {
+ if ($psgItemInfo.PowerShellGetFormatVersion -and
+ ($script:SupportedPSGetFormatVersionMajors -notcontains $psgItemInfo.PowerShellGetFormatVersion.Major))
+ {
+ $message = $LocalizedData.NotSupportedPowerShellGetFormatVersionScripts -f ($psgItemInfo.Name, $psgItemInfo.PowerShellGetFormatVersion, $psgItemInfo.Name)
+ Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation
+ continue
+ }
+
+ $sourceScriptPath = Microsoft.PowerShell.Management\Join-Path -Path $tempPackagePath -ChildPath "$($pkg.Name).ps1"
+
+ $currentScriptInfo = $null
+ if(-not $IsSavePackage)
+ {
+ # Validate the script
+ $currentScriptInfo = Test-ScriptFileInfo -Path $sourceScriptPath -ErrorAction SilentlyContinue
+
+ if(-not $currentScriptInfo)
+ {
+ $message = $LocalizedData.InvalidPowerShellScriptFile -f ($pkg.Name)
+ Write-Error -Message $message -ErrorId "InvalidPowerShellScriptFile" -Category InvalidOperation -TargetObject $pkg.Name
+ continue
+ }
+ }
+
+ # Test if script is already installed
+ $InstalledScriptInfo2 = if(-not $IsSavePackage){ Test-ScriptInstalled -Name $pkg.Name }
+
+ if($pkg.Name -ne $packageName)
+ {
+ if(-not $Force -and $InstalledScriptInfo2)
+ {
+ if(-not $installUpdate)
+ {
+ $message = $LocalizedData.ScriptAlreadyInstalledVerbose -f ($InstalledScriptInfo2.Version, $InstalledScriptInfo2.Name, $InstalledScriptInfo2.ScriptBase)
+ Write-Verbose $message
+ Continue
+ }
+ else
+ {
+ if($pkg.version -gt $InstalledScriptInfo2.Version)
+ {
+ $message = $LocalizedData.FoundScriptUpdate -f ($pkg.Name, $pkg.Version)
+ Write-Verbose $message
+ }
+ else
+ {
+ $message = $LocalizedData.NoScriptUpdateAvailable -f ($pkg.Name)
+ Write-Verbose $message
+ Continue
+ }
+ }
+ }
+
+ if($IsSavePackage)
+ {
+ $DependencyInstallMessage = $LocalizedData.SavingDependencyScript -f ($pkg.Name, $pkg.Version, $packageName)
+ }
+ else
+ {
+ $DependencyInstallMessage = $LocalizedData.InstallingDependencyScript -f ($pkg.Name, $pkg.Version, $packageName)
+ }
+
+ Write-Verbose $DependencyInstallMessage
+ }
+
+ Write-Debug "SourceScriptPath is $sourceScriptPath and DestinationscriptPath is $destinationscriptPath"
+ Copy-ScriptFile -SourcePath $sourceScriptPath -DestinationPath $destinationscriptPath -PSGetItemInfo $psgItemInfo -Scope $Scope
+
+ if(-not $IsSavePackage)
+ {
+ # Write warning messages if externally managed module dependencies are not installed.
+ foreach($ExternalDependency in $currentScriptInfo.ExternalModuleDependencies)
+ {
+ $depModuleInfo = Test-ModuleInstalled -Name $ExternalDependency
+
+ if(-not $depModuleInfo)
+ {
+ Write-Warning -Message ($LocalizedData.ScriptMissingExternallyManagedModuleDependency -f $ExternalDependency,$pkg.Name,$ExternalDependency)
+ }
+ else
+ {
+ Write-Verbose -Message ($LocalizedData.ExternallyManagedModuleDependencyIsInstalled -f $ExternalDependency)
+ }
+ }
+
+ # Write warning messages if externally managed script dependencies are not installed.
+ foreach($ExternalDependency in $currentScriptInfo.ExternalScriptDependencies)
+ {
+ $depScriptInfo = Test-ScriptInstalled -Name $ExternalDependency
+
+ if(-not $depScriptInfo)
+ {
+ Write-Warning -Message ($LocalizedData.ScriptMissingExternallyManagedScriptDependency -f $ExternalDependency,$pkg.Name,$ExternalDependency)
+ }
+ else
+ {
+ Write-Verbose -Message ($LocalizedData.ScriptExternallyManagedScriptDependencyIsInstalled -f $ExternalDependency)
+ }
+ }
+ }
+
+ # Remove the old scriptfile if it's path different from the required destination script path when -Force is specified
+ if($Force -and
+ $InstalledScriptInfo2 -and
+ -not $destinationscriptPath.StartsWith($InstalledScriptInfo2.ScriptBase, [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ Microsoft.PowerShell.Management\Remove-Item -Path $InstalledScriptInfo2.Path `
+ -Force `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue `
+ -Confirm:$false -WhatIf:$false
+ }
+
+ if($IsSavePackage)
+ {
+ $message = $LocalizedData.ScriptSavedSuccessfully -f ($psgItemInfo.Name)
+ }
+ else
+ {
+ $message = $LocalizedData.ScriptInstalledSuccessfully -f ($psgItemInfo.Name)
+ }
+ Write-Verbose $message
+ }
+
+ Write-Output -InputObject $sid
+ }
+ }
+ finally
+ {
+ Microsoft.PowerShell.Management\Remove-Item $tempDestination -Force -Recurse -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
+ }
+ }
+}
+
+function Uninstall-Package
+{
+ [CmdletBinding()]
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $fastPackageReference
+ )
+
+ Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Uninstall-Package'))
+
+ Write-Debug -Message ($LocalizedData.FastPackageReference -f $fastPackageReference)
+
+ # take the fastPackageReference and get the package object again.
+ $parts = $fastPackageReference -Split '[|]'
+ $Force = $false
+
+ $options = $request.Options
+ if($options)
+ {
+ foreach( $o in $options.Keys )
+ {
+ Write-Debug -Message ("OPTION: {0} => {1}" -f ($o, $request.Options[$o]) )
+ }
+ }
+
+ if($parts.Length -eq 5)
+ {
+ $providerName = $parts[0]
+ $packageName = $parts[1]
+ $version = $parts[2]
+ $sourceLocation= $parts[3]
+ $artfactType = $parts[4]
+
+ if($request.IsCanceled)
+ {
+ return
+ }
+
+ if($options.ContainsKey('Force'))
+ {
+ $Force = $options['Force']
+
+ if($Force.GetType().ToString() -eq 'System.String')
+ {
+ if($Force -eq 'false')
+ {
+ $Force = $false
+ }
+ elseif($Force -eq 'true')
+ {
+ $Force = $true
+ }
+ }
+ }
+
+ if($artfactType -eq $script:PSArtifactTypeModule)
+ {
+ $moduleName = $packageName
+ $InstalledModuleInfo = $script:PSGetInstalledModules["$($moduleName)$($version)"]
+
+ if(-not $InstalledModuleInfo)
+ {
+ $message = $LocalizedData.ModuleUninstallationNotPossibleAsItIsNotInstalledUsingPowerShellGet -f $moduleName
+
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "ModuleUninstallationNotPossibleAsItIsNotInstalledUsingPowerShellGet" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+
+ return
+ }
+
+ $moduleBase = $InstalledModuleInfo.PSGetItemInfo.InstalledLocation
+
+ if(-not (Test-RunningAsElevated) -and $moduleBase.StartsWith($script:programFilesModulesPath, [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $message = $LocalizedData.AdminPrivilegesRequiredForUninstall -f ($moduleName, $moduleBase)
+
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "AdminPrivilegesRequiredForUninstall" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation
+
+ return
+ }
+
+ $dependentModuleScript = {
+ param ([string] $moduleName)
+ Microsoft.PowerShell.Core\Get-Module -ListAvailable |
+ Microsoft.PowerShell.Core\Where-Object {
+ ($moduleName -ne $_.Name) -and (
+ ($_.RequiredModules -and $_.RequiredModules.Name -contains $moduleName) -or
+ ($_.NestedModules -and $_.NestedModules.Name -contains $moduleName))
+ }
+ }
+ $dependentModulesJob = Microsoft.PowerShell.Core\Start-Job -ScriptBlock $dependentModuleScript -ArgumentList $moduleName
+ Microsoft.PowerShell.Core\Wait-Job -job $dependentModulesJob
+ $dependentModules = Microsoft.PowerShell.Core\Receive-Job -job $dependentModulesJob
+
+ if(-not $Force -and $dependentModules)
+ {
+ $message = $LocalizedData.UnableToUninstallAsOtherModulesNeedThisModule -f ($moduleName, $version, $moduleBase, $(($dependentModules.Name | Select-Object -Unique) -join ','), $moduleName)
+
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "UnableToUninstallAsOtherModulesNeedThisModule" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation
+
+ return
+ }
+
+ $moduleInUse = Test-ModuleInUse -ModuleBasePath $moduleBase `
+ -ModuleName $InstalledModuleInfo.PSGetItemInfo.Name`
+ -ModuleVersion $InstalledModuleInfo.PSGetItemInfo.Version `
+ -Verbose:$VerbosePreference `
+ -WarningAction $WarningPreference `
+ -ErrorAction $ErrorActionPreference `
+ -Debug:$DebugPreference
+
+ if($moduleInUse)
+ {
+ $message = $LocalizedData.ModuleIsInUse -f ($moduleName)
+
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "ModuleIsInUse" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation
+
+ return
+ }
+
+ $ModuleBaseFolderToBeRemoved = $moduleBase
+
+ # With SxS version support, more than one version of the module can be installed.
+ # - Remove the parent directory of the module version base when only one version is installed
+ # - Don't remove the modulebase when it was installed before SxS version support and
+ # other versions are installed under the module base folder
+ #
+ if(Test-ModuleSxSVersionSupport)
+ {
+ $ModuleBaseWithoutVersion = $moduleBase
+ $IsModuleInstalledAsSxSVersion = $false
+
+ if($moduleBase.EndsWith("$version", [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $IsModuleInstalledAsSxSVersion = $true
+ $ModuleBaseWithoutVersion = Microsoft.PowerShell.Management\Split-Path -Path $moduleBase -Parent
+ }
+
+ $InstalledVersionsWithSameModuleBase = @()
+ Get-Module -Name $moduleName -ListAvailable |
+ Microsoft.PowerShell.Core\ForEach-Object {
+ if($_.ModuleBase.StartsWith($ModuleBaseWithoutVersion, [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $InstalledVersionsWithSameModuleBase += $_.ModuleBase
+ }
+ }
+
+ # Remove ..\ModuleName directory when only one module is installed with the same ..\ModuleName path
+ # like ..\ModuleName\1.0 or ..\ModuleName
+ if($InstalledVersionsWithSameModuleBase.Count -eq 1)
+ {
+ $ModuleBaseFolderToBeRemoved = $ModuleBaseWithoutVersion
+ }
+ elseif($ModuleBaseWithoutVersion -eq $moduleBase)
+ {
+ # There are version specific folders under the same module base dir
+ # Throw an error saying uninstall other versions then uninstall this current version
+ $message = $LocalizedData.UnableToUninstallModuleVersion -f ($moduleName, $version, $moduleBase)
+
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "UnableToUninstallModuleVersion" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation
+
+ return
+ }
+ # Otherwise specified version folder will be removed as current module base is assigned to $ModuleBaseFolderToBeRemoved
+ }
+
+ Microsoft.PowerShell.Management\Remove-Item -Path $ModuleBaseFolderToBeRemoved `
+ -Force -Recurse `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue `
+ -Confirm:$false -WhatIf:$false
+
+ $message = $LocalizedData.ModuleUninstallationSucceeded -f $moduleName, $moduleBase
+ Write-Verbose $message
+
+ Write-Output -InputObject $InstalledModuleInfo.SoftwareIdentity
+ }
+ elseif($artfactType -eq $script:PSArtifactTypeScript)
+ {
+ $scriptName = $packageName
+ $InstalledScriptInfo = $script:PSGetInstalledScripts["$($scriptName)$($version)"]
+
+ if(-not $InstalledScriptInfo)
+ {
+ $message = $LocalizedData.ScriptUninstallationNotPossibleAsItIsNotInstalledUsingPowerShellGet -f $scriptName
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "ScriptUninstallationNotPossibleAsItIsNotInstalledUsingPowerShellGet" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+
+ return
+ }
+
+ $scriptBase = $InstalledScriptInfo.PSGetItemInfo.InstalledLocation
+ $installedScriptInfoPath = $script:MyDocumentsInstalledScriptInfosPath
+
+ if($scriptBase.StartsWith($script:ProgramFilesScriptsPath, [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ if(-not (Test-RunningAsElevated))
+ {
+ $message = $LocalizedData.AdminPrivilegesRequiredForScriptUninstall -f ($scriptName, $scriptBase)
+
+ ThrowError -ExceptionName "System.InvalidOperationException" `
+ -ExceptionMessage $message `
+ -ErrorId "AdminPrivilegesRequiredForUninstall" `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation
+
+ return
+ }
+
+ $installedScriptInfoPath = $script:ProgramFilesInstalledScriptInfosPath
+ }
+
+ # Check if there are any dependent scripts
+ $dependentScriptDetails = $script:PSGetInstalledScripts.Values |
+ Microsoft.PowerShell.Core\Where-Object {
+ $_.PSGetItemInfo.Dependencies -contains $scriptName
+ }
+
+ $dependentScriptNames = $dependentScriptDetails |
+ Microsoft.PowerShell.Core\ForEach-Object { $_.PSGetItemInfo.Name }
+
+ if(-not $Force -and $dependentScriptNames)
+ {
+ $message = $LocalizedData.UnableToUninstallAsOtherScriptsNeedThisScript -f
+ ($scriptName,
+ $version,
+ $scriptBase,
+ $(($dependentScriptNames | Select-Object -Unique) -join ','),
+ $scriptName)
+
+ ThrowError -ExceptionName 'System.InvalidOperationException' `
+ -ExceptionMessage $message `
+ -ErrorId 'UnableToUninstallAsOtherScriptsNeedThisScript' `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidOperation
+ return
+ }
+
+ $scriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $scriptBase `
+ -ChildPath "$($scriptName).ps1"
+
+ $installledScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $installedScriptInfoPath `
+ -ChildPath "$($scriptName)_$($script:InstalledScriptInfoFileName)"
+
+ # Remove the script file and it's corresponding InstalledScriptInfo.xml
+ if(Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)
+ {
+ Microsoft.PowerShell.Management\Remove-Item -Path $scriptFilePath `
+ -Force `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue `
+ -Confirm:$false -WhatIf:$false
+ }
+
+ if(Microsoft.PowerShell.Management\Test-Path -Path $installledScriptInfoFilePath -PathType Leaf)
+ {
+ Microsoft.PowerShell.Management\Remove-Item -Path $installledScriptInfoFilePath `
+ -Force `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue `
+ -Confirm:$false -WhatIf:$false
+ }
+
+ $message = $LocalizedData.ScriptUninstallationSucceeded -f $scriptName, $scriptBase
+ Write-Verbose $message
+
+ Write-Output -InputObject $InstalledScriptInfo.SoftwareIdentity
+ }
+ }
+}
+
+function Get-InstalledPackage
+{
+ [CmdletBinding()]
+ param
+ (
+ [Parameter()]
+ [string]
+ $Name,
+
+ [Parameter()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter()]
+ [Version]
+ $MaximumVersion
+ )
+
+ Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Get-InstalledPackage'))
+
+ $options = $request.Options
+
+ foreach( $o in $options.Keys )
+ {
+ Write-Debug ( "OPTION: {0} => {1}" -f ($o, $options[$o]) )
+ }
+
+ $artifactTypes = $script:PSArtifactTypeModule
+ if($options.ContainsKey($script:PSArtifactType))
+ {
+ $artifactTypes = $options[$script:PSArtifactType]
+ }
+
+ if($artifactTypes -eq $script:All)
+ {
+ $artifactTypes = @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript)
+ }
+
+ if($artifactTypes -contains $script:PSArtifactTypeModule)
+ {
+ Get-InstalledModuleDetails -Name $Name `
+ -RequiredVersion $RequiredVersion `
+ -MinimumVersion $MinimumVersion `
+ -MaximumVersion $MaximumVersion | Microsoft.PowerShell.Core\ForEach-Object {$_.SoftwareIdentity}
+ }
+
+ if($artifactTypes -contains $script:PSArtifactTypeScript)
+ {
+ Get-InstalledScriptDetails -Name $Name `
+ -RequiredVersion $RequiredVersion `
+ -MinimumVersion $MinimumVersion `
+ -MaximumVersion $MaximumVersion | Microsoft.PowerShell.Core\ForEach-Object {$_.SoftwareIdentity}
+ }
+}
+
+#endregion
+
+#region Internal Utility functions for the PackageManagement Provider Implementation
+
+function Set-InstalledScriptsVariable
+{
+ # Initialize list of scripts installed by the PowerShellGet provider
+ $script:PSGetInstalledScripts = [ordered]@{}
+ $scriptPaths = @($script:ProgramFilesInstalledScriptInfosPath, $script:MyDocumentsInstalledScriptInfosPath)
+
+ foreach ($location in $scriptPaths)
+ {
+ # find all scripts installed using PowerShellGet
+ $scriptInfoFiles = Get-ChildItem -Path $location `
+ -Filter "*$script:InstalledScriptInfoFileName" `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+
+ if($scriptInfoFiles)
+ {
+ foreach ($scriptInfoFile in $scriptInfoFiles)
+ {
+ $psgetItemInfo = DeSerialize-PSObject -Path $scriptInfoFile.FullName
+
+ $scriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $psgetItemInfo.InstalledLocation `
+ -ChildPath "$($psgetItemInfo.Name).ps1"
+
+ # Remove the InstalledScriptInfo.xml file if the actual script file was manually uninstalled by the user
+ if(-not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf))
+ {
+ Microsoft.PowerShell.Management\Remove-Item -Path $scriptInfoFile.FullName -Force -ErrorAction SilentlyContinue
+
+ continue
+ }
+
+ $package = New-SoftwareIdentityFromPSGetItemInfo -PSGetItemInfo $psgetItemInfo
+
+ if($package)
+ {
+ $script:PSGetInstalledScripts["$($psgetItemInfo.Name)$($psgetItemInfo.Version)"] = @{
+ SoftwareIdentity = $package
+ PSGetItemInfo = $psgetItemInfo
+ }
+ }
+ }
+ }
+ }
+}
+
+function Get-InstalledScriptDetails
+{
+ [CmdletBinding()]
+ param
+ (
+ [Parameter()]
+ [string]
+ $Name,
+
+ [Parameter()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter()]
+ [Version]
+ $MaximumVersion
+ )
+
+ Set-InstalledScriptsVariable
+
+ # Keys in $script:PSGetInstalledScripts are "",
+ # first filter the installed scripts using "$Name*" wildcard search
+ # then apply $Name wildcard search to get the script name which meets the specified name with wildcards.
+ #
+ $wildcardPattern = New-Object System.Management.Automation.WildcardPattern "$Name*",$script:wildcardOptions
+ $nameWildcardPattern = New-Object System.Management.Automation.WildcardPattern $Name,$script:wildcardOptions
+
+ $script:PSGetInstalledScripts.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object {
+ if($wildcardPattern.IsMatch($_.Key))
+ {
+ $InstalledScriptDetails = $_.Value
+
+ if(-not $Name -or $nameWildcardPattern.IsMatch($InstalledScriptDetails.PSGetItemInfo.Name))
+ {
+ if($RequiredVersion)
+ {
+ if($RequiredVersion -eq $InstalledScriptDetails.PSGetItemInfo.Version)
+ {
+ $InstalledScriptDetails
+ }
+ }
+ else
+ {
+ if( (-not $MinimumVersion -or ($MinimumVersion -le $InstalledScriptDetails.PSGetItemInfo.Version)) -and
+ (-not $MaximumVersion -or ($MaximumVersion -ge $InstalledScriptDetails.PSGetItemInfo.Version)))
+ {
+ $InstalledScriptDetails
+ }
+ }
+ }
+ }
+ }
+}
+
+function Get-InstalledModuleDetails
+{
+ [CmdletBinding()]
+ param
+ (
+ [Parameter()]
+ [string]
+ $Name,
+
+ [Parameter()]
+ [Version]
+ $RequiredVersion,
+
+ [Parameter()]
+ [Version]
+ $MinimumVersion,
+
+ [Parameter()]
+ [Version]
+ $MaximumVersion
+ )
+
+ Set-InstalledModulesVariable
+
+ # Keys in $script:PSGetInstalledModules are "",
+ # first filter the installed modules using "$Name*" wildcard search
+ # then apply $Name wildcard search to get the module name which meets the specified name with wildcards.
+ #
+ $wildcardPattern = New-Object System.Management.Automation.WildcardPattern "$Name*",$script:wildcardOptions
+ $nameWildcardPattern = New-Object System.Management.Automation.WildcardPattern $Name,$script:wildcardOptions
+
+ $script:PSGetInstalledModules.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object {
+ if($wildcardPattern.IsMatch($_.Key))
+ {
+ $InstalledModuleDetails = $_.Value
+
+ if(-not $Name -or $nameWildcardPattern.IsMatch($InstalledModuleDetails.PSGetItemInfo.Name))
+ {
+ if($RequiredVersion)
+ {
+ if($RequiredVersion -eq $InstalledModuleDetails.PSGetItemInfo.Version)
+ {
+ $InstalledModuleDetails
+ }
+ }
+ else
+ {
+ if( (-not $MinimumVersion -or ($MinimumVersion -le $InstalledModuleDetails.PSGetItemInfo.Version)) -and
+ (-not $MaximumVersion -or ($MaximumVersion -ge $InstalledModuleDetails.PSGetItemInfo.Version)))
+ {
+ $InstalledModuleDetails
+ }
+ }
+ }
+ }
+ }
+}
+
+function New-SoftwareIdentityFromPackage
+{
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ $Package,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $PackageManagementProviderName,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $SourceLocation,
+
+ [Parameter()]
+ [switch]
+ $IsFromTrustedSource,
+
+ [Parameter(Mandatory=$true)]
+ $request,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $Type,
+
+ [Parameter()]
+ [string]
+ $InstalledLocation,
+
+ [Parameter()]
+ [System.DateTime]
+ $InstalledDate,
+
+ [Parameter()]
+ [System.DateTime]
+ $UpdatedDate
+ )
+
+ $fastPackageReference = New-FastPackageReference -ProviderName $PackageManagementProviderName `
+ -PackageName $Package.Name `
+ -Version $Package.Version `
+ -Source $SourceLocation `
+ -ArtifactType $Type
+
+ $links = New-Object -TypeName System.Collections.ArrayList
+ foreach($lnk in $Package.Links)
+ {
+ if( $lnk.Relationship -eq "icon" -or $lnk.Relationship -eq "license" -or $lnk.Relationship -eq "project" )
+ {
+ $links.Add( (New-Link -Href $lnk.HRef -RelationShip $lnk.Relationship ) )
+ }
+ }
+
+ $entities = New-Object -TypeName System.Collections.ArrayList
+ foreach( $entity in $Package.Entities )
+ {
+ if( $entity.Role -eq "author" -or $entity.Role -eq "owner" )
+ {
+ $entities.Add( (New-Entity -Name $entity.Name -Role $entity.Role -RegId $entity.RegId -Thumbprint $entity.Thumbprint) )
+ }
+ }
+
+ $deps = (new-Object -TypeName System.Collections.ArrayList)
+ foreach( $dep in $pkg.Dependencies )
+ {
+ # Add each dependency and say it's from this provider.
+ $newDep = New-Dependency -ProviderName $script:PSModuleProviderName `
+ -PackageName $request.Services.ParsePackageName($dep) `
+ -Version $request.Services.ParsePackageVersion($dep) `
+ -Source $SourceLocation
+
+ $deps.Add( $newDep )
+ }
+
+
+ $details = New-Object -TypeName System.Collections.Hashtable
+
+ foreach ( $key in $Package.Metadata.Keys.LocalName)
+ {
+ if (!$details.ContainsKey($key))
+ {
+ $details.Add($key, (Get-First $Package.Metadata[$key]) )
+ }
+ }
+
+ $details.Add( "PackageManagementProvider" , $PackageManagementProviderName )
+ $details.Add( "Type" , $Type )
+
+ if($InstalledLocation)
+ {
+ $details.Add( $script:InstalledLocation , $InstalledLocation )
+ }
+
+ if($InstalledDate)
+ {
+ $details.Add( 'installeddate' , $InstalledDate.ToString() )
+ }
+
+ if($UpdatedDate)
+ {
+ $details.Add( 'updateddate' , $UpdatedDate.ToString() )
+ }
+
+ # Initialize package source name to the source location
+ $sourceNameForSoftwareIdentity = $SourceLocation
+
+ $sourceName = (Get-SourceName -Location $SourceLocation)
+
+ if($sourceName)
+ {
+ $details.Add( "SourceName" , $sourceName )
+
+ # Override the source name only if we are able to map source location to source name
+ $sourceNameForSoftwareIdentity = $sourceName
+ }
+
+ $params = @{FastPackageReference = $fastPackageReference;
+ Name = $Package.Name;
+ Version = $Package.Version;
+ versionScheme = "MultiPartNumeric";
+ Source = $sourceNameForSoftwareIdentity;
+ Summary = $Package.Summary;
+ SearchKey = $Package.Name;
+ FullPath = $Package.FullPath;
+ FileName = $Package.Name;
+ Details = $details;
+ Entities = $entities;
+ Links = $links;
+ Dependencies = $deps;
+ }
+
+ if($IsFromTrustedSource)
+ {
+ $params["FromTrustedSource"] = $true
+ }
+
+ $sid = New-SoftwareIdentity @params
+
+ return $sid
+}
+
+function New-PackageSourceFromModuleSource
+{
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ $ModuleSource
+ )
+
+ $ScriptSourceLocation = $null
+ if(Get-Member -InputObject $ModuleSource -Name $script:ScriptSourceLocation)
+ {
+ $ScriptSourceLocation = $ModuleSource.ScriptSourceLocation
+ }
+
+ $ScriptPublishLocation = $ModuleSource.PublishLocation
+ if(Get-Member -InputObject $ModuleSource -Name $script:ScriptPublishLocation)
+ {
+ $ScriptPublishLocation = $ModuleSource.ScriptPublishLocation
+ }
+
+ $packageSourceDetails = @{}
+ $packageSourceDetails["InstallationPolicy"] = $ModuleSource.InstallationPolicy
+ $packageSourceDetails["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $ModuleSource)
+ $packageSourceDetails[$script:PublishLocation] = $ModuleSource.PublishLocation
+ $packageSourceDetails[$script:ScriptSourceLocation] = $ScriptSourceLocation
+ $packageSourceDetails[$script:ScriptPublishLocation] = $ScriptPublishLocation
+
+ $ModuleSource.ProviderOptions.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object {
+ $packageSourceDetails[$_.Key] = $_.Value
+ }
+
+ # create a new package source
+ $src = New-PackageSource -Name $ModuleSource.Name `
+ -Location $ModuleSource.SourceLocation `
+ -Trusted $ModuleSource.Trusted `
+ -Registered $ModuleSource.Registered `
+ -Details $packageSourceDetails
+
+ Write-Verbose ( $LocalizedData.RepositoryDetails -f ($src.Name, $src.Location, $src.IsTrusted, $src.IsRegistered) )
+
+ # return the package source object.
+ Write-Output -InputObject $src
+}
+
+function New-ModuleSourceFromPackageSource
+{
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ $PackageSource
+ )
+
+ $moduleSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
+ Name = $PackageSource.Name
+ SourceLocation = $PackageSource.Location
+ Trusted=$PackageSource.IsTrusted
+ Registered=$PackageSource.IsRegistered
+ InstallationPolicy = $PackageSource.Details['InstallationPolicy']
+ PackageManagementProvider=$PackageSource.Details['PackageManagementProvider']
+ PublishLocation=$PackageSource.Details[$script:PublishLocation]
+ ScriptSourceLocation=$PackageSource.Details[$script:ScriptSourceLocation]
+ ScriptPublishLocation=$PackageSource.Details[$script:ScriptPublishLocation]
+ ProviderOptions = @{}
+ })
+
+ $PackageSource.Details.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object {
+ if($_.Key -ne 'PackageManagementProvider' -and
+ $_.Key -ne $script:PublishLocation -and
+ $_.Key -ne $script:ScriptPublishLocation -and
+ $_.Key -ne $script:ScriptSourceLocation -and
+ $_.Key -ne 'InstallationPolicy')
+ {
+ $moduleSource.ProviderOptions[$_.Key] = $_.Value
+ }
+ }
+
+ $moduleSource.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepository")
+
+ # return the module source object.
+ Write-Output -InputObject $moduleSource
+}
+
+function New-FastPackageReference
+{
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ [string]
+ $ProviderName,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $PackageName,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $Version,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $Source,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $ArtifactType
+ )
+
+ return "$ProviderName|$PackageName|$Version|$Source|$ArtifactType"
+}
+
+function Get-First
+{
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ $IEnumerator
+ )
+
+ foreach($item in $IEnumerator)
+ {
+ return $item
+ }
+
+ return $null
+}
+
+function Set-InstalledModulesVariable
+{
+ # Initialize list of modules installed by the PowerShellGet provider
+ $script:PSGetInstalledModules = [ordered]@{}
+
+ $modulePaths = @($script:ProgramFilesModulesPath, $script:MyDocumentsModulesPath)
+
+ foreach ($location in $modulePaths)
+ {
+ # find all modules installed using PowerShellGet
+ $moduleBases = Get-ChildItem $location -Recurse `
+ -Attributes Hidden -Filter $script:PSGetItemInfoFileName `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue `
+ | Foreach-Object { $_.Directory }
+
+
+ foreach ($moduleBase in $moduleBases)
+ {
+ $PSGetItemInfoPath = Microsoft.PowerShell.Management\Join-Path $moduleBase.FullName $script:PSGetItemInfoFileName
+
+ # Check if this module got installed using PSGet, read its contents to create a SoftwareIdentity object
+ if (Microsoft.PowerShell.Management\Test-Path $PSGetItemInfoPath)
+ {
+ $psgetItemInfo = DeSerialize-PSObject -Path $PSGetItemInfoPath
+
+ # Add InstalledLocation if this module was installed with older version of PowerShellGet
+ if(-not (Get-Member -InputObject $psgetItemInfo -Name $script:InstalledLocation))
+ {
+ Microsoft.PowerShell.Utility\Add-Member -InputObject $psgetItemInfo `
+ -MemberType NoteProperty `
+ -Name $script:InstalledLocation `
+ -Value $moduleBase.FullName
+ }
+
+ $package = New-SoftwareIdentityFromPSGetItemInfo -PSGetItemInfo $psgetItemInfo
+
+ if($package)
+ {
+ $script:PSGetInstalledModules["$($psgetItemInfo.Name)$($psgetItemInfo.Version)"] = @{
+ SoftwareIdentity = $package
+ PSGetItemInfo = $psgetItemInfo
+ }
+ }
+ }
+ }
+ }
+}
+
+function New-SoftwareIdentityFromPSGetItemInfo
+{
+ param
+ (
+ [Parameter(Mandatory=$true)]
+ $PSGetItemInfo
+ )
+
+ $SourceLocation = $psgetItemInfo.RepositorySourceLocation
+
+ if(Get-Member -InputObject $PSGetItemInfo -Name $script:PSArtifactType)
+ {
+ $artifactType = $psgetItemInfo.Type
+ }
+ else
+ {
+ $artifactType = $script:PSArtifactTypeModule
+ }
+
+ $fastPackageReference = New-FastPackageReference -ProviderName (Get-ProviderName -PSCustomObject $psgetItemInfo) `
+ -PackageName $psgetItemInfo.Name `
+ -Version $psgetItemInfo.Version `
+ -Source $SourceLocation `
+ -ArtifactType $artifactType
+
+ $links = New-Object -TypeName System.Collections.ArrayList
+ if($psgetItemInfo.IconUri)
+ {
+ $links.Add( (New-Link -Href $psgetItemInfo.IconUri -RelationShip "icon") )
+ }
+
+ if($psgetItemInfo.LicenseUri)
+ {
+ $links.Add( (New-Link -Href $psgetItemInfo.LicenseUri -RelationShip "license") )
+ }
+
+ if($psgetItemInfo.ProjectUri)
+ {
+ $links.Add( (New-Link -Href $psgetItemInfo.ProjectUri -RelationShip "project") )
+ }
+
+ $entities = New-Object -TypeName System.Collections.ArrayList
+ if($psgetItemInfo.Author)
+ {
+ $entities.Add( (New-Entity -Name $psgetItemInfo.Author -Role 'author') )
+ }
+
+ if($psgetItemInfo.CompanyName -and $psgetItemInfo.CompanyName.ToString())
+ {
+ $entities.Add( (New-Entity -Name $psgetItemInfo.CompanyName -Role 'owner') )
+ }
+
+ $details = @{
+ description = $psgetItemInfo.Description
+ copyright = $psgetItemInfo.Copyright
+ published = $psgetItemInfo.PublishedDate.ToString()
+ installeddate = $null
+ updateddate = $null
+ tags = $psgetItemInfo.Tags
+ releaseNotes = $psgetItemInfo.ReleaseNotes
+ PackageManagementProvider = (Get-ProviderName -PSCustomObject $psgetItemInfo)
+ }
+
+ if((Get-Member -InputObject $psgetItemInfo -Name 'InstalledDate') -and $psgetItemInfo.InstalledDate)
+ {
+ $details['installeddate'] = $psgetItemInfo.InstalledDate.ToString()
+ }
+
+ if((Get-Member -InputObject $psgetItemInfo -Name 'UpdatedDate') -and $psgetItemInfo.UpdatedDate)
+ {
+ $details['updateddate'] = $psgetItemInfo.UpdatedDate.ToString()
+ }
+
+ if(Get-Member -InputObject $psgetItemInfo -Name $script:InstalledLocation)
+ {
+ $details[$script:InstalledLocation] = $psgetItemInfo.InstalledLocation
+ }
+
+ $details[$script:PSArtifactType] = $artifactType
+
+ $sourceName = Get-SourceName -Location $SourceLocation
+ if($sourceName)
+ {
+ $details["SourceName"] = $sourceName
+ }
+
+ $params = @{
+ FastPackageReference = $fastPackageReference;
+ Name = $psgetItemInfo.Name;
+ Version = $psgetItemInfo.Version;
+ versionScheme = "MultiPartNumeric";
+ Source = $SourceLocation;
+ Summary = $psgetItemInfo.Description;
+ Details = $details;
+ Entities = $entities;
+ Links = $links
+ }
+
+ if($sourceName -and $script:PSGetModuleSources[$sourceName].Trusted)
+ {
+ $params["FromTrustedSource"] = $true
+ }
+
+ $sid = New-SoftwareIdentity @params
+
+ return $sid
+}
+
+#endregion
+
+#region Common functions
+
+function Get-EnvironmentVariable
+{
+ param
+ (
+ [parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [String]
+ $Name,
+
+ [parameter(Mandatory = $true)]
+ [int]
+ $Target
+ )
+
+ if ($Target -eq $script:EnvironmentVariableTarget.Process)
+ {
+ return [System.Environment]::GetEnvironmentVariable($Name)
+ }
+ elseif ($Target -eq $script:EnvironmentVariableTarget.Machine)
+ {
+ $itemPropertyValue = Microsoft.PowerShell.Management\Get-ItemProperty -Path $script:SystemEnvironmentKey -Name $Name -ErrorAction SilentlyContinue
+
+ if($itemPropertyValue)
+ {
+ return $itemPropertyValue.$Name
+ }
+ }
+ elseif ($Target -eq $script:EnvironmentVariableTarget.User)
+ {
+ $itemPropertyValue = Microsoft.PowerShell.Management\Get-ItemProperty -Path $script:UserEnvironmentKey -Name $Name -ErrorAction SilentlyContinue
+
+ if($itemPropertyValue)
+ {
+ return $itemPropertyValue.$Name
+ }
+ }
+}
+
+function Set-EnvironmentVariable
+{
+ param
+ (
+ [parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [String]
+ $Name,
+
+ [parameter()]
+ [String]
+ $Value,
+
+ [parameter(Mandatory = $true)]
+ [int]
+ $Target
+ )
+
+ if ($Target -eq $script:EnvironmentVariableTarget.Process)
+ {
+ [System.Environment]::SetEnvironmentVariable($Name, $Value)
+
+ return
+ }
+ elseif ($Target -eq $script:EnvironmentVariableTarget.Machine)
+ {
+ if ($Name.Length -ge $script:SystemEnvironmentVariableMaximumLength)
+ {
+ $message = $LocalizedData.InvalidEnvironmentVariableName -f ($Name, $script:SystemEnvironmentVariableMaximumLength)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId 'InvalidEnvironmentVariableName' `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Name
+ return
+ }
+
+ $Path = $script:SystemEnvironmentKey
+ }
+ elseif ($Target -eq $script:EnvironmentVariableTarget.User)
+ {
+ if ($Name.Length -ge $script:UserEnvironmentVariableMaximumLength)
+ {
+ $message = $LocalizedData.InvalidEnvironmentVariableName -f ($Name, $script:UserEnvironmentVariableMaximumLength)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId 'InvalidEnvironmentVariableName' `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Name
+ return
+ }
+
+ $Path = $script:UserEnvironmentKey
+ }
+
+ if (!$Value)
+ {
+ Microsoft.PowerShell.Management\Remove-ItemProperty $Path -Name $Name -ErrorAction SilentlyContinue
+ }
+ else
+ {
+ Microsoft.PowerShell.Management\Set-ItemProperty $Path -Name $Name -Value $Value
+ }
+}
+
+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)
+}
+
+function Log-ArtifactNotFoundInPSGallery
+{
+ [CmdletBinding()]
+ Param
+ (
+ [Parameter()]
+ [string[]]
+ $SearchedName,
+
+ [Parameter()]
+ [string[]]
+ $FoundName,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $operationName
+ )
+
+ if (-not $script:TelemetryEnabled)
+ {
+ return
+ }
+
+ if(-not $SearchedName)
+ {
+ return
+ }
+
+ $SearchedNameNoWildCards = @()
+
+ # Ignore wild cards
+ foreach ($artifactName in $SearchedName)
+ {
+ if (-not (Test-WildcardPattern $artifactName))
+ {
+ $SearchedNameNoWildCards += $artifactName
+ }
+ }
+
+ # Find artifacts searched, but not found in the specified gallery
+ $notFoundArtifacts = @()
+ foreach ($element in $SearchedNameNoWildCards)
+ {
+ if (-not ($FoundName -contains $element))
+ {
+ $notFoundArtifacts += $element
+ }
+ }
+
+ # Perform Telemetry only if searched artifacts are not available in specified Gallery
+ if ($notFoundArtifacts)
+ {
+ [Microsoft.PowerShell.Get.Telemetry]::TraceMessageArtifactsNotFound($notFoundArtifacts, $operationName)
+ }
+}
+
+# Function to record non-PSGallery registration for telemetry
+# Function consumes the type of registration (i.e hosted (http(s)), non-hosted (file/unc)), locations, installation policy, provider and event name
+function Log-NonPSGalleryRegistration
+{
+ [CmdletBinding()]
+ Param
+ (
+ [Parameter()]
+ [string]
+ $sourceLocation,
+
+ [Parameter()]
+ [string]
+ $installationPolicy,
+
+ [Parameter()]
+ [string]
+ $packageManagementProvider,
+
+ [Parameter()]
+ [string]
+ $publishLocation,
+
+ [Parameter()]
+ [string]
+ $scriptSourceLocation,
+
+ [Parameter()]
+ [string]
+ $scriptPublishLocation,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $operationName
+ )
+
+ if (-not $script:TelemetryEnabled)
+ {
+ return
+ }
+
+ # Initialize source location type - this can be hosted (http(s)) or not hosted (unc/file)
+ $sourceLocationType = "NON_WEB_HOSTED"
+ if (Test-WebUri -uri $sourceLocation)
+ {
+ $sourceLocationType = "WEB_HOSTED"
+ }
+
+ # Create a hash of the source location
+ # We cannot log the actual source location, since this might contain PII (Personally identifiable information) data
+ $sourceLocationHash = Get-Hash -locationString $sourceLocation
+ $publishLocationHash = Get-Hash -locationString $publishLocation
+ $scriptSourceLocationHash = Get-Hash -locationString $scriptSourceLocation
+ $scriptPublishLocationHash = Get-Hash -locationString $scriptPublishLocation
+
+ # Log the telemetry event
+ [Microsoft.PowerShell.Get.Telemetry]::TraceMessageNonPSGalleryRegistration($sourceLocationType, $sourceLocationHash, $installationPolicy, $packageManagementProvider, $publishLocationHash, $scriptSourceLocationHash, $scriptPublishLocationHash, $operationName)
+}
+
+# Returns a SHA1 hash of the specified string
+function Get-Hash
+{
+ [CmdletBinding()]
+ Param
+ (
+ [string]
+ $locationString
+ )
+
+ if(-not $locationString)
+ {
+ return ""
+ }
+
+ $sha1Object = New-Object System.Security.Cryptography.SHA1Managed
+ $stringHash = $sha1Object.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($locationString));
+ $stringHashInHex = [System.BitConverter]::ToString($stringHash)
+
+ if ($stringHashInHex)
+ {
+ # Remove all dashes in the hex string
+ return $stringHashInHex.Replace('-', '')
+ }
+
+ return ""
+}
+
+function Get-ValidModuleLocation
+{
+ [CmdletBinding()]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $LocationString,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $ParameterName
+ )
+
+ # Get the actual Uri from the Location
+ if(-not (Microsoft.PowerShell.Management\Test-Path $LocationString))
+ {
+ # Append '/api/v2/' to the $LocationString, return if that URI works.
+ if(($LocationString -notmatch 'LinkID') -and
+ -not ($LocationString.EndsWith('/api/v2', [System.StringComparison]::OrdinalIgnoreCase)) -and
+ -not ($LocationString.EndsWith('/api/v2/', [System.StringComparison]::OrdinalIgnoreCase))
+ )
+ {
+ $tempLocation = $null
+
+ if($LocationString.EndsWith('/', [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $tempLocation = $LocationString + 'api/v2/'
+ }
+ else
+ {
+ $tempLocation = $LocationString + '/api/v2/'
+ }
+
+ if($tempLocation)
+ {
+ # Ping and resolve the specified location
+ $tempLocation = Resolve-Location -Location $tempLocation `
+ -LocationParameterName $ParameterName `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+ if($tempLocation)
+ {
+ return $tempLocation
+ }
+ # No error if we can't resolve the URL appended with '/api/v2/'
+ }
+ }
+
+ # Ping and resolve the specified location
+ $LocationString = Resolve-Location -Location $LocationString `
+ -LocationParameterName $ParameterName `
+ -CallerPSCmdlet $PSCmdlet
+ }
+
+ return $LocationString
+}
+
+function Save-ModuleSources
+{
+ if($script:PSGetModuleSources)
+ {
+ if(-not (Microsoft.PowerShell.Management\Test-Path $script:PSGetAppLocalPath))
+ {
+ $null = Microsoft.PowerShell.Management\New-Item -Path $script:PSGetAppLocalPath `
+ -ItemType Directory -Force `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue `
+ -Confirm:$false -WhatIf:$false
+ }
+ Microsoft.PowerShell.Utility\Out-File -FilePath $script:PSGetModuleSourcesFilePath -Force -InputObject ([System.Management.Automation.PSSerializer]::Serialize($script:PSGetModuleSources))
+ }
+}
+
+function Test-ModuleSxSVersionSupport
+{
+ # Side-by-Side module version is avialable on PowerShell 5.0 or later versions only
+ # By default, PowerShell module versions will be installed/updated Side-by-Side.
+ $PSVersionTable.PSVersion -ge [Version]"5.0"
+}
+
+function Test-ModuleInstalled
+{
+ [CmdletBinding(PositionalBinding=$false)]
+ [OutputType("PSModuleInfo")]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Name,
+
+ [Parameter()]
+ [Version]
+ $RequiredVersion
+ )
+
+ # Check if module is already installed
+ $availableModule = Microsoft.PowerShell.Core\Get-Module -ListAvailable -Name $Name -Verbose:$false |
+ Microsoft.PowerShell.Core\Where-Object {-not (Test-ModuleSxSVersionSupport) -or -not $RequiredVersion -or ($RequiredVersion -eq $_.Version)} |
+ Microsoft.PowerShell.Utility\Select-Object -Unique
+
+ return $availableModule
+}
+
+function Test-ScriptInstalled
+{
+ [CmdletBinding(PositionalBinding=$false)]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Name,
+
+ [Parameter()]
+ [Version]
+ $RequiredVersion
+ )
+
+ $scriptInfo = $null
+ $scriptFileName = "$Name.ps1"
+ $scriptPaths = @($script:ProgramFilesScriptsPath, $script:MyDocumentsScriptsPath)
+ $scriptInfos = @()
+
+ foreach ($location in $scriptPaths)
+ {
+ $scriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $location -ChildPath $scriptFileName
+
+ if(Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)
+ {
+ $scriptInfo = $null
+ try
+ {
+ $scriptInfo = Test-ScriptFileInfo -Path $scriptFilePath -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
+ }
+ catch
+ {
+ # Ignore any terminating error from the Test-ScriptFileInfo cmdlet,
+ # if it does not contain valid Script metadata
+ Write-Verbose -Message "$_"
+ }
+
+ if($scriptInfo)
+ {
+ $scriptInfos += $scriptInfo
+ }
+ else
+ {
+ # Since the script file doesn't contain the valid script metadata,
+ # create dummy PSScriptInfo object with 0.0 version
+ $scriptInfo = New-PSScriptInfoObject -Path $scriptFilePath
+ $scriptInfo.$script:Version = [Version]'0.0'
+
+ $scriptInfos += $scriptInfo
+ }
+ }
+ }
+
+ $scriptInfo = $scriptInfos | Microsoft.PowerShell.Core\Where-Object {
+ (-not $RequiredVersion) -or ($RequiredVersion -eq $_.Version)
+ } | Microsoft.PowerShell.Utility\Select-Object -First 1
+
+ return $scriptInfo
+}
+
+function New-PSScriptInfoObject
+{
+ [CmdletBinding(PositionalBinding=$false)]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [string]
+ $Path
+ )
+
+ $PSScriptInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{})
+ $script:PSScriptInfoProperties | Microsoft.PowerShell.Core\ForEach-Object {
+ Microsoft.PowerShell.Utility\Add-Member -InputObject $PSScriptInfo `
+ -MemberType NoteProperty `
+ -Name $_ `
+ -Value $null
+ }
+
+ $PSScriptInfo.$script:Name = [System.IO.Path]::GetFileNameWithoutExtension($Path)
+ $PSScriptInfo.$script:Path = $Path
+ $PSScriptInfo.$script:ScriptBase = (Microsoft.PowerShell.Management\Split-Path -Path $Path -Parent)
+
+ return $PSScriptInfo
+}
+
+function Get-OrderedPSScriptInfoObject
+{
+ [CmdletBinding(PositionalBinding=$false)]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [PSCustomObject]
+ $PSScriptInfo
+ )
+
+ $NewPSScriptInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
+ $script:Name = $PSScriptInfo.$script:Name
+ $script:Version = $PSScriptInfo.$script:Version
+ $script:Guid = $PSScriptInfo.$script:Guid
+ $script:Path = $PSScriptInfo.$script:Path
+ $script:ScriptBase = $PSScriptInfo.$script:ScriptBase
+ $script:Description = $PSScriptInfo.$script:Description
+ $script:Author = $PSScriptInfo.$script:Author
+ $script:CompanyName = $PSScriptInfo.$script:CompanyName
+ $script:Copyright = $PSScriptInfo.$script:Copyright
+ $script:Tags = $PSScriptInfo.$script:Tags
+ $script:ReleaseNotes = $PSScriptInfo.$script:ReleaseNotes
+ $script:RequiredModules = $PSScriptInfo.$script:RequiredModules
+ $script:ExternalModuleDependencies = $PSScriptInfo.$script:ExternalModuleDependencies
+ $script:RequiredScripts = $PSScriptInfo.$script:RequiredScripts
+ $script:ExternalScriptDependencies = $PSScriptInfo.$script:ExternalScriptDependencies
+ $script:LicenseUri = $PSScriptInfo.$script:LicenseUri
+ $script:ProjectUri = $PSScriptInfo.$script:ProjectUri
+ $script:IconUri = $PSScriptInfo.$script:IconUri
+ $script:DefinedCommands = $PSScriptInfo.$script:DefinedCommands
+ $script:DefinedFunctions = $PSScriptInfo.$script:DefinedFunctions
+ $script:DefinedWorkflows = $PSScriptInfo.$script:DefinedWorkflows
+ })
+
+ $NewPSScriptInfo.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSScriptInfo")
+
+ return $NewPSScriptInfo
+}
+
+function Get-AvailableScriptFilePath
+{
+ [CmdletBinding(PositionalBinding=$false)]
+ Param
+ (
+ [Parameter()]
+ [string]
+ $Name
+ )
+
+ $scriptInfo = $null
+ $scriptFileName = '*.ps1'
+ $scriptBasePaths = @($script:ProgramFilesScriptsPath, $script:MyDocumentsScriptsPath)
+ $scriptFilePaths = @()
+ $wildcardPattern = $null
+
+ if($Name)
+ {
+ if(Test-WildcardPattern -Name $Name)
+ {
+ $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $Name,$script:wildcardOptions
+ }
+ else
+ {
+ $scriptFileName = "$Name.ps1"
+ }
+
+ }
+
+ foreach ($location in $scriptBasePaths)
+ {
+ $scriptFiles = Get-ChildItem -Path $location `
+ -Filter $scriptFileName `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+
+ if($wildcardPattern)
+ {
+ $scriptFiles | Microsoft.PowerShell.Core\ForEach-Object {
+ if($wildcardPattern.IsMatch($_.BaseName))
+ {
+ $scriptFilePaths += $_.FullName
+ }
+ }
+ }
+ else
+ {
+ $scriptFiles | Microsoft.PowerShell.Core\ForEach-Object { $scriptFilePaths += $_.FullName }
+ }
+ }
+
+ return $scriptFilePaths
+}
+
+function Get-InstalledScriptFilePath
+{
+ [CmdletBinding(PositionalBinding=$false)]
+ Param
+ (
+ [Parameter()]
+ [string]
+ $Name
+ )
+
+ $installedScriptFilePaths = @()
+ $scriptFilePaths = Get-AvailableScriptFilePath @PSBoundParameters
+
+ foreach ($scriptFilePath in $scriptFilePaths)
+ {
+ $scriptInfo = Test-ScriptInstalled -Name ([System.IO.Path]::GetFileNameWithoutExtension($scriptFilePath))
+
+ if($scriptInfo)
+ {
+ $installedScriptInfoFilePath = $null
+ $installedScriptInfoFileName = "$($scriptInfo.Name)_$script:InstalledScriptInfoFileName"
+
+ if($scriptInfo.Path.StartsWith($script:ProgramFilesScriptsPath, [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesInstalledScriptInfosPath `
+ -ChildPath $installedScriptInfoFileName
+ }
+ elseif($scriptInfo.Path.StartsWith($script:MyDocumentsScriptsPath, [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsInstalledScriptInfosPath `
+ -ChildPath $installedScriptInfoFileName
+ }
+
+ if($installedScriptInfoFilePath -and (Microsoft.PowerShell.Management\Test-Path -Path $installedScriptInfoFilePath -PathType Leaf))
+ {
+ $installedScriptFilePaths += $scriptInfo.Path
+ }
+ }
+ }
+
+ return $installedScriptFilePaths
+}
+
+
+function Update-ModuleManifest
+{
+<#
+.ExternalHelp PSGet.psm1-help.xml
+#>
+[CmdletBinding(SupportsShouldProcess=$true,
+ PositionalBinding=$false,
+ HelpUri='http://go.microsoft.com/fwlink/?LinkId=619311')]
+ Param
+ (
+ [Parameter(Mandatory=$true,
+ Position=0,
+ ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Path,
+
+ [ValidateNotNullOrEmpty()]
+ [Object[]]
+ $NestedModules,
+
+ [ValidateNotNullOrEmpty()]
+ [Guid]
+ $Guid,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Author,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [String]
+ $CompanyName,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Copyright,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $RootModule,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Version]
+ $ModuleVersion,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $Description,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [System.Reflection.ProcessorArchitecture]
+ $ProcessorArchitecture,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Version]
+ $PowerShellVersion,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Version]
+ $ClrVersion,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Version]
+ $DotNetFrameworkVersion,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [String]
+ $PowerShellHostName,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Version]
+ $PowerShellHostVersion,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Object[]]
+ $RequiredModules,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $TypesToProcess,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $FormatsToProcess,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $ScriptsToProcess,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $RequiredAssemblies,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $FileList,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [object[]]
+ $ModuleList,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $FunctionsToExport,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $AliasesToExport,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $VariablesToExport,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $CmdletsToExport,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $DscResourcesToExport,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [System.Collections.Hashtable]
+ $PrivateData,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string[]]
+ $Tags,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $ProjectUri,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $LicenseUri,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $IconUri,
+
+ [Parameter()]
+ [string[]]
+ $ReleaseNotes,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $HelpInfoUri,
+
+ [Parameter()]
+ [switch]
+ $PassThru,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [String]
+ $DefaultCommandPrefix,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [String[]]
+ $ExternalModuleDependencies,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [String[]]
+ $PackageManagementProviders
+ )
+
+
+ Import-LocalizedData -BindingVariable ModuleManifestHashTable `
+ -FileName (Microsoft.PowerShell.Management\Split-Path $Path -Leaf) `
+ -BaseDirectory (Microsoft.PowerShell.Management\Split-Path $Path -Parent) `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+
+ if(-not (Microsoft.PowerShell.Management\Test-Path $Path))
+ {
+ $message = $LocalizedData.UpdateModuleManifestPathCannotFound -f ($Path)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidModuleManifestFilePath" `
+ -ExceptionObject $Path `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+
+ #Get the original module manifest and migrate all the fields to the new module manifest, including the specified parameter values
+ try
+ {
+ $moduleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $Path -ErrorAction Stop
+ }
+ catch
+ {
+ $message = $LocalizedData.TestModuleManifestFail -f ($_.Exception.Message)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidModuleManifestFile" `
+ -ExceptionObject $Path `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ return
+ }
+
+ #Params to pass to New-ModuleManifest module
+ $params = @{}
+
+ #NestedModules is read-only property
+ if($NestedModules)
+ {
+ $params.Add("NestedModules",$NestedModules)
+ }
+ elseif($moduleInfo.NestedModules)
+ {
+ #Get the original module info from ManifestHashTab
+ if($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("NestedModules"))
+ {
+ $params.Add("NestedModules",$ModuleManifestHashtable.NestedModules)
+ }
+ }
+
+ #Guid is read-only property
+ if($Guid)
+ {
+ $params.Add("Guid",$Guid)
+ }
+ elseif($moduleInfo.Guid)
+ {
+ $params.Add("Guid",$moduleInfo.Guid)
+ }
+
+ if($Author)
+ {
+ $params.Add("Author",$Author)
+ }
+ elseif($moduleInfo.Author)
+ {
+ $params.Add("Author",$moduleInfo.Author)
+ }
+
+ if($CompanyName)
+ {
+ $params.Add("CompanyName",$CompanyName)
+ }
+ elseif($moduleInfo.CompanyName)
+ {
+ $params.Add("CompanyName",$moduleInfo.CompanyName)
+ }
+
+ if($Copyright)
+ {
+ $params.Add("CopyRight",$Copyright)
+ }
+ elseif($moduleInfo.Copyright)
+ {
+ $params.Add("Copyright",$moduleInfo.Copyright)
+ }
+
+ if($RootModule)
+ {
+ $params.Add("RootModule",$RootModule)
+ }
+ elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("RootModule") -and $moduleInfo.RootModule)
+ {
+ $params.Add("RootModule",$ModuleManifestHashTable.RootModule)
+ }
+
+ if($ModuleVersion)
+ {
+ $params.Add("ModuleVersion",$ModuleVersion)
+ }
+ elseif($moduleInfo.Version)
+ {
+ $params.Add("ModuleVersion",$moduleInfo.Version)
+ }
+
+ if($Description)
+ {
+ $params.Add("Description",$Description)
+ }
+ elseif($moduleInfo.Description)
+ {
+ $params.Add("Description",$moduleInfo.Description)
+ }
+
+ if($ProcessorArchitecture)
+ {
+ $params.Add("ProcessorArchitecture",$ProcessorArchitecture)
+ }
+ #Check if ProcessorArchitecture has a value and is not 'None' on lower verison PS
+ elseif($moduleInfo.ProcessorArchitecture -and $moduleInfo.ProcessorArchitecture -ne 'None')
+ {
+ $params.Add("ProcessorArchitecture",$moduleInfo.ProcessorArchitecture)
+ }
+
+ if($PowerShellVersion)
+ {
+ $params.Add("PowerShellVersion",$PowerShellVersion)
+ }
+ elseif($moduleinfo.PowerShellVersion)
+ {
+ $params.Add("PowerShellVersion",$moduleinfo.PowerShellVersion)
+ }
+
+ if($ClrVersion)
+ {
+ $params.Add("ClrVersion",$ClrVersion)
+ }
+ elseif($moduleInfo.ClrVersion)
+ {
+ $params.Add("ClrVersion",$moduleInfo.ClrVersion)
+ }
+
+ if($DotNetFrameworkVersion)
+ {
+ $params.Add("DotNetFrameworkVersion",$DotNetFrameworkVersion)
+ }
+ elseif($moduleInfo.DotNetFrameworkVersion)
+ {
+ $params.Add("DotNetFrameworkVersion",$moduleInfo.DotNetFrameworkVersion)
+ }
+
+ if($PowerShellHostName)
+ {
+ $params.Add("PowerShellHostName",$PowerShellHostName)
+ }
+ elseif($moduleInfo.PowerShellHostName)
+ {
+ $params.Add("PowerShellHostName",$moduleInfo.PowerShellHostName)
+ }
+
+ if($PowerShellHostVersion)
+ {
+ $params.Add("PowerShellHostVersion",$PowerShellHostVersion)
+ }
+ elseif($moduleInfo.PowerShellHostVersion)
+ {
+ $params.Add("PowerShellHostVersion",$moduleInfo.PowerShellHostVersion)
+ }
+
+ if($RequiredModules)
+ {
+ $params.Add("RequiredModules",$RequiredModules)
+ }
+ elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("RequiredModules") -and $moduleInfo.RequiredModules)
+ {
+ $params.Add("RequiredModules",$ModuleManifestHashtable.RequiredModules)
+ }
+
+ if($TypesToProcess)
+ {
+ $params.Add("TypesToProcess",$TypesToProcess)
+ }
+ elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("TypesToProcess") -and $moduleInfo.ExportedTypeFiles)
+ {
+ $params.Add("TypesToProcess",$ModuleManifestHashTable.TypesToProcess)
+ }
+
+ if($FormatsToProcess)
+ {
+ $params.Add("FormatsToProcess",$FormatsToProcess)
+ }
+ elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("FormatsToProcess") -and $moduleInfo.ExportedFormatFiles)
+ {
+ $params.Add("FormatsToProcess",$ModuleManifestHashTable.FormatsToProcess)
+ }
+
+ if($ScriptsToProcess)
+ {
+ $params.Add("ScriptsToProcess",$ScriptstoProcess)
+ }
+ elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("ScriptsToProcess") -and $moduleInfo.Scripts)
+ {
+ $params.Add("ScriptsToProcess",$ModuleManifestHashTable.ScriptsToProcess)
+ }
+
+ if($RequiredAssemblies)
+ {
+ $params.Add("RequiredAssemblies",$RequiredAssemblies)
+ }
+ elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("RequiredAssemblies") -and $moduleInfo.RequiredAssemblies)
+ {
+ $params.Add("RequiredAssemblies",$moduleInfo.RequiredAssemblies)
+ }
+
+ if($FileList)
+ {
+ $params.Add("FileList",$FileList)
+ }
+ elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("FileList") -and $moduleInfo.FileList)
+ {
+ $params.Add("FileList",$ModuleManifestHashTable.FileList)
+ }
+
+ #Make sure every path defined under FileList is within module base
+ $moduleBase = $moduleInfo.ModuleBase
+ foreach($file in $params["FileList"])
+ {
+ #If path is not root path, append the module base to it and check if the file exists
+ if(-not [System.IO.Path]::IsPathRooted($file))
+ {
+ $combinedPath = Join-Path $moduleBase -ChildPath $file
+ }
+ else
+ {
+ $combinedPath = $file
+ }
+ if(-not (Microsoft.PowerShell.Management\Test-Path -Type Leaf -LiteralPath $combinedPath))
+ {
+ $message = $LocalizedData.FilePathInFileListNotWithinModuleBase -f ($file,$moduleBase)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "FilePathInFileListNotWithinModuleBase" `
+ -ExceptionObject $file `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+
+ return
+ }
+ }
+
+ if($ModuleList)
+ {
+ $params.Add("ModuleList",$ModuleList)
+ }
+ elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("ModuleList") -and $moduleInfo.ModuleList)
+ {
+ $params.Add("ModuleList",$ModuleManifestHashtable.ModuleList)
+ }
+
+ if($FunctionsToExport)
+ {
+ $params.Add("FunctionsToExport",$FunctionsToExport)
+ }
+
+ elseif($moduleInfo.ExportedFunctions)
+ {
+ #Since $moduleInfo.ExportedFunctions is a hashtable, we need to take the name of the
+ #functions and make them into a list
+ $params.Add("FunctionsToExport",($moduleInfo.ExportedFunctions.Keys -split ' '))
+ }
+
+
+ if($AliasesToExport)
+ {
+ $params.Add("AliasesToExport",$AliasesToExport)
+ }
+ elseif($moduleInfo.ExportedAliases)
+ {
+ $params.Add("AliasesToExport",($moduleInfo.ExportedAliases.Keys -split ' '))
+ }
+ if($VariablesToExport)
+ {
+ $params.Add("VariablesToExport",$VariablesToExport)
+ }
+ elseif($moduleInfo.ExportedVariables)
+ {
+ $params.Add("VariablesToExport",($moduleInfo.ExportedVariables.Keys -split ' '))
+ }
+ if($CmdletsToExport)
+ {
+ $params.Add("CmdletsToExport", $CmdletsToExport)
+ }
+ elseif($moduleInfo.ExportedCmdlets)
+ {
+ $params.Add("CmdletsToExport",($moduleInfo.ExportedCmdlets.Keys -split ' '))
+ }
+ if($DscResourcesToExport)
+ {
+ #DscResourcesToExport field is not available in PowerShell version lower than 5.0
+
+ if (($PSVersionTable.PSVersion -lt [Version]"5.0") -or ($PowerShellVersion -and $PowerShellVersion -lt [Version]"5.0") `
+ -or (-not $PowerShellVersion -and $moduleInfo.PowerShellVersion -and $moduleInfo.PowerShellVersion -lt [Version]"5.0") `
+ -or (-not $PowerShellVersion -and -not $moduleInfo.PowerShellVersion))
+ {
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $LocalizedData.ExportedDscResourcesNotSupportedOnLowerPowerShellVersion `
+ -ErrorId "ExportedDscResourcesNotSupported" `
+ -ExceptionObject $DscResourcesToExport `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ return
+ }
+
+ $params.Add("DscResourcesToExport",$DscResourcesToExport)
+ }
+ elseif(Microsoft.PowerShell.Utility\Get-Member -InputObject $moduleInfo -name "ExportedDscResources")
+ {
+ if($moduleInfo.ExportedDscResources)
+ {
+ $params.Add("DscResourcesToExport",$moduleInfo.ExportedDscResources)
+ }
+ }
+
+ if($HelpInfoUri)
+ {
+ $params.Add("HelpInfoUri",$HelpInfoUri)
+ }
+ elseif($moduleInfo.HelpInfoUri)
+ {
+ $params.Add("HelpInfoUri",$moduleInfo.HelpInfoUri)
+ }
+
+ if($DefaultCommandPrefix)
+ {
+ $params.Add("DefaultCommandPrefix",$DefaultCommandPrefix)
+ }
+ elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("DefaultCommandPrefix") -and $ModuleManifestHashTable.DefaultCommandPrefix)
+ {
+ $params.Add("DefaultCommandPrefix",$ModuleManifestHashTable.DefaultCommandPrefix)
+ }
+
+ #Create a temp file within the directory and generate a new temporary manifest with the input
+ $tempPath = Microsoft.PowerShell.Management\Join-Path -Path $moduleInfo.ModuleBase -ChildPath "PSGet_$($moduleInfo.Name).psd1"
+ $params.Add("Path",$tempPath)
+
+ try
+ {
+ #Terminates if there is error creating new module manifest
+ try{
+ Microsoft.PowerShell.Core\New-ModuleManifest @params -Confirm:$false -WhatIf:$false
+ }
+ catch
+ {
+ $ErrorMessage = $LocalizedData.UpdatedModuleManifestNotValid -f ($Path, $_.Exception.Message)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $ErrorMessage `
+ -ErrorId "NewModuleManifestFailure" `
+ -ExceptionObject $params `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ return
+ }
+
+ #Manually update the section in PrivateData since New-ModuleManifest works differently on different PS version
+ $PrivateDataInput = ""
+ $ExistingData = $moduleInfo.PrivateData
+ $Data = @{}
+ if($ExistingData)
+ {
+ foreach($key in $ExistingData.Keys)
+ {
+ if($key -ne "PSData"){
+ $Data.Add($key,$ExistingData[$key])
+ }
+ else
+ {
+ $PSData = $ExistingData["PSData"]
+ foreach($entry in $PSData.Keys)
+ {
+ $Data.Add($entry,$PSData[$Entry])
+ }
+ }
+ }
+ }
+
+ if($PrivateData)
+ {
+ foreach($key in $PrivateData.Keys)
+ {
+ #if user provides PSData within PrivateData, we will parse through the PSData
+ if($key -ne "PSData")
+ {
+ $Data[$key] = $PrivateData[$Key]
+ }
+
+ else
+ {
+ $PSData = $ExistingData["PSData"]
+ foreach($entry in $PSData.Keys)
+ {
+ $Data[$entry] = $PSData[$entry]
+ }
+ }
+ }
+ }
+
+ #Tags is a read-only property
+ if($Tags)
+ {
+ $Data["Tags"] = $Tags
+ }
+
+
+ #The following Uris and ReleaseNotes cannot be empty
+ if($ProjectUri)
+ {
+ $Data["ProjectUri"] = $ProjectUri
+ }
+
+ if($LicenseUri)
+ {
+ $Data["LicenseUri"] = $LicenseUri
+ }
+ if($IconUri)
+ {
+ $Data["IconUri"] = $IconUri
+ }
+
+ if($ReleaseNotes)
+ {
+ #If value is provided as an array, we append the string.
+ $Data["ReleaseNotes"] = $($ReleaseNotes -join "`r`n")
+ }
+
+ if($ExternalModuleDependencies)
+ {
+ #ExternalModuleDependencies have to be specified either under $RequiredModules or $NestedModules
+ #Extract all the module names specified in the moduleInfo of NestedModules and RequiredModules
+ $DependentModuleNames = @()
+ foreach($moduleInfo in $params["NestedModules"])
+ {
+ if($moduleInfo.GetType() -eq [System.Collections.Hashtable])
+ {
+ $DependentModuleNames += $moduleInfo.ModuleName
+ }
+ }
+
+ foreach($moduleInfo in $params["RequiredModules"])
+ {
+ if($moduleInfo.GetType() -eq [System.Collections.Hashtable])
+ {
+ $DependentModuleNames += $moduleInfo.ModuleName
+ }
+ }
+
+ foreach($dependency in $ExternalModuleDependencies)
+ {
+ if($params["NestedModules"] -notcontains $dependency -and
+ $params["RequiredModules"] -notContains $dependency -and
+ $DependentModuleNames -notcontains $dependency)
+ {
+ $message = $LocalizedData.ExternalModuleDependenciesNotSpecifiedInRequiredOrNestedModules -f ($dependency)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidExternalModuleDependencies" `
+ -ExceptionObject $Exception `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ return
+ }
+ }
+ if($Data.ContainsKey("ExternalModuleDependencies"))
+ {
+ $Data["ExternalModuleDependencies"] = $ExternalModuleDependencies
+ }
+ else
+ {
+ $Data.Add("ExternalModuleDependencies", $ExternalModuleDependencies)
+ }
+ }
+ if($PackageManagementProviders)
+ {
+ #Check if the provided value is within the relative path
+ $ModuleBase = Microsoft.PowerShell.Management\Split-Path $Path -Parent
+ $Files = Microsoft.PowerShell.Management\Get-ChildItem -Path $ModuleBase
+ foreach($provider in $PackageManagementProviders)
+ {
+ if ($Files.Name -notcontains $provider)
+ {
+ $message = $LocalizedData.PackageManagementProvidersNotInModuleBaseFolder -f ($provider,$ModuleBase)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidPackageManagementProviders" `
+ -ExceptionObject $PackageManagementProviders `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ return
+ }
+ }
+
+ $Data["PackageManagementProviders"] = $PackageManagementProviders
+ }
+ $PrivateDataInput = Get-PrivateData -PrivateData $Data
+
+ #Repleace the PrivateData section by first locating the linenumbers of start line and endline.
+ $PrivateDataBegin = Select-String -Path $tempPath -Pattern "PrivateData ="
+ $PrivateDataBeginLine = $PrivateDataBegin.LineNumber
+
+ $newManifest = Microsoft.PowerShell.Management\Get-Content -Path $tempPath
+ #Look up the endline of PrivateData section by finding the matching brackets since private data could
+ #consist of multiple pairs of brackets.
+ $PrivateDataEndLine=0
+ if($PrivateDataBegin -match "@{")
+ {
+ $leftBrace = 0
+ $EndLineOfFile = $newManifest.Length-1
+
+ For($i = $PrivateDataBeginLine;$i -lt $EndLineOfFile; $i++)
+ {
+ if($newManifest[$i] -match "{")
+ {
+ $leftBrace ++
+ }
+ elseif($newManifest[$i] -match "}")
+ {
+ if($leftBrace -gt 0)
+ {
+ $leftBrace --
+ }
+ else
+ {
+ $PrivateDataEndLine = $i
+ break
+ }
+ }
+ }
+ }
+
+
+ try
+ {
+ if($PrivateDataEndLine -ne 0)
+ {
+ #If PrivateData section has more than one line, we will remove the old content and insert the new PrivataData
+ $newManifest | where {$_.readcount -le $PrivateDataBeginLine -or $_.readcount -gt $PrivateDataEndLine+1} `
+ | ForEach-Object {
+ $_
+ if($_ -match "PrivateData = ")
+ {
+ $PrivateDataInput
+ }
+ } | Set-Content -Path $tempPath -Confirm:$false -WhatIf:$false
+ }
+
+ #In lower version, PrivateData is just a single line
+ else
+ {
+ $PrivateDataForDownlevelPS = "PrivateData = @{ `n"+$PrivateDataInput
+
+ $newManifest | where {$_.readcount -le $PrivateDataBeginLine -or $_.readcount -gt $PrivateDataBeginLine } `
+ | ForEach-Object {
+ $_
+ if($_ -match "PrivateData = ")
+ {
+ $PrivateDataForDownlevelPS
+ }
+ } | Set-Content -Path $tempPath -Confirm:$false -WhatIf:$false
+ }
+
+ #Verify the new module manifest is valid
+ $testModuleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $tempPath `
+ -Verbose:$VerbosePreference `
+ }
+ #Catch the exceptions from Test-ModuleManifest
+ catch
+ {
+ $message = $LocalizedData.UpdatedModuleManifestNotValid -f ($Path, $_.Exception.Message)
+
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "UpdateManifestFileFail" `
+ -ExceptionObject $_.Exception `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ return
+ }
+
+
+ $newContent = Microsoft.PowerShell.Management\Get-Content -Path $tempPath
+
+ try{
+ #Ask for confirmation of the new manifest before replacing the original one
+ if($PSCmdlet.ShouldProcess($Path,$LocalizedData.UpdateManifestContentMessage+$newContent))
+ {
+ Microsoft.PowerShell.Management\Set-Content -Path $Path -Value $newContent -Confirm:$false -WhatIf:$false
+ }
+
+ #Return the new content if -PassThru is specified
+ if($PassThru)
+ {
+ return $newContent
+ }
+ }
+ catch
+ {
+ $message = $LocalizedData.ManifestFileReadWritePermissionDenied -f ($Path)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "ManifestFileReadWritePermissionDenied" `
+ -ExceptionObject $Path `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ }
+ }
+ finally
+ {
+ Microsoft.PowerShell.Management\Remove-Item -LiteralPath $tempPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
+ }
+}
+
+#Utility function to help form the content string for PrivateData
+function Get-PrivateData
+{
+ param
+ (
+ [System.Collections.Hashtable]
+ $PrivateData
+ )
+
+ if($PrivateData.Keys.Count -eq 0)
+ {
+ $content = "
+ PSData = @{
+
+ # Tags applied to this module. These help with module discovery in online galleries.
+ # Tags = @()
+
+ # A URL to the license for this module.
+ # LicenseUri = ''
+
+ # A URL to the main website for this project.
+ # ProjectUri = ''
+
+ # A URL to an icon representing this module.
+ # IconUri = ''
+
+ # ReleaseNotes of this module
+ # ReleaseNotes = ''
+
+ # External dependent modules of this module
+ # ExternalModuleDependencies = ''
+
+ } # End of PSData hashtable
+
+} # End of PrivateData hashtable"
+ return $content
+ }
+
+
+ #Validate each of the property of PSData is of the desired data type
+ $Tags= $PrivateData["Tags"] -join "','" | %{"'$_'"}
+ $LicenseUri = $PrivateData["LicenseUri"]| %{"'$_'"}
+ $ProjectUri = $PrivateData["ProjectUri"] | %{"'$_'"}
+ $IconUri = $PrivateData["IconUri"] | %{"'$_'"}
+ $ReleaseNotesEscape = $PrivateData["ReleaseNotes"] -Replace "'","''"
+ $ReleaseNotes = $ReleaseNotesEscape | %{"'$_'"}
+ $ExternalModuleDependencies = $PrivateData["ExternalModuleDependencies"] -join "','" | %{"'$_'"}
+
+ $DefaultProperties = @("Tags","LicenseUri","ProjectUri","IconUri","ReleaseNotes","ExternalModuleDependencies")
+
+ $ExtraProperties = @()
+ foreach($key in $PrivateData.Keys)
+ {
+ if($DefaultProperties -notcontains $key)
+ {
+ $PropertyString = "#"+"$key"+ " of this module"
+ $PropertyString += "`r`n "
+ $PropertyString += $key +" = " + "'"+$PrivateData[$key]+"'"
+ $ExtraProperties += ,$PropertyString
+ }
+ }
+
+ $ExtraPropertiesString = ""
+ $firstProperty = $true
+ foreach($property in $ExtraProperties)
+ {
+ if($firstProperty)
+ {
+ $firstProperty = $false
+ }
+ else
+ {
+ $ExtraPropertiesString += "`r`n`r`n "
+ }
+ $ExtraPropertiesString += $Property
+ }
+
+ $TagsLine ="# Tags = @()"
+ if($Tags -ne "''")
+ {
+ $TagsLine = "Tags = "+$Tags
+ }
+ $LicenseUriLine = "# LicenseUri = ''"
+ if($LicenseUri -ne "''")
+ {
+ $LicenseUriLine = "LicenseUri = "+$LicenseUri
+ }
+ $ProjectUriLine = "# ProjectUri = ''"
+ if($ProjectUri -ne "''")
+ {
+ $ProjectUriLine = "ProjectUri = " +$ProjectUri
+ }
+ $IconUriLine = "# IconUri = ''"
+ if($IconUri -ne "''")
+ {
+ $IconUriLine = "IconUri = " +$IconUri
+ }
+ $ReleaseNotesLine = "# ReleaseNotes = ''"
+ if($ReleaseNotes -ne "''")
+ {
+ $ReleaseNotesLine = "ReleaseNotes = "+$ReleaseNotes
+ }
+ $ExternalModuleDependenciesLine ="# ExternalModuleDependencies = ''"
+ if($ExternalModuleDependencies -ne "''")
+ {
+ $ExternalModuleDependenciesLine = "ExternalModuleDependencies = "+$ExternalModuleDependencies
+ }
+
+ if(-not $ExtraPropertiesString -eq "")
+ {
+ $Content = "
+ ExtraProperties
+
+ PSData = @{
+
+ # Tags applied to this module. These help with module discovery in online galleries.
+ $TagsLine
+
+ # A URL to the license for this module.
+ $LicenseUriLine
+
+ # A URL to the main website for this project.
+ $ProjectUriLine
+
+ # A URL to an icon representing this module.
+ $IconUriLine
+
+ # ReleaseNotes of this module
+ $ReleaseNotesLine
+
+ # External dependent modules of this module
+ $ExternalModuleDependenciesLine
+
+ } # End of PSData hashtable
+
+} # End of PrivateData hashtable"
+
+ #Replace the Extra PrivateData in the block
+ $Content -replace "ExtraProperties", $ExtraPropertiesString
+ }
+ else
+ {
+ $content = "
+ PSData = @{
+
+ # Tags applied to this module. These help with module discovery in online galleries.
+ $TagsLine
+
+ # A URL to the license for this module.
+ $LicenseUriLine
+
+ # A URL to the main website for this project.
+ $ProjectUriLine
+
+ # A URL to an icon representing this module.
+ $IconUriLine
+
+ # ReleaseNotes of this module
+ $ReleaseNotesLine
+
+ # External dependent modules of this module
+ $ExternalModuleDependenciesLine
+
+ } # End of PSData hashtable
+
+ } # End of PrivateData hashtable"
+ return $content
+ }
+}
+
+function Copy-ScriptFile
+{
+ [CmdletBinding(PositionalBinding=$false)]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $SourcePath,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $DestinationPath,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNull()]
+ [PSCustomObject]
+ $PSGetItemInfo,
+
+ [Parameter()]
+ [string]
+ $Scope
+ )
+
+ # Copy the script file to destination
+ if(-not (Microsoft.PowerShell.Management\Test-Path -Path $DestinationPath))
+ {
+ $null = Microsoft.PowerShell.Management\New-Item -Path $DestinationPath `
+ -ItemType Directory `
+ -Force `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue `
+ -Confirm:$false `
+ -WhatIf:$false
+ }
+
+ Microsoft.PowerShell.Management\Copy-Item -Path $SourcePath -Destination $DestinationPath -Force -Confirm:$false -WhatIf:$false -Verbose
+
+ if($Scope)
+ {
+ # Create _InstalledScriptInfo.xml
+ $InstalledScriptInfoFileName = "$($PSGetItemInfo.Name)_$script:InstalledScriptInfoFileName"
+
+ if($scope -eq 'AllUsers')
+ {
+ $scriptInfopath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesInstalledScriptInfosPath `
+ -ChildPath $InstalledScriptInfoFileName
+ }
+ else
+ {
+ $scriptInfopath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsInstalledScriptInfosPath `
+ -ChildPath $InstalledScriptInfoFileName
+ }
+
+ Microsoft.PowerShell.Utility\Out-File -FilePath $scriptInfopath `
+ -Force `
+ -InputObject ([System.Management.Automation.PSSerializer]::Serialize($PSGetItemInfo))
+ }
+}
+
+function Copy-Module
+{
+ [CmdletBinding(PositionalBinding=$false)]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $SourcePath,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $DestinationPath,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNull()]
+ [PSCustomObject]
+ $PSGetItemInfo
+ )
+
+ if(Microsoft.PowerShell.Management\Test-Path $DestinationPath)
+ {
+ Microsoft.PowerShell.Management\Remove-Item -Path $DestinationPath -Recurse -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
+ }
+
+ # Copy the module to destination
+ $null = Microsoft.PowerShell.Management\New-Item -Path $DestinationPath -ItemType Directory -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
+ Microsoft.PowerShell.Management\Copy-Item -Path "$SourcePath\*" -Destination $DestinationPath -Force -Recurse -Confirm:$false -WhatIf:$false
+
+ # Remove the *.nupkg file
+ if(Microsoft.PowerShell.Management\Test-Path "$DestinationPath\$($PSGetItemInfo.Name).nupkg")
+ {
+ Microsoft.PowerShell.Management\Remove-Item -Path "$DestinationPath\$($PSGetItemInfo.Name).nupkg" -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
+ }
+
+ # Create PSGetModuleInfo.xml
+ $psgetItemInfopath = Microsoft.PowerShell.Management\Join-Path $DestinationPath $script:PSGetItemInfoFileName
+
+ Microsoft.PowerShell.Utility\Out-File -FilePath $psgetItemInfopath -Force -InputObject ([System.Management.Automation.PSSerializer]::Serialize($PSGetItemInfo))
+
+ [System.IO.File]::SetAttributes($psgetItemInfopath, [System.IO.FileAttributes]::Hidden)
+}
+
+function Test-FileInUse
+{
+ [CmdletBinding()]
+ [OutputType([bool])]
+ param
+ (
+ [string]
+ $FilePath
+ )
+
+ if(Microsoft.PowerShell.Management\Test-Path -LiteralPath $FilePath -PathType Leaf)
+ {
+ # Attempts to open a file and handles the exception if the file is already open/locked
+ try
+ {
+ $fileInfo = New-Object System.IO.FileInfo $FilePath
+ $fileStream = $fileInfo.Open( [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None )
+
+ if ($fileStream)
+ {
+ $fileStream.Close()
+ }
+ }
+ catch
+ {
+ Write-Debug "In Test-FileInUse function, unable to open the $FilePath file in ReadWrite access. $_"
+ return $true
+ }
+ }
+
+ return $false
+}
+
+function Test-ModuleInUse
+{
+ [CmdletBinding()]
+ [OutputType([bool])]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $ModuleBasePath,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $ModuleName,
+
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Version]
+ $ModuleVersion
+ )
+
+ $FileList = Get-ChildItem -Path $ModuleBasePath `
+ -File `
+ -Recurse `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+ $IsModuleInUse = $false
+
+ foreach($file in $FileList)
+ {
+ $IsModuleInUse = Test-FileInUse -FilePath $file.FullName
+
+ if($IsModuleInUse)
+ {
+ break
+ }
+ }
+
+ if($IsModuleInUse)
+ {
+ $message = $LocalizedData.ModuleVersionInUse -f ($ModuleVersion, $ModuleName)
+ Write-Error -Message $message -ErrorId 'ModuleIsInUse' -Category InvalidOperation
+
+ return $true
+ }
+
+ return $false
+}
+
+function Test-ValidManifestModule
+{
+ [CmdletBinding()]
+ [OutputType([bool])]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [string]
+ $ModuleBasePath
+ )
+
+ $moduleName = Microsoft.PowerShell.Management\Split-Path $ModuleBasePath -Leaf
+ $manifestPath = Microsoft.PowerShell.Management\Join-Path $ModuleBasePath "$moduleName.psd1"
+ $PSModuleInfo = $null
+
+ if(Microsoft.PowerShell.Management\Test-Path $manifestPath)
+ {
+ $PSModuleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $manifestPath -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
+ }
+
+ return $PSModuleInfo
+}
+
+function Get-ScriptSourceLocation
+{
+ [CmdletBinding()]
+ Param
+ (
+ [Parameter()]
+ [String]
+ $Location
+ )
+
+ $scriptLocation = $null
+
+ if($Location)
+ {
+ # For local dir or SMB-share locations, ScriptSourceLocation is SourceLocation.
+ if(Microsoft.PowerShell.Management\Test-Path -Path $Location)
+ {
+ $scriptLocation = $Location
+ }
+ else
+ {
+ $tempScriptLocation = $null
+
+ if($Location.EndsWith('/api/v2', [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $tempScriptLocation = $Location + '/items/psscript/'
+ }
+ elseif($Location.EndsWith('/api/v2/', [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $tempScriptLocation = $Location + 'items/psscript/'
+ }
+
+ if($tempScriptLocation)
+ {
+ # Ping and resolve the specified location
+ $scriptLocation = Resolve-Location -Location $tempScriptLocation `
+ -LocationParameterName 'ScriptSourceLocation' `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+ }
+ }
+ }
+
+ return $scriptLocation
+}
+
+function Get-PublishLocation
+{
+ [CmdletBinding()]
+ Param
+ (
+ [Parameter()]
+ [String]
+ $Location
+ )
+
+ $PublishLocation = $null
+
+ if($Location)
+ {
+ # For local dir or SMB-share locations, ScriptPublishLocation is PublishLocation.
+ if(Microsoft.PowerShell.Management\Test-Path -Path $Location)
+ {
+ $PublishLocation = $Location
+ }
+ else
+ {
+ $tempPublishLocation = $null
+
+ if($Location.EndsWith('/api/v2', [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $tempPublishLocation = $Location + '/package/'
+ }
+ elseif($Location.EndsWith('/api/v2/', [System.StringComparison]::OrdinalIgnoreCase))
+ {
+ $tempPublishLocation = $Location + 'package/'
+ }
+
+ if($tempPublishLocation)
+ {
+ $PublishLocation = $tempPublishLocation
+ }
+ }
+ }
+
+ return $PublishLocation
+}
+
+function Resolve-Location
+{
+ [CmdletBinding()]
+ [OutputType([string])]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [string]
+ $Location,
+
+ [Parameter(Mandatory=$true)]
+ [string]
+ $LocationParameterName,
+
+ [Parameter()]
+ [System.Management.Automation.PSCmdlet]
+ $CallerPSCmdlet
+ )
+
+ # Ping and resolve the specified location
+ if(-not (Test-WebUri -uri $Location))
+ {
+ if(Microsoft.PowerShell.Management\Test-Path -Path $Location)
+ {
+ return $Location
+ }
+ elseif($CallerPSCmdlet)
+ {
+ $message = $LocalizedData.PathNotFound -f ($Location)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "PathNotFound" `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Location
+ }
+ }
+ else
+ {
+ $pingResult = Ping-Endpoint -Endpoint $Location
+ $statusCode = $null
+ $exception = $null
+ $resolvedLocation = $null
+ if($pingResult -and $pingResult.ContainsKey($Script:ResponseUri))
+ {
+ $resolvedLocation = $pingResult[$Script:ResponseUri]
+ }
+
+ if($pingResult -and $pingResult.ContainsKey($Script:StatusCode))
+ {
+ $statusCode = $pingResult[$Script:StatusCode]
+ }
+
+ Write-Debug -Message "Ping-Endpoint: location=$Location, statuscode=$statusCode, resolvedLocation=$resolvedLocation"
+
+ if((($statusCode -eq 200) -or ($statusCode -eq 401)) -and $resolvedLocation)
+ {
+ return $resolvedLocation
+ }
+ elseif($CallerPSCmdlet)
+ {
+ $message = $LocalizedData.InvalidWebUri -f ($Location, $LocationParameterName)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidWebUri" `
+ -CallerPSCmdlet $CallerPSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Location
+ }
+ }
+}
+
+function Test-WebUri
+{
+ [CmdletBinding()]
+ [OutputType([bool])]
+ Param
+ (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $uri
+ )
+
+ return ($uri.AbsoluteURI -ne $null) -and ($uri.Scheme -match '[http|https]')
+}
+
+function Test-WildcardPattern
+{
+ [CmdletBinding()]
+ [OutputType([bool])]
+ param(
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNull()]
+ $Name
+ )
+
+ return [System.Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Name)
+}
+
+# Utility to throw an errorrecord
+function ThrowError
+{
+ param
+ (
+ [parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [System.Management.Automation.PSCmdlet]
+ $CallerPSCmdlet,
+
+ [parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [System.String]
+ $ExceptionName,
+
+ [parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [System.String]
+ $ExceptionMessage,
+
+ [System.Object]
+ $ExceptionObject,
+
+ [parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [System.String]
+ $ErrorId,
+
+ [parameter(Mandatory = $true)]
+ [ValidateNotNull()]
+ [System.Management.Automation.ErrorCategory]
+ $ErrorCategory
+ )
+
+ $exception = New-Object $ExceptionName $ExceptionMessage;
+ $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $ErrorId, $ErrorCategory, $ExceptionObject
+ $CallerPSCmdlet.ThrowTerminatingError($errorRecord)
+}
+
+
+#endregion
+
+# Create install locations for scripts if they are not already created
+if(-not (Microsoft.PowerShell.Management\Test-Path -Path $script:ProgramFilesInstalledScriptInfosPath) -and (Test-RunningAsElevated))
+{
+ $null = Microsoft.PowerShell.Management\New-Item -Path $script:ProgramFilesInstalledScriptInfosPath `
+ -ItemType Directory `
+ -Force `
+ -Confirm:$false `
+ -WhatIf:$false
+}
+
+if(-not (Microsoft.PowerShell.Management\Test-Path -Path $script:MyDocumentsInstalledScriptInfosPath))
+{
+ $null = Microsoft.PowerShell.Management\New-Item -Path $script:MyDocumentsInstalledScriptInfosPath `
+ -ItemType Directory `
+ -Force `
+ -Confirm:$false `
+ -WhatIf:$false
+}
+
+Set-Alias -Name fimo -Value Find-Module
+Set-Alias -Name inmo -Value Install-Module
+Set-Alias -Name upmo -Value Update-Module
+Set-Alias -Name pumo -Value Publish-Module
+Set-Alias -Name uimo -Value Uninstall-Module
+
+Export-ModuleMember -Function Find-Module, `
+ Save-Module, `
+ Install-Module, `
+ Update-Module, `
+ Publish-Module, `
+ Uninstall-Module, `
+ Get-InstalledModule, `
+ Find-Command, `
+ Find-DscResource, `
+ Find-RoleCapability, `
+ Install-Script, `
+ Find-Script, `
+ Save-Script, `
+ Update-Script, `
+ Publish-Script, `
+ Get-InstalledScript, `
+ Uninstall-Script, `
+ Test-ScriptFileInfo, `
+ New-ScriptFileInfo, `
+ Update-ScriptFileInfo, `
+ Get-PSRepository, `
+ Register-PSRepository, `
+ Unregister-PSRepository, `
+ Set-PSRepository, `
+ Find-Package, `
+ Get-PackageDependencies, `
+ Download-Package, `
+ Install-Package, `
+ Uninstall-Package, `
+ Get-InstalledPackage, `
+ Remove-PackageSource, `
+ Resolve-PackageSource, `
+ Add-PackageSource, `
+ Get-DynamicOptions, `
+ Initialize-Provider, `
+ Get-Feature, `
+ Get-PackageProviderName, `
+ Update-ModuleManifest `
+ -Alias fimo, `
+ inmo, `
+ upmo, `
+ pumo
diff --git a/src/Microsoft.PowerShell.Linux.Host/Modules/Pester b/src/Modules/Pester
similarity index 100%
rename from src/Microsoft.PowerShell.Linux.Host/Modules/Pester
rename to src/Modules/Pester
diff --git a/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs b/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs
index f6fb21d0b3..ec69e4fa4c 100644
--- a/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs
+++ b/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs
@@ -3,8 +3,6 @@
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
-#if CORECLR
-
using System.Globalization;
using System.Linq;
using System.Reflection;
@@ -1679,5 +1677,3 @@ namespace Microsoft.PowerShell.CoreCLR
}
#endif
-
-#endif
diff --git a/src/System.Management.Automation/CoreCLR/CorePsStub.cs b/src/System.Management.Automation/CoreCLR/CorePsStub.cs
index e17511684a..319e359ffa 100644
--- a/src/System.Management.Automation/CoreCLR/CorePsStub.cs
+++ b/src/System.Management.Automation/CoreCLR/CorePsStub.cs
@@ -12,8 +12,6 @@ using System.Diagnostics.CodeAnalysis;
using Microsoft.Win32;
using System.Management.Automation.Remoting;
-#if CORECLR
-
#pragma warning disable 1591, 1572, 1571, 1573, 1587, 1570, 0067
#region CLR_STUBS
@@ -1874,5 +1872,3 @@ namespace System
#pragma warning restore 1591, 1572, 1571, 1573, 1587, 1570, 0067
#endif
-
-#endif
diff --git a/src/TypeCatalogParser/Main.cs b/src/TypeCatalogParser/Main.cs
index 2bca648ef3..4a8fa2f0ae 100644
--- a/src/TypeCatalogParser/Main.cs
+++ b/src/TypeCatalogParser/Main.cs
@@ -17,7 +17,7 @@ namespace ConsoleApplication
var outputPath = "../TypeCatalogGen/powershell.inc";
// Get a context for our top level project
- var context = ProjectContext.Create("../Microsoft.PowerShell.Linux.Host", NuGetFramework.Parse("netstandardapp1.5"));
+ var context = ProjectContext.Create("../Microsoft.PowerShell.Host", NuGetFramework.Parse("netstandardapp1.5"));
System.IO.File.WriteAllLines(outputPath,
// Get the target for the current runtime
diff --git a/src/TypeCatalogParser/project.json b/src/TypeCatalogParser/project.json
index f3e2050da0..ed52514f47 100644
--- a/src/TypeCatalogParser/project.json
+++ b/src/TypeCatalogParser/project.json
@@ -13,5 +13,14 @@
"netstandardapp1.5": {
"imports": [ "dnxcore50", "portable-net45+win8" ]
}
+ },
+
+ "runtimes": {
+ "ubuntu.14.04-x64": { },
+ "centos.7.1-x64": { },
+ "win7-x64": { },
+ "win10-x64": { },
+ "osx.10.10-x64": { },
+ "osx.10.11-x64": { }
}
}
diff --git a/src/libpsl-native b/src/libpsl-native
deleted file mode 160000
index 4bb241ad11..0000000000
--- a/src/libpsl-native
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 4bb241ad11c54985617343fbeb8700cfdcdf7ae0
diff --git a/src/libpsl-native/.gitignore b/src/libpsl-native/.gitignore
new file mode 100644
index 0000000000..0dff693725
--- /dev/null
+++ b/src/libpsl-native/.gitignore
@@ -0,0 +1,12 @@
+CMakeCache.txt
+CMakeFiles
+CMakeScripts
+Makefile
+cmake_install.cmake
+install_manifest.txt
+CTestTestfile.cmake
+Testing/
+test/psl-native-test
+src/libpsl-native.so
+src/libpsl-native.dylib
+test/native-tests.xml
diff --git a/src/libpsl-native/CMakeLists.txt b/src/libpsl-native/CMakeLists.txt
new file mode 100644
index 0000000000..8aa0988875
--- /dev/null
+++ b/src/libpsl-native/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.4)
+project(PSL-NATIVE)
+
+add_compile_options(-std=c++11 -Wall -Werror)
+set(LIBRARY_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/../Microsoft.PowerShell.Host")
+
+# test in BUILD_DIR
+enable_testing()
+add_subdirectory(src)
+add_subdirectory(test)
diff --git a/src/libpsl-native/README.md b/src/libpsl-native/README.md
new file mode 100644
index 0000000000..930ea3630d
--- /dev/null
+++ b/src/libpsl-native/README.md
@@ -0,0 +1,56 @@
+# libpsl-native
+
+This library provides functionality missing from .NET Core via system calls,
+that are called from from the `CorePsPlatform.cs` file of PowerShell. The
+method to do this is a Platform Invoke, which is C#'s Foreign Function
+Interface to C code (and C++ by way of `extern C`).
+
+## Build
+
+[CMake][] is used to build the project, which results in a `libpsl-native.so`
+library on Linux, and `libpsl-native.dylib` on OS X.
+
+```sh
+cmake -DCMAKE_BUILD_TYPE=Debug .
+make -j
+```
+
+[CMake]: https://cmake.org/cmake/help/v2.8.12/cmake.html
+
+## Test
+
+The [Google Test][] framework is used for unit tests.
+
+Use either `make test` or `ctest --verbose` for more output.
+
+[Google Test]: https://github.com/google/googletest/tree/release-1.7.0
+
+## Notes
+
+Marshalling data from native to managed code is much easier on Linux than it is
+on Windows. For instance, to return a string, you simply return a copy of it on
+the heap. Since only one memory allocator is used on Linux, the .NET runtime
+has no problem later freeing the buffer. Additionally, .NET presumes that the
+codepage "Ansi" on Linux is always UTF-8. So just marshal the string as
+`UnmanagedType.LPStr`.
+
+### C# (Managed)
+
+```c#
+[DllImport("libpsl-native", CharSet = CharSet.Ansi)]
+[return: MarshalAs(UnmanagedType.LPStr)]
+internal static extern string GetSomeString();
+```
+
+### C (Native)
+
+```c
+char *GetSomeString()
+{
+ return strdup("some string");
+}
+```
+
+The CoreFX team has an excellent guide for [UNIX Interop][].
+
+[UNIX Interop]: https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/interop-guidelines.md#unix-shims
diff --git a/src/libpsl-native/src/CMakeLists.txt b/src/libpsl-native/src/CMakeLists.txt
new file mode 100644
index 0000000000..5b2ec24199
--- /dev/null
+++ b/src/libpsl-native/src/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_library(psl-native SHARED
+ getcurrentprocessorid.cpp
+ getusername.cpp
+ getcomputername.cpp
+ getlinkcount.cpp
+ getfullyqualifiedname.cpp
+ issymlink.cpp
+ isexecutable.cpp
+ setdate.cpp
+ createhardlink.cpp
+ createsymlink.cpp
+ followsymlink.cpp)
+
+target_include_directories(psl-native PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/src/libpsl-native/src/createhardlink.cpp b/src/libpsl-native/src/createhardlink.cpp
new file mode 100644
index 0000000000..2f131efaa5
--- /dev/null
+++ b/src/libpsl-native/src/createhardlink.cpp
@@ -0,0 +1,115 @@
+//! @file createsymlink.cpp
+//! @author George FLeming
+//! @brief create new hard link
+
+#include
+#include
+#include
+#include "createhardlink.h"
+
+//! @brief Createhardlink create new symbolic link
+//!
+//! Createhardlink
+//!
+//! @param[in] link
+//! @parblock
+//! A pointer to the buffer that contains the symbolic link to create
+//!
+//! char* is marshaled as an LPStr, which on Linux is UTF-8.
+//! @endparblock
+//!
+//! @param[in] target
+//! @parblock
+//! A pointer to the buffer that contains the existing file
+//!
+//! char* is marshaled as an LPStr, which on Linux is UTF-8.
+//! @endparblock
+//!
+//! @exception errno Passes these errors via errno to GetLastError:
+//! - ERROR_INVALID_PARAMETER: parameter is not valid
+//! - ERROR_FILE_NOT_FOUND: file does not exist
+//! - ERROR_ACCESS_DENIED: access is denied
+//! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified
+//! - ERROR_INVALID_ADDRESS: attempt to access invalid address
+//! - ERROR_TOO_MANY_LINK: max number of hard links has been exceeded
+//! - ERROR_GEN_FAILURE: device attached to the system is not functioning
+//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file
+//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect
+//! - ERROR_BUFFER_OVERFLOW: file name is too long
+//! - ERROR_INVALID_FUNCTION: incorrect function
+//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters
+//!
+//! @retval 1 if creation is successful
+//! @retval 0 if createion failed
+//!
+
+int32_t CreateHardLink(const char *newlink, const char *target)
+{
+ errno = 0;
+
+ // Check parameters
+ if (!newlink || !target)
+ {
+ errno = ERROR_INVALID_PARAMETER;
+ return 0;
+ }
+
+ int returnCode = link(target, newlink);
+
+ if (returnCode == 0)
+ {
+ return 1;
+ }
+
+ switch(errno)
+ {
+ case EACCES:
+ errno = ERROR_ACCESS_DENIED;
+ break;
+ case EDQUOT:
+ errno = ERROR_DISK_FULL;
+ break;
+ case EEXIST:
+ errno = ERROR_FILE_EXISTS;
+ break;
+ case EFAULT:
+ errno = ERROR_INVALID_ADDRESS;
+ break;
+ case EIO:
+ errno = ERROR_GEN_FAILURE;
+ break;
+ case ELOOP:
+ errno = ERROR_TOO_MANY_LINKS;
+ break;
+ case EMLINK:
+ errno = ERROR_TOO_MANY_LINKS;
+ break;
+ case ENAMETOOLONG:
+ errno = ERROR_BAD_PATH_NAME;
+ break;
+ case ENOENT:
+ errno = ERROR_FILE_NOT_FOUND;
+ break;
+ case ENOMEM:
+ errno = ERROR_OUTOFMEMORY;
+ break;
+ case ENOTDIR:
+ errno = ERROR_INVALID_NAME;
+ break;
+ case ENOSPC:
+ errno = ERROR_DISK_FULL;
+ break;
+ case EPERM:
+ errno = ERROR_ACCESS_DENIED;
+ break;
+ case EROFS:
+ errno = ERROR_ACCESS_DENIED;
+ break;
+ case EXDEV:
+ errno = ERROR_GEN_FAILURE;
+ break;
+ default:
+ errno = ERROR_INVALID_FUNCTION;
+ }
+ return 0;
+}
diff --git a/src/libpsl-native/src/createhardlink.h b/src/libpsl-native/src/createhardlink.h
new file mode 100644
index 0000000000..b8e62ddcc2
--- /dev/null
+++ b/src/libpsl-native/src/createhardlink.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "pal.h"
+
+PAL_BEGIN_EXTERNC
+
+int32_t CreateHardLink(const char *link, const char *target);
+
+PAL_END_EXTERNC
diff --git a/src/libpsl-native/src/createsymlink.cpp b/src/libpsl-native/src/createsymlink.cpp
new file mode 100644
index 0000000000..4ea8d6fd9d
--- /dev/null
+++ b/src/libpsl-native/src/createsymlink.cpp
@@ -0,0 +1,106 @@
+//! @file createsymlink.cpp
+//! @author George FLeming
+//! @brief create new symbolic link
+
+#include
+#include
+#include
+#include "createsymlink.h"
+
+//! @brief Createsymlink create new symbolic link
+//!
+//! Createsymlink
+//!
+//! @param[in] link
+//! @parblock
+//! A pointer to the buffer that contains the symbolic link to create
+//!
+//! char* is marshaled as an LPStr, which on Linux is UTF-8.
+//! @endparblock
+//!
+//! @param[in] target
+//! @parblock
+//! A pointer to the buffer that contains the existing file
+//!
+//! char* is marshaled as an LPStr, which on Linux is UTF-8.
+//! @endparblock
+//!
+//! @exception errno Passes these errors via errno to GetLastError:
+//! - ERROR_INVALID_PARAMETER: parameter is not valid
+//! - ERROR_FILE_NOT_FOUND: file does not exist
+//! - ERROR_ACCESS_DENIED: access is denied
+//! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified
+//! - ERROR_INVALID_ADDRESS: attempt to access invalid address
+//! - ERROR_STOPPED_ON_SYMLINK: the operation stopped after reaching a symbolic link
+//! - ERROR_GEN_FAILURE: device attached to the system is not functioning
+//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file
+//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect
+//! - ERROR_BUFFER_OVERFLOW: file name is too long
+//! - ERROR_INVALID_FUNCTION: incorrect function
+//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters
+//!
+//! @retval 1 if creation is successful
+//! @retval 0 if createion failed
+//!
+
+int32_t CreateSymLink(const char *link, const char *target)
+{
+ errno = 0;
+
+ // Check parameters
+ if (!link || !target)
+ {
+ errno = ERROR_INVALID_PARAMETER;
+ return 0;
+ }
+
+ int returnCode = symlink(target, link);
+
+ if (returnCode == 0)
+ {
+ return 1;
+ }
+
+ switch(errno)
+ {
+ case EACCES:
+ errno = ERROR_ACCESS_DENIED;
+ break;
+ case EDQUOT:
+ errno = ERROR_DISK_FULL;
+ break;
+ case EEXIST:
+ errno = ERROR_FILE_EXISTS;
+ break;
+ case EFAULT:
+ errno = ERROR_INVALID_ADDRESS;
+ break;
+ case EIO:
+ errno = ERROR_GEN_FAILURE;
+ break;
+ case ELOOP:
+ errno = ERROR_STOPPED_ON_SYMLINK;
+ break;
+ case ENAMETOOLONG:
+ errno = ERROR_BAD_PATH_NAME;
+ break;
+ case ENOENT:
+ errno = ERROR_FILE_NOT_FOUND;
+ break;
+ case ENOMEM:
+ errno = ERROR_OUTOFMEMORY;
+ break;
+ case ENOTDIR:
+ errno = ERROR_INVALID_NAME;
+ break;
+ case ENOSPC:
+ errno = ERROR_DISK_FULL;
+ break;
+ case EPERM:
+ errno = ERROR_GEN_FAILURE;
+ break;
+ default:
+ errno = ERROR_INVALID_FUNCTION;
+ }
+ return 0;
+}
diff --git a/src/libpsl-native/src/createsymlink.h b/src/libpsl-native/src/createsymlink.h
new file mode 100644
index 0000000000..e47bce3fa1
--- /dev/null
+++ b/src/libpsl-native/src/createsymlink.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "pal.h"
+
+PAL_BEGIN_EXTERNC
+
+int32_t CreateSymLink(const char *link, const char *target);
+
+PAL_END_EXTERNC
diff --git a/src/libpsl-native/src/followsymlink.cpp b/src/libpsl-native/src/followsymlink.cpp
new file mode 100644
index 0000000000..40e12b9b78
--- /dev/null
+++ b/src/libpsl-native/src/followsymlink.cpp
@@ -0,0 +1,90 @@
+//! @file followSymLink.cpp
+//! @author George FLeming
+//! @brief returns whether a path is a symbolic link
+
+#include
+#include
+#include
+#include
+#include "followsymlink.h"
+
+//! @brief Followsymlink determines target path of a sym link
+//!
+//! Followsymlink
+//!
+//! @param[in] fileName
+//! @parblock
+//! A pointer to the buffer that contains the file name
+//!
+//! char* is marshaled as an LPStr, which on Linux is UTF-8.
+//! @endparblock
+//!
+//! @exception errno Passes these errors via errno to GetLastError:
+//! - ERROR_INVALID_PARAMETER: parameter is not valid
+//! - ERROR_FILE_NOT_FOUND: file does not exist
+//! - ERROR_ACCESS_DENIED: access is denied
+//! - ERROR_INVALID_ADDRESS: attempt to access invalid address
+//! - ERROR_STOPPED_ON_SYMLINK: too many symbolic links
+//! - ERROR_GEN_FAILURE: I/O error occurred
+//! - ERROR_INVALID_NAME: file provided is not a symbolic link
+//! - ERROR_INVALID_FUNCTION: incorrect function
+//! - ERROR_BAD_PATH_NAME: pathname is too long
+//! - ERROR_OUTOFMEMORY insufficient kernal memory
+//!
+//! @retval target path, or NULL if unsuccessful
+//!
+
+char* FollowSymLink(const char* fileName)
+{
+ errno = 0;
+
+ // Check parameters
+ if (!fileName)
+ {
+ errno = ERROR_INVALID_PARAMETER;
+ return NULL;
+ }
+
+ char buffer[PATH_MAX];
+ ssize_t sz = readlink(fileName, buffer, PATH_MAX);
+
+ if (sz == -1)
+ {
+ switch(errno)
+ {
+ case EACCES:
+ errno = ERROR_ACCESS_DENIED;
+ break;
+ case EFAULT:
+ errno = ERROR_INVALID_ADDRESS;
+ break;
+ case EINVAL:
+ errno = ERROR_INVALID_NAME;
+ break;
+ case EIO:
+ errno = ERROR_GEN_FAILURE;
+ break;
+ case ELOOP:
+ errno = ERROR_STOPPED_ON_SYMLINK;
+ break;
+ case ENAMETOOLONG:
+ errno = ERROR_BAD_PATH_NAME;
+ break;
+ case ENOENT:
+ errno = ERROR_FILE_NOT_FOUND;
+ break;
+ case ENOMEM:
+ errno = ERROR_OUTOFMEMORY;
+ break;
+ case ENOTDIR:
+ errno = ERROR_BAD_PATH_NAME;
+ break;
+ default:
+ errno = ERROR_INVALID_FUNCTION;
+ }
+ return NULL;
+ }
+
+ buffer[sz] = '\0';
+ return strndup(buffer, sz + 1);
+}
diff --git a/src/libpsl-native/src/followsymlink.h b/src/libpsl-native/src/followsymlink.h
new file mode 100644
index 0000000000..fac7f5244f
--- /dev/null
+++ b/src/libpsl-native/src/followsymlink.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "pal.h"
+
+PAL_BEGIN_EXTERNC
+
+char* FollowSymLink(const char* fileName);
+
+PAL_END_EXTERNC
diff --git a/src/libpsl-native/src/getcomputername.cpp b/src/libpsl-native/src/getcomputername.cpp
new file mode 100644
index 0000000000..3e480b9ad4
--- /dev/null
+++ b/src/libpsl-native/src/getcomputername.cpp
@@ -0,0 +1,45 @@
+//! @file getcomputername.cpp
+//! @author George Fleming
+//! @brief Implements GetComputerName Win32 API
+
+#include
+#include
+#include
+#include "getcomputername.h"
+
+//! @brief GetComputerName retrieves the name of the host associated with
+//! the current thread.
+//!
+//! @exception errno Passes these errors via errno to GetLastError:
+//! - ERROR_INVALID_FUNCTION: getlogin_r() returned an unrecognized error code
+//! - ERROR_INVALID_ADDRESS: buffer is an invalid address
+//! - ERROR_GEN_FAILURE: buffer not large enough
+//!
+//! @retval username as UTF-8 string, or null if unsuccessful
+
+char* GetComputerName()
+{
+ errno = 0;
+ // Get computername from system, note that gethostname(2) gets the
+ // nodename from uname
+ std::string computername(_POSIX_HOST_NAME_MAX, 0);
+ int err = gethostname(&computername[0], computername.length());
+ // Map errno to Win32 Error Codes
+ if (err != 0)
+ {
+ switch (errno)
+ {
+ case EFAULT:
+ errno = ERROR_INVALID_ADDRESS;
+ break;
+ case ENAMETOOLONG:
+ errno = ERROR_GEN_FAILURE;
+ break;
+ default:
+ errno = ERROR_INVALID_FUNCTION;
+ }
+ return NULL;
+ }
+
+ return strdup(computername.c_str());
+}
diff --git a/src/libpsl-native/src/getcomputername.h b/src/libpsl-native/src/getcomputername.h
new file mode 100644
index 0000000000..363210921b
--- /dev/null
+++ b/src/libpsl-native/src/getcomputername.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "pal.h"
+
+PAL_BEGIN_EXTERNC
+
+char *GetComputerName();
+
+PAL_END_EXTERNC
diff --git a/src/libpsl-native/src/getcurrentprocessorid.cpp b/src/libpsl-native/src/getcurrentprocessorid.cpp
new file mode 100644
index 0000000000..eea80937b9
--- /dev/null
+++ b/src/libpsl-native/src/getcurrentprocessorid.cpp
@@ -0,0 +1,9 @@
+#include "getcurrentprocessorid.h"
+#include
+
+int32_t GetCurrentProcessId()
+{
+ pid_t pid = getpid();
+ return static_cast(pid);
+}
+
diff --git a/src/libpsl-native/src/getcurrentprocessorid.h b/src/libpsl-native/src/getcurrentprocessorid.h
new file mode 100644
index 0000000000..3c768e72e5
--- /dev/null
+++ b/src/libpsl-native/src/getcurrentprocessorid.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "pal.h"
+
+PAL_BEGIN_EXTERNC
+
+int32_t GetCurrentProcessId();
+
+PAL_END_EXTERNC
+
diff --git a/src/libpsl-native/src/getcurrentthreadid.cpp b/src/libpsl-native/src/getcurrentthreadid.cpp
new file mode 100644
index 0000000000..efd7a31361
--- /dev/null
+++ b/src/libpsl-native/src/getcurrentthreadid.cpp
@@ -0,0 +1,9 @@
+#include "getcurrentthreadid.h"
+#include
+#include
+
+HANDLE GetCurrentThreadId()
+{
+ pid_t tid = pthread_self();
+ return reinterpret_cast(tid);
+}
diff --git a/src/libpsl-native/src/getcurrentthreadid.h b/src/libpsl-native/src/getcurrentthreadid.h
new file mode 100644
index 0000000000..258c3c397f
--- /dev/null
+++ b/src/libpsl-native/src/getcurrentthreadid.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "pal.h"
+
+PAL_BEGIN_EXTERNC
+
+HANDLE GetCurrentThreadId();
+
+PAL_END_EXTERNC
+
diff --git a/src/libpsl-native/src/getfullyqualifiedname.cpp b/src/libpsl-native/src/getfullyqualifiedname.cpp
new file mode 100644
index 0000000000..44178a0a5a
--- /dev/null
+++ b/src/libpsl-native/src/getfullyqualifiedname.cpp
@@ -0,0 +1,64 @@
+//! @file getfullyqualifiedname.cpp
+//! @author George Fleming
+//! @brief Implements GetFullyQualifiedName on Linux
+
+#include
+#include
+#include
+#include
+#include "getcomputername.h"
+#include "getfullyqualifiedname.h"
+
+//! @brief GetFullyQualifiedName retrieves the fully qualifed dns name of the host
+//!
+//! @exception errno Passes these errors via errno to GetLastError:
+//! - ERROR_INVALID_FUNCTION: getlogin_r() returned an unrecognized error code (from GetComputerName)
+//! - ERROR_INVALID_ADDRESS: buffer is an invalid address (from GetComputerName)
+//! - ERROR_GEN_FAILURE: buffer not large enough (from GetComputerName)
+//! - ERROR_BAD_NET_NAME: Cannot determine network short name
+//!
+//! @retval username as UTF-8 string, or null if unsuccessful
+//!
+
+char *GetFullyQualifiedName()
+{
+ errno = 0;
+
+ char *computerName = GetComputerName();
+ if (computerName == NULL)
+ {
+ return NULL;
+ }
+
+ if (strchr(computerName, '.') != NULL)
+ {
+ return computerName;
+ }
+
+ struct addrinfo hints, *info;
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC; /*either IPV4 or IPV6*/
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_CANONNAME;
+
+ /* There are several ways to get the domain name:
+ * uname(2), gethostbyname(3), resolver(3), getdomainname(2),
+ * and getaddrinfo(3). Some of these are not portable, some aren't
+ * POSIX compliant, and some are being deprecated. getaddrinfo seems
+ * to be the best choice.
+ */
+ if (getaddrinfo(computerName, "http", &hints, &info) != 0)
+ {
+ errno = ERROR_BAD_NET_NAME;
+ return NULL;
+ }
+
+ // info is actually a link-list. We'll just return the first full name
+
+ char *fullName = strndup(info->ai_canonname, strlen(info->ai_canonname));
+
+ freeaddrinfo(info);
+ free(computerName);
+ return fullName;
+}
diff --git a/src/libpsl-native/src/getfullyqualifiedname.h b/src/libpsl-native/src/getfullyqualifiedname.h
new file mode 100644
index 0000000000..b44ab68fd5
--- /dev/null
+++ b/src/libpsl-native/src/getfullyqualifiedname.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "pal.h"
+
+PAL_BEGIN_EXTERNC
+
+char *GetFullyQualifiedName();
+
+PAL_END_EXTERNC
diff --git a/src/libpsl-native/src/getlinkcount.cpp b/src/libpsl-native/src/getlinkcount.cpp
new file mode 100644
index 0000000000..1b97a41671
--- /dev/null
+++ b/src/libpsl-native/src/getlinkcount.cpp
@@ -0,0 +1,104 @@
+//! @file getlinkcount.cpp
+//! @author George FLeming
+//! @brief Retrieve link count of a file
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "getlinkcount.h"
+
+//! @brief GetLinkCount retrieves the file link count (number of hard links)
+//! for the given file
+//!
+//! GetLinkCount
+//!
+//! @param[in] fileName
+//! @parblock
+//! A pointer to the buffer that contains the file name
+//!
+//! char* is marshaled as an LPStr, which on Linux is UTF-8.
+//! @endparblock
+//!
+//! @param[out] count
+//! @parblock
+//! This function returns the number of hard links associated with this file
+//! @endparblock
+//!
+//! @exception errno Passes these errors via errno to GetLastError:
+//! - ERROR_INVALID_PARAMETER: parameter is not valid
+//! - ERROR_FILE_NOT_FOUND: file does not exist
+//! - ERROR_ACCESS_DENIED: access is denied
+//! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified
+//! - ERROR_INVALID_ADDRESS: attempt to access invalid address
+//! - ERROR_STOPPED_ON_SYMLINK: the operation stopped after reaching a symbolic link
+//! - ERROR_GEN_FAILURE: device attached to the system is not functioning
+//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file
+//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect
+//! - ERROR_BUFFER_OVERFLOW: file name is too long
+//! - ERROR_INVALID_FUNCTION: incorrect function
+//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters
+//!
+//! @retval 1 If the function succeeds, and the variable pointed to by buffer contains
+//! infomation about the files
+//! @retval 0 If the function fails, the return value is zero. To get
+//! extended error information, call GetLastError.
+//!
+
+int32_t GetLinkCount(const char* fileName, int32_t *count)
+{
+ errno = 0;
+
+ // Check parameters
+ if (!fileName)
+ {
+ errno = ERROR_INVALID_PARAMETER;
+ return 0;
+ }
+
+ struct stat statBuf;
+
+ int returnCode = lstat(fileName, &statBuf);
+
+ if (returnCode != 0)
+ {
+ switch(errno)
+ {
+ case EACCES:
+ errno = ERROR_ACCESS_DENIED;
+ break;
+ case EBADF:
+ errno = ERROR_FILE_NOT_FOUND;
+ break;
+ case EFAULT:
+ errno = ERROR_INVALID_ADDRESS;
+ break;
+ case ELOOP:
+ errno = ERROR_STOPPED_ON_SYMLINK;
+ break;
+ case ENAMETOOLONG:
+ errno = ERROR_GEN_FAILURE;
+ break;
+ case ENOENT:
+ errno = ERROR_FILE_NOT_FOUND;
+ break;
+ case ENOMEM:
+ errno = ERROR_NO_SUCH_USER;
+ break;
+ case ENOTDIR:
+ errno = ERROR_INVALID_NAME;
+ break;
+ case EOVERFLOW:
+ errno = ERROR_BUFFER_OVERFLOW;
+ break;
+ default:
+ errno = ERROR_INVALID_FUNCTION;
+ }
+ return 0;
+ }
+
+ *count = statBuf.st_nlink;
+ return 1;
+}
diff --git a/src/libpsl-native/src/getlinkcount.h b/src/libpsl-native/src/getlinkcount.h
new file mode 100644
index 0000000000..6a3c8b8e41
--- /dev/null
+++ b/src/libpsl-native/src/getlinkcount.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "pal.h"
+
+PAL_BEGIN_EXTERNC
+
+int32_t GetLinkCount(const char* fileName, int32_t *count);
+
+PAL_END_EXTERNC
diff --git a/src/libpsl-native/src/getusername.cpp b/src/libpsl-native/src/getusername.cpp
new file mode 100644
index 0000000000..0efab96688
--- /dev/null
+++ b/src/libpsl-native/src/getusername.cpp
@@ -0,0 +1,65 @@
+//! @file getusername.cpp
+//! @author Andrew Schwartzmeyer
+//! @brief Implements GetUserName for Linux
+
+#include
+#include
+#include
+#include
+#include
+#include "getusername.h"
+
+//! @brief GetUserName retrieves the name of the user associated with
+//! the current thread.
+//!
+//! @exception errno Passes these errors via errno to GetLastError:
+//! - ERROR_INVALID_PARAMETER: parameter is not valid
+//! - ERROR_NO_SUCH_USER: there was no corresponding user
+//! - ERROR_GEN_FAILURE: sysconf() or getpwuid() failed for unknown reasons
+//!
+//! @retval username as UTF-8 string, or null if unsuccessful
+char* GetUserName()
+{
+ errno = 0;
+
+ struct passwd pwd;
+ struct passwd* result;
+ // gets the initial suggested size for buf
+ int buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (buflen == -1)
+ {
+ errno = ERROR_GEN_FAILURE;
+ return NULL;
+ }
+ std::string buf(buflen, 0);
+
+ // geteuid() gets the effective user ID of the calling process, and is always successful
+ int ret = getpwuid_r(geteuid(), &pwd, &buf[0], buflen, &result);
+
+ // Map errno to Win32 Error Codes
+ if (ret)
+ {
+ switch (errno)
+ {
+ case ENOENT:
+ case ESRCH:
+ case EBADF:
+ case EPERM:
+ errno = ERROR_NO_SUCH_USER;
+ break;
+ default:
+ errno = ERROR_GEN_FAILURE;
+ }
+ return NULL;
+ }
+
+ // Check if no user matched
+ if (result == NULL)
+ {
+ errno = ERROR_NO_SUCH_USER;
+ return NULL;
+ }
+
+ // allocate copy on heap so CLR can free it
+ return strdup(result->pw_name);
+}
diff --git a/src/libpsl-native/src/getusername.h b/src/libpsl-native/src/getusername.h
new file mode 100644
index 0000000000..1326298f42
--- /dev/null
+++ b/src/libpsl-native/src/getusername.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "pal.h"
+
+PAL_BEGIN_EXTERNC
+
+char* GetUserName();
+
+PAL_END_EXTERNC
diff --git a/src/libpsl-native/src/isexecutable.cpp b/src/libpsl-native/src/isexecutable.cpp
new file mode 100644
index 0000000000..38f6ad1844
--- /dev/null
+++ b/src/libpsl-native/src/isexecutable.cpp
@@ -0,0 +1,81 @@
+//! @file isExecutable.cpp
+//! @author George FLeming
+//! @brief returns whether a file is executable
+
+#include
+#include
+#include
+#include "isexecutable.h"
+
+//! @brief IsExecutable determines if path is executable
+//!
+//! IsExecutable
+//!
+//! @param[in] fileName
+//! @parblock
+//! A pointer to the buffer that contains the file name
+//!
+//! char* is marshaled as an LPStr, which on Linux is UTF-8.
+//! @endparblock
+//!
+//! @exception errno Passes these errors via errno to GetLastError:
+//! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified
+//! - ERROR_INVALID_ADDRESS: attempt to access invalid address
+//! - ERROR_GEN_FAILURE: device attached to the system is not functioning
+//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect
+//! - ERROR_INVALID_FUNCTION: incorrect function
+//! - ERROR_INVALID_PARAMETER: parameter to access(2) call is incorrect
+//!
+//! @retval 1 if path is an executable
+//! @retval 0 if path is not a executable
+//! @retval -1 If the function fails.. To get extended error information, call GetLastError.
+//!
+
+int32_t IsExecutable(const char* fileName)
+{
+ errno = 0;
+
+ // Check parameters
+ if (!fileName)
+ {
+ errno = ERROR_INVALID_PARAMETER;
+ return -1;
+ }
+
+ int returnCode = access(fileName, X_OK);
+
+ if (returnCode == 0)
+ {
+ return 1;
+ }
+
+ switch(errno)
+ {
+ case EACCES:
+ return 0;
+ case EBADF:
+ case ENOENT:
+ errno = ERROR_FILE_NOT_FOUND;
+ break;
+ case EFAULT:
+ errno = ERROR_INVALID_ADDRESS;
+ break;
+ case ELOOP:
+ errno = ERROR_STOPPED_ON_SYMLINK;
+ break;
+ case EIO:
+ case ENOMEM:
+ errno = ERROR_GEN_FAILURE;
+ break;
+ case ENOTDIR:
+ case ENAMETOOLONG:
+ errno = ERROR_INVALID_NAME;
+ break;
+ case EINVAL:
+ errno = ERROR_INVALID_PARAMETER;
+ break;
+ default:
+ errno = ERROR_INVALID_FUNCTION;
+ }
+ return -1;
+}
diff --git a/src/libpsl-native/src/isexecutable.h b/src/libpsl-native/src/isexecutable.h
new file mode 100644
index 0000000000..da4e9f8f36
--- /dev/null
+++ b/src/libpsl-native/src/isexecutable.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "pal.h"
+
+PAL_BEGIN_EXTERNC
+
+int32_t IsExecutable(const char* fileName);
+
+PAL_END_EXTERNC
diff --git a/src/libpsl-native/src/issymlink.cpp b/src/libpsl-native/src/issymlink.cpp
new file mode 100644
index 0000000000..d4ce011cba
--- /dev/null
+++ b/src/libpsl-native/src/issymlink.cpp
@@ -0,0 +1,96 @@
+//! @file isSymLink.cpp
+//! @author George FLeming
+//! @brief returns whether a path is a symbolic link
+
+#include
+#include
+#include
+#include
+#include
+#include "issymlink.h"
+
+//! @brief IsSymLink determines if path is a symbolic link
+//!
+//! IsSymLink
+//!
+//! @param[in] fileName
+//! @parblock
+//! A pointer to the buffer that contains the file name
+//!
+//! char* is marshaled as an LPStr, which on Linux is UTF-8.
+//! @endparblock
+//!
+//! @exception errno Passes these errors via errno to GetLastError:
+//! - ERROR_INVALID_PARAMETER: parameter is not valid
+//! - ERROR_FILE_NOT_FOUND: file does not exist
+//! - ERROR_ACCESS_DENIED: access is denied
+//! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified
+//! - ERROR_INVALID_ADDRESS: attempt to access invalid address
+//! - ERROR_STOPPED_ON_SYMLINK: the operation stopped after reaching a symbolic link
+//! - ERROR_GEN_FAILURE: device attached to the system is not functioning
+//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file
+//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect
+//! - ERROR_BUFFER_OVERFLOW: file name is too long
+//! - ERROR_INVALID_FUNCTION: incorrect function
+//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters
+//!
+//! @retval 1 if path is a symbolic link
+//! @retval 0 if path is not a symbolic link
+//! @retval -1 If the function fails.. To get extended error information, call GetLastError.
+//!
+
+int32_t IsSymLink(const char* fileName)
+{
+
+ errno = 0;
+
+ // Check parameters
+ if (!fileName)
+ {
+ errno = ERROR_INVALID_PARAMETER;
+ return -1;
+ }
+
+ struct stat statBuf;
+
+ int returnCode = lstat(fileName, &statBuf);
+
+ if (returnCode != 0)
+ {
+ switch(errno)
+ {
+ case EACCES:
+ errno = ERROR_ACCESS_DENIED;
+ break;
+ case EBADF:
+ errno = ERROR_FILE_NOT_FOUND;
+ break;
+ case EFAULT:
+ errno = ERROR_INVALID_ADDRESS;
+ break;
+ case ELOOP:
+ errno = ERROR_STOPPED_ON_SYMLINK;
+ break;
+ case ENAMETOOLONG:
+ errno = ERROR_GEN_FAILURE;
+ break;
+ case ENOENT:
+ errno = ERROR_FILE_NOT_FOUND;
+ break;
+ case ENOMEM:
+ errno = ERROR_NO_SUCH_USER;
+ break;
+ case ENOTDIR:
+ errno = ERROR_INVALID_NAME;
+ break;
+ case EOVERFLOW:
+ errno = ERROR_BUFFER_OVERFLOW;
+ break;
+ default:
+ errno = ERROR_INVALID_FUNCTION;
+ }
+ return -1;
+ }
+
+ return S_ISLNK(statBuf.st_mode) ? 1 : 0;
+}
diff --git a/src/libpsl-native/src/issymlink.h b/src/libpsl-native/src/issymlink.h
new file mode 100644
index 0000000000..066a4060c1
--- /dev/null
+++ b/src/libpsl-native/src/issymlink.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "pal.h"
+
+PAL_BEGIN_EXTERNC
+
+int32_t IsSymLink(const char* fileName);
+
+PAL_END_EXTERNC
diff --git a/src/libpsl-native/src/pal.h b/src/libpsl-native/src/pal.h
new file mode 100644
index 0000000000..39fb6db82c
--- /dev/null
+++ b/src/libpsl-native/src/pal.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#define ERROR_INVALID_PARAMETER 87
+#define ERROR_OUTOFMEMORY 14
+#define ERROR_BAD_ENVIRONMENT 0x0000000A
+#define ERROR_TOO_MANY_OPEN_FILES 0x00000004
+#define ERROR_INSUFFICIENT_BUFFER 0x0000007A
+#define ERROR_NO_ASSOCIATION 0x00000483
+#define ERROR_NO_SUCH_USER 0x00000525
+#define ERROR_INVALID_FUNCTION 0x00000001
+#define ERROR_INVALID_ADDRESS 0x000001e7
+#define ERROR_GEN_FAILURE 0x0000001F
+#define ERROR_ACCESS_DENIED 0x00000005
+#define ERROR_INVALID_NAME 0x0000007B
+#define ERROR_STOPPED_ON_SYMLINK 0x000002A9
+#define ERROR_BUFFER_OVERFLOW 0x0000006F
+#define ERROR_FILE_NOT_FOUND 0x00000002
+#define ERROR_BAD_PATH_NAME 0x000000A1
+#define ERROR_BAD_NET_NAME 0x00000043
+#define ERROR_DISK_FULL 0x00000070
+#define ERROR_FILE_EXISTS 0x00000050
+#define ERROR_TOO_MANY_LINKS 0x00000476
+
+/*
+**==============================================================================
+**
+** PAL_BEGIN_EXTERNC
+** PAL_END_EXTERNC
+**
+**==============================================================================
+*/
+
+#if defined(__cplusplus)
+# define PAL_BEGIN_EXTERNC extern "C" {
+# define PAL_END_EXTERNC }
+#else
+# define PAL_BEGIN_EXTERNC
+# define PAL_END_EXTERNC
+#endif
+
diff --git a/src/libpsl-native/src/setdate.cpp b/src/libpsl-native/src/setdate.cpp
new file mode 100644
index 0000000000..81bfa3417e
--- /dev/null
+++ b/src/libpsl-native/src/setdate.cpp
@@ -0,0 +1,73 @@
+//! @file setdate.cpp
+//! @author George FLeming
+//! @brief set local/system date and time
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "setdate.h"
+
+//! @brief SetDate sets the date and time on local computer. You must
+//! be super-user to set the time.
+//!
+//! SetDate
+//!
+//! @param[in] info
+//! @parblock
+//! A struct that contains program to execute and its parameters
+//!
+//! @exception errno Passes these errors via errno to GetLastError:
+//! - ERROR_BAD_ENVIRONMENT: locale is not UTF-8
+//! - ERROR_INVALID_PARAMETER: time was not passed in correctly
+//! - ERROR_ACCESS_DENIED: you must be super-user to set the date
+//!
+//! @retval 0 successfully set date
+//! @retval -1 if failure occurred. To get extended error information, call GetLastError.
+//!
+
+int32_t SetDate(const SetDateInfo &info)
+{
+ errno = 0;
+
+ // Select locale from environment
+ setlocale(LC_ALL, "");
+ // Check that locale is UTF-8
+ if (nl_langinfo(CODESET) != std::string("UTF-8"))
+ {
+ errno = ERROR_BAD_ENVIRONMENT;
+ return -1;
+ }
+
+ struct tm bdTime;
+ struct timeval tv;
+
+ bdTime.tm_year = info.Year - 1900;
+ bdTime.tm_mon = info.Month - 1; // This is zero-based
+ bdTime.tm_mday = info.Day;
+ bdTime.tm_hour = info.Hour;
+ bdTime.tm_min = info.Minute;
+ bdTime.tm_sec = info.Second;
+ bdTime.tm_isdst = info.DST;
+
+ time_t newTime = mktime(&bdTime);
+ if (newTime == -1)
+ {
+ errno = ERROR_INVALID_PARAMETER;
+ return -1;
+ }
+
+ tv.tv_sec = newTime;
+ tv.tv_usec = 0;
+
+ int result = settimeofday(&tv, NULL);
+ if (result == -1)
+ {
+ errno = ERROR_ACCESS_DENIED;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/libpsl-native/src/setdate.h b/src/libpsl-native/src/setdate.h
new file mode 100644
index 0000000000..b55a7d1e7a
--- /dev/null
+++ b/src/libpsl-native/src/setdate.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "pal.h"
+
+PAL_BEGIN_EXTERNC
+
+typedef struct setDateInfo
+{
+ // the order of members does matter here
+ int32_t Year;
+ int32_t Month;
+ int32_t Day;
+ int32_t Hour;
+ int32_t Minute;
+ int32_t Second;
+ int32_t Millisecond;
+ int32_t DST;
+} SetDateInfo;
+
+int32_t SetDate(const SetDateInfo &info);
+
+PAL_END_EXTERNC
diff --git a/src/libpsl-native/test/CMakeLists.txt b/src/libpsl-native/test/CMakeLists.txt
new file mode 100644
index 0000000000..4ddc538361
--- /dev/null
+++ b/src/libpsl-native/test/CMakeLists.txt
@@ -0,0 +1,22 @@
+add_subdirectory(googletest)
+
+add_executable(psl-native-test
+ test-locale.cpp
+ test-getcurrentprocessid.cpp
+ test-getusername.cpp
+ test-getcomputername.cpp
+ test-getlinkcount.cpp
+ test-getfullyqualifiedname.cpp
+ test-issymlink.cpp
+ test-isexecutable.cpp
+ test-createsymlink.cpp
+ test-createhardlink.cpp
+ main.cpp)
+
+# manually include gtest headers
+target_include_directories(psl-native-test PRIVATE ${gtest_SOURCE_DIR}/include)
+
+target_link_libraries(psl-native-test psl-native gtest)
+
+add_test(NAME psl-native-test
+ COMMAND psl-native-test --gtest_output=xml:native-tests.xml)
diff --git a/src/libpsl-native/test/googletest b/src/libpsl-native/test/googletest
new file mode 160000
index 0000000000..c99458533a
--- /dev/null
+++ b/src/libpsl-native/test/googletest
@@ -0,0 +1 @@
+Subproject commit c99458533a9b4c743ed51537e25989ea55944908
diff --git a/src/libpsl-native/test/main.cpp b/src/libpsl-native/test/main.cpp
new file mode 100644
index 0000000000..9bb465e024
--- /dev/null
+++ b/src/libpsl-native/test/main.cpp
@@ -0,0 +1,7 @@
+#include
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/src/libpsl-native/test/test-createhardlink.cpp b/src/libpsl-native/test/test-createhardlink.cpp
new file mode 100644
index 0000000000..090864b9f7
--- /dev/null
+++ b/src/libpsl-native/test/test-createhardlink.cpp
@@ -0,0 +1,91 @@
+//! @file test-createhardlink.cpp
+//! @author George Fleming
+//! @brief Implements test for CreateHardLink()
+
+#include
+#include
+#include
+#include "getlinkcount.h"
+#include "createhardlink.h"
+
+using namespace std;
+
+class CreateHardLinkTest : public ::testing::Test
+{
+protected:
+
+ static const int bufSize = 64;
+ const string fileTemplate = "/tmp/symlinktest.fXXXXXX";
+ const string dirTemplate = "/tmp/symlinktest.dXXXXXX";
+ const string fileHardLink = "/tmp/symlinktest.flink";
+ const string dirHardLink = "/tmp/symlinktest.dlink";
+ char *file, *dir;
+ char fileTemplateBuf[bufSize], dirTemplateBuf[bufSize];
+
+ CreateHardLinkTest()
+ {
+ // since mkstemp and mkdtemp modifies the template string, let's give them writable buffers
+ strcpy(fileTemplateBuf, fileTemplate.c_str());
+ strcpy(dirTemplateBuf, dirTemplate.c_str());
+
+ // First create a temp file
+ int fd = mkstemp(fileTemplateBuf);
+ EXPECT_TRUE(fd != -1);
+ file = fileTemplateBuf;
+
+ // Create a temp directory
+ dir = mkdtemp(dirTemplateBuf);
+ EXPECT_TRUE(dir != NULL);
+
+ // Create hard link to file
+ int ret1 = CreateHardLink(fileHardLink.c_str(), file);
+ EXPECT_EQ(ret1, 1);
+
+ // Create hard link to directory - should fail
+ int ret2 = CreateHardLink(dirHardLink.c_str(), dir);
+ EXPECT_EQ(ret2, 0);
+ }
+
+ ~CreateHardLinkTest()
+ {
+ int ret;
+
+ ret = unlink(fileHardLink.c_str());
+ EXPECT_EQ(0, ret);
+
+ ret = unlink(file);
+ EXPECT_EQ(0, ret);
+
+ ret = rmdir(dir);
+ EXPECT_EQ(0, ret);
+ }
+};
+
+TEST_F(CreateHardLinkTest, FilePathNameIsNull)
+{
+ int retVal = CreateHardLink(NULL, NULL);
+ EXPECT_EQ(retVal, 0);
+ EXPECT_EQ(ERROR_INVALID_PARAMETER, errno);
+}
+
+TEST_F(CreateHardLinkTest, FilePathNameDoesNotExist)
+{
+ std::string invalidFile = "/tmp/symlinktest_invalidFile";
+ std::string invalidLink = "/tmp/symlinktest_invalidLink";
+
+ // make sure neither exists
+ unlink(invalidFile.c_str());
+ unlink(invalidLink.c_str());
+
+ int retVal = CreateHardLink(invalidLink.c_str(), invalidFile.c_str());
+ EXPECT_EQ(retVal, 0);
+}
+
+TEST_F(CreateHardLinkTest, VerifyLinkCount)
+{
+ int count = 0;
+ int retVal = GetLinkCount(fileHardLink.c_str(), &count);
+ EXPECT_EQ(1, retVal);
+ EXPECT_EQ(2, count);
+}
+
diff --git a/src/libpsl-native/test/test-createsymlink.cpp b/src/libpsl-native/test/test-createsymlink.cpp
new file mode 100644
index 0000000000..abc0646c61
--- /dev/null
+++ b/src/libpsl-native/test/test-createsymlink.cpp
@@ -0,0 +1,117 @@
+//! @file test-createsymlink.cpp
+//! @author George Fleming
+//! @brief Implements test for CreateSymLink() and FollowSymLink()
+
+#include
+#include
+#include
+#include "issymlink.h"
+#include "createsymlink.h"
+#include "followsymlink.h"
+
+using namespace std;
+
+class CreateSymLinkTest : public ::testing::Test
+{
+protected:
+
+ static const int bufSize = 64;
+ const string fileTemplate = "/tmp/symlinktest.fXXXXXX";
+ const string dirTemplate = "/tmp/symlinktest.dXXXXXX";
+ const string fileSymLink = "/tmp/symlinktest.flink";
+ const string dirSymLink = "/tmp/symlinktest.dlink";
+ char *file, *dir;
+ char fileTemplateBuf[bufSize], dirTemplateBuf[bufSize];
+
+ CreateSymLinkTest()
+ {
+ // since mkstemp and mkdtemp modifies the template string, let's give them writable buffers
+ strcpy(fileTemplateBuf, fileTemplate.c_str());
+ strcpy(dirTemplateBuf, dirTemplate.c_str());
+
+ // First create a temp file
+ int fd = mkstemp(fileTemplateBuf);
+ EXPECT_TRUE(fd != -1);
+ file = fileTemplateBuf;
+
+ // Create a temp directory
+ dir = mkdtemp(dirTemplateBuf);
+ EXPECT_TRUE(dir != NULL);
+
+ // Create symbolic link to file
+ int ret1 = CreateSymLink(fileSymLink.c_str(), file);
+ EXPECT_EQ(ret1, 1);
+
+ // Create symbolic link to directory
+ int ret2 = CreateSymLink(dirSymLink.c_str(), dir);
+ EXPECT_EQ(ret2, 1);
+ }
+
+ ~CreateSymLinkTest()
+ {
+ int ret;
+
+ ret = unlink(fileSymLink.c_str());
+ EXPECT_EQ(0, ret);
+
+ ret = unlink(dirSymLink.c_str());
+ EXPECT_EQ(0, ret);
+
+ ret = unlink(file);
+ EXPECT_EQ(0, ret);
+
+ ret = rmdir(dir);
+ EXPECT_EQ(0, ret);
+ }
+};
+
+TEST_F(CreateSymLinkTest, FilePathNameIsNull)
+{
+ int retVal = CreateSymLink(NULL, NULL);
+ EXPECT_EQ(retVal, 0);
+ EXPECT_EQ(ERROR_INVALID_PARAMETER, errno);
+}
+
+TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist)
+{
+ std::string invalidFile = "/tmp/symlinktest_invalidFile";
+ std::string invalidLink = "/tmp/symlinktest_invalidLink";
+
+ // make sure neither exists
+ unlink(invalidFile.c_str());
+ unlink(invalidLink.c_str());
+
+ // Linux allows creation of symbolic link that points to an invalid file
+ int retVal = CreateSymLink(invalidLink.c_str(), invalidFile.c_str());
+ EXPECT_EQ(retVal, 1);
+
+ std::string target = FollowSymLink(invalidLink.c_str());
+ EXPECT_EQ(target, invalidFile);
+
+ unlink(invalidLink.c_str());
+}
+
+TEST_F(CreateSymLinkTest, SymLinkToFile)
+{
+ int retVal = IsSymLink(fileSymLink.c_str());
+ EXPECT_EQ(1, retVal);
+
+ std::string target = FollowSymLink(fileSymLink.c_str());
+ EXPECT_EQ(target, file);
+}
+
+TEST_F(CreateSymLinkTest, SymLinkToDirectory)
+{
+ int retVal = IsSymLink(dirSymLink.c_str());
+ EXPECT_EQ(1, retVal);
+
+ std::string target = FollowSymLink(dirSymLink.c_str());
+ EXPECT_EQ(target, dir);
+}
+
+TEST_F(CreateSymLinkTest, SymLinkAgain)
+{
+ int retVal = CreateSymLink(fileSymLink.c_str(), file);
+ EXPECT_EQ(0, retVal);
+ EXPECT_EQ(ERROR_FILE_EXISTS, errno);
+}
diff --git a/src/libpsl-native/test/test-getcomputername.cpp b/src/libpsl-native/test/test-getcomputername.cpp
new file mode 100644
index 0000000000..9c1d676cbd
--- /dev/null
+++ b/src/libpsl-native/test/test-getcomputername.cpp
@@ -0,0 +1,33 @@
+//! @file test-getcomputername.cpp
+//! @author George Fleming
+//! @brief Unit tests for GetComputerName
+
+#include
+#include "getcomputername.h"
+
+//! Test fixture for GetComputerNameTest
+class GetComputerNameTest : public ::testing::Test
+{
+};
+
+TEST_F(GetComputerNameTest, Success)
+{
+ char expectedComputerName[_POSIX_HOST_NAME_MAX];
+
+ // the gethostname system call gets the nodename from uname
+ FILE *fPtr = popen("uname -n", "r");
+ ASSERT_TRUE(fPtr != NULL);
+
+ char *linePtr = fgets(expectedComputerName, sizeof(expectedComputerName), fPtr);
+ ASSERT_TRUE(linePtr != NULL);
+
+ // There's a tendency to have \n at end of fgets string, so remove it before compare
+ size_t sz = strlen(expectedComputerName);
+ if (sz > 0 && expectedComputerName[sz - 1] == '\n')
+ {
+ expectedComputerName[sz - 1] = '\0';
+ }
+ pclose(fPtr);
+
+ ASSERT_STREQ(GetComputerName(), expectedComputerName);
+}
diff --git a/src/libpsl-native/test/test-getcurrentprocessid.cpp b/src/libpsl-native/test/test-getcurrentprocessid.cpp
new file mode 100644
index 0000000000..a1d10a0bee
--- /dev/null
+++ b/src/libpsl-native/test/test-getcurrentprocessid.cpp
@@ -0,0 +1,16 @@
+#include
+#include "getcurrentprocessorid.h"
+
+// This is a very simple test case to show how tests can be written
+TEST(GetCurrentProcessId,simple)
+{
+ const int32_t currentProcessId = GetCurrentProcessId();
+ const pid_t pid = getpid();
+
+ // first make sure that on this platform those types are of the same size
+ ASSERT_TRUE(sizeof(int32_t) >= sizeof(pid_t));
+
+ // now compare the actual values
+ ASSERT_EQ(currentProcessId,static_cast(pid));
+}
+
diff --git a/src/libpsl-native/test/test-getcurrentthreadid.cpp b/src/libpsl-native/test/test-getcurrentthreadid.cpp
new file mode 100644
index 0000000000..7488d192dd
--- /dev/null
+++ b/src/libpsl-native/test/test-getcurrentthreadid.cpp
@@ -0,0 +1,16 @@
+#include
+#include "getcurrentthreadid.h"
+#include
+
+TEST(GetCurrentThreadId,simple)
+{
+ const HANDLE currentThreadId = GetCurrentThreadId();
+ const pid_t tid = pthread_self();
+
+ // first make sure that on this platform those types are of the same size
+ ASSERT_TRUE(sizeof(HANDLE) >= sizeof(pid_t));
+
+ // now compare the actual values
+ ASSERT_EQ(currentThreadId,reinterpret_cast(tid));
+}
+
diff --git a/src/libpsl-native/test/test-getfullyqualifiedname.cpp b/src/libpsl-native/test/test-getfullyqualifiedname.cpp
new file mode 100644
index 0000000000..7c0353cd1d
--- /dev/null
+++ b/src/libpsl-native/test/test-getfullyqualifiedname.cpp
@@ -0,0 +1,40 @@
+//! @file test-getfullyqualifiedname.cpp
+//! @author George Fleming
+//! @brief Unit tests for GetFullyQualifiedName
+
+#include
+#include "getfullyqualifiedname.h"
+#include
+#include
+#include
+#include
+
+//! Test fixture for GetComputerNameTest
+class GetFullyQualifiedNameTest : public ::testing::Test
+{
+};
+
+TEST_F(GetFullyQualifiedNameTest, ValidateLinuxGetFullyQualifiedDomainName)
+{
+ std::string actual(GetFullyQualifiedName());
+
+ std::string hostname(_POSIX_HOST_NAME_MAX, 0);
+ ASSERT_FALSE(gethostname(&hostname[0], hostname.length()));
+ // trim null characters from string
+ hostname = std::string(hostname.c_str());
+
+ struct addrinfo hints, *info;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_CANONNAME;
+ ASSERT_FALSE(getaddrinfo(hostname.c_str(), "http", &hints, &info));
+
+ // Compare hostname part of FQDN
+ ASSERT_EQ(hostname, actual.substr(0, hostname.length()));
+
+ // Compare canonical name to FQDN
+ ASSERT_EQ(info->ai_canonname, actual);
+
+ freeaddrinfo(info);
+}
diff --git a/src/libpsl-native/test/test-getlinkcount.cpp b/src/libpsl-native/test/test-getlinkcount.cpp
new file mode 100644
index 0000000000..fbe1a001fc
--- /dev/null
+++ b/src/libpsl-native/test/test-getlinkcount.cpp
@@ -0,0 +1,95 @@
+//! @file test-getlinkcount.cpp
+//! @author George Fleming
+//! @brief Implements test for getLinkCount()
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "getlinkcount.h"
+
+class getLinkCountTest : public ::testing::Test
+{
+protected:
+
+ static const int bufSize = 64;
+ const std::string fileTemplate = "/tmp/createFile.XXXXXX";
+ char fileTemplateBuf[bufSize];
+
+ int32_t count;
+ char *file;
+
+ getLinkCountTest()
+ {
+ // since mkstemp modifies the template string, let's give it writable buffer
+ strcpy(fileTemplateBuf, fileTemplate.c_str());
+
+ int fd = mkstemp(fileTemplateBuf);
+ EXPECT_TRUE(fd != -1);
+ file = fileTemplateBuf;
+ }
+
+ void createFileForTesting(const std::string &theFile)
+ {
+ std::ofstream ofs;
+ ofs.open(theFile, std::ofstream::out);
+ ofs << "hi there, ms ostc!";
+ ofs.close();
+ }
+
+ std::string createHardLink(const std::string &origFile)
+ {
+ std::string newFile = origFile + "_link";
+ int ret = link(origFile.c_str(), newFile.c_str());
+ EXPECT_EQ(0, ret);
+
+ return newFile;
+ }
+
+ void removeFile(const std::string &fileName)
+ {
+ int ret = unlink(fileName.c_str());
+ EXPECT_EQ(0, ret);
+ }
+};
+
+TEST_F(getLinkCountTest, FilePathNameIsNull)
+{
+ int32_t retVal = GetLinkCount(NULL, &count );
+ ASSERT_FALSE(retVal);
+ EXPECT_EQ(ERROR_INVALID_PARAMETER, errno);
+}
+
+TEST_F(getLinkCountTest, FilePathNameDoesNotExist)
+{
+ std::string invalidFile = "/tmp/createFile";
+ int32_t retVal = GetLinkCount(invalidFile.c_str(), &count);
+ ASSERT_FALSE(retVal);
+ EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno);
+}
+
+TEST_F(getLinkCountTest, LinkCountOfSinglyLinkedFile)
+{
+ createFileForTesting(file);
+ int32_t retVal = GetLinkCount(file, &count);
+ ASSERT_TRUE(retVal);
+ EXPECT_EQ(1, count);
+
+ removeFile(file);
+}
+
+TEST_F(getLinkCountTest, LinkCountOfMultipliLinkedFile)
+{
+ createFileForTesting(file);
+ std::string newFile = createHardLink(file);
+ int32_t retVal = GetLinkCount(file, &count);
+ ASSERT_TRUE(retVal);
+ EXPECT_EQ(2, count);
+
+ removeFile(file);
+ removeFile(newFile);
+}
+
diff --git a/src/libpsl-native/test/test-getusername.cpp b/src/libpsl-native/test/test-getusername.cpp
new file mode 100644
index 0000000000..2ccb29f68a
--- /dev/null
+++ b/src/libpsl-native/test/test-getusername.cpp
@@ -0,0 +1,17 @@
+//! @file test-getusername.cpp
+//! @author Andrew Schwartzmeyer
+//! @brief Unit tests for GetUserName
+
+#include
+#include
+#include
+#include
+#include
+#include "getusername.h"
+
+TEST(GetUserName, Success)
+{
+ char* expected = getpwuid(geteuid())->pw_name;
+ ASSERT_TRUE(expected != NULL);
+ ASSERT_EQ(GetUserName(), std::string(expected));
+}
diff --git a/src/libpsl-native/test/test-isexecutable.cpp b/src/libpsl-native/test/test-isexecutable.cpp
new file mode 100644
index 0000000000..36955912ff
--- /dev/null
+++ b/src/libpsl-native/test/test-isexecutable.cpp
@@ -0,0 +1,94 @@
+//! @file test-isexecutable.cpp
+//! @author George Fleming
+//! @brief Implements test for isexecutable()
+
+#include
+#include
+#include
+#include
+#include "isexecutable.h"
+
+using namespace std;
+
+class IsExecutableTest : public ::testing::Test
+{
+protected:
+
+ static const int bufSize = 64;
+ const string fileTemplate = "/tmp/isexecutabletest.fXXXXXXX";
+ const mode_t mode_700 = S_IRUSR | S_IWUSR | S_IXUSR;
+ const mode_t mode_070 = S_IRGRP | S_IWGRP | S_IXGRP;
+ const mode_t mode_007 = S_IROTH | S_IWOTH | S_IXOTH;
+ const mode_t mode_777 = mode_700 | mode_070 | mode_007;
+ const mode_t mode_444 = S_IRUSR | S_IRGRP | S_IROTH;
+
+ char *file;
+ char fileTemplateBuf[bufSize];
+
+ IsExecutableTest()
+ {
+ // since mkstemp modifies the template string, let's give it writable buffers
+ strcpy(fileTemplateBuf, fileTemplate.c_str());
+
+ // First create a file
+ int fd = mkstemp(fileTemplateBuf);
+ EXPECT_TRUE(fd != -1);
+ file = fileTemplateBuf;
+ }
+
+ ~IsExecutableTest()
+ {
+ int ret;
+
+ ret = unlink(file);
+ EXPECT_EQ(0, ret);
+ }
+
+ void ChangeFilePermission(const char* file, mode_t mode)
+ {
+ int ret = chmod(file, mode);
+ EXPECT_EQ(ret, 0);
+ }
+};
+
+TEST_F(IsExecutableTest, FilePathNameIsNull)
+{
+ int32_t retVal = IsExecutable(NULL);
+ EXPECT_EQ(retVal, -1);
+ EXPECT_EQ(ERROR_INVALID_PARAMETER, errno);
+}
+
+TEST_F(IsExecutableTest, FilePathNameDoesNotExist)
+{
+ std::string invalidFile = "/tmp/isexecutabletest_invalidFile";
+ int32_t retVal = IsExecutable(invalidFile.c_str());
+ EXPECT_EQ(retVal, -1);
+ EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno);
+}
+
+TEST_F(IsExecutableTest, NormalFileIsNotIsexecutable)
+{
+ int32_t retVal = IsExecutable(file);
+ EXPECT_EQ(0, retVal);
+
+ ChangeFilePermission(file, mode_444);
+
+ retVal = IsExecutable(file);
+ EXPECT_EQ(0, retVal);
+}
+
+TEST_F(IsExecutableTest, FilePermission_700)
+{
+ ChangeFilePermission(file, mode_700);
+
+ int32_t retVal = IsExecutable(file);
+ EXPECT_EQ(1, retVal);
+}
+
+TEST_F(IsExecutableTest, FilePermission_777)
+{
+ ChangeFilePermission(file, mode_777);
+
+ int32_t retVal = IsExecutable(file);
+ EXPECT_EQ(1, retVal);
+}
diff --git a/src/libpsl-native/test/test-issymlink.cpp b/src/libpsl-native/test/test-issymlink.cpp
new file mode 100644
index 0000000000..4aaa3eb541
--- /dev/null
+++ b/src/libpsl-native/test/test-issymlink.cpp
@@ -0,0 +1,104 @@
+//! @file test-issymlink.cpp
+//! @author George Fleming
+//! @brief Implements test for isSymLink()
+
+#include
+#include
+#include
+#include "issymlink.h"
+
+using namespace std;
+
+class isSymLinkTest : public ::testing::Test
+{
+protected:
+
+ static const int bufSize = 64;
+ const string fileTemplate = "/tmp/symlinktest.fXXXXXX";
+ const string dirTemplate = "/tmp/symlinktest.dXXXXXX";
+ const string fileSymLink = "/tmp/symlinktest.flink";
+ const string dirSymLink = "/tmp/symlinktest.dlink";
+ char *file, *dir;
+ char fileTemplateBuf[bufSize], dirTemplateBuf[bufSize];
+
+ isSymLinkTest()
+ {
+ // since mkstemp and mkdtemp modifies the template string, let's give them writable buffers
+ strcpy(fileTemplateBuf, fileTemplate.c_str());
+ strcpy(dirTemplateBuf, dirTemplate.c_str());
+
+ // First create a file
+ int fd = mkstemp(fileTemplateBuf);
+ EXPECT_TRUE(fd != -1);
+ file = fileTemplateBuf;
+
+ // Create a temp directory
+ dir = mkdtemp(dirTemplateBuf);
+ EXPECT_TRUE(dir != NULL);
+
+ // Create symbolic link to file
+ int ret1 = symlink(file, fileSymLink.c_str());
+ EXPECT_EQ(ret1, 0);
+
+ // Create symbolic link to directory
+ int ret2 = symlink(dir, dirSymLink.c_str());
+ EXPECT_EQ(ret2, 0);
+ }
+
+ ~isSymLinkTest()
+ {
+ int ret;
+
+ ret = unlink(fileSymLink.c_str());
+ EXPECT_EQ(0, ret);
+
+ ret = unlink(dirSymLink.c_str());
+ EXPECT_EQ(0, ret);
+
+ ret = unlink(file);
+ EXPECT_EQ(0, ret);
+
+ ret = rmdir(dir);
+ EXPECT_EQ(0, ret);
+ }
+};
+
+TEST_F(isSymLinkTest, FilePathNameIsNull)
+{
+ int retVal = IsSymLink(NULL);
+ EXPECT_EQ(retVal, -1);
+ EXPECT_EQ(ERROR_INVALID_PARAMETER, errno);
+}
+
+TEST_F(isSymLinkTest, FilePathNameDoesNotExist)
+{
+ std::string invalidFile = "/tmp/symlinktest_invalidFile";
+ int retVal = IsSymLink(invalidFile.c_str());
+ EXPECT_EQ(retVal, -1);
+ EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno);
+}
+
+TEST_F(isSymLinkTest, NormalFileIsNotSymLink)
+{
+ int retVal = IsSymLink(file);
+ EXPECT_EQ(0, retVal);
+}
+
+TEST_F(isSymLinkTest, SymLinkToFile)
+{
+ int retVal = IsSymLink(fileSymLink.c_str());
+ EXPECT_EQ(1, retVal);
+}
+
+TEST_F(isSymLinkTest, NormalDirectoryIsNotSymbLink)
+{
+ int retVal = IsSymLink(dir);
+ EXPECT_EQ(0, retVal);
+}
+
+TEST_F(isSymLinkTest, SymLinkToDirectory)
+{
+ int retVal = IsSymLink(dirSymLink.c_str());
+ EXPECT_EQ(1, retVal);
+}
+
diff --git a/src/libpsl-native/test/test-locale.cpp b/src/libpsl-native/test/test-locale.cpp
new file mode 100644
index 0000000000..043e98910e
--- /dev/null
+++ b/src/libpsl-native/test/test-locale.cpp
@@ -0,0 +1,21 @@
+//! @file test-locale.cpp
+//! @author Alex Jordan
+//! @brief Unit tests for linux locale
+
+#include
+#include
+#include
+#include
+#include
+//! Test fixture for LocaleTest
+
+class LocaleTest : public ::testing::Test
+{
+};
+
+TEST_F(LocaleTest, Success)
+{
+ setlocale (LC_ALL, "");
+ ASSERT_FALSE (nl_langinfo(CODESET) == NULL);
+ ASSERT_TRUE(nl_langinfo(CODESET) == std::string("UTF-8"));
+}
diff --git a/src/powershell-native/CMakeLists.txt b/src/powershell-native/CMakeLists.txt
index 183988d69f..5811791588 100644
--- a/src/powershell-native/CMakeLists.txt
+++ b/src/powershell-native/CMakeLists.txt
@@ -3,6 +3,13 @@ project(PowerShell)
add_compile_options()
+# set the output path for `powershell.exe`
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/../Microsoft.PowerShell.ConsoleHost")
+foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES})
+ string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG)
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
+endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES )
+
# set these flags, so build does static linking for msvcr120.dll
# otherwise this dll need to be present on the system
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
diff --git a/test/csharp/fixture_AssemblyLoadContext.cs b/test/csharp/fixture_AssemblyLoadContext.cs
index 71362729e3..7afc152636 100644
--- a/test/csharp/fixture_AssemblyLoadContext.cs
+++ b/test/csharp/fixture_AssemblyLoadContext.cs
@@ -1,7 +1,7 @@
using Xunit;
using System;
using System.Management.Automation;
-using Microsoft.PowerShell.Linux.Host;
+using Microsoft.PowerShell.Host;
// This collection fixture initializes Core PowerShell's AssemblyLoadContext once and only
// once. Attempting to initialize in a class level fixture will cause multiple
diff --git a/test/csharp/project.json b/test/csharp/project.json
index cf66793456..bcef766617 100644
--- a/test/csharp/project.json
+++ b/test/csharp/project.json
@@ -5,7 +5,7 @@
"authors": [ "andschwa" ],
"dependencies": {
- "Microsoft.PowerShell.Linux.Host": "1.0.0-*"
+ "Microsoft.PowerShell.Host": "1.0.0-*"
},
"frameworks": {
@@ -18,5 +18,15 @@
}
},
- "testRunner": "xunit"
+ "testRunner": "xunit",
+
+ "runtimes": {
+ "ubuntu.14.04-x64": { },
+ "centos.7.1-x64": { },
+ "win7-x64": { },
+ "win81-x64": { },
+ "win10-x64": { },
+ "osx.10.10-x64": { },
+ "osx.10.11-x64": { }
+ }
}
diff --git a/test/csharp/test_FileSystemProvider.cs b/test/csharp/test_FileSystemProvider.cs
index 3c720f28a8..c1e7a42f8c 100644
--- a/test/csharp/test_FileSystemProvider.cs
+++ b/test/csharp/test_FileSystemProvider.cs
@@ -13,7 +13,7 @@ using System.Management.Automation.Provider;
using System.Management.Automation.Runspaces;
using Microsoft.PowerShell;
using Microsoft.PowerShell.Commands;
-using Microsoft.PowerShell.Linux.Host;
+using Microsoft.PowerShell.Host;
namespace PSTests
{
diff --git a/test/csharp/test_Runspace.cs b/test/csharp/test_Runspace.cs
index 0a7b00eb98..3115077d94 100644
--- a/test/csharp/test_Runspace.cs
+++ b/test/csharp/test_Runspace.cs
@@ -2,7 +2,7 @@ using Xunit;
using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
-using Microsoft.PowerShell.Linux.Host;
+using Microsoft.PowerShell.Host;
namespace PSTests
{
diff --git a/test/csharp/test_SessionState.cs b/test/csharp/test_SessionState.cs
index adfc9e7a38..bdc4f01beb 100644
--- a/test/csharp/test_SessionState.cs
+++ b/test/csharp/test_SessionState.cs
@@ -9,7 +9,7 @@ using System.Management.Automation.Internal;
using System.Management.Automation.Internal.Host;
using System.Management.Automation.Runspaces;
using Microsoft.PowerShell;
-using Microsoft.PowerShell.Linux.Host;
+using Microsoft.PowerShell.Host;
namespace PSTests
{
diff --git a/test/powershell/Add-Type.Tests.ps1 b/test/powershell/Add-Type.Tests.ps1
index 142e7e0f5e..f0a4e7f972 100644
--- a/test/powershell/Add-Type.Tests.ps1
+++ b/test/powershell/Add-Type.Tests.ps1
@@ -1,5 +1,5 @@
Describe "Add-Type" {
- It "Should not throw given a simple class definition" {
+ It "Should not throw given a simple class definition" -Skip {
{ Add-Type -TypeDefinition "public static class foo { }" } | Should Not Throw
}
}
diff --git a/test/powershell/Json.Tests.ps1 b/test/powershell/Json.Tests.ps1
index 53305d2a0b..978f11f643 100644
--- a/test/powershell/Json.Tests.ps1
+++ b/test/powershell/Json.Tests.ps1
@@ -1,15 +1,6 @@
-# While Core PowerShell does not support the JSON cmdlets, a third
-# party C# library, [Json.NET](http://www.newtonsoft.com/json), can be
-# loaded into PowerShell and used directly.
-
# http://www.newtonsoft.com/json/help/html/ParsingLINQtoJSON.htm
Describe "Json.NET LINQ Parsing" {
- # load third party Json.NET library
- $base = [System.AppContext]::BaseDirectory
- $path = Join-Path $base Newtonsoft.Json.dll
- [Microsoft.PowerShell.CoreCLR.AssemblyExtensions]::LoadFrom($path)
-
BeforeEach {
$jsonFile = Join-Path -Path (Join-Path $PSScriptRoot -ChildPath assets) -ChildPath TestJson.json
$jsonData = (Get-Content $jsonFile | Out-String)
diff --git a/xunit.sh b/xunit.sh
deleted file mode 100755
index 2813b4274f..0000000000
--- a/xunit.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env bash
-
-# Test for build dependencies
-hash cmake 2>/dev/null || { echo >&2 "No cmake, please run 'sudo apt-get install cmake'"; exit 1; }
-hash g++ 2>/dev/null || { echo >&2 "No g++, please run 'sudo apt-get install g++'"; exit 1; }
-hash dotnet 2>/dev/null || { echo >&2 "No dotnet, please visit https://dotnet.github.io/getting-started/"; exit 1; }
-
-# Test for lock file
-test -r test/csharp/project.lock.json || { echo >&2 "Please run 'dotnet restore' to download .NET Core packages"; exit 2; }
-
-# Run xUnit tests
-pushd test/csharp
-## Build
-dotnet build -c Linux
-## Work-around dotnet/cli#753
-cp -r -f ../../src/Microsoft.PowerShell.Linux.Host/{Modules,*.so,*.dylib} bin/Linux/netstandardapp1.5/ubuntu.14.04-x64 2>/dev/null
-## Test
-dotnet test -c Linux
-result=$?
-popd
-
-exit $result