PowerShell: Obtain Domain Admin Credential and Save It as an XML for Subsequent Execution

Working Version:
# Initialize with defaults
$credFileExists=$False

# This function is a workaround to the issue of variable $PSCommandPath being inaccessible outside of a function
function setCredentialFilePaths($userID){
# Export some variables
$GLOBAL:scriptPath=Split-Path -Path $PSCommandPath
$GLOBAL:credentialsFolder="$scriptPath\Credentials"
$GLOBAL:credentialFile="$credentialsFolder\"+"$userID`.clixml"
}

function checkFile($file){
$fileExists=[System.IO.File]::Exists($file)
if($fileExists){return $True}else{return $False;}
}

function checkCredentialFile($userID){
# Export some variables
$GLOBAL:path=Split-Path -Path $PSCommandPath
$GLOBAL:folder="$path\Credentials"
$GLOBAL:credentialFile="$folder\"+"$userID`.clixml"
return (checkFile $credentialFile);
}

# Check whether a given username matches the list of Domain Admins
function validateDomainAdminMembership{
param (
[string]$username
)
$matchedAdmin=$username -in $domainAdmins
if($matchedAdmin){
Write-Host "$username is a Domain Admin";
return $True;
}else{
Write-Host "$username not a Domain Admin.";
return $False;
}
}

function testCredential{
param (
[string]$username,
[string]$password
)
$plaintextPassword = (New-Object System.Management.Automation.PSCredential 'N/A',$providedPassword).GetNetworkCredential().Password
$domainBindTest = (New-Object System.DirectoryServices.DirectoryEntry($domainObject,$username,$plaintextPassword)).DistinguishedName
if ($domainBindTest){return $True;} else{Return $False;}
}

function obtainDomainAdminCred{
$domainAdmins=(Get-ADGroupMember -Identity "Domain Admins" -Recursive | %{Get-ADUser -Identity $_.distinguishedName} | Where-Object {$_.Enabled -eq $True}).SamAccountName
$global:cred=$False
do {
$providedID=Read-Host -Prompt 'Input a domain admin username'
# Check if credential file exists
If (!(checkCredentialFile $providedID)){
If (validateDomainAdminMembership $providedID){
$providedPassword = Read-Host -assecurestring "Please enter the password"
#$providedPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))
#$providedCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $providedID,$providedPassword
$goodCredential=testCredential -username $providedID -password $providedPassword
if($goodCredential){
"Domain Admin Credential validated!";
$GLOBAL:user=$providedID
$GLOBAL:cred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $providedID,$providedPassword;
saveCredentialToXml $providedID;
#return $True;
}
else{
"Password doesn't match.";
$global:cred=$False;
#return $False;
}
}else{
"Try again..."
#return $False;
}
}else{"This credential has already been saved previously.";break;}
} until ($cred)
}

function saveCredentialToXml($userID){
setCredentialFilePaths $userID
"Checking $credentialFile...";
If (!(checkFile $credentialFile)){
# Create folder if it doesn't exist
if(!(Test-Path -Path $credentialsFolder)){New-Item -path $credentialsFolder -type directory;}
"This credential has not been saved previously.`nSaving now...";
$cred | Export-Clixml $credentialFile;
}
}

function getCredentialfromXML($file){
checkCredentialFile $user
if (checkFile $file){
"Credential found...`n";
# Export stored XML credential
$GLOBAL:xmlCred=Import-clixml $file
}else{
"Credential NOT found...`n";
$GLOBAL:xmlCred=$null
pause;
break;
}
}

function runasDomainAdmin{

If (checkCredentialFile $env:USERNAME){
# Change the title and background color to signify an elevated session
$Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated as Domain Admin)"
$Host.UI.RawUI.BackgroundColor = "Black"
clear-host
"This script has been relaunched in the context as a member of Domain Admins with the ID: $(whoami)";
}else{
obtainDomainAdminCred;
getCredentialfromXML $credentialFile;
$runasUser="$env:USERDOMAIN\"+$xmlCred.GetNetworkCredential().username
$runasPassword=ConvertTo-securestring $xmlCred.GetNetworkCredential().password -AsPlainText -Force
$runasCred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $runasUser,$runasPassword
Start-Process powershell.exe -Credential $runasCred -NoNewWindow -ArgumentList "Start-Process powershell.exe -Verb runAs $PSCommandPath"

# Exit from the current process
exit
}

}

runasDomainAdmin;
"Now, we can execute other functions..."
pause;
Another Working Version
#### Run As Exchange Admin (Enterprise Admins) ####

# Initialize with defaults
$credFileExists=$False
$groupName="Enterprise Admins"
# $cred=[System.Net.CredentialCache]::DefaultNetworkCredentials; # this credential parsing doesn't work

# This function is a workaround to the issue of variable $PSCommandPath being inaccessible outside of a function
function setCredentialFilePaths($userID){
# Export some variables
$GLOBAL:scriptPath=Split-Path -Path $PSCommandPath
$GLOBAL:credentialsFolder="$scriptPath\Credentials"
$GLOBAL:credentialFile="$credentialsFolder\"+"$userID`.clixml"
}

function checkFile($file){
$fileExists=[System.IO.File]::Exists($file)
if($fileExists){return $True}else{return $False;}
}

function checkCredentialFile($userID){
# Export some variables
$GLOBAL:path=Split-Path -Path $PSCommandPath
$GLOBAL:folder="$path\Credentials"
$GLOBAL:credentialFile="$folder\"+"$userID`.clixml"
return (checkFile $credentialFile);
}

# Check whether a given username matches the list of Domain Admins
function validateDomainAdminMembership{
param (
[string]$username
)
$matchedAdmin=$username -in $exchangeAdmins
if($matchedAdmin){
Write-Host "$username is an Exchange Admin";
return $True;
}else{
Write-Host "$username not an Exchange Admin.";
return $False;
}
}

function testCredential{
param (
[string]$username,
[string]$password
)
$plaintextPassword = (New-Object System.Management.Automation.PSCredential 'N/A',$providedPassword).GetNetworkCredential().Password
$domainBindTest = (New-Object System.DirectoryServices.DirectoryEntry($domainObject,$username,$plaintextPassword)).DistinguishedName
if ($domainBindTest){return $True;} else{Return $False;}
}

function obtainExchangeAdminCred{
$exchangeAdmins=(Get-ADGroupMember -Identity $groupName -Recursive | %{Get-ADUser -Identity $_.distinguishedName} | Where-Object {$_.Enabled -eq $True}).SamAccountName
$global:cred=$False
do {
$providedID=Read-Host -Prompt 'Input a domain admin username'
# Check if credential file exists
If (!(checkCredentialFile $providedID)){
If (validateDomainAdminMembership $providedID){
$providedPassword = Read-Host -assecurestring "Please enter the password"
#$providedPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))
#$providedCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $providedID,$providedPassword
$goodCredential=testCredential -username $providedID -password $providedPassword
if($goodCredential){
"Domain Admin Credential validated!";
$GLOBAL:user=$providedID
$GLOBAL:cred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $providedID,$providedPassword;
saveCredentialToXml $providedID;
#return $True;
}
else{
"Password doesn't match.";
$global:cred=$False;
#return $False;
}
}else{
"Try again..."
#return $False;
}
}else{"This credential has already been saved previously.";break;}
} until ($cred)
}

function saveCredentialToXml($userID){
setCredentialFilePaths $userID
"Checking $credentialFile...";
If (!(checkFile $credentialFile)){
# Create folder if it doesn't exist
if(!(Test-Path -Path $credentialsFolder)){New-Item -path $credentialsFolder -type directory;}
"This credential has not been saved previously.`nSaving now...";
$cred | Export-Clixml $credentialFile;
}
}

function getCredentialfromXML($file){
checkCredentialFile $user
if (checkFile $file){
"Credential found...`n";
# Export stored XML credential
$GLOBAL:xmlCred=Import-clixml $file
}else{
"Credential NOT found...`n";
$GLOBAL:xmlCred=$null
pause;
break;
}
}

function runasExchangeAdmin{

If (checkCredentialFile $env:USERNAME){
# Change the title and background color to signify an elevated session
$Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated as Domain Admin)"
$Host.UI.RawUI.BackgroundColor = "Black"
clear-host
"This script has been relaunched in the context as a member of Domain Admins with the ID: $(whoami)";
}else{
obtainExchangeAdminCred;
getCredentialfromXML $credentialFile;
$runasUser="$env:USERDOMAIN\"+$xmlCred.GetNetworkCredential().username
$runasPassword=ConvertTo-securestring $xmlCred.GetNetworkCredential().password -AsPlainText -Force
$runasCred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $runasUser,$runasPassword

# Export the global credential to be used in subsequent functions
$GLOBAL:globalCred=$runasCred

# Start-Process powershell.exe -Credential $runasCred -NoNewWindow -ArgumentList "Start-Process powershell.exe -Verb runAs $PSCommandPath"
# Exit from the current process
# exit
}

}

runasExchangeAdmin;
"Enterprise Admin Credential has been loaded. Now connecting to remote server..."
################################################################################################################

$exchangeServer="EXCH02"
function enterPsSessionRemote($server){
Enter-PSSession -ComputerName $exchangeServer -Credential $globalCred
}
enterPsSessionRemote $exchangeServer
Work-in-Progress Version
function saveCredAsXML{
# Save Credentials into XML file for future use
$domain=$env:USERDOMAIN
$goodCredential=$False
$credentialsFolder="$scriptPath\Credentials"
$credentialsFolderExists=[System.IO.Directory]::Exists($credentialsFolder)
If(!($credentialsFolderExists)){mkdir $credentialsFolder;}

# Obtain username to check whether such credential has been saved prior
$user=(Read-Host -Prompt 'Input an Administrator User ID');
$credentialFile="$credentialsFolder\"+"$user`.clixml"
$credentialFileExists=[System.IO.File]::Exists($credentialFile)
if(!($credentialFileExists)){
"This credential has not been saved previously.";
$GLOBAL:repromptUsername=$False;
$goodCredential=$False;
}

function getCredential{
If ($repromptUsername){
$GLOBAL:user=(Read-Host -Prompt 'Input an Administrator User ID');
}
$GLOBAL:credentialFile="$credentialsFolder\"+"$user`.clixml"
$userID = "$domain\"+"$user"
$securedValue = (Read-Host -AsSecureString -Prompt "Input the password for account $userID")
$password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($securedValue))
$pass = ConvertTo-SecureString -AsPlainText $Password -Force
$GLOBAL:cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $userID,$pass
$GLOBAL:credentialFile="$credentialsFolder\"+"$user`.clixml"
$GLOBAL:credentialFileExists=[System.IO.File]::Exists($credentialFile)
}

function testCredential{
#$domainAdmins=(Get-ADGroupMember -Identity "Domain Admins" -Recursive | %{Get-ADUser -Identity $_.distinguishedName} | Where-Object {$_.Enabled -eq $True}).SamAccountName
$connection=connect-viserver $vSpheres[0] -Protocol https -Credential $cred -ErrorAction SilentlyContinue
if($connection -eq $null) {
write-host "No connected servers or credential doesnt work."
$GLOBAL:goodCredential=$false;
$GLOBAL:repromptUsername=$True;
}
else{
#"Credential works. Thus, it has been saved at $credentialFile for future use."
Disconnect-VIServer -Server $global:DefaultVIServers -Force -Confirm:$false
cls;
$cred | Export-Clixml $credentialFile;
#$GLOBAL:goodCredential=$True;
break;
}
}

If(!($credentialFileExists)){
# Test credential and reprompt if it doesn't work
while ($goodCredential -eq $False){
getCredential;
testCredential;
}
}
}

######################################################

# Check whether a given username matches the list of Domain Admins
function validateDomainAdminMembership{
param (
[string]$username
)
$matchedAdmin=$username -in $domainAdmins
if($matchedAdmin){
Write-Host "$username is a Domain Admin";
return $True;
}else{
Write-Host "$username not a Domain Admin.";
return $False;
}
}

function testCredential{
param (
[string]$username,
[string]$password
)
$plaintextPassword = (New-Object System.Management.Automation.PSCredential 'N/A',$providedPassword).GetNetworkCredential().Password
$domainBindTest = (New-Object System.DirectoryServices.DirectoryEntry($domainObject,$username,$plaintextPassword)).DistinguishedName
if ($domainBindTest){return $True;} else{Return $False;}
}

function obtainDomainAdminCred{
$domainAdmins=(Get-ADGroupMember -Identity "Domain Admins" -Recursive | %{Get-ADUser -Identity $_.distinguishedName} | Where-Object {$_.Enabled -eq $True}).SamAccountName
$global:cred=$False
do {
$providedID=Read-Host -Prompt 'Input a domain admin username'
if (validateDomainAdminMembership $providedID){
$providedPassword = Read-Host -assecurestring "Please enter the password"
#$providedPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))
#$providedCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $providedID,$providedPassword
$goodCredential=testCredential -username $providedID -password $providedPassword
if($goodCredential){
"Domain Admin Credential validated!";
$GLOBAL:user=$providedID
$GLOBAL:cred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $providedID,$providedPassword;
#return $True;
}
else{
"Password doesn't match.";
$global:cred=$False;
#return $False;
}
}else{
"Try again..."
#return $False;
}
} until ($cred)
}

function validateCurrentAccountAsDomainAdmin{
if((whoami /groups) -match 'domain admins'){
# "This account is a Domain Admins member";
return $True;
}else{
# "This account is NOT a Domain Admins member";
return $False;
}
}

function checkFile($file){
$fileExists=[System.IO.File]::Exists($file)
if($fileExists){return $True}else{return $False;}
}

function saveCredentialToXml($username){
$scriptName=$PSCommandPath
$scriptPath=Split-Path -Path $scriptName
$GLOBAL:credentialsFolder="$scriptPath\Credentials"
$GLOBAL:credentialFile="$credentialsFolder\"+"$user`.clixml"

"Checking $credentialFile...";
If (!(checkFile $credentialFile)){
# Create folder if it doesn't exist
if(!(Test-Path -Path $credentialsFolder)){New-Item -path $credentialsFolder -type directory;}
"This credential has not been saved previously.`nSaving now...";
$cred | Export-Clixml $credentialFile;
}else{
"This credential file already exists.'nSkipping..."
}
}

<# Since Windows has intentionally unexposed the credentials of the currently logged on user for security purposes; hence, the current user credentials cannot be exported.
If(validateCurrentAccountAsDomainAdmin){
"Current Login User is a Member of Domain Admins";
$cred=[System.Net.CredentialCache]::DefaultNetworkCredentials;
saveCredentialToXml $user;
}else{
"Current Login User is NOT a Member of Domain Admins.";


}
#>

function getCredentialfromXML($file){
# Export stored XML credential
$GLOBAL:xmlCred=Import-clixml $file
}

obtainDomainAdminCred;
saveCredentialToXml $user;
getCredentialfromXML $credentialFile;
$xmlCred;
pause;

Leave a Reply

Your email address will not be published. Required fields are marked *