• Welf Alberts started the topic Smart card runas authentication in IT Administration Forum 1 month, 3 weeks ago


    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{
    $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:CurrentUserMy’)
    $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?

© 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