using System.Collections.ObjectModel; using System.IO.Compression; using System.Management.Automation; using System.Management.Automation.Runspaces; using Microsoft.PowerShell; namespace App; public static class HttpClientExtensions { public static async Task DownloadFileTaskAsync(this HttpClient client, Uri uri, string fileName) { await using var s = await client.GetStreamAsync(uri); await using var fs = new FileStream(fileName, FileMode.CreateNew); await s.CopyToAsync(fs); } } public static class PowerShellUtility { /// /// See this: https://www.powershellgallery.com/packages/PowerShellGet/3.0.17-beta17 /// private const string PowerShellGetVersion = "3.0.17-beta17"; private const string PowerShellGet = "PowerShellGet"; private const string PowerShellGetNupkg = $"{PowerShellGet}.nupkg"; public readonly record struct PowerShellResponse( Collection? Result, List ErrorMessages, bool Failed); /// /// This function runs a PowerShell script inside C#. /// 1) downloads PowerShelGet nupkg from PowerShell gallery /// 2) unzip nupkg file to access modules folder /// 3) Import-Module PowerShellGet so Install-Module Cmdlet becomes available /// 4) Runs the PowerShell script /// /// Environment variables accessible to PowerShell /// PowerShell script to run /// public static async Task RunPsScript(Dictionary environments, string script) { var sessionId = Guid.NewGuid().ToString(); var folderPrefix = Path.Combine(Directory.GetCurrentDirectory(), sessionId); var powerShellGetNupkgPath = Path.Combine(folderPrefix, PowerShellGetNupkg); var powerShellGetModulePath = Path.Combine(folderPrefix, PowerShellGet); try { Directory.CreateDirectory(folderPrefix); // Manually download PowerShellGet module using var client = new HttpClient(); await client.DownloadFileTaskAsync( new Uri($"https://psg-prod-eastus.azureedge.net/packages/powershellget.{PowerShellGetVersion}.nupkg"), powerShellGetNupkgPath); // UnZip Nupkg file ZipFile.ExtractToDirectory( powerShellGetNupkgPath, powerShellGetModulePath); var errorMessages = new List(); using var powershell = PowerShell.Create(); // Setting up the PowerShell runspace var sessionState = InitialSessionState.CreateDefault2(); sessionState.ExecutionPolicy = ExecutionPolicy.Unrestricted; // Add environment variables foreach (var (key, value) in environments) { sessionState.EnvironmentVariables.Add( new SessionStateVariableEntry( key, value, $"{folderPrefix}/{key}={value}")); } // Using PSGet v3 in order to save the Az modules and its dependencies powershell.AddScript( $"Import-Module {powerShellGetModulePath} -Force"); powershell.AddScript(@" if ((Get-Module -Name PSPackageProject -ListAvailable).Count -eq 0) { Install-Module -Name PSPackageProject -Repository PSGallery } "); powershell.AddScript(script); var result = powershell.Invoke(); if (powershell.HadErrors) { errorMessages.AddRange(powershell.Streams.Error.Select(x => x.ToString())); } return new PowerShellResponse(result, errorMessages, powershell.HadErrors); } catch (Exception e) { return new PowerShellResponse( null, new List { $"Error occured while running command: {e.Message}" }, true); } finally { Directory.Delete(folderPrefix, true); } } } class Program { public static async Task Main(string[] args) { var (_, errors, _) = await PowerShellUtility.RunPsScript(new Dictionary(), @" Install-PSResource -Name Az -Repository PSGallery -TrustRepository -Reinstall # Import Azure module Import-Module 'Az' Import-Module 'Az.Accounts' Import-Module 'Az.RecoveryServices' try { New-AzResourceGroup -Name 'TestRg123' -Location 'eastus2euap' } catch { $string_err = $_ | Out-String Write-Output ""Failed to run test $testname because $string_err"" } "); foreach (var errorMsg in errors) { Console.WriteLine(errorMsg); } } }