I am trying to create a Remote PowerShell (RPS) that will form connection between machines to execute RPS Commands. I have this following example setup "HostPC with C# console application (that executes RPS) to form connection between two Remote PCs"
The following link (Certificate (password-less) based authentication in WinRM) was found from one of the comments in answer in separate question. From the article, the author presented with high-level approach to create Certificate (password-less) based authentication in WinRM and they are the following:
- Configure SSL connectivity to winrm on the endpoint
- Generate a user certificate used for authentication
- Enable Certificate authentication on the endpoint. Its disabled by default for server auth and enabled on the client side.
- Add the user certificate and its issuing CA certificate to the certificate store of the endpoint
- Create a user mapping in winrm with the thumbprint of the issuing certificate on the endpoint.
So what I have done are the following:
Certificate Authentication Setup:
- Configured WinRM to work with HTTPS in Remote PCs
- Created Client Certificate in HostPC
- Exported the Client Certificate and imported it on the Remote PCs
- Configured WinRM to enable the Certificate Authentication on the Remote PCs
- Created Certificates in each Remote PC
- Binded the Remote PC certificates to the HTTPS Listener
- Created the winrm user mapping using the HostPC certificate in each Remote PC
Configured WinRM to work with HTTPS
winrm quickconfig -transport:https
Certificate Creation
New-SelfSignedCertificate `
-DnsName <PCName> `
-CertStoreLocation <CertificateLocation> `
-KeyLength 2048 `
-NotAfter (Get-Date).AddYears(xx) `
-TextExtension @("2.5.29.37={text}<OID Purpose>")
Certificate Authentication
winrm set winrm/config/service/auth @{Certificate="true"}
Binding Certificate to HTTPS Listener
winrm create winrm/config/Listener?Address=*+Transport=HTTPS "@{Hostname=<RemotePCName>";CertificateThumbprint=<RemotePC Certificate Thumbprint>"}"
User Mapping
New-Item -Path WSMan:\localhost\ClientCertificate `
-Subject '<HostPCName>' `
-URI * `
-Issuer <HostPC Certificate Thumbprint> `
-Credential (Get-Credential)
C# Application Side:
<Program.cs Section>
connectionInfo = new WSManConnectionInfo(new Uri($"https://{MachineName}:5986/wsman"),
"http://schemas.microsoft.com/powershell/Microsoft.PowerShell", (PSCredential?)null);
connectionInfo.CertificateThumbprint = CertLoader.CertificateLoad(MachineName);
<CertificateLoader>
public string? CertificateLoad(string? machinename)
{
X509Store? store = null;
X509Certificate2? cert = null;
try
{
if(machinename == null)
{
<Console Write Message Error>
return null;
}
store = new X509Store(<CertificateLocation>, <CertificateLocationType>);
store.Open(OpenFlags.ReadOnly);
cert = store.Certificates.OfType<X509Certificate2>().FirstOrDefault(c =>
c.Subject.Contains($"{machinename}", StringComparison.OrdinalIgnoreCase));
store.Close();
return cert.Thumbprint;
}
catch (Exception ex)
{
<Console Write Message Error>
return null;
}
}
<In Separate Class>
<PowerShell Execution Function>
using (runspace = RunspaceFactory.CreateRunspace(connectioninfo))
{
runspace.Open();
using (pipeline = PowerShell.Create())
{
However, It keeps on failing when it gets to the using (runspace = RunspaceFactory.CreateRunspace(connectioninfo)) with the following error message:
Exception Message: System.Management.Automation.PSInvalidOperationException: The WS-Management service cannot find the certificate that was requested.
at System.Management.Automation.Remoting.Client.WSManClientSessionTransportManager.Initialize(Uri connectionUri, WSManConnectionInfo connectionInfo)
at System.Management.Automation.Remoting.Client.WSManClientSessionTransportManager..ctor(Guid runspacePoolInstanceId, WSManConnectionInfo connectionInfo, PSRemotingCryptoHelper cryptoHelper, String sessionName)
at System.Management.Automation.Runspaces.WSManConnectionInfo.CreateClientSessionTransportManager(Guid instanceId, String sessionName, PSRemotingCryptoHelper cryptoHelper)
at System.Management.Automation.Remoting.ClientRemoteSessionDSHandlerImpl..ctor(ClientRemoteSession session, PSRemotingCryptoHelper cryptoHelper, RunspaceConnectionInfo connectionInfo, URIDirectionReported uriRedirectionHandler)
at System.Management.Automation.Remoting.ClientRemoteSessionImpl..ctor(RemoteRunspacePoolInternal rsPool, URIDirectionReported uriRedirectionHandler)
at System.Management.Automation.Internal.ClientRunspacePoolDataStructureHandler.CreateClientRemoteSession(RemoteRunspacePoolInternal rsPoolInternal)
at System.Management.Automation.Internal.ClientRunspacePoolDataStructureHandler..ctor(RemoteRunspacePoolInternal clientRunspacePool, TypeTable typeTable)
at System.Management.Automation.Runspaces.Internal.RemoteRunspacePoolInternal.CreateDSHandler(TypeTable typeTable)
at System.Management.Automation.Runspaces.Internal.RemoteRunspacePoolInternal..ctor(Int32 minRunspaces, Int32 maxRunspaces, TypeTable typeTable, PSHost host, PSPrimitiveDictionary applicationArguments, RunspaceConnectionInfo connectionInfo, String name)
at System.Management.Automation.Runspaces.RunspacePool..ctor(Int32 minRunspaces, Int32 maxRunspaces, TypeTable typeTable, PSHost host, PSPrimitiveDictionary applicationArguments, RunspaceConnectionInfo connectionInfo, String name)
at System.Management.Automation.RemoteRunspace..ctor(TypeTable typeTable, RunspaceConnectionInfo connectionInfo, PSHost host, PSPrimitiveDictionary applicationArguments, String name, Int32 id)
at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(RunspaceConnectionInfo connectionInfo, PSHost host, TypeTable typeTable, PSPrimitiveDictionary applicationArguments, String name)
at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(RunspaceConnectionInfo connectionInfo, PSHost host, TypeTable typeTable)
at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(PSHost host, RunspaceConnectionInfo connectionInfo)
at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(RunspaceConnectionInfo connectionInfo)
In addition, (I can't remember what I have done) Before I got the error above, it failed in the runspace.Open(); part with the following message:
System.Management.Automation.Remoting.PSRemotingTransportException: 'Connecting to remote server xxxxxxxxx failed with the following error message :
WS-Management cannot process the request.
The operation failed because of an HTTP error.
The HTTP error (12186) is: The client certificate credentials were not recognized. . For more information, see the about_Remote_Troubleshooting Help topic.'
So, Can anyone help me:
- Identify what I did wrong?
- Understand how to fix these error messages?
CertLoader.CertificateLoad(MachineName);in the client application. The identity of the calling machine doesn't change because the target PC does.