Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8ef85a9
Add concurrent find and install
alerickson Dec 24, 2025
4e4741f
Use threadsafe types and add better use of _knownLatestPkgVersion
alerickson Dec 24, 2025
cb925dc
save before changes
alerickson Dec 27, 2025
5bf4ceb
Add async find and install calls
alerickson Jan 2, 2026
329eb39
Add async calls
alerickson Jan 21, 2026
d65e232
Change packagesHash and updatedPackagesHash to be thread safe Concurr…
alerickson Jan 23, 2026
321a38e
add error handling & clean up code
alerickson Feb 18, 2026
26f5168
Remove out ref errorRecord from async method
alerickson Feb 18, 2026
f04925b
fix error handling
alerickson Feb 18, 2026
80c2368
Merge branch 'master' of https://github.com/powershell/PSResourceGet …
alerickson Feb 18, 2026
5bcf88c
clean up
alerickson Feb 18, 2026
f83d929
temp comment out find local tests to debug CI
alerickson Feb 19, 2026
7ea4451
try commenting out default runspace
alerickson Feb 19, 2026
3df00b6
Bug fix and test update
alerickson Feb 22, 2026
c8bedb4
add bug fix for prerelease versions
alerickson Feb 26, 2026
8051a23
fix exception handling
alerickson Feb 26, 2026
26cf187
add debug and verbose logging to some tests
alerickson Feb 26, 2026
f53c7e3
add debug messages
alerickson Feb 26, 2026
6df8a2b
add more logging
alerickson Feb 27, 2026
5231d68
Add more CI logging
alerickson Mar 1, 2026
513b9aa
Add more logging
alerickson Mar 1, 2026
e2d31bb
add more logging
alerickson Mar 2, 2026
133a22e
add a lot more logging
alerickson Mar 2, 2026
0fef51e
try removing shouldprocess condition in installhelper
alerickson Mar 2, 2026
e43e194
Add more debug logging
alerickson Mar 3, 2026
ce20d1d
Fix TryReadPSDataFile()
alerickson Mar 3, 2026
c5b49fe
Comment out GH pkgs tests
alerickson Mar 3, 2026
acdf110
Bug fix for null exception when writing error
alerickson Mar 3, 2026
9289198
Update tests
alerickson Mar 3, 2026
8f05b25
Fix update test suite
alerickson Mar 3, 2026
7f24c34
Add flaky tests to Release run only
alerickson Mar 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/code/ContainerRegistryServerAPICalls.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ public ContainerRegistryServerAPICalls(PSRepositoryInfo repository, PSCmdlet cmd

#region Overridden Methods

public override Task<FindResults> FindVersionAsync(string packageName, string version, ResourceType type)
{
return null;
}

public override Task<FindResults> FindVersionGlobbingAsync(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, bool getOnlyLatest)
{
return null;
}

/// <summary>
/// Find method which allows for searching for all packages from a repository and returns latest version for each.
/// </summary>
Expand Down Expand Up @@ -146,6 +156,12 @@ public override FindResults FindName(string packageName, bool includePrerelease,
return new FindResults(stringResponse: new string[] { }, hashtableResponse: pkgResult.ToArray(), responseType: containerRegistryFindResponseType);
}


public override Task<FindResults> FindNameAsync(string packageName, bool includePrerelease, ResourceType type)
{
return null;
}

/// <summary>
/// Find method which allows for searching for single name and tag and returns latest version.
/// Name: no wildcard support
Expand Down
568 changes: 338 additions & 230 deletions src/code/FindHelper.cs

Large diffs are not rendered by default.

383 changes: 238 additions & 145 deletions src/code/InstallHelper.cs

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions src/code/LocalServerApiCalls.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using System.Net;
using System.Management.Automation;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;

namespace Microsoft.PowerShell.PSResourceGet.Cmdlets
{
Expand All @@ -39,6 +40,15 @@ public LocalServerAPICalls (PSRepositoryInfo repository, PSCmdlet cmdletPassedIn

#region Overridden Methods

public override Task<FindResults> FindVersionAsync(string packageName, string version, ResourceType type)
{
throw new NotImplementedException();
}

public override Task<FindResults> FindVersionGlobbingAsync(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, bool getOnlyLatest)
{
throw new NotImplementedException();
}
/// <summary>
/// Find method which allows for searching for all packages from a repository and returns latest version for each.
/// Examples: Search -Repository PSGallery
Expand Down Expand Up @@ -109,6 +119,11 @@ public override FindResults FindName(string packageName, bool includePrerelease,
return FindNameHelper(packageName, Utils.EmptyStrArray, includePrerelease, type, out errRecord);
}

public override Task<FindResults> FindNameAsync(string packageName, bool includePrerelease, ResourceType type)
{
throw new NotImplementedException();
}

/// <summary>
/// Find method which allows for searching for single name and tag and returns latest version.
/// Name: no wildcard support
Expand Down
14 changes: 14 additions & 0 deletions src/code/NuGetServerAPICalls.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ public NuGetServerAPICalls (PSRepositoryInfo repository, PSCmdlet cmdletPassedIn

#region Overridden Methods

public override Task<FindResults> FindVersionAsync(string packageName, string version, ResourceType type)
{
throw new NotImplementedException();
}

public override Task<FindResults> FindVersionGlobbingAsync(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, bool getOnlyLatest)
{
throw new NotImplementedException();
}
/// <summary>
/// Find method which allows for searching for all packages from a repository and returns latest version for each.
/// Examples: Search -Repository MyNuGetServer
Expand Down Expand Up @@ -183,6 +192,11 @@ public override FindResults FindName(string packageName, bool includePrerelease,
return new FindResults(stringResponse: new string[]{ response }, hashtableResponse: emptyHashResponses, responseType: FindResponseType);
}

public override Task<FindResults> FindNameAsync(string packageName, bool includePrerelease, ResourceType type)
{
throw new NotImplementedException();
}

/// <summary>
/// Find method which allows for searching for single name and tag and returns latest version.
/// Name: no wildcard support
Expand Down
25 changes: 25 additions & 0 deletions src/code/ServerApiCall.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.Text;
using System.Runtime.ExceptionServices;
using System.Management.Automation;
using System.Threading.Tasks;

namespace Microsoft.PowerShell.PSResourceGet.Cmdlets
{
Expand Down Expand Up @@ -81,6 +82,13 @@ public ServerApiCall(PSRepositoryInfo repository, NetworkCredential networkCrede
/// </summary>
public abstract FindResults FindName(string packageName, bool includePrerelease, ResourceType type, out ErrorRecord errRecord);

/// <summary>
/// Find method which allows for async searching for package by single name and returns latest version.
/// Name: no wildcard support
/// Examples: Search "PowerShellGet"
/// </summary>
public abstract Task<FindResults> FindNameAsync(string packageName, bool includePrerelease, ResourceType type);

/// <summary>
/// Find method which allows for searching for package by single name and tag and returns latest version.
/// Name: no wildcard support
Expand All @@ -95,6 +103,15 @@ public ServerApiCall(PSRepositoryInfo repository, NetworkCredential networkCrede
/// </summary>
public abstract FindResults FindNameGlobbing(string packageName, bool includePrerelease, ResourceType type, out ErrorRecord errRecord);

/// <summary>
/// Find method which allows for async searching for single name with version range.
/// Name: no wildcard support
/// Version: supports wildcards
/// Examples: Search "PowerShellGet" "[3.0.0.0, 5.0.0.0]"
/// Search "PowerShellGet" "3.*"
/// </summary>
public abstract Task<FindResults> FindVersionGlobbingAsync(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, bool getOnlyLatest);

/// <summary>
/// Find method which allows for searching for single name with wildcards and tag and returns latest version.
/// Name: supports wildcards
Expand All @@ -118,6 +135,14 @@ public ServerApiCall(PSRepositoryInfo repository, NetworkCredential networkCrede
/// </summary>
public abstract FindResults FindVersion(string packageName, string version, ResourceType type, out ErrorRecord errRecord);

/// <summary>
/// Find method which allows for async searching for single name with specific version.
/// Name: no wildcard support
/// Version: no wildcard support
/// Examples: Search "PowerShellGet" "2.2.5"
/// </summary>
public abstract Task<FindResults> FindVersionAsync(string packageName, string version, ResourceType type);

/// <summary>
/// Find method which allows for searching for single name with specific version.
/// Name: no wildcard support
Expand Down
100 changes: 81 additions & 19 deletions src/code/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1342,37 +1342,99 @@ private static bool TryReadPSDataFile(
out Hashtable dataFileInfo,
out Exception error)
{
dataFileInfo = null;
error = null;
try
{
if (filePath is null)
{
throw new PSArgumentNullException(nameof(filePath));
}

string contents = System.IO.File.ReadAllText(filePath);
var scriptBlock = System.Management.Automation.ScriptBlock.Create(contents);

// Ensure that the content script block is safe to convert into a PSDataFile Hashtable.
// This will throw for unsafe content.
scriptBlock.CheckRestrictedLanguage(
allowedCommands: allowedCommands,
allowedVariables: allowedVariables,
allowEnvironmentVariables: allowEnvironmentVariables);

// Convert contents into PSDataFile Hashtable by executing content as script.
object result = scriptBlock.InvokeReturnAsIs();
if (result is PSObject psObject)

// Parallel.ForEach calls into this method.
// Each thread needs its own runspace created to provide a separate environment for operations to run independently.
// The runspace must be disposed when done and DefaultRunspace must be set/restored per-thread
// to prevent cross-contamination when thread-pool threads are reused across tests.
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
runspace.SessionStateProxy.LanguageMode = PSLanguageMode.ConstrainedLanguage;

// Save and set the default runspace for the current thread to prevent
// stale DefaultRunspace from a prior operation on this reused thread-pool thread.
Runspace previousDefaultRunspace = Runspace.DefaultRunspace;
try
{
result = psObject.BaseObject;
}
Runspace.DefaultRunspace = runspace;

dataFileInfo = (Hashtable)result;
error = null;
return true;
using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create())
{
pwsh.Runspace = runspace;

var cmd = new Command(
command: contents,
isScript: true,
useLocalScope: true);
cmd.MergeMyResults(
myResult: PipelineResultTypes.Error | PipelineResultTypes.Warning | PipelineResultTypes.Verbose | PipelineResultTypes.Debug | PipelineResultTypes.Information,
toResult: PipelineResultTypes.Output);
pwsh.Commands.AddCommand(cmd);

try
{
// Invoke the pipeline and retrieve the results
var results = pwsh.Invoke();

if (results[0] is PSObject pwshObj)
{
switch (pwshObj.BaseObject)
{
case ErrorRecord err:
//_cmdletPassedIn.WriteError(error);
break;

case WarningRecord warning:
//cmdlet.WriteWarning(warning.Message);
break;

case VerboseRecord verbose:
//cmdlet.WriteVerbose(verbose.Message);
break;

case DebugRecord debug:
//cmdlet.WriteDebug(debug.Message);
break;

case InformationRecord info:
//cmdlet.WriteInformation(info);
break;

case Hashtable result:
dataFileInfo = result;
return true;
}
}
}
catch (Exception ex)
{
error = ex;
}
}
// Return false to indicate "we couldn't parse a valid Hashtable from this .psd1 file."
// The only success path is the 'case Hashtable result' branch above which does return true.
return false;
}
finally
{
// Always restore the previous default runspace and close/dispose
// the per-thread runspace, even on success (return true) or exception paths.
Runspace.DefaultRunspace = previousDefaultRunspace;
runspace.Close();
runspace.Dispose();
}
}
catch (Exception ex)
{
dataFileInfo = null;
error = ex;
return false;
}
Expand Down
Loading
Loading