1- using Keyfactor . Platform . Extensions . Agents ;
1+
2+ using Keyfactor . Platform . Extensions . Agents ;
23using Keyfactor . Platform . Extensions . Agents . Delegates ;
34using Keyfactor . Platform . Extensions . Agents . Enums ;
45using Keyfactor . Platform . Extensions . Agents . Interfaces ;
5- using Microsoft . Web . Administration ;
66using Newtonsoft . Json ;
77using System ;
88using System . Collections . Generic ;
9- using System . Linq ;
10- using System . Security . Cryptography . X509Certificates ;
11- using System . Text ;
12- using System . Threading . Tasks ;
9+ using System . Management . Automation ;
10+ using System . Management . Automation . Runspaces ;
11+ using System . Net ;
12+ using System . Security ;
1313
1414namespace Keyfactor . Extensions . Orchestrator . IISWithBinding
1515{
@@ -23,76 +23,87 @@ public override AnyJobCompleteInfo processJob(AnyJobConfigInfo config, SubmitInv
2323
2424 private AnyJobCompleteInfo PerformInventory ( AnyJobConfigInfo config , SubmitInventoryUpdate submitInventory )
2525 {
26- dynamic properties = JsonConvert . DeserializeObject ( config . Store . Properties . ToString ( ) ) ;
27- StorePath storePath = new StorePath ( properties . siteName . Value , properties . ipAddress . Value , properties . port . Value , properties . hostName . Value ) ;
28-
29- List < AgentCertStoreInventoryItem > inventoryItems = new List < AgentCertStoreInventoryItem > ( ) ;
26+ try
27+ {
28+ StorePath storePath = JsonConvert . DeserializeObject < StorePath > ( config . Store . Properties . ToString ( ) , new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling . Populate } ) ;
29+ List < AgentCertStoreInventoryItem > inventoryItems = new List < AgentCertStoreInventoryItem > ( ) ;
3030
31- Logger . Trace ( $ "Begin Inventory for Cert Store { $@ "\\{ config . Store . ClientMachine } \{ config . Store . StorePath } "} ") ;
31+ Logger . Trace ( $ "Begin Inventory for Cert Store { $@ "\\{ config . Store . ClientMachine } \{ config . Store . StorePath } "} ") ;
3232
33- using ( X509Store certStore = new X509Store ( $@ "\\{ config . Store . ClientMachine } \{ config . Store . StorePath } ", StoreLocation . LocalMachine ) )
34- {
35- try
36- {
37- certStore . Open ( OpenFlags . MaxAllowed ) ;
38- }
39- catch ( System . Security . Cryptography . CryptographicException ex )
40- {
41- Logger . Trace ( ex ) ;
42- return new AnyJobCompleteInfo ( ) { Status = 4 , Message = $ "Site { config . Store . StorePath } on server { config . Store . ClientMachine } : { ex . Message } " } ;
43- }
33+ WSManConnectionInfo connInfo = new WSManConnectionInfo ( new Uri ( $ "http://{ config . Store . ClientMachine } :5985/wsman") ) ;
34+ connInfo . IncludePortInSPN = storePath . SPNPortFlag ;
35+ SecureString pw = new NetworkCredential ( config . Server . Username , config . Server . Password ) . SecurePassword ;
36+ connInfo . Credential = new PSCredential ( config . Server . Username , pw ) ;
4437
45- using ( ServerManager serverManager = ServerManager . OpenRemote ( config . Store . ClientMachine ) )
38+ using ( Runspace runspace = RunspaceFactory . CreateRunspace ( connInfo ) )
4639 {
47- try
40+ runspace . Open ( ) ;
41+ PowerShellCertStore psCertStore = new PowerShellCertStore ( config . Store . ClientMachine , config . Store . StorePath , runspace ) ;
42+ using ( PowerShell ps = PowerShell . Create ( ) )
4843 {
49- Site site = serverManager . Sites [ storePath . SiteName ] ;
50- if ( site == null )
51- {
52- return new AnyJobCompleteInfo ( ) { Status = 4 , Message = $ "Site { config . Store . StorePath } on server { config . Store . ClientMachine } not found." } ;
44+ ps . Runspace = runspace ;
45+
46+ ps . AddCommand ( "Import-Module" )
47+ . AddParameter ( "Name" , "WebAdministration" )
48+ . AddStatement ( ) ;
49+ ps . AddCommand ( "Get-WebBinding" )
50+ . AddParameter ( "Name" , storePath . SiteName )
51+ . AddParameter ( "Protocol" , storePath . Protocol )
52+ . AddParameter ( "Port" , storePath . Port )
53+ . AddParameter ( "HostHeader" , storePath . HostName )
54+ . AddStatement ( ) ;
55+
56+ var iisBindings = ps . Invoke ( ) ;
57+
58+ if ( ps . HadErrors ) {
59+ return new AnyJobCompleteInfo ( ) { Status = 4 , Message = $ "Inventory for Site { storePath . SiteName } on server { config . Store . ClientMachine } failed." } ;
5360 }
5461
55- foreach ( Binding binding in site . Bindings . Where ( p => p . Protocol . Equals ( "https" , StringComparison . CurrentCultureIgnoreCase ) &&
56- p . BindingInformation . Equals ( storePath . FormatForIIS ( ) , StringComparison . CurrentCultureIgnoreCase ) ) . ToList ( ) )
57- {
58- string thumbPrint = binding . GetAttributeValue ( "CertificateHash" ) . ToString ( ) ;
62+ if ( iisBindings . Count == 0 ) {
63+ submitInventory . Invoke ( inventoryItems ) ;
64+ return new AnyJobCompleteInfo ( ) { Status = 3 , Message = $ " { storePath . Protocol } binding for Site { storePath . SiteName } on server { config . Store . ClientMachine } not found." } ;
65+ }
5966
67+ //in theory should only be one, but keeping for future update to chance inventory
68+ foreach ( var binding in iisBindings )
69+ {
70+ var thumbPrint = $ "{ ( binding . Properties [ "certificateHash" ] ? . Value ) } ";
6071 if ( string . IsNullOrEmpty ( thumbPrint ) )
6172 continue ;
6273
63- X509Certificate2Collection x509Certs = certStore . Certificates . Find ( X509FindType . FindByThumbprint , thumbPrint , true ) ;
64- if ( x509Certs . Count == 0 )
74+ var foundCert = psCertStore . Certificates . Find ( m => m . Thumbprint . Equals ( thumbPrint ) ) ;
75+
76+ if ( foundCert == null )
6577 continue ;
6678
6779 inventoryItems . Add (
6880 new AgentCertStoreInventoryItem ( )
6981 {
70- Certificates = new string [ ] { Convert . ToBase64String ( x509Certs [ 0 ] . RawData ) } ,
82+ Certificates = new string [ ] { foundCert . CertificateData } ,
7183 Alias = thumbPrint ,
72- PrivateKeyEntry = x509Certs [ 0 ] . HasPrivateKey ,
84+ PrivateKeyEntry = foundCert . HasPrivateKey ,
7385 UseChainLevel = false ,
7486 ItemStatus = AgentInventoryItemStatus . Unknown
7587 }
7688 ) ;
7789 }
7890 }
79- catch ( Exception ex )
80- {
81- Logger . Trace ( ex ) ;
82- return new AnyJobCompleteInfo ( ) { Status = 4 , Message = $ "Site { config . Store . StorePath } on server { config . Store . ClientMachine } : { ex . Message } " } ;
83- }
91+ runspace . Close ( ) ;
8492 }
85- }
8693
87- try
88- {
8994 submitInventory . Invoke ( inventoryItems ) ;
9095 return new AnyJobCompleteInfo ( ) { Status = 2 , Message = "Successful" } ;
9196 }
97+ catch ( PSCertStoreException psEx )
98+ {
99+ Logger . Trace ( psEx ) ;
100+ return new AnyJobCompleteInfo ( ) { Status = 4 , Message = $ "Unable to open remote certificate store: { psEx . Message } " } ;
101+ }
92102 catch ( Exception ex )
93103 {
94104 Logger . Trace ( ex ) ;
95105 return new AnyJobCompleteInfo ( ) { Status = 4 , Message = $ "Site { config . Store . StorePath } on server { config . Store . ClientMachine } : { ex . Message } " } ;
106+
96107 }
97108 }
98109 }
0 commit comments