Updated to explain my root problem: If Azure has extensions for VM's, as they are being provisioned, to join a domain, and to run scripts, how can I run a script as a domain user?
The script needs to be run as a domain user in order to access a file share to retrieve installation files and other scripts that are neither part of the VM template image nor can (reasonably) be uploaded to Azure blob storage and downloaded as part of provisioning.
I split this question in two because the 2nd half (represented here) didn't get solved.
What I have working is a Powershell script that takes a JSON file to create a new VM; the JSON file contains instructions for the VM to join a domain and run a custom script. Both things do happen, but the script runs as the user workgroup\system
and therefore doesn't have access to a network drive.
- How can I best provide a specific user's credentials for such a script?
I'm trying to have the script spawn a new Powershell session with the credentials of a different user, but I'm having a hard time figuring out the syntax -- I can't even get it to work on my development workstation. Naturally, security is a concern but if I could get this to work using encrypted stored credentials, this might be acceptable.
... but don't limit your answers -- maybe there's an entirely different way to go about this and achieve the same effect?
Param(
[switch]$sudo, # Indicates we've already tried to elevate to admin
[switch]$su # Indicates we've already tried to switch to domain user
)
try {
# Pseudo-constants
$DevOrProd=(Get-Item $MyInvocation.MyCommand.Definition).Directory.Parent.Name
$PsScriptPath = Split-Path -parent $MyInvocation.MyCommand.Definition
$pathOnPDrive = "\\dkfile01\P\SoftwareTestData\Azure\automation\$DevOrProd\run-once"
$fileScriptLocal = $MyInvocation.MyCommand.Source
$fileScriptRemote = "$pathOnPDrive\run-once-from-netdrive.ps1"
# $filePw = "$pathOnPDrive\cred.txt"
$fileLog="$PsScriptPath\switch-user.log"
$Myuser="mohican"
$Myuserpass="alhambra"
$Mydomainuser="mydomain\$Myuser"
$Mydomain="mydomain.com"
# Check variables
write-output("SUDO=[$SUDO]")
write-output("SU=[$SU]")
# Functions
function Test-Admin {
$currentUser = New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent())
return ($currentUser.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator))
}
# Main
write-output("Run-once script starting ...")
# Check admin privilege
write-output("Checking admin privilege ...")
if (Test-Admin) {
write-output("- Is admin.")
} else {
write-output("- Not an admin.")
if ($sudo) {
write-output(" - Already tried elevating, didn't work.")
write-output("Run-once script on local VM finished.")
write-output("")
exit(0) # Don't return failure exit code because Azure will report it as if the deployment broke...
} else {
write-output(" - Attempting to elevate ...")
$arguments = "-noprofile -file $fileScriptLocal"
$arguments = $arguments +" -sudo"
try {
Start-Process powershell.exe -Verb RunAs -ArgumentList $arguments
write-output(" - New process started.")
} catch {
write-output(" - New process failed to start.")
}
write-output("Run-once script on local VM finished.")
write-output("")
exit(0) # The action will continue in the spawned process
}
}
write-output("Checked admin privilege ... [OK]")
# Check current user
write-output("Checking user account ...")
$hostname = $([Environment]::MachineName).tolower()
$domainname = $([Environment]::UserDomainName).tolower()
$thisuser = $([Environment]::UserName).tolower()
write-output("- Current user is ""$domainname\$thisuser"" on ""$hostname"".")
write-output("- Want to be user ""$Myuser"".")
if ($Myuser -eq $thisuser) {
write-output(" - Correct user.")
} else {
write-output(" - Incorrect user.")
if ($su) {
write-output(" - Already tried switching user, didn't work.")
write-output("Run-once script on local VM finished.")
write-output("")
exit(0) # Don't return failure exit code because Azure will report it as if the deployment broke...
} else {
write-output(" - Attempting to switch to user ""$Mydomainuser"" with passwond ""$Myuserpass"" ...")
# FIXME -- This does not work... :-(
$MyuserpassSecure = ConvertTo-SecureString $Myuserpass -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential $Mydomainuser, $MyuserpassSecure
$arguments = "-noprofile -file $fileScriptLocal"
$arguments = $arguments +" -sudo -su -Credential $credential -computername $hostname"
try {
Start-Process powershell.exe -Verb RunAs -ArgumentList $arguments
write-output(" - New process started.")
} catch {
write-output(" - New process failed to start.")
}
write-output("Run-once script on local VM finished.")
write-output("")
exit(0) # The action will continue in the spawned process
}
}
write-output("Checked user account ... [OK]")
# Run script from P: drive (finally!)
write-output("Attempting to run script from P: drive ...")
write-output("- Script file: ""$fileScriptRemote""")
if (test-path $fileScriptRemote) {
write-output("Running script from P: drive ...")
$arguments = "-noprofile -file $fileScriptRemote"
try {
Start-Process powershell.exe -Verb RunAs -ArgumentList $arguments
write-output(" - New process started.")
} catch {
write-output(" - New process failed to start.")
}
write-output("Run-once script on local VM finished.")
write-output("")
exit(0) # The action will continue in the spawned process
} else {
write-output("- Could not locate/access script file!")
write-output("Ran script from P: drive ... [ERROR]")
}
write-output("Run-once script on local VM finished.")
write-output("")
} catch {
write-warning("Unhandled error in line $($_.InvocationInfo.ScriptLineNumber): $($error[0])")
write-output("ABEND")
write-output("")
}