0

更新以解释我的根本问题:如果 Azure 在配置VM 时具有扩展,以加入域和运行脚本,我如何以域用户身份运行脚本?

该脚本需要以域用户身份运行才能访问文件共享以检索安装文件和其他脚本,这些脚本既不是 VM 模板映像的一部分,也不能(合理地)上传到 Azure Blob 存储并作为预配的一部分下载.

我把这个问题一分为二,因为第二部分(在这里表示)没有得到解决。

我正在工作的是一个 Powershell 脚本,它需要一个 JSON 文件来创建一个新的 VM;JSON 文件包含 VM 加入域和运行自定义脚本的说明。这两件事都发生了,但脚本以用户身份运行workgroup\system,因此无权访问网络驱动器。

  • 我怎样才能最好地为这样的脚本提供特定用户的凭据?

我试图让脚本使用不同用户的凭据生成一个新的 Powershell 会话,但我很难弄清楚语法——我什至无法让它在我的开发工作站上工作。自然,安全性是一个问题,但如果我可以使用加密的存储凭据使其工作,这可能是可以接受的。

...但不要限制你的答案——也许有一种完全不同的方法可以解决这个问题并达到相同的效果?

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("")
}
4

1 回答 1

0

这个问题也有几个部分!

首先在那里获取凭据,在某些时候您需要将凭据传递给机器,即使它是获取凭据的凭据。

我个人的解决方案是创建一个证书来加密 PSCredential 对象,将该对象存储在 HTTP 服务器上,然后在脚本中传递证书和 pfx 密码。当然,如果您正在预构建服务器,您可以预安装此证书。(对此代码有一个代码审查问题

或者,您可以使用 Azure Key Vault 之类的东西来存储 pfx 密码。

对于 runas 部分。有几个选项

自 v1 以来,我还没有以其他用户身份启动 Powershell!所以我希望其他人谈论那个。

您可以运行以其他用户身份登录的计划任务,这应该可以。

如果您在不同的上下文中运行,您可以设置自动登录属性,重新启动机器使其脚本运行,然后删除自动登录条目并再次重新启动。这带来了额外的好处,您可以拥有一个特定的受到严格限制的域帐户,该帐户只能访问您需要的共享,一旦构建,它的管理员/登录权限就会从每台机器上剥离。这样,您还可以将所有构建脚本保留在 Active Directory 中,并让该用户自动将它们拉下来并运行。

于 2016-03-17T16:49:13.273 回答