Skip to content

Commit

Permalink
Added PowerShell runspace for localMachines
Browse files Browse the repository at this point in the history
  • Loading branch information
Bob Pokorny committed Oct 22, 2024
1 parent b921fc4 commit 3f1b1a9
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 103 deletions.
5 changes: 0 additions & 5 deletions IISU/ImplementedStoreTypes/WinIIS/Inventory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,6 @@ public List<CurrentInventoryItem> QueryIISCertificates(RemoteSettings settings)
{
ps.Initialize();

// Check if IISAdministration is available and loaded
command = "Get-Module -ListAvailable";
Dictionary<string, object> parameters = new Dictionary<string, object>();
results = ps.ExecuteScriptBlock(command, parameters);

command = "Get-KFIISBoundCertificates";
results = ps.ExecuteFunction(command);

Expand Down
219 changes: 121 additions & 98 deletions IISU/PSHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
using System.Management.Automation.Runspaces;
using System.Net;
using System.Text.Json;
using System.Xml.Serialization;

namespace Keyfactor.Extensions.Orchestrator.WindowsCertStore
{
Expand Down Expand Up @@ -105,75 +106,107 @@ public void Initialize()
_logger.LogDebug($"Protocol is set to: {protocol}");

scriptFileLocation = FindPSLocation(AppDomain.CurrentDomain.BaseDirectory, "WinCertFull.ps1");
if (scriptFileLocation == null) { throw new Exception("Unable to find the accompanying PowerShell Script file: WinCertFull.ps1"); }

_logger.LogTrace($"Script file located here: {scriptFileLocation}");

if (!isLocalMachine)
{
if (protocol == "ssh")
{
// TODO: Need to add logic when using keyfilePath
// TODO: Need to add keyfilePath parameter
PS.AddCommand("New-PSSession")
.AddParameter("HostName", ClientMachineName)
.AddParameter("UserName", serverUserName);
InitializeRemoteSession();
}
else
{
InitializeLocalSession();
}
}

}
else
{
var pw = new NetworkCredential(serverUserName, serverPassword).SecurePassword;
PSCredential myCreds = new PSCredential(serverUserName, pw);
private void InitializeRemoteSession()
{
if (protocol == "ssh")
{
// TODO: Need to add logic when using keyfilePath
// TODO: Need to add keyfilePath parameter
PS.AddCommand("New-PSSession")
.AddParameter("HostName", ClientMachineName)
.AddParameter("UserName", serverUserName);

// Create the PSSessionOption object
var sessionOption = new PSSessionOption
{
IncludePortInSPN = useSPN
};

PS.AddCommand("New-PSSession")
.AddParameter("ComputerName", ClientMachineName)
.AddParameter("Port", port)
.AddParameter("Credential", myCreds)
.AddParameter("SessionOption", sessionOption);
}
}
else
{
var pw = new NetworkCredential(serverUserName, serverPassword).SecurePassword;
PSCredential myCreds = new PSCredential(serverUserName, pw);

_logger.LogTrace("Attempting to invoke PS-Session command on remote machine.");
_PSSession = PS.Invoke();
if (PS.HadErrors)
// Create the PSSessionOption object
var sessionOption = new PSSessionOption
{
foreach (var error in PS.Streams.Error)
{
_logger.LogError($"Error: {error}");
}
throw new Exception($"An error occurred while attempting to connect to the client machine: {clientMachineName}");
}
IncludePortInSPN = useSPN
};

PS.AddCommand("New-PSSession")
.AddParameter("ComputerName", ClientMachineName)
.AddParameter("Port", port)
.AddParameter("Credential", myCreds)
.AddParameter("SessionOption", sessionOption);
}

PS.Commands.Clear();
_logger.LogTrace("PS-Session established");
_logger.LogTrace("Attempting to invoke PS-Session command on remote machine.");
_PSSession = PS.Invoke();
CheckErrors();

PS.AddCommand("Invoke-Command")
.AddParameter("Session", _PSSession)
.AddParameter("ScriptBlock", ScriptBlock.Create(PSHelper.LoadScript(scriptFileLocation)));
PS.Commands.Clear();
_logger.LogTrace("PS-Session established");

var results = PS.Invoke();
}
else
{
_logger.LogTrace("Setting Execution Policy to Unrestricted");
// PS.AddScript("Set-ExecutionPolicy Unrestricted -Scope Process -Force");
PS.AddScript("Set-ExecutionPolicy Unrestricted -Scope CurrentUser -Force");
PS.Invoke(); // Ensure the script is invoked and loaded
PS.Commands.Clear(); // Clear commands after loading functions

_logger.LogTrace("Setting script file into memory");
PS.AddScript(". '" + scriptFileLocation + "'");
PS.Invoke(); // Ensure the script is invoked and loaded
PS.Commands.Clear(); // Clear commands after loading functions
}
PS.AddCommand("Invoke-Command")
.AddParameter("Session", _PSSession)
.AddParameter("ScriptBlock", ScriptBlock.Create(PSHelper.LoadScript(scriptFileLocation)));

var results = PS.Invoke();
CheckErrors();
}

private void InitializeLocalSession()
{
_logger.LogTrace("Setting Execution Policy to Unrestricted");
PS.AddScript("Set-ExecutionPolicy Unrestricted -Scope Process -Force");
PS.Invoke(); // Ensure the script is invoked and loaded
CheckErrors();

PS.Commands.Clear(); // Clear commands after loading functions

// Trying this to get IISAdministration loaded!!
PowerShellProcessInstance psInstance = new PowerShellProcessInstance(new Version(5, 1), null, null, false);
Runspace rs = RunspaceFactory.CreateOutOfProcessRunspace(new TypeTable(Array.Empty<string>()), psInstance);
rs.Open();

PS.Runspace = rs;

_logger.LogTrace("Setting script file into memory");
PS.AddScript(". '" + scriptFileLocation + "'");
PS.Invoke(); // Ensure the script is invoked and loaded
CheckErrors();

PS.Commands.Clear(); // Clear commands after loading functions
}


public void Terminate()
{
PS.Commands.Clear();
if (_PSSession.Count > 0)
{
PS.AddCommand("Remove-Session").AddParameter("Session", _PSSession);
PS.Invoke();
CheckErrors();
}

try
{
PS.Runspace.Close();
}
catch (Exception)
{
}

PS.Dispose();
}

Expand All @@ -187,28 +220,20 @@ public void Terminate()
// THIS IS ONLY FOR TESTING
//using (PS)
//{
PS.AddCommand(scriptBlock);
foreach (var param in parameters)
{
PS.AddParameter(param.Key, param.Value);
}

var results = PS.Invoke();

// Display the results
foreach (var result in results)
{
Console.WriteLine(result);
}
PS.AddCommand(scriptBlock);
foreach (var param in parameters)
{
PS.AddParameter(param.Key, param.Value);
}

// Handle any errors
if (PS.Streams.Error.Count > 0)
{
foreach (var error in PS.Streams.Error)
{
Console.WriteLine($"Error: {error}");
}
}
var results = PS.Invoke();
CheckErrors();

// Display the results
foreach (var result in results)
{
Console.WriteLine(result);
}
//}

return ExecutePowerShell(scriptBlock, parameters);
Expand Down Expand Up @@ -237,28 +262,19 @@ public void Terminate()
}
else
{
PS.AddCommand("Invoke-Command")
.AddParameter("ScriptBlock", ScriptBlock.Create(scriptBlock))
.AddParameter("ArgumentList", argList.ToArray());
PS.AddScript(scriptBlock).AddArgument(argList.ToArray());
//PS.AddCommand("Invoke-Command")
// .AddParameter("ScriptBlock", ScriptBlock.Create(scriptBlock))
// .AddParameter("ArgumentList", argList.ToArray());
}

bool hadErrors = false;
string errorList = string.Empty;
_logger.LogTrace($"Script block:\n{scriptBlock}");

var results = PS.Invoke();
if (PS.HadErrors)
{
errorList = string.Empty;
foreach (var error in PS.Streams.Error)
{
errorList += error + "\n";
_logger.LogError($"Error: {error}");
}
CheckErrors();

throw new ApplicationException(errorList);
}

return results;
}
catch (Exception ex)
Expand Down Expand Up @@ -295,16 +311,7 @@ public void Terminate()
{
_logger.LogTrace("Ready to invoke the script");
var results = PS.Invoke();
if (PS.HadErrors)
{
_logger.LogTrace("There were errors detected.");
foreach (var error in PS.Streams.Error)
{
_logger.LogError($"Error: {error}");
}

throw new Exception("An error occurred when executing a PowerShell script. Please review the logs for more information.");
}
CheckErrors();

var jsonResults = results[0].ToString();
var certInfoList = JsonSerializer.Deserialize<List<CertificateInfo>>(jsonResults);
Expand All @@ -320,6 +327,22 @@ public void Terminate()
}
}

private void CheckErrors()
{
string errorList = string.Empty;
if (PS.HadErrors)
{
errorList = string.Empty;
foreach (var error in PS.Streams.Error)
{
errorList += error + "\n";
_logger.LogError($"Error: {error}");
}

throw new ApplicationException(errorList);
}
}

public static string LoadScript(string scriptFileName)
{
string scriptFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PowerShellScripts", scriptFileName);
Expand Down

0 comments on commit 3f1b1a9

Please sign in to comment.