2016-01-17 71 views
0

我想使用Read-Host -AsSecureString來避免在我的腳本中輸入密碼。我想遍歷服務器列表並在密碼中包含每個服務器名稱 - 因此所有密碼都不相同。如果我使用變量將腳本中的密碼放入腳本,該腳本將按照我的意願工作,但如果我使用相同的變量作爲Read-Host的值,則腳本無法工作。 Read-Host -AsSecureString可以不包含變量嗎?可以讀取主機接受一個變量作爲輸入?

查看下面的代碼。當使用$passwordsecure變量(Read-Host值)密碼是字面上什麼即鍵入$computername,然而$password(其被註釋)產生預期的機器名作爲密碼的一部分:

<# 
Info: 
- Launch the script and respond to the on-screen prompts: 
    - Enter the local user account housed on the remote servers whose password 
    needs to be changed (e.g. administrator or testUser) 
    - Enter path to txt file containing server list (e.g. E:Temp\servers.txt) 
    - Enter new password 
    - The script will connect to each server and change the password of the local 
    user account defined 
#> 

# Changes PS prompt to directory in which the script is being run from whether using Powershell console or the ISE. 
function Get-ScriptDirectory { 
    $Invocation = (Get-Variable MyInvocation -Scope 1).Value 
    Split-Path $Invocation.MyCommand.Path 
} 

$ISEScriptPath = Split-Path -Parent $psISE.CurrentFile.Fullpath -EA SilentlyContinue 

if ($ISEScriptPath -eq $null) { 
    cd $(Get-ScriptDirectory -ea SilentlyContinue) 
} else { 
    cd $ISEScriptPath 
} 

############## Main Script ########### 

$fail = @() 
$pass = @() 
$passLog = @() 
$failLog = @() 
$date = "_$(get-date -uf %H%M_%d%h%Y)" 
$Results = Test-Path "$PWD\Results" 

if (-not $Results) { 
    md "$PWD\Results" 
} 

$user = Read-Host "Enter local account name whose password is to be changed on remote servers (e.g. testUser)" 

Write-Host "N.B. If the .txt file is located in '$PWD' just enter the filename (e.g. servers.txt)" 
"`n" 
$path = (Read-Host "Enter path to the .txt file containing servers for which the $(($user).toupper()) password will be changed (e.g. e:\temp\servers.txt)") 
$computerNames = Get-Content $path 
$passwordSecure = Read-Host -AsSecureString "Enter new password" 

$password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($passwordSecure)) 
#$password = "$($computername)!!" 

foreach ($computername in $computernames) { 
    $date2 = (Get-Date).ToString('dd-MM-yyyy hh:mm:ss tt') 
    $computername 
    $adminUser = [ADSI] "WinNT://$computerName/$user,User" 
    $adminUser.SetPassword($Password) 

    if ($?) { 
     "$computername was successfully updated" 
     $PassLog +="$computername updated successfully at $date2" 
     $Pass+="`n$computername updated successfully" 
     Start-Sleep -m 500 
    } else { 
     "$computername failed to update" 
     $failLog +="$computername failed to update at $date2" 
     $fail+="`n$computername failed to update" 
     Start-Sleep -m 500 
    } 
} 

"$(($fail).count) $(($user).toupper()) password failed to be reset on following servers and needs to be checked manually..`n"; 
Write-Host $fail -ForegroundColor "Red" 

"`n$(($Pass).count) servers had the $(($user).toupper()) account password updated successfully..`n" 
Write-Host $Pass -ForegroundColor "green" 
"`n" 

          "Processing servers provided in $PWD\$path...." | Out-File ("$PWD\Results\" + $("$user"+"_PasswordReset" + $date + ".log")) -Append 
                    "`n`n" | Out-File ("$PWD\Results\" + $("$user"+"_PasswordReset" + $date + ".log")) -Append 
     "Failed to Reset $(($fail).count) $(($user).toupper()) passwords:`n"| Out-File ("$PWD\Results\" + $("$user"+"_PasswordReset" + $date + ".log")) -Append 
                    "`n" | Out-File ("$PWD\Results\" + $("$user"+"_PasswordReset" + $date + ".log")) -Append 
                   $failLog | Out-File ("$PWD\Results\" + $("$user"+"_PasswordReset" + $date + ".log")) -Append 
                    "`n`n" | Out-File ("$PWD\Results\" + $("$user"+"_PasswordReset" + $date + ".log")) -Append 
"Successfully Updated $(($Pass).count) $(($user).toupper()) passwords:`n" | Out-File ("$PWD\Results\" + $("$user"+"_PasswordReset" + $date + ".log")) -Append 
                    "`n" | Out-File ("$PWD\Results\" + $("$user"+"_PasswordReset" + $date + ".log")) -Append 
                   $passLog | Out-File ("$PWD\Results\" + $("$user"+"_PasswordReset" + $date + ".log")) -Append 

Write-Host "A results file has been created: $PWD\Results\$("$user"+"_PasswordReset" + $date + ".log`n")" -ForegroundColor Yellow 

回答

2

如果您在Read-Host提示處輸入變量(例如$computername),您將得到一個文字字符串'$computername'。爲了能夠擴大字符串中變量,你需要這樣的事:

$value = Read-Host 
$ExecutionContext.InvokeCommand.ExpandString($value) 

然而,這隻會與普通字符串的工作,而不是與安全的弦。我不會首先推薦它,因爲它需要用戶知道哪些變量在腳本運行時可用。它也可能導致不希望的副作用,因爲如果您輸入$computer_some%orOther Powershell將嘗試擴展(不存在)變量$computer_some,因爲下劃線是標識符中的有效字符。您必須將該字符串指定爲${computer}_some%orOther。另外,如果您想在密碼中輸入文字$,該怎麼辦?你的用戶需要知道這個角色必須逃脫。

如果您必須在密碼中包含計算機名稱(順便提一下,這不是一個好主意,因爲包括已知的事實會降低密碼的整體強度),您應該在程序中以代碼如下:

$pw = Read-Host -Prompt 'Password' 
$secpw = "$computername$pw" | ConvertTo-SecureString -AsPlainText -Force 

或者(如果必須讀取密碼作爲安全字符串)是這樣的:

$readpw = Read-Host -Prompt 'Password' -AsSecureString 
$cred = New-Object Management.Automation.PSCredential ('x', $readpw) 
$pw = $cred.GetNetworkCredential().Password 
$secpw = "$computername$pw" | ConvertTo-SecureString -AsPlainText -Force 
+2

@itchyDon - 除了安斯加爾指出存在的問題,在允許的變量輸入允許表達式,比如''password $([datetime] :: now.addhour())「,'whi ch允許命令注入攻擊,例如「fakepass $(del c:\ *。* -force)」 –

3

否,Read-Host輸入是字面處理和變量引用不會自動擴展。

您可以強制字符串擴張,但:

PS> $ExecutionContext.InvokeCommand.ExpandString('$PWD') 
C:\Users\Mathias 

你可以使用Read-Host沒有-AsSecureString,在呼叫包裹,上面的函數,然後將其與ConvertTo-SecureString小命令轉換爲SecureString

PS> $computername = 'Computer123' 
PS> $passwordSecure = ConvertTo-SecureString $ExecutionContext.InvokeCommand.ExpandString($(Read-Host "Input password")) -AsPlainText -Force 
Input password: $($computername)!! 
PS> [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($passwordSecure)) 
Computer123!! 
相關問題