Viewing 1 reply thread
  • Author
    • #1565203
      Welf Alberts
      Member Points: 905
      Rank: 2


      Imagine you are using a SmartCard to logon to windows, a SmartCard with different Credentials on it.

      When you want to run something as different user, you press shift while right-clicking the executable to select “run as different user”, enter you SmartCard PIN and that’s it.

      I would like to script that process to have a 1-click experience. The script should ask for the SmartCard-PIN and start my executable. I already have a script and it works as long as I use a Yubikey-like device, that is, a SmardCardreader that utilizes the laptop keyboard. However, I prefer to use an external SmartCard reader that has its own Pin-Pad, but with that thing, the script does not work.

      Expected behavior: the Pin Pad activates and asks for the PIN. Observed behavior: the PIN needs to be entered using the keyboard.

      Question: who of you PowerShell heroes understands what needs to be changed here to make this work:

      Function Get-SmartCardCred{
      Get certificate credentials from the user’s certificate store.
      Returns a PSCredential object of the user’s selected certificate.
      UserName Password
      ——– ——–
      @@BVkEYkWiqJgd2d9xz3-5BiHs1cAN System.Security.SecureString
      $Cred = Get-SmartCardCred
      Author: Joshua Chase
      Last Modified: 01 August 2018
      C# code used from
      $SmartCardCode = @”
      // Copyright (c) Microsoft Corporation. All rights reserved.
      // Licensed under the MIT License.
      using System;
      using System.Management.Automation;
      using System.Runtime.InteropServices;
      using System.Security;
      using System.Security.Cryptography.X509Certificates;
      namespace SmartCardLogon{
      static class NativeMethods
      public enum CRED_MARSHAL_TYPE
      CertCredential = 1,
      internal struct CERT_CREDENTIAL_INFO
      public uint cbSize;
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
      public byte[] rgbHashOfCert;
      [DllImport(“advapi32.dll”, CharSet = CharSet.Unicode, SetLastError = true)]
      public static extern bool CredMarshalCredential(
      IntPtr Credential,
      out IntPtr MarshaledCredential
      [DllImport(“advapi32.dll”, SetLastError = true)]
      public static extern bool CredFree([In] IntPtr buffer);
      public class Certificate
      public static PSCredential MarshalFlow(string thumbprint, SecureString pin)
      // Set up the data struct
      NativeMethods.CERT_CREDENTIAL_INFO certInfo = new NativeMethods.CERT_CREDENTIAL_INFO();
      certInfo.cbSize = (uint)Marshal.SizeOf(typeof(NativeMethods.CERT_CREDENTIAL_INFO));
      // Locate the certificate in the certificate store
      X509Certificate2 certCredential = new X509Certificate2();
      X509Store userMyStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
      X509Certificate2Collection certsReturned = userMyStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
      if (certsReturned.Count == 0)
      throw new Exception(“Unable to find the specified certificate.”);
      // Marshal the certificate
      certCredential = certsReturned[0];
      certInfo.rgbHashOfCert = certCredential.GetCertHash();
      int size = Marshal.SizeOf(certInfo);
      IntPtr pCertInfo = Marshal.AllocHGlobal(size);
      Marshal.StructureToPtr(certInfo, pCertInfo, false);
      IntPtr marshaledCredential = IntPtr.Zero;
      bool result = NativeMethods.CredMarshalCredential(NativeMethods.CRED_MARSHAL_TYPE.CertCredential, pCertInfo, out marshaledCredential);
      string certBlobForUsername = null;
      PSCredential psCreds = null;
      if (result)
      certBlobForUsername = Marshal.PtrToStringUni(marshaledCredential);
      psCreds = new PSCredential(certBlobForUsername, pin);
      if (marshaledCredential != IntPtr.Zero)
      return psCreds;
      Add-Type -TypeDefinition $SmartCardCode -Language CSharp
      Add-Type -AssemblyName System.Security
      $ValidCerts = [System.Security.Cryptography.X509Certificates.X509Certificate2[]](Get-ChildItem ‘Cert:\CurrentUser\My’)
      $Cert = [System.Security.Cryptography.X509Certificates.X509Certificate2UI]::SelectFromCollection($ValidCerts, ‘Choose a certificate’, ‘Choose a certificate’, 0)
      $Pin = Read-Host “Enter your PIN: ” -AsSecureString
      Write-Output ([SmartCardLogon.Certificate]::MarshalFlow($Cert.Thumbprint, $Pin))
      $StartInfo = New-Object System.Diagnostics.ProcessStartInfo
      $StartInfo.FileName = ‘cmd.exe’
      $StartInfo.UseShellExecute = $false
      $StartInfo.UserName = $Cred.Username
      $StartInfo.Password = $Cred.Password
      $StartInfo.WorkingDirectory = $env:windir
      $Process = New-Object System.Diagnostics.Process
      $Process.StartInfo = $StartInfo
      $Cred = $null

      How do code tags work here?

      You must be logged in to view attached files.
    • #1565237
      Welf Alberts
      Member Points: 905
      Rank: 2

      Self-solved, and the solution is rather cute: the above script brings up a dialogue window in which you may enter the PIN using your keyboard. If you leave it blank and JUST PRESS ENTER, the PIN-Pad activates on its own. Found accidentally 🙂

Viewing 1 reply thread
  • You must be logged in to reply to this topic.
© 4sysops 2006 - 2022


Please ask IT administration questions in the forums. Any other messages are welcome.


Log in with your credentials


Forgot your details?

Create Account