Ask for creds only if some specified

241 views Asked by At

I'm trying to create a module with a bunch of functions, but I'm stuck with a problem: sometimes I need to run functions with a different from current credentials. But the thing is: I don't want to ask for credentials if I didn't specify a username. Like this:

function MyFunction ($ComputerName='localhost', $UserName) {
    if ($UserName) {
        Get-WmiObject -Class Win32_OperatingSystem -ComputerName $ComputerName -Credential $UserName
    } else {
        Get-WmiObject -Class Win32_OperatingSystem -ComputerName $ComputerName
    }
}

Can I somehow get rid of the if statement? Can I just let the function use current credentials unless I specify -UserName?

If I leave it like this:

Get-WmiObject -Class Win32_OperatingSystem -ComputerName $ComputerName -Credential $UserName

and call a function without specifying -UserName, it asks for credentialls every time. Yes, it uses current if I close the 'get-cred' box, but it's not what I want.

3

There are 3 answers

6
Vesper On BEST ANSWER

You can populate a PSCredential object with current credentials using the default credential acquired like in here:

if ($UserName) {
   $cred = get-credential $username # this prompts for credentials
} else {
   $cred=[PSCredential][System.Net.CredentialCache]::DefaultCredentials
}

Then just use -credential $cred whenever you need without building a wall of if's.

EDIT: Apparently, as the current user's PSCredential object has its password as SecureString encrypted by the very same user's private key, if one would be able to get a PSCredential out of default credentials object, he'll be able to decrypt the password into plaintext, so this hole existed but was eventually closed. (Maybe let this answer hang here so that people won't get the asme error as I did) This question has the canonical answer on what arised in here.

Another way to do this might be using a variation of splatting, explained in detail by Ansgar Wiechers and here to construct only credential block in a single if statement and then use that block wherever you need, instead of writing direct -credential parameter.

$creds=@{}
if ($UserName) {
   $cred = get-credential $username # this prompts for credentials
   $creds['Credential']=$cred
}

And then add @creds wherever you require alternate credentials:

Get-WmiObject -Class Win32_OperatingSystem -ComputerName $ComputerName @creds

This way you'll be asked for user's password once if $UserName is supplied, and then the $creds will either be empty or contain valid credentials of $UserName, so all subsequent if's can be replaced by explicit adding of @creds.

3
Richard On

Your never really going to lose the IF, but you could create a string on the fly and then invoke it as and expression:

If $UserName is $null the credential parameter will not be added to the expression.

function MyFunction ([String]$ComputerName='localhost', [String]$UserName) {

    Invoke-Expression ("Get-WmiObject -Class Win32_OperatingSystem -ComputerName $ComputerName $(IF($UserName){'-Credential $UserName'})")

}
0
Ansgar Wiechers On

You could use splatting for dynamically building a parameter list, but you'd still need an if statement to decide whether or not to add the -Credential parameter:

function MyFunction ($ComputerName='localhost', $UserName) {
    $params = @{
      Class        = 'Win32_OperatingSystem'
      ComputerName = $ComputerName
    }
    if ($UserName) { $params['Credential'] = $UserName }

    Get-WmiObject @params
}