|
| 1 | + |
| 2 | +function Get-CredsFromCredentialProvider { |
| 3 | + [CmdletBinding()] |
| 4 | + Param |
| 5 | + ( |
| 6 | + [Parameter()] |
| 7 | + [ValidateNotNullOrEmpty()] |
| 8 | + [Uri] |
| 9 | + $SourceLocation, |
| 10 | + |
| 11 | + [Parameter()] |
| 12 | + [bool] |
| 13 | + $isRetry = $false |
| 14 | + ) |
| 15 | + |
| 16 | + |
| 17 | + Write-Verbose "PowerShellGet Calling 'CallCredProvider' on $SourceLocation" |
| 18 | + # Example query: https://pkgs.dev.azure.com/onegettest/_packaging/onegettest/nuget/v2 |
| 19 | + $regex = [regex] '^(\S*pkgs.dev.azure.com\S*/v2)$|^(\S*pkgs.visualstudio.com\S*/v2)$' |
| 20 | + |
| 21 | + if (!($SourceLocation -match $regex)) { |
| 22 | + return $null; |
| 23 | + } |
| 24 | + |
| 25 | + # Find credential provider |
| 26 | + # Option 1. Use env var 'NUGET_PLUGIN_PATHS' to find credential provider |
| 27 | + # See: https://docs.microsoft.com/en-us/nuget/reference/extensibility/nuget-cross-platform-plugins#plugin-installation-and-discovery |
| 28 | + # Note: OSX and Linux can only use option 1 |
| 29 | + # Nuget prioritizes credential providers stored in the NUGET_PLUGIN_PATHS env var |
| 30 | + $credProviderPath = $null |
| 31 | + $defaultEnvPath = "NUGET_PLUGIN_PATHS" |
| 32 | + $nugetPluginPath = Get-Childitem env:$defaultEnvPath -ErrorAction SilentlyContinue |
| 33 | + $callDotnet = $true; |
| 34 | + |
| 35 | + if ($nugetPluginPath -and $nugetPluginPath.value) { |
| 36 | + # Obtion 1a) The environment variable NUGET_PLUGIN_PATHS should contain a full path to the executable, |
| 37 | + # .exe in the .NET Framework case and .dll in the .NET Core case |
| 38 | + $credProviderPath = $nugetPluginPath.value |
| 39 | + $extension = $credProviderPath.Substring($credProviderPath.get_Length() - 4) |
| 40 | + if ($extension -eq ".exe") { |
| 41 | + $callDotnet = $false |
| 42 | + } |
| 43 | + } |
| 44 | + else { |
| 45 | + # Option 1b) Find User-location - The NuGet Home location - %UserProfile%/.nuget/plugins/ |
| 46 | + $path = "$env:UserProfile/.nuget/plugins/netcore/CredentialProvider.Microsoft/CredentialProvider.Microsoft.dll"; |
| 47 | + |
| 48 | + if ($script:IsLinux -or $script:IsMacOS) { |
| 49 | + $path = "$HOME/.nuget/plugins/netcore/CredentialProvider.Microsoft/CredentialProvider.Microsoft.dll"; |
| 50 | + } |
| 51 | + if (Test-Path $path -PathType Leaf) { |
| 52 | + $credProviderPath = $path |
| 53 | + } |
| 54 | + } |
| 55 | + |
| 56 | + # Option 2. Use Visual Studio path to find credential provider |
| 57 | + # Visual Studio comes pre-installed with the Azure Artifacts credential provider, so we'll search for that file using vswhere.exe |
| 58 | + # If Windows (ie not unix), we'll use vswhere.exe to find installation path of VsWhere |
| 59 | + # If credProviderPath is already set we can skip option 2 |
| 60 | + if (!$credProviderPath -and $script:IsWindows) { |
| 61 | + if (${Env:ProgramFiles(x86)}) { |
| 62 | + $programFiles = ${Env:ProgramFiles(x86)} |
| 63 | + } |
| 64 | + elseif ($Env:Programfiles) { |
| 65 | + $programFiles = $Env:Programfiles |
| 66 | + } |
| 67 | + else { |
| 68 | + return $null |
| 69 | + } |
| 70 | + |
| 71 | + $vswhereExePath = $programFiles + "\\Microsoft Visual Studio\\Installer\\vswhere.exe"; |
| 72 | + if (!(Test-Path $vswhereExePath -PathType Leaf)) { |
| 73 | + return $null |
| 74 | + } |
| 75 | + |
| 76 | + $RedirectedOutput = Join-Path ([System.IO.Path]::GetTempPath()) 'RedirectedOutput.txt' |
| 77 | + Start-Process $vswhereExePath ` |
| 78 | + -Wait ` |
| 79 | + -WorkingDirectory $PSHOME ` |
| 80 | + -RedirectStandardOutput $RedirectedOutput ` |
| 81 | + -NoNewWindow |
| 82 | + |
| 83 | + $content = Get-Content $RedirectedOutput |
| 84 | + Remove-Item $RedirectedOutput -Force -Recurse -ErrorAction SilentlyContinue |
| 85 | + |
| 86 | + $vsInstallationPath = "" |
| 87 | + if ([System.Text.RegularExpressions.Regex]::IsMatch($content, "installationPath")) { |
| 88 | + $vsInstallationPath = [System.Text.RegularExpressions.Regex]::Match($content, "(?<=installationPath: ).*(?= installationVersion:)"); |
| 89 | + $vsInstallationPath = $vsInstallationPath.ToString() |
| 90 | + } |
| 91 | + |
| 92 | + # Then use the installation path discovered by vswhere.exe to create the path to search for credential provider |
| 93 | + # ex: "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise" + "\Common7\IDE\CommonExtensions\Microsoft\NuGet\Plugins\CredentialProvider.Microsoft\CredentialProvider.Microsoft.exe" |
| 94 | + if ($vsInstallationPath) { |
| 95 | + $credProviderPath = ($vsInstallationPath + '\Common7\IDE\CommonExtensions\Microsoft\NuGet\Plugins\CredentialProvider.Microsoft\CredentialProvider.Microsoft.exe') |
| 96 | + if (!(Test-Path $credProviderPath -PathType Leaf)) { |
| 97 | + return $null |
| 98 | + } |
| 99 | + $callDotnet = $false; |
| 100 | + } |
| 101 | + } |
| 102 | + |
| 103 | + if (!(Test-Path $credProviderPath -PathType Leaf)) { |
| 104 | + return $null |
| 105 | + } |
| 106 | + |
| 107 | + $filename = $credProviderPath |
| 108 | + $arguments = "-U $SourceLocation" |
| 109 | + if ($callDotnet) { |
| 110 | + $filename = "dotnet" |
| 111 | + $arguments = "$credProviderPath $arguments" |
| 112 | + } |
| 113 | + $argumentsNoRetry = $arguments |
| 114 | + if ($isRetry) { |
| 115 | + $arguments = "$arguments -I"; |
| 116 | + Write-Debug "Credential provider is re-running with -IsRetry" |
| 117 | + } |
| 118 | + |
| 119 | + Write-Debug "Credential provider path is: $credProviderPath" |
| 120 | + # Using a process to run CredentialProvider.Microsoft.exe with arguments -V verbose -U query (and -IsRetry when appropriate) |
| 121 | + # See: https://github.com/Microsoft/artifacts-credprovider |
| 122 | + Start-Process $filename -ArgumentList "$arguments -V minimal" ` |
| 123 | + -Wait ` |
| 124 | + -WorkingDirectory $PSHOME ` |
| 125 | + -NoNewWindow |
| 126 | + |
| 127 | + # This should never run IsRetry |
| 128 | + $RedirectedOutput = Join-Path ([System.IO.Path]::GetTempPath()) 'RedirectedOutput.txt' |
| 129 | + Start-Process $filename -ArgumentList "$argumentsNoRetry -V verbose" ` |
| 130 | + -Wait ` |
| 131 | + -WorkingDirectory $PSHOME ` |
| 132 | + -RedirectStandardOutput $RedirectedOutput ` |
| 133 | + -NoNewWindow |
| 134 | + |
| 135 | + $content = Get-Content $RedirectedOutput |
| 136 | + Remove-Item $RedirectedOutput -Force -Recurse -ErrorAction SilentlyContinue |
| 137 | + |
| 138 | + $username = [System.Text.RegularExpressions.Regex]::Match($content, '(?<=Username: )\S*') |
| 139 | + $password = [System.Text.RegularExpressions.Regex]::Match($content, '(?<=Password: ).*') |
| 140 | + |
| 141 | + if ($username -and $password) { |
| 142 | + $secstr = ConvertTo-SecureString $password -AsPlainText -Force |
| 143 | + $credential = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr |
| 144 | + |
| 145 | + return $credential |
| 146 | + } |
| 147 | + |
| 148 | + return $null |
| 149 | +} |
0 commit comments