Code stuck in while loop and not exiting in powershell - powershell

I am this weird problem while working with powershell.When I run a while loop to check if the VM tools status, it gets stuck inside only. Here's the code:
Connect-VIServer $vmserver -User $vmuser -Password $vmpass
$status1 = (Get-VM -Name $vmname).Extensiondata.Summary.Guest.ToolsStatus
Write-Host $status1
while(!($status1 -eq 'toolsOK')){
Write-Host "tool status is:" $status1
Start-Sleep -Seconds 5
}
Write-Host "success"
I ran this code when that machine was off and in b/w started that machine($vmname).While it was swtiched off it's understood that "tool status is:"toolsNotRunning.But even after getting switched on and getting the remote of machine it shows same status,whereas I checked in ESXI status was running.I tried the above mentioned thing like it might get stuck so pressed ENTER,Mouse click etc,but no USE..I am using powershell ISE-host,version3.0..

You're only running the update-code once. The while loop only runs the sleep command and write-host (which will never change).. try this:
Connect-VIServer $vmserver -User $vmuser -Password $vmpass
do {
#This will min. once, until $status is 'toolsOK'
$status1 = (Get-VM -Name $vmname).Extensiondata.Summary.Guest.ToolsStatus
if($status1 -ne 'toolsOK') {
Write-Host "tool status is:" $status
Start-Sleep -Seconds 5
}
}
until($status1 -eq 'toolsOK')
Write-Host "success"
or
Connect-VIServer $vmserver -User $vmuser -Password $vmpass
$status1 = (Get-VM -Name $vmname).Extensiondata.Summary.Guest.ToolsStatus
while ($status1 -ne 'toolsOK') {
Write-Host "tool status is:" $status
Start-Sleep -Seconds 5
$status1 = (Get-VM -Name $vmname).Extensiondata.Summary.Guest.ToolsStatus
}
Write-Host "success"

Related

Powershell Delete Computer Object

Can some one help me on the next code im trying to run..
it seem's to be ok for me but does not delete the Object when i execute-it
Import-Module ActiveDirectory
Clear-Host
$Computer = Read-Host "Type in the Host to Delete"
$rute = Get-ADComputer -Identity:"CN=$Computadora,OU=GDL,OU=ClientComputers,OU=ZAP,OU=MX,DC=kabi,DC=ads,DC=fresenius,DC=com" -Server:"DCKABI02.kabi.ads.fresenius.com"
if($rute.Contains($Computer)){
Clear-Host
Remove-ADComputer -Identity=$Computadora,OU=GDL,OU=ClientComputers,OU=ZAP,OU=MX,DC=kabi,DC=ads,DC=fresenius,DC=com" -Server:"DCKABI02.kabi.ads.fresenius.com" -Confirm:$false
#Clear-Host
Write-Host "The Computer Exist and it has been deleted" -ForegroundColor Green
Start-Sleep -Seconds 5
} else{
Clear-Host
Write-Host "The Host does not exist on AD" -ForegroundColor Red
Start-Sleep -Seconds 3
}
try to delete a Active directory object.. expected to work
Your code is not very clear and seems overengineered, $rute.Contains($Computer) will never ever be $true, you probably meant $rute.DistinguishedName.Contains($Computer) which could be $true but .Contains is case-sensitive so it could also be $false.
Your Read-Host statement is assigned to $Computer but then you're using $Computadora. Also, it's unclear why you are hardcoding OU=GDL,OU=ClientComputers,OU=ZAP,OU=MX,DC=kabi,DC=ads,DC=fresenius,DC=com, I would assume you want to use this OU as your -SearchBase.
Here is how you can approach and will most likely work:
$param = #{
SearchBase = "OU=GDL,OU=ClientComputers,OU=ZAP,OU=MX,DC=kabi,DC=ads,DC=fresenius,DC=com"
LDAPFilter = "(name={0})" -f (Read-Host "Type in the Host to Delete")
Server = "DCKABI02.kabi.ads.fresenius.com"
}
$computer = Get-ADComputer #param
if($computer) {
Clear-Host
$computer | Remove-ADComputer -Server "DCKABI02.kabi.ads.fresenius.com" -Confirm:$false
Write-Host "The Computer Exist and it has been deleted" -ForegroundColor Green
Start-Sleep -Seconds 5
}
else {
Clear-Host
Write-Host "The Host does not exist on AD" -ForegroundColor Red
Start-Sleep -Seconds 3
}

Make Azure powershell wait for task to complete

I have a powershell script that stops/starts VM in parallel at specific time using Jenkins. This script uses the -AsJob powershell cmdlet, this way the VMs show they are stopped in Jenkins output but really they are in process of deallocating in the Azure portal.
I also have a sleep timer for 5 minutes to get the Get-AzureRmVM -Status command.
Question:- Is there a way to loop it where I can check for the status of the VMs and if the VMs are NOT in Deallocated or Running state, the Script checks back in another minute or so. Once the VMs are finally in deallocated or running state, the script/job exits with success.
Code snippet
$JobList = #()
foreach ($VM in $vms)
{
if ($env:OPTION -eq "start")
{
Write-Output "Starting :- $($VM.Name) in $($VM.ResourceGroupName)"
$JobList += Start-AzureRmVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name -AsJob -Verbose
Write-Output "$($VM.Name) has started successfully `n"
Write-Output "--------------------------------------------------"
}
elseif ($env:OPTION -eq "stop")
{
Write-Output "Deallocating :- $($VM.Name) in $($VM.ResourceGroupName)"
$JobList += Stop-AzureRmVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name -Force -AsJob -Verbose
Write-Output "$($VM.Name) has been deallocated successfully `n"
Write-Output "--------------------------------------------------"
}
else
{
Write-Output "ERROR!!! No option selected, select an option"
}
}
sleep 300
Write-Output "`n##############################################"
Write-Output "### Writing Status of VMs to Workspace ###"
Write-Output "##############################################"
Get-AzureRmVM -Status | Where-Object {($_.tags.ManagedBy -eq "blaah") -And ($_.tags.Environment -eq "stage")}
EDIT - This code checks the status of the VM to see if it is deallocated. I cannot get it to run the loop over again because the VMs are in Running state.
$vms = (Get-AzureRmResource | Where-Object {($_.tags.ManagedBy -eq "blaah") -And ($_.tags.Environment -eq "Stage")}
foreach ($VM in $VMs) {
$vmDetail = Get-AzureRmVM -Name $VM.Name -ResourceGroupName $VM.ResourceGroupName -Status
foreach ($vmDetail in $vmDetail.Statuses[1]) {
$VMStatusDetail = $vmDetail.DisplayStatus
if ($VMStatusDetail -ne "Stopped") {
Write-Output "Waiting for $($VM.Name) to deallocate"
Write-Output "State:- $($VM.Name) is $VMStatusDetail"
start-sleep -s 5
}
else {
Write-Output "State:- $($VM.Name) is $VMStatusDetail"
}
}
}
If you throw the Stop-AzureRMVM as Jobs and keep the output in array of Jobs called $JobList, once all jobs have started, at the end and outside the loop you can add the following command to wait the jobs finish.
Write-Host $JobList
$JobList| Get-Job | Wait-Job | Receive-Job | Format-Table -AutoSize

how to automate Wusa with remoting and overcoming the lack of wait cmd

Scenario: Taking a list of kb files and executing them remotely with WUSA install of target machines across network.
The flow is like this:
enter a powershell session W/ target computer
for each loop $KB in $List
wusa.exe $kb
wait 'til installed
back to the wusa.exe for next device in $list
Code:
# SET UP ERROR-HANDLING FOR THE PS SESSION
$ErrorActionPreference = "continue"
# DECLARE VARIABLE THAT CONTAINS LIST OF PATCHES AVAILABLE FOR INSTALL
$PatchList = (Get-ChildItem -Path C:\WinPatch -recurse | Where-Object {$_.Extension -eq '.msu'})
# ESTABLISH LOOP TO ITERATE THRU PATCHES
foreach ($Patch in $PatchList)
{
Try
{
Write-Host ("`n Preparing to install: " + $Patch) -ForegroundColor Yellow
Write-Host ("`n Installing...") -ForegroundColor Magenta
$SB = {
$arglist = "$Patch", "/quiet", "/norestart"
Start-Process -FilePath "C:\windows\system32\wusa.exe" -ArgumentList $arglist -Wait}
Invoke-Command -ScriptBlock $SB
Write-Host "`n Installation complete`n" -ForegroundColor Green
}
Catch
{
[System.Exception]
Write-Host "Installation failed with Error -- $Error()" -ForegroundColor Red
$Error.Clear()
}
}
# RESTART OPTIONS
$Ans1 = Read-Host "`n Would you like to restart this computer now (Type Y for yes or N for no)"
if ($Ans1 -eq 'Y' -or $Ans1 -eq 'y')
{
Remove-Item -Path C:\WinPatch\*.msu -Force
Write-Host "`n This computer will restart in 5 seconds..." -ForegroundColor Yellow
Start-Sleep -Seconds 5
Restart-Computer -Force
}
else
{
# TEST COMPUTER FOR PS VERSION
$Tester = test-wsman -computername localhost | Select-Object -Property ProductVersion
if ($Tester.ProductVersion.EndsWith("1.0"))
{
Write-Host "`n This computer has PS v1.0 installed and you will have to open Task Scheduler to schedule restart" -ForegroundColor Red
Read-Host "`n Press ENTER to continue..."
}
elseif ($Tester.ProductVersion.EndsWith("2.0"))
{
Write-Host "`n This computer has PS v2.0 installed and you will have to open Task Scheduler to schedule restart" -ForegroundColor Red
Read-Host "`n Press ENTER to continue..."
}
else
{
# SCHEDULE RESTART
Import-Module PSScheduledJob
$RST = Read-Host -Prompt "`n Enter date/time to restart computer...format is --> mm/dd/yyyy hh:mmAM/PM"
$Ans2 = Read-Host -Prompt "`n You entered: $RST... if this is correct, enter Y for yes"
if ($Ans2 -eq 'Y' -or $Ans2 -eq 'y')
{
$Nomen = Read-Host -Prompt "`n Enter name for scheduled restart "
$Trig = New-JobTrigger -Once -At $RST
Register-ScheduledJob -Name $Nomen -Trigger $Trig -ScriptBlock { Restart-Computer -force } -RunAs32
}
else
{
Write-Host "`n Please restart the script and try again" -ForegroundColor Red
}
}
}
Break
PsExec.exe -u $domain\$username -p $password -h -s -accepteula \\$computer wusa.exe /quiet 'C:\Program Files\WindowsPowershell\Modules\windows10.0-kb5005112-x64.msu' /wait /forcerestart
This works for me. If you wrap this in an Invoke-Command block you can run this remotely. :-)
Thanks,

Assistance in properly scripting a Join and Un-Join Domain script

Hello guys i have started to create a script that would basically automate the un-join and joining of a computer via a script this initially works fine right up until the point i need to start pinging for the computer to come back online. For the instance of un-joining it works fine but all the issue arise when trying to join.
Maybe fresh pair of eyes can lend me some Intel on the matter thank you.
<#
############################################################################################################
# Written by CPineda # NOTE: This only works if computer is on the wire. #
# This Script un-joins and re-joins the domain. # So its very important that we connect the devce #
# Created: 04/27/2016 # to the LAN. #
# Last revision 4/6/2016 # #
############################################################################################################
#>
# Set up your Variables
$ComputerIP = "" #Stores the Computers IP
$ComputerName = "" #Stores the Name of the computer you will be working with.
#$LocalCredentials = "" #Stores the Local Administrator credentials. (As Neeeded)
$DomainCredentials = "" #Stores the Domain Administrator credentials.
# Get information needed for the script to run.
while ($ComputerIP -eq ""){
Clear-Host #Clear the PS Console Window
$ComputerIP = Read-Host "Enter the name of the Computer IP"
}
while ($ComputerName -eq ""){
Clear-Host #Clear the PS Console Window
$ComputerName = Read-Host "Enter the name of the Computer"
}
<# while ($LocalCredentials -eq ""){
Clear-Host #Clear the PS Console Window
$LocalCredentials = Read-Host "Enter the User name of the Local User Admin Account"
}
#>
while ($DomainCredentials -eq ""){
Clear-Host #Clear the PS Console Window
$DomainCredentials = Read-Host "Enter the User name of the Domain User Admin Account"
}
# Remove the computer from the Domain.
Remove-Computer -ComputerName $ComputerName -LocalCredential $ComputerName\administrator -UnJoinDomainCredential kelsonfla\$DomainCredentials -WorkgroupName WORKGROUP -Force -Restart
Read-Host "Hit ENTER to continue"
# Ping until computer returns on the wire.
Clear-Host
Write-Host "At this time we will ping the compputer in question untill it returns back online"
Write-Host "Hit ENTER to continue"
Read-Host
Test-Connection ($ComputerIP) {
$result = Test-Connection $ComputerIP -Count 3 -Delay 10 -Quiet
if ($Result | where { $_ -match 'Reply from ' }){$true}
else {$false}
}
Write-Verbose "The computer $ComputerIP has went down for a reboot. Waiting for it to come back up..."
while (!(Test-Connection -ComputerName $ComputerIP)) {
Start-Sleep -Seconds 5
Write-Verbose "Waiting for $ComputerIP to come back online"
}
Write-Verbose "The computer $ComputerIP has come online. Waiting for OS to initialize"
$EapBefore = $ErrorActionPreference
$ErrorActionPreference = [System.Management.Automation.ActionPreference]::SilentlyContinue
while (!(Get-WmiObject -ComputerName $ComputerIP -Class Win32_OperatingSystem -Credential $LocalCredentials)) {
Start-Sleep -Seconds 5
Write-Verbose "Waiting for OS to initialize..."
$ErrorActionPreference = $EapBefore
}
# Add computer back to the Domain.
Add-Computer -ComputerName $ComputerIP -LocalCredential $ComputerName\administrator -DomainName kelsonfla.local -Credential kelsonfla\$DomainCredentials -Restart -Force
Read-Host "Hit ENTER to continue"
# Ping until computer returns on the wire.
Clear-Host
Write-Host "At this time we will ping the compputer in question untill it returns back online"
Write-Host "Hit ENTER to continue"
Read-Host
Test-Connection ($ComputerIP) {
$result = Test-Connection $ComputerIP -Count 3 -Delay 10 -Quiet
if ($Result | where { $_ -match 'Reply from ' }){$true}
else {$false}
}
Write-Verbose "The computer $ComputerIP has went down for a reboot. Waiting for it to come back up..."
while (!(Test-Connection -ComputerName $ComputerIP)) {
Start-Sleep -Seconds 5
Write-Verbose "Waiting for $ComputerIP to come back online"
}
Write-Verbose "The computer $ComputerIP has come online. Waiting for OS to initialize"
$EapBefore = $ErrorActionPreference
$ErrorActionPreference = [System.Management.Automation.ActionPreference]::SilentlyContinue
while (!(Get-WmiObject -ComputerName $ComputerIP -Class Win32_OperatingSystem -Credential $LocalCredentials)) {
Start-Sleep -Seconds 5
Write-Verbose "Waiting for OS to initialize..."
$ErrorActionPreference = $EapBefore
}
Clear-Host
Write-Output "If you are Reading this then you have successfully Unjoined and Re-Joined a Computer to the Network"
Start-Sleep -Seconds 3
Clear-Host
First : for the ping part, you should remove the code :
Test-Connection ($ComputerIP) {
$Result = ping $ComputerIP -n 3
if ($Result | where { $_ -match 'Reply from ' }) {
$true
} else {
$false
}
}
and simply use
!$result = $false
do {
Write-Verbose "Waiting for $ComputerIP to come back online"
$result = Test-Connection $ComputerIP -Count 2 -Delay 5 -Quiet
} while (!$result)
And then use the value of the $result boolean to see if your computer is reponding again. Test-Connection is a Cmdlet that cover the ping role.

Using Powershell To Distribute Script Level Jobs On Remote Servers

More of a theory question...
I have a powershell script that exists on three servers. In this example the three servers are:
server1
server2
server3
I am using another machine, server4, to call script C:\ExampleScript.ps1 remotely using Invoke-Command while specifying the remote machine via the ComputerName parameter. The ultimate goal of the script is to detect whether powershell is running, if it is not, then the computer is "not busy" and can open up the script being called remotely. If the computer is "busy", move onto the next server and continue on through the three machines until all the parameter values have been exhausted. If all machines are busy, it would be ideal if there was a way to periodically check the processes and see if they are still open. In this way, execution of the script can be balanced across the various machines, in an albeit primitive fashion.
Consider the following code:
$servers = "server1","server2","server3"
$data = "param1", "param2", "param3", "param4", "param5", "param6"
#somehow loop through the different servers/data using the above arrays
$job = Invoke-Command $servers[0] {
$ProcessActive = Get-Process powershell -ErrorAction SilentlyContinue
if($ProcessActive -eq $null)
{
"Running"
Invoke-Command -ComputerName $env:computername -FilePath C:\ExampleScript.ps1 -ArgumentList $data[0]
}
else
{
"Busy go to next machine"
}
} -AsJob
Wait-Job $job
$r = Receive-Job $job
$r
The expected result trying to be achieved is attempting to load balance the script across the machines based on whether there is an active powershell process, if not move onto the next machine and perform the same test and subsequent possible execution. The script should go through all the values as specified in the $data array (or whatever).
I found this question interesting, so I wanted to give it a try.
$servers = "server1","server2","server3"
$data = New-Object System.Collections.ArrayList
$data.AddRange(#("param1", "param2", "param3", "param4", "param5", "param6"))
$jobs = New-Object System.Collections.ArrayList
do
{
Write-Host "Checking job states." -ForegroundColor Yellow
$toremove = #()
foreach ($job in $jobs)
{
if ($job.State -ne "Running")
{
$result = Receive-Job $job
if ($result -ne "ScriptRan")
{
Write-Host " Adding data back to que >> $($job.InData)" -ForegroundColor Green
$data.Add($job.InData) | Out-Null
}
$toremove += $job
}
}
Write-Host "Removing completed/failed jobs" -ForegroundColor Yellow
foreach ($job in $toremove)
{
Write-Host " Removing job >> $($job.Location)" -ForegroundColor Green
$jobs.Remove($job) | Out-Null
}
# Check if there is room to start another job
if ($jobs.Count -lt $servers.Count -and $data.Count -gt 0)
{
Write-Host "Checking servers if they can start a new job." -ForegroundColor Yellow
foreach ($server in $servers)
{
$job = $jobs | ? Location -eq $server
if ($job -eq $null)
{
Write-Host " Adding job for $server >> $($data[0])" -ForegroundColor Green
# No active job was found for the server, so add new job
$job = Invoke-Command $server -ScriptBlock {
param($data, $hostname)
$ProcessActive = Get-Process powershell -ErrorAction SilentlyContinue
if($ProcessActive -eq $null)
{
# This will block the thread on the server, so the JobState will not change till it's done or fails.
Invoke-Command -ComputerName $hostname -FilePath C:\ExampleScript.ps1 -ArgumentList $data
Write-Output "ScriptRan"
}
} -ArgumentList $data[0], $env:computername -AsJob
$job | Add-Member -MemberType NoteProperty -Name InData -Value $data[0]
$jobs.Add($job) | Out-Null
$data.Remove($data[0])
}
}
}
# Just a manual check of $jobs
Write-Output $jobs
# Wait a bit before checking again
Start-Sleep -Seconds 10
} while ($data.Count -gt 0)
Basically I create an array, and keep it constantly populated with one job for each server.
Data is removed from the list when a new job starts, and is added back if a job fails. This is to avoid servers running the script with the same data/params.
I lack a proper environment to test this properly at the moment, but will give it a whirl at work tomorrow and update my answer with any changes if needed.