-
Notifications
You must be signed in to change notification settings - Fork 100
Description
I have a very simple problem I want to solve: Due to reasons beyond my control, the company I work for uses a ".local" domain name internally, for everything. My repository url is "http://packages.mycompany.local/nuget/Mycompany-Development/api/v2" - which according to Register-PSRepository is not a "Web Uri" (whatever the heck that means).
It appears this is a bogus error message, largely due to the sophisticated and overly complicated sanity checks Register-PSRepository tries to perform. I've extracted all the required sub-functions to replicate the behavior, modulo the final error trap that surfaces the wrong error.
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
}
function Resolve-Location
{
[CmdletBinding()]
[OutputType([string])]
Param
(
[Parameter(Mandatory=$true)]
[string]
$Location,
[Parameter(Mandatory=$true)]
[string]
$LocationParameterName,
[Parameter()]
$Credential,
[Parameter()]
$Proxy,
[Parameter()]
$ProxyCredential,
[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 -Credential $Credential -Proxy $Proxy -ProxyCredential $ProxyCredential
$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 Ping-Endpoint
{
[CmdletBinding()]
param
(
[Parameter()]
[ValidateNotNullOrEmpty()]
[string]
$Endpoint,
[Parameter()]
$Credential,
[Parameter()]
$Proxy,
[Parameter()]
$ProxyCredential,
[Parameter()]
[switch]
$AllowAutoRedirect = $true
)
$results = @{}
$WebProxy = $null
if($Proxy -and ('Microsoft.PowerShell.Commands.PowerShellGet.InternalWebProxy' -as [Type]))
{
$ProxyNetworkCredential = $null
if($ProxyCredential)
{
$ProxyNetworkCredential = $ProxyCredential.GetNetworkCredential()
}
$WebProxy = New-Object Microsoft.PowerShell.Commands.PowerShellGet.InternalWebProxy -ArgumentList $Proxy,$ProxyNetworkCredential
}
if(HttpClientApisAvailable)
{
$response = $null
try
{
$handler = New-Object System.Net.Http.HttpClientHandler
if($Credential)
{
$handler.Credentials = $Credential.GetNetworkCredential()
}
else
{
$handler.UseDefaultCredentials = $true
}
if($WebProxy)
{
$handler.Proxy = $WebProxy
}
$httpClient = New-Object System.Net.Http.HttpClient -ArgumentList $handler
$response = $httpclient.GetAsync($endpoint)
}
catch
{
}
if ($response -ne $null -and $response.result -ne $null)
{
Write-Host $response.Result
$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 = @'
param($Credential, $WebProxy)
try
{{
$request = [System.Net.WebRequest]::Create("{0}")
$request.Method = 'GET'
$request.Timeout = 30000
if($Credential)
{{
$request.Credentials = $Credential.GetNetworkCredential()
}}
else
{{
$request.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
}}
$request.AllowAutoRedirect = ${1}
if($WebProxy)
{{
$request.Proxy = $WebProxy
}}
$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)
if($WebProxy)
{
$null = $ps.AddParameter('WebProxy', $WebProxy)
}
if($Credential)
{
$null = $ps.AddParameter('Credential', $Credential)
}
$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 HttpClientApisAvailable
{
$HttpClientApisAvailable = $false
try
{
[System.Net.Http.HttpClient]
$HttpClientApisAvailable = $true
}
catch
{
}
return $HttpClientApisAvailable
}$SourceLocation = [Uri] "http://packages.mycompany.local/nuget/Mycompany-Development/api/v2"
# Ping and resolve the specified location
$SourceLocation = Resolve-Location -Location (Get-LocationString -LocationUri $SourceLocation) `
-LocationParameterName 'SourceLocation' `
-Credential $Credential `
-Proxy $Proxy `
-ProxyCredential $ProxyCredential `
-CallerPSCmdlet $PSCmdletI'm not 100% sure, but I think the issue is that Resolve-Location treats any failures as "Web Uri" failures, even though the error appears to be due to $Script:$ResponseUri not existing/being a null key. (I'm not a PowerShell expert and while I generally understand the concept of scope-modifiers, I generally program in C# where you can't dynamically change scopes. To a C# programmer, this looks like bad code or non-sensical code.)
This appears to be an issue since PowerShellGet was called OneGet: OneGet/TestBuild#2
In that issue, it appears that Ping-Endpoint was to blame. Oddly, this was 3 years ago and still not fixed as OneGet got renamed PowerShellGet.