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

      Hi.

      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{
      
      <#
      
      .SYNOPSIS
      
      Get certificate credentials from the user’s certificate store.
      
       
      
      .DESCRIPTION
      
      Returns a PSCredential object of the user’s selected certificate.
      
       
      
      .EXAMPLE
      
      Get-SmartCardCred
      
      UserName Password
      
      ——– ——–
      
      @@BVkEYkWiqJgd2d9xz3-5BiHs1cAN System.Security.SecureString
      
       
      
      .EXAMPLE
      
      $Cred = Get-SmartCardCred
      
       
      
      .OUTPUTS
      
      [System.Management.Automation.PSCredential]
      
       
      
      .NOTES
      
      Author: Joshua Chase
      
      Last Modified: 01 August 2018
      
      C# code used from https://github.com/bongiovimatthew-microsoft/pscredentialWithCert
      
      #>
      
      [cmdletbinding()]
      
      param()
      
       
      
      $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,
      
      UsernameTargetCredential
      
      }
      
       
      
      [StructLayout(LayoutKind.Sequential)]
      
      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(
      
      CRED_MARSHAL_TYPE CredType,
      
      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);
      
      userMyStore.Open(OpenFlags.ReadOnly);
      
      X509Certificate2Collection certsReturned = userMyStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
      
      userMyStore.Close();
      
       
      
      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);
      
      }
      
       
      
      Marshal.FreeHGlobal(pCertInfo);
      
      if (marshaledCredential != IntPtr.Zero)
      
      {
      
      NativeMethods.CredFree(marshaledCredential);
      
      }
      
       
      
      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))
      
      }
      
      $cred=Get-SmartCardCred
      
      $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
      
      $Process.Start()
      
      $Cred = $null

      How do code tags work here?

      Attachments:
      You must be logged in to view attached files.
      avatar
    • #1565237
      Welf Alberts
      Participant
      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

CONTACT US

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

Sending

Log in with your credentials

or    

Forgot your details?

Create Account