Add Alt Credentials To -verb RunAS

This topic contains 12 replies, has 2 voices, and was last updated by Profile photo of Dave Wyatt Dave Wyatt 2 years, 2 months ago.

  • Author
    Posts
  • #18743
    Profile photo of H Man
    H Man
    Participant

    I am using a bacth file to kick off a powershell script that is self elevating, I would like to add specific creds to it. i am saving the creds to an xml file. Heres what i have so far

    [
    
    powershell to create xml file
    
    $MyCredentials=GET-CREDENTIAL –Credential “company\jdoe” | EXPORT-CLIXML C:\mycreds.xml
    $MyCredentials=IMPORT-CLIXML  C:\mycreds.xml
    
    now for the bacth file to kick off a powershell script
    
    @ECHO OFF
    SET ThisScriptsDirectory=%~dp0
    SET PowerShellScriptPath=%ThisScriptsDirectory%Auto-Restore.ps1
    PowerShell  -NoProfile -ExecutionPolicy Bypass -Command "";
    
    
    

    can i incorporate $MyCredentials with -verb runas?

  • #18756
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    Well, you won't be able to load that XML file from batch, so you'd need to include that part of the code in the PowerShell script in some way. Perhaps by adding a -CredentialPath parameter to the script, something along these lines:

    [CmdletBinding()]
    param (
        [string] $CredentialPath
    )
    
    $me = [System.Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = [System.Security.Principal.WindowsPrincipal]$me
    
    if (-not $principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator))
    {
        $credSplat = @{}
    
        if ($CredentialPath)
        {
            $creds = Import-Clixml -Path $CredentialPath -ErrorAction Stop
            if ($creds -isnot [pscredential])
            {
                throw "File '$CredentialPath' was imported successfully, but does not contain a PSCredential object."
            }
    
            $credSplat = @{ Credential = $creds }
        }
    
        $argList = @(
            '-File'
            $MyInvocation.MyCommand.Path
    
            # Add any other parameters that were passed to the script
        )
        
        Start-Process -FilePath powershell.exe -Verb RunAs -WorkingDirectory $pwd -ArgumentList $argList @credSplat
        exit
    }
    
    # The rest of your script here; if it reaches this point, it's running as Administrator
    
  • #18757
    Profile photo of H Man
    H Man
    Participant

    Hi Dave thx for the response . im getting this error

    [pre ]

    Import-Clixml : Key not valid for use in specified state.
    At E:\EFI\Hpack\Auto-Restore\Auto-Restore.ps1:15 char:18
    + $creds = Import-Clixml -Path $CredentialPath -ErrorAction Stop
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Import-Clixml], CryptographicException
    + FullyQualifiedErrorId : System.Security.Cryptography.CryptographicException,Microsoft.PowerShell.Commands.ImportClixmlCommand
    File '\\fllfile01\PublishedApps\USMT\mycreds.xml' was imported successfully, but does not contain a PSCredential object.
    At E:\EFI\Hpack\Auto-Restore\Auto-Restore.ps1:18 char:13
    + throw "File '$CredentialPath' was imported successfully, but does no ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : OperationStopped: (File '\\fllfile...dential object.:String) [], RuntimeException
    + FullyQualifiedErrorId : File '\\fllfile01\PublishedApps\USMT\mycreds.xml' was imported successfully, but does not contain a PS
    Credential object.

    here is how i am creating the xml file

    $MyCredentials=GET-CREDENTIAL –Credential “company\jdoe” | EXPORT-CLIXML C:\mycreds.xml
    $MyCredentials=IMPORT-CLIXML C:\mycreds.xml

    Is there a better way to create the credential?

    thank you

  • #18758
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    That error is what I would expect to see if you encrypted the credentials as a different user from the one who's actually running the script. Export-Clixml encrypts the creds using the Data Protection API, with encryption keys that are unique to each user account (and frequently unique to each computer that the user logs onto, as well.)

    Before we go too much farther here, I'd need to understand what you're trying to do. Is your intention to allow non-admin users to launch an admin script, without exposing the admin credentials to those users? If so, there's no way you can do this locally. The script has to be able to decrypt the credentials in order to use them, and if the script can do it, so can the users themselves. In that situation, what you want to do is set up a custom PowerShell Remoting endpoint to perform the admin tasks. Jeffrey Snover's JEA (Just Enough Admin) module is designed for exactly this purpose.

    On the other hand, if you don't mind whether the users who run the script are able to obtain the credentials – if they're trusted to know the password, and this is just more of a convenience measure – then you need to choose a method of encryption which can be shared among other user accounts or to other computers. For that, I wrote the [url="http://gallery.technet.microsoft.com/Share-encrypted-data-2f91fd3f"]ProtectedData[/url] module. The latest PowerShell 5.0 preview has similar commands with Protect-CmsMessage and Unprotect-CmsMessage ; they and the ProtectedData module both leverage digital certificates to enable the data to be securely shared among other users.

  • #18760
    Profile photo of H Man
    H Man
    Participant

    Hi Dave

    My intention is to allow non-admin users to launch an admin script, without exposing the admin credentials to those users. they will be running the script locally

  • #18761
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    OK, then you should look into the JEA module, or something similar. There is no way to leverage those admin credentials in a 100% local script while simultaneously preventing the users from being able to read the credentials themselves. Regardless of how you do it, the idea is to set up a network service which runs the admin commands on behalf of a user, without ever needing to have those credentials sent or stored on the client's computer.

  • #18762
    Profile photo of H Man
    H Man
    Participant

    ok can u give me an example where I dont mind if they can see the creds, i can create a separate account just for this

    thank you

  • #18767
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    The basic premise for the ProtectedData module and the CmsMessage cmdlets is that you have digital certificates already deployed ahead of time, and that anyone who has the correct certificate with private key is allowed to decrypt the data. In the following example, I'm just going to make up a certificate thumbprint that you would associate with this script / credential, and send out to the authorized users ahead of time. Each user would also need to have the ProtectedData module available to their PowerShell sessions:

    To set up the encrypted file on any source machine:

    Import-Module ProtectedData -ErrorAction Stop
    $thumbprint = '85C86E97A4377DC7C258DC4436D7B757CC7F9944'
    
    $creds = Get-Credential
    $creds | Protect-Data -CertificateThumbprint $thumbprint | Export-Clixml -Path .\EncryptedCredentials.xml
    

    To use the file later, by a user who has the proper certificate with its private key available:

    Import-Module ProtectedData -ErrorAction Stop
    $thumbprint = '85C86E97A4377DC7C258DC4436D7B757CC7F9944'
    
    $creds = Import-Clixml Path .\EncryptedCredentials.xml | Unprotect-Data -CertificateThumbprint $thumbprint
    

    Using the new *-CmsMessage cmdlets in PowerShell 5.0 is very similar. The command names and parameters are different, but the end result is the same. You deploy a digital certificate, use the public key to encrypt the data, and anyone with the private key can decrypt it.

  • #18768
    Profile photo of H Man
    H Man
    Participant

    Thank you Dave I am going to give it a try

  • #18770
    Profile photo of H Man
    H Man
    Participant

    Im getting this error

    
    $thumbprint = '85C86E97A4377DC7C258DC4436D7B757CC7F9944'
     
    $creds = Get-Credential $cred
    $creds | Protect-Data -CertificateThumbprint $thumbprint | Export-Clixml -Path .\EncryptedCredentials.xml
    Protect-Data : Certificate '85C86E97A4377DC7C258DC4436D7B757CC7F9944' was not found.
    At line:5 char:10
    + $creds | Protect-Data -CertificateThumbprint $thumbprint | Export-Clixml -Path . ...
    +          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : OperationStopped: (Certificate '85... was not found.:String) [Write-Error], RuntimeException
        + FullyQualifiedErrorId : Certificate '85C86E97A4377DC7C258DC4436D7B757CC7F9944' was not found.,Protect-Data
     
    None of the specified certificates could be used for encryption, and no passwords were specified. Data protection cannot be performed.
    At C:\Users\halexander\Documents\WindowsPowerShell\Modules\ProtectedData\Commands.ps1:167 char:13
    +             throw ('None of the specified certificates could be used for encrypt ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : OperationStopped: (None of the spe...t be performed.:String) [], RuntimeException
        + FullyQualifiedErrorId : None of the specified certificates could be used for encryption, and no passwords were specified. Data prote 
       ction cannot be performed.
     
    
    
    
  • #18771
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    That certificate thumbprint was just a bogus value I made up for the example. In your script, you would need to use the actual thumbprint of a digital certificate that you are going to use to encrypt these credentials. This can be a self-signed certificate, if you like, but then you need to add the -SkipCertificateVerification switch to your calls to Protect-Data and Unprotect-Data.

  • #18772
    Profile photo of H Man
    H Man
    Participant

    Ok I never made a self-signed certificate before is there a powerhsell cmdlet for that?

  • #18775
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    There is, yes. If I remember correctly, it was added in PowerShell version 4.0:

    New-SelfSignedCertificate -CertStoreLocation Cert:\CurrentUser\My -DnsName ProtectedCreds.mycompany.org
    

    As you can see by the required -DnsName parameter, this cmdlet was probably designed with machine certificates in mind, but it does produce a cert that works fine with the ProtectedData module. You would need to export the certificate to a PFX file in order to distribute it to other users. You can technically do this with scripts if you like, but I tend to use the GUI for that task. I just run certmgr.msc, browse to Personal\Certificates , right-click on the cert and choose All Tasks -> Export. You'll want to select the option for "yes, export private key", and you'll be required to give the PFX file a password.

You must be logged in to reply to this topic.