Add Alt Credentials To -verb RunAS

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?

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

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: (:slight_smile: [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

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 ProtectedData 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.

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

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.

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

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.

Thank you Dave I am going to give it a try

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.
 


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.

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

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.