Skip to content

Commit 3895002

Browse files
authored
switch to using PowerShell session when calling cmdlets (#1385)
1 parent e71e500 commit 3895002

File tree

2 files changed

+227
-98
lines changed

2 files changed

+227
-98
lines changed

src/code/UpdateModuleManifest.cs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -605,17 +605,14 @@ protected override void EndProcessing()
605605
{
606606
try
607607
{
608-
var results = PowerShellInvoker.InvokeScriptWithHost<object>(
609-
cmdlet: this,
610-
script: @"
611-
param (
612-
[hashtable] $params
613-
)
614-
615-
New-ModuleManifest @params
616-
",
617-
args: new object[] { parsedMetadata },
618-
out Exception terminatingErrors);
608+
var results = pwsh.AddCommand("Microsoft.PowerShell.Core\\New-ModuleManifest").AddArgument(new object[] { parsedMetadata }).Invoke<Object>();
609+
if (pwsh.HadErrors || pwsh.Streams.Error.Count > 0)
610+
{
611+
foreach (var err in pwsh.Streams.Error)
612+
{
613+
WriteError(err);
614+
}
615+
}
619616
}
620617
catch (Exception e)
621618
{

src/code/Utils.cs

Lines changed: 219 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -528,48 +528,101 @@ public static PSCredential GetRepositoryCredentialFromSecretManagement(
528528
return null;
529529
}
530530

531-
var results = PowerShellInvoker.InvokeScriptWithHost<object>(
532-
cmdlet: cmdletPassedIn,
533-
script: @"
534-
param (
535-
[string] $VaultName,
536-
[string] $SecretName
537-
)
538-
$module = Microsoft.PowerShell.Core\Import-Module -Name Microsoft.PowerShell.SecretManagement -PassThru
539-
if ($null -eq $module) {
540-
return
531+
try
532+
{
533+
using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create())
534+
{
535+
var module = pwsh.AddCommand("Microsoft.PowerShell.Core\\Import-Module").AddParameters(
536+
new Hashtable() {
537+
{ "Name", "Microsoft.PowerShell.SecretManagement"},
538+
{ "PassThru", true}
539+
}).Invoke<PSModuleInfo>();
540+
541+
if (pwsh.HadErrors || pwsh.Streams.Error.Count > 0)
542+
{
543+
foreach (var err in pwsh.Streams.Error)
544+
{
545+
cmdletPassedIn.WriteError(err);
546+
}
547+
548+
return null;
549+
}
550+
551+
if (module == null)
552+
{
553+
cmdletPassedIn.ThrowTerminatingError(
554+
new ErrorRecord(
555+
new PSInvalidOperationException(
556+
message: $"Microsoft.PowerShell.SecretManagement module could not be imported for PSResourceRepository '{repositoryName}' authentication."),
557+
"RepositoryCredentialCannotLoadSecretManagementModule",
558+
ErrorCategory.InvalidOperation,
559+
cmdletPassedIn));
560+
561+
return null;
562+
}
563+
564+
pwsh.Commands.Clear();
565+
var results = pwsh.AddCommand("Microsoft.PowerShell.SecretManagement\\Get-Secret").AddParameters(
566+
new Hashtable() {
567+
{ "Vault", repositoryCredentialInfo.VaultName },
568+
{ "Name", repositoryCredentialInfo.SecretName }
569+
}).Invoke<Object>();
570+
571+
if (pwsh.HadErrors || pwsh.Streams.Error.Count > 0)
572+
{
573+
foreach (var err in pwsh.Streams.Error)
574+
{
575+
cmdletPassedIn.WriteError(err);
576+
}
577+
578+
return null;
579+
}
580+
581+
var secretValue = (results?.Count == 1) ? results[0] : null;
582+
if (secretValue == null)
583+
{
584+
cmdletPassedIn.ThrowTerminatingError(
585+
new ErrorRecord(
586+
new PSInvalidOperationException(
587+
message: $"Microsoft.PowerShell.SecretManagement\\Get-Secret encountered an error while reading secret '{repositoryCredentialInfo.SecretName}' from vault '{repositoryCredentialInfo.VaultName}' for PSResourceRepository '{repositoryName}' authentication."),
588+
"RepositoryCredentialCannotGetSecretFromVault",
589+
ErrorCategory.InvalidOperation,
590+
cmdletPassedIn));
591+
592+
return null;
593+
}
594+
595+
if (secretValue is PSObject secretObject)
596+
{
597+
if (secretObject.BaseObject is PSCredential secretCredential)
598+
{
599+
return secretCredential;
600+
}
541601
}
542-
& $module ""Get-Secret"" -Name $SecretName -Vault $VaultName
543-
",
544-
args: new object[] { repositoryCredentialInfo.VaultName, repositoryCredentialInfo.SecretName },
545-
out Exception terminatingError);
546602

547-
var secretValue = (results.Count == 1) ? results[0] : null;
548-
if (secretValue == null)
603+
cmdletPassedIn.ThrowTerminatingError(
604+
new ErrorRecord(
605+
new PSNotSupportedException($"Secret '{repositoryCredentialInfo.SecretName}' from vault '{repositoryCredentialInfo.VaultName}' has an invalid type. The only supported type is PSCredential."),
606+
"RepositoryCredentialInvalidSecretType",
607+
ErrorCategory.InvalidType,
608+
cmdletPassedIn));
609+
610+
return null;
611+
}
612+
}
613+
catch (Exception e)
549614
{
550615
cmdletPassedIn.ThrowTerminatingError(
551616
new ErrorRecord(
552617
new PSInvalidOperationException(
553-
message: $"Microsoft.PowerShell.SecretManagement\\Get-Secret encountered an error while reading secret \"{repositoryCredentialInfo.SecretName}\" from vault \"{repositoryCredentialInfo.VaultName}\" for PSResourceRepository ({repositoryName}) authentication.",
554-
innerException: terminatingError),
618+
message: $"Microsoft.PowerShell.SecretManagement\\Get-Secret encountered an error while reading secret '{repositoryCredentialInfo.SecretName}' from vault '{repositoryCredentialInfo.VaultName}' for PSResourceRepository '{repositoryName}' authentication.",
619+
innerException: e),
555620
"RepositoryCredentialCannotGetSecretFromVault",
556621
ErrorCategory.InvalidOperation,
557622
cmdletPassedIn));
623+
624+
return null;
558625
}
559-
560-
if (secretValue is PSCredential secretCredential)
561-
{
562-
return secretCredential;
563-
}
564-
565-
cmdletPassedIn.ThrowTerminatingError(
566-
new ErrorRecord(
567-
new PSNotSupportedException($"Secret \"{repositoryCredentialInfo.SecretName}\" from vault \"{repositoryCredentialInfo.VaultName}\" has an invalid type. The only supported type is PSCredential."),
568-
"RepositoryCredentialInvalidSecretType",
569-
ErrorCategory.InvalidType,
570-
cmdletPassedIn));
571-
572-
return null;
573626
}
574627

575628
public static void SaveRepositoryCredentialToSecretManagementVault(
@@ -588,30 +641,65 @@ public static void SaveRepositoryCredentialToSecretManagementVault(
588641
return;
589642
}
590643

591-
PowerShellInvoker.InvokeScriptWithHost(
592-
cmdlet: cmdletPassedIn,
593-
script: @"
594-
param (
595-
[string] $VaultName,
596-
[string] $SecretName,
597-
[object] $SecretValue
598-
)
599-
$module = Microsoft.PowerShell.Core\Import-Module -Name Microsoft.PowerShell.SecretManagement -PassThru
600-
if ($null -eq $module) {
601-
return
644+
try
645+
{
646+
using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create())
647+
{
648+
var module = pwsh.AddCommand("Microsoft.PowerShell.Core\\Import-Module").AddParameters(
649+
new Hashtable() {
650+
{ "Name", "Microsoft.PowerShell.SecretManagement"},
651+
{ "PassThru", true}
652+
}).Invoke<PSModuleInfo>();
653+
654+
if (pwsh.HadErrors || pwsh.Streams.Error.Count > 0)
655+
{
656+
foreach (var err in pwsh.Streams.Error)
657+
{
658+
cmdletPassedIn.WriteError(err);
659+
}
660+
661+
return;
662+
}
663+
664+
if (module == null)
665+
{
666+
cmdletPassedIn.ThrowTerminatingError(
667+
new ErrorRecord(
668+
new PSInvalidOperationException(
669+
message: $"Microsoft.PowerShell.SecretManagement module could not be imported for PSResourceRepository '{repositoryName}' authentication."),
670+
"RepositoryCredentialCannotLoadSecretManagementModule",
671+
ErrorCategory.InvalidOperation,
672+
cmdletPassedIn));
673+
674+
return;
675+
}
676+
677+
pwsh.Commands.Clear();
678+
var results = pwsh.AddCommand("Microsoft.PowerShell.SecretManagement\\Set-Secret").AddParameters(
679+
new Hashtable() {
680+
{ "Secret", repositoryCredentialInfo.Credential},
681+
{ "Vault", repositoryCredentialInfo.VaultName },
682+
{ "Name", repositoryCredentialInfo.SecretName }
683+
}).Invoke<Object>();
684+
685+
if (pwsh.HadErrors || pwsh.Streams.Error.Count > 0)
686+
{
687+
foreach (var err in pwsh.Streams.Error)
688+
{
689+
cmdletPassedIn.WriteError(err);
690+
}
602691
}
603-
& $module ""Set-Secret"" -Name $SecretName -Vault $VaultName -Secret $SecretValue
604-
",
605-
args: new object[] { repositoryCredentialInfo.VaultName, repositoryCredentialInfo.SecretName, repositoryCredentialInfo.Credential },
606-
out Exception terminatingError);
607692

608-
if (terminatingError != null)
693+
return;
694+
}
695+
}
696+
catch (Exception e)
609697
{
610698
cmdletPassedIn.ThrowTerminatingError(
611699
new ErrorRecord(
612700
new PSInvalidOperationException(
613-
message: $"Microsoft.PowerShell.SecretManagement\\Set-Secret encountered an error while adding secret \"{repositoryCredentialInfo.SecretName}\" to vault \"{repositoryCredentialInfo.VaultName}\" for PSResourceRepository ({repositoryName}) authentication.",
614-
innerException: terminatingError),
701+
message: $"Microsoft.PowerShell.SecretManagement\\Set-Secret encountered an error while adding secret '{repositoryCredentialInfo.SecretName}' to vault '{repositoryCredentialInfo.VaultName}' for PSResourceRepository '{repositoryName}' authentication.",
702+
innerException: e),
615703
"RepositoryCredentialCannotAddSecretToVault",
616704
ErrorCategory.InvalidOperation,
617705
cmdletPassedIn));
@@ -622,71 +710,115 @@ public static bool IsSecretManagementModuleAvailable(
622710
string repositoryName,
623711
PSCmdlet cmdletPassedIn)
624712
{
625-
var results = PowerShellInvoker.InvokeScriptWithHost<int>(
626-
cmdlet: cmdletPassedIn,
627-
script: @"
628-
$module = Microsoft.PowerShell.Core\Get-Module -Name Microsoft.PowerShell.SecretManagement -ErrorAction Ignore
629-
if ($null -eq $module) {
630-
$module = Microsoft.PowerShell.Core\Import-Module -Name Microsoft.PowerShell.SecretManagement -PassThru -ErrorAction Ignore
631-
}
632-
if ($null -eq $module) {
633-
return 1
713+
try
714+
{
715+
using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create())
716+
{
717+
var module = pwsh.AddCommand("Microsoft.PowerShell.Core\\Import-Module").AddParameters(
718+
new Hashtable() {
719+
{ "Name", "Microsoft.PowerShell.SecretManagement"},
720+
{ "PassThru", true},
721+
{ "ErrorAction", "Ignore"}
722+
}).Invoke<PSModuleInfo>();
723+
724+
if (pwsh.HadErrors || pwsh.Streams.Error.Count > 0)
725+
{
726+
foreach (var err in pwsh.Streams.Error)
727+
{
728+
cmdletPassedIn.WriteError(err);
729+
}
730+
731+
return false;
634732
}
635-
return 0
636-
",
637-
args: new object[] {},
638-
out Exception terminatingError);
639733

640-
if (terminatingError != null)
734+
if (module == null)
735+
{
736+
return false;
737+
}
738+
}
739+
}
740+
catch (Exception e)
641741
{
642742
cmdletPassedIn.ThrowTerminatingError(
643743
new ErrorRecord(
644744
new PSInvalidOperationException(
645-
message: $"Cannot validate Microsoft.PowerShell.SecretManagement module setup for PSResourceRepository ({repositoryName}) authentication.",
646-
innerException: terminatingError),
745+
message: $"Cannot validate Microsoft.PowerShell.SecretManagement module setup for PSResourceRepository '{repositoryName}' authentication.",
746+
innerException: e),
647747
"RepositoryCredentialSecretManagementInvalidModule",
648748
ErrorCategory.InvalidOperation,
649749
cmdletPassedIn));
650750
}
651751

652-
int result = (results.Count > 0) ? results[0] : 1;
653-
return result == 0;
752+
return true;
654753
}
655754

656755
public static bool IsSecretManagementVaultAccessible(
657756
string repositoryName,
658757
PSCredentialInfo repositoryCredentialInfo,
659758
PSCmdlet cmdletPassedIn)
660759
{
661-
var results = PowerShellInvoker.InvokeScriptWithHost<bool>(
662-
cmdlet: cmdletPassedIn,
663-
script: @"
664-
param (
665-
[string] $VaultName
666-
)
667-
$module = Microsoft.PowerShell.Core\Import-Module -Name Microsoft.PowerShell.SecretManagement -PassThru
668-
if ($null -eq $module) {
669-
return
760+
try
761+
{
762+
using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create())
763+
{
764+
var module = pwsh.AddCommand("Microsoft.PowerShell.Core\\Import-Module").AddParameters(
765+
new Hashtable() {
766+
{ "Name", "Microsoft.PowerShell.SecretManagement"},
767+
{ "PassThru", true}
768+
}).Invoke<PSModuleInfo>();
769+
770+
if (pwsh.HadErrors || pwsh.Streams.Error.Count > 0)
771+
{
772+
foreach (var err in pwsh.Streams.Error)
773+
{
774+
cmdletPassedIn.WriteError(err);
775+
}
776+
777+
return false;
778+
}
779+
780+
if (module == null)
781+
{
782+
return false;
783+
}
784+
785+
pwsh.Commands.Clear();
786+
var results = pwsh.AddCommand("Microsoft.PowerShell.SecretManagement\\Test-SecretVault").AddParameters(
787+
new Hashtable() {
788+
{ "Name", repositoryCredentialInfo.VaultName }
789+
}).Invoke<bool>();
790+
791+
if (pwsh.HadErrors || pwsh.Streams.Error.Count > 0)
792+
{
793+
foreach (var err in pwsh.Streams.Error)
794+
{
795+
cmdletPassedIn.WriteError(err);
796+
}
797+
798+
return false;
799+
}
800+
801+
if (results == null)
802+
{
803+
return false;
670804
}
671-
& $module ""Test-SecretVault"" -Name $VaultName
672-
",
673-
args: new object[] { repositoryCredentialInfo.VaultName },
674-
out Exception terminatingError);
675805

676-
if (terminatingError != null)
806+
return results.Count > 0 ? results[0] : false;
807+
}
808+
}
809+
catch (Exception e)
677810
{
678811
cmdletPassedIn.ThrowTerminatingError(
679812
new ErrorRecord(
680813
new PSInvalidOperationException(
681-
message: $"Microsoft.PowerShell.SecretManagement\\Test-SecretVault encountered an error while validating the vault \"{repositoryCredentialInfo.VaultName}\" for PSResourceRepository ({repositoryName}) authentication.",
682-
innerException: terminatingError),
814+
message: $"Microsoft.PowerShell.SecretManagement\\Test-SecretVault encountered an error while validating the vault '{repositoryCredentialInfo.VaultName}' for PSResourceRepository '{repositoryName}' authentication.",
815+
innerException: e),
683816
"RepositoryCredentialSecretManagementInvalidVault",
684817
ErrorCategory.InvalidOperation,
685818
cmdletPassedIn));
686-
}
687819

688-
bool result = (results.Count > 0) ? results[0] : false;
689-
return result;
820+
return false;
821+
}
690822
}
691823

692824
public static NetworkCredential SetNetworkCredential(

0 commit comments

Comments
 (0)