I am trying to change administrator password on windows machines using invoke-vmscript in runasync mode but observed two issues with the script
1.All Invoke-VMScript @sInvoke -RunAsync tasks are kept under $tasks+ array and passed to a while loop but I'm not clear where I need to keep this while loop because its waiting till all the tasks are completed and moving to next line.(foreach ($task in $tasks)). I am expecting in $tasks array if any tasks state is completed then it should write output and go in a loop and wait till next task to be completed.
2. The output of each vm is repeating multiple times. Looks like some issue in loop.
3.Anyway to run the script inside the guest os with runas administrator because the account 'admin' which I am using to invoke has administrator privilege on the machines. However on few machines its failing with "This operation requires an interactive window station". UAC setting issue I believe run as administrator mode will fix the issue.
$script = @'
$NewPassword='password'
try {
$user=Get-WmiObject win32_useraccount |?{$_.Name -eq 'Administrator'}
$ComputerName=(“WinNT://”+$user.caption).replace(“\”,”/”)
$account = [ADSI]"$ComputerName,user"
$account.psbase.invoke("setpassword",$NewPassword)
$result= "Password Change completed successfully"
}
catch {
#$status = "FAILED"
$result= "Failed to Change the administrator password. Error: $_"
}
$result
'@
$tasks = @()
foreach($singlevm in Get-VM "TestVM01", "TestVM02", "TestVM03", "TestVM04", "TestVM05"){
$sInvoke = @{
VM = $singlevm.Name
GuestUser = 'admin'
GuestPassword = ''
ScriptText = $script
ScriptType = 'Powershell'
ErrorAction = 'Stop'
}
$tasks+=Invoke-VMScript @sInvoke -RunAsync -Confirm:$false
}
foreach ($task in $tasks) {
while ($tasks.State -contains 'running') {
Start-Sleep 1
}
$task.Result.ScriptOutput.Split("`n") | Where-Object { $_ -ne '' } | Select-Object @{N='VM';E={$task.Result.VM.Name}},
@{N ='Result'; E={$_.Trim("`r`n")}}
}
You can use the Wait-Task cmdlet instead of the While-construct.
You are seeing the same VM for each line in ScriptOutput.
Yes, that 'interactive window' requirement is also discussed in the thread I mentioned in your other post on this subject.
Try like this
$NewPassword='password'
try {
$user=Get-WmiObject win32_useraccount |?{$_.Name -eq 'Administrator'}
$ComputerName=(“WinNT://”+$user.caption).replace(“\”,”/”)
$account = [ADSI]"$ComputerName,user"
$account.psbase.invoke("setpassword",$NewPassword)
$result= "Password Change completed successfully"
}
catch {
$result= "Failed to Change the administrator password. Error: $_"
}
$result
'@
$tasks = @()
foreach($singlevm in Get-VM "TestVM01", "TestVM02", "TestVM03", "TestVM04", "TestVM05"){
$sInvoke = @{
VM = $singlevm.Name
GuestUser = 'admin'
GuestPassword = ''
ScriptText = $script
ScriptType = 'Powershell'
ErrorAction = 'Stop'
}
$tasks+=Invoke-VMScript @sInvoke -RunAsync -Confirm:$false
}
Wait-Task -Task $tasks
foreach ($task in $tasks) {
'' | Select-Object @{N='VM';E={$task.Result.VM.Name}},
@{N ='Result'; E={
$task.Result.ScriptOutput.Split("`n") |
Where-Object { $_ -ne '' } | %{
$_.Trim("`r`n")}}}
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
You can use the Wait-Task cmdlet instead of the While-construct.
You are seeing the same VM for each line in ScriptOutput.
Yes, that 'interactive window' requirement is also discussed in the thread I mentioned in your other post on this subject.
Try like this
$NewPassword='password'
try {
$user=Get-WmiObject win32_useraccount |?{$_.Name -eq 'Administrator'}
$ComputerName=(“WinNT://”+$user.caption).replace(“\”,”/”)
$account = [ADSI]"$ComputerName,user"
$account.psbase.invoke("setpassword",$NewPassword)
$result= "Password Change completed successfully"
}
catch {
$result= "Failed to Change the administrator password. Error: $_"
}
$result
'@
$tasks = @()
foreach($singlevm in Get-VM "TestVM01", "TestVM02", "TestVM03", "TestVM04", "TestVM05"){
$sInvoke = @{
VM = $singlevm.Name
GuestUser = 'admin'
GuestPassword = ''
ScriptText = $script
ScriptType = 'Powershell'
ErrorAction = 'Stop'
}
$tasks+=Invoke-VMScript @sInvoke -RunAsync -Confirm:$false
}
Wait-Task -Task $tasks
foreach ($task in $tasks) {
'' | Select-Object @{N='VM';E={$task.Result.VM.Name}},
@{N ='Result'; E={
$task.Result.ScriptOutput.Split("`n") |
Where-Object { $_ -ne '' } | %{
$_.Trim("`r`n")}}}
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
You can use the Wait-Task cmdlet instead of the While-construct.
Yes wait-task is working as expected. How ever the script output is displaying the results while wait-task is in progress. Is it something expected? or should I do (Wait-Task -Task $tasks -Verbose |Out-Null)
For failed vms I believe its not writing complete error output.
Sample output for failed vms:
Yes, that 'interactive window' requirement is also discussed in the thread I mentioned in your other post on this subject.
Thanks I will fix manually for 'interactive window' issue vms.
Seems I gave you the wrong version.
Those last lines should have been (and yes, I only produce output for the successful tasks,but you can change that).
$tasks | where{$_.State -eq 'Success'} |
Select @{N='VM';E={$_.Result.vm.Name}},
@{N='Result';E={$_.Result.ScriptOutput}}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thanks it’s working