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);
}
}
}