Stop a continuous Ping - powershell

I am trying to create Powershell script where
User will provide text file with ipaddress/ hostname and test Duration
• Script should take each ip address/ Hostname, open cmd/ powershell and run ping test
For this I created a bat file containing
ping -t %1 |find /v ""|cmd /q /v:on /c "for /l %%a in (0) do (set "data="&set /p "data="&if defined data echo(!Date! !time! !data!)" > %2
In powershell I am running it
$Script = "C:\Ping\pingTest\pingstat.cmd $hostName $outputFile"
$Runpingtest = cmd.exe /c $script
Please give me ideas to spot the contiguous ping as per test duration

You can't stop a continuous ping without signaling the ping process to stop. You would need to use ping /n COUNT for a number of pings.
But you can do something similar with pure PowerShell and Test-NetConnection, then export the results to CSV like so:
1..$pingCount | Foreach-Object {
Test-NetConnection google.com |
Select-Object #{
Name='Date'
Expression={ Get-Date -Format 'ddd MM/dd/yyyy hh:mm:ss.ff' }
}, ComputerName, SourceAddress, RemoteAddress, PingSucceeded,
#{
Name='Latency'
Expression={ "$($_.PingReplyDetails.RoundTripTime) ms" }
}
} | Export-Csv -NoTypeInformation C:\Path\To\file.csv
Note that Test-NetConnection doesn't have a -Count parameter, which is why the my above code wraps the Test-NetConnection call in a loop. You may also need to adjust the Get-Date format for your locale as my code uses a date formation suitable in the US.
Also note that I'm using Select-Object to create custom Date and Latency columns, as Test-NetConnection doesn't provide the current time it was run, and the ping latency is buried in a nested object.

Related

Open multiple remote sessions using 'mstsc' in powershell script

I am trying to write a powershell script that opens a remote desktop connection for each machine name saved in a text file. When I run the script, it only connects to the first machine in the list and outputs to the console: CMDKEY: Credential added successfully once (not once for each machine). mstcs seems to terminate the process after executing, and I'm not sure I'm adding credentials the right way. Can anyone point me in the right direction?
Here are some tests I've tried to figure out what's going on:
Print after mstsc. Doesn't print. Process seems to terminate after
mstcs is called. This seems to be the crux of the issue.
cmdkey /list shows all the credentials I have stored and their targets. The output does not include all the targets defined in the text file. Even if I comment out mstsc, then cmdkey /add:$MachineName /user:$User /pass:$Password only seems to execute for the first line, evidenced by the lack of more console outputs and cmdkey /list not yielding the expected targets. In addition, I have added a print statement after this cmdkey line and it prints for each line, so it doesn't terminate after running (which I already knew because mstcs executes after this line when it's not commented out).
# Read from file
$Lines = Get-Content -Path .\machines.txt | Out-String
# For each machine ...
foreach($Line in $Lines){
# Split line, save name and domain
$Tokens = $Line.Split(".")
$MachineName = $Tokens[0]
$Domain = $Tokens[1]
$User = "someDomain\someUsername"
$Password="somePassword"
# Switch username if someOtherDomain
if ($Domain -eq "someOtherDomain"){
$User = "someOtherDomain\someOtherUsername"
}
#set credentials and open connection
cmdkey /add:$MachineName /user:$User /pass:$Password
mstsc /v:$MachineName /console
}
EDIT: I have also tried replacing mstsc /v:$MachineName with Start-Process -FilePath "$env:windir\system32\mstsc.exe" -ArgumentList "/v:$MachineName" -Wait. The result is opening the session and then the script does not finish in the console but nothing additional happens.
This behavior is cause by your use of Out-String.
Get-Content outputs multiple strings, one per line in the file - but Out-String stitches them back together into a single multi-line string:
PS C:\> $machines = Get-Content machines.txt
PS C:\> $machines.GetType().Name # definitely an array
Object[]
PS C:\> $machines.Count # multiple strings in there
4
PS C:\> $machines = Get-Content machines.txt | Out-String
PS C:\> $machines.GetType().Name # now it's just a single string
String
So your foreach(){} loop only runs once, and the value of $MachineName is no longer the name of a single machine, but a multi-line string with all of them at once - which is probably why mstsc exits immediately :)
Remove |Out-String from the first line and your loop will work

Is there a way to disable and enable network connection when internet is lost

this is my first post so hopefully I am doing it right.
I am looking for a way to automate the process of disabling my Ethernet network connection and then reenable it.
I am on a camp internet connection (work away for weeks at a time) and the internet connection is fine besides it dropping out every half an hour or so and requiring me to refresh the connection. Usually I just disconnect the Ethernet plug for a second and plug it back in but I am wanting to automate the process so I can remote connect to the pc when I am away.
Any help on how to accomplish this would be appreciated.
Edit: I left a vital part out of my description. I am wanting the script to detect when the internet connection is lost and then refresh the connection. Once the connection is lost it never regains it until I refresh the connection.
If you are using DHCP
Then Dollars to donuts you are just needing to renew your DHCP lease.
That is something you can do in CMD easily (I'm sure there is likely as easy a method in PS, but I don't know it offhand)
This will release the currently assigned DHCP Address wait a few seconds and then renew it.
IPConfig /Release & timeout 5 & IPConfig /Renew
At the CLI or in a batch script you could set up a do-while loop to loop until you return an expected up address if you wanted.
Example of a costume loop in cmd cli.
For /L %L (1,1,2147483648) DO (
IPConfig /Release & timeout 3 & IPConfig /Renew &timeout 3 &(
Ping -n 2 4.2.2.2 | find /I "Reply From" | find /I " 4.2.2.2" &&(
Exit /b 0
)
)
)
Disabling and enabling your NIC can be done through CMD or Powershell.
Here Powershell is easier.
Get only currently enabled adapters, use that to disable them wait a few seconds and enable them again
$NIC_Original_State = get-NetAdapter | ? {$_.Status -eq "Enabled"}
$NIC_Original_State | Disable-NetAdapter -name $_.name -confirm:$false
Sleep 5
$NIC_Original_State | Enable-NetAdapter -name $_.name -confirm:$false
Combine with checking the ping to the internet (as in cmd example) to generate a loop until we have a good connection.
$NIC_Original_State = get-NetAdapter | ? {$_.Status -eq "Enabled"}
DO {
$NIC_Original_State | Disable-NetAdapter -name $_.name -confirm:$false
Sleep 5
$NIC_Original_State | Enable-NetAdapter -name $_.name -confirm:$false
Sleep 5
} While ( ! $(test-connection -TargetName 4.2.2.2 -Quiet ) )
Now, PowerShell will need to be instantiated from a CMD prompt, I usually write a .cmd script wrapper for the .ps1 script to be called from in task scedualer or by hand.
Sometimes I will write a combo .cmd script with the ps code embedded and just create a hardline. To the original .cmd script as a. .ps1 to execute the ps code.
Although for something this simple it might be simplest to use PowerShell.exe to run the script as an in-line command.
But all roads lead to Rome, you do you on executing PowerShell, but in order to run it periodically, you will need to schedule the script to run, and by default there is no way to run ps scripts directly, so pick a method that you like that works for running the script and then use windows scheduler to schedule the task to run every x interval you like (say hourly)
Make surw you select a new task (not a basic task) and select run with highest priviledges" checkbox, and select the newest version of windows available in the compatibility list-box.
Make sure to provide a useename and password of an administrator, and select to save the password/run whether the user is logged on or not.
Set your triggers and put in the method you chose to execute the script and run some tests to make sure it works as expected.
Edit:
The original method is int he form DO { Action } WHILE ( Condition To Check Returns True) Since the While is at the end it guarantees one iteration.
Since you don't want to disable and enable the NIC even once if the internet is pingable, you can use a WHILE ( Condition To Check Returns True) { Action }
$NIC_Original_State = get-NetAdapter | ? {$_.Status -eq "Enabled"}
While ( ! $( test-connection -ComputerName 4.2.2.2 -Quiet ) ) {
$NIC_Original_State | Disable-NetAdapter -name $_.name -confirm:$false
Sleep 5
$NIC_Original_State | Enable-NetAdapter -name $_.name -confirm:$false
Sleep 5
}
You absolutely need to have a scheduled task to run this regularly.
Even if you want to only start it once and leave it in the background, and havit checking always (which we could do) you'll need to set up a scheduled task to kill it if still running and start it again at some interval as it's possible to have a process become unresponsive or be killed or have the computer restart etc and you forget to start the script etc.
This version will just loop every one minute to check, and only executes when the internet is not reachable.
while ($true) {
$NIC_Original_State = get-NetAdapter | ? {$_.Status -eq "Enabled"}
While ( ! $( test-connection -ComputerName 4.2.2.2 -Quiet ) ) {
$NIC_Original_State | Disable-NetAdapter -name $_.name -confirm:$false
Sleep 5
$NIC_Original_State | Enable-NetAdapter -name $_.name -confirm:$false
Sleep 5
}
sleep 60
}
Again, you ca just run this in powershell, sure, btu then if it gets stopped for any reason it won;t be started again.
Use task scheduler ad set up an action to run this o Startup and once an hour, killing any previously running copy of the script.
Usually for running a CMD script I just write a simple cmd script so if I want to edit any part of anything I only change the script never the task.
<# ## & REM Script Name:
#(
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO OFF
(
NET SESSION 2>&1 >NUL
) || (
powershell.exe -Command "Start-Process cmd \"/k %~dpnx0\" -Verb RunAs"
pause
GOTO :EOF
)
IF EXIST "%~dpn0.ps1" (
DEL /Q /F %~dpn0.ps1"
)
MKLINK /H "%~dpn0.ps1" "%~f0"
)
Powershell.exe -ExecutionPolicy Bypass -File "%~dpn0.ps1"
(
ENDLOCAL
EXIT /B %_eLvl%
)
#>
## Script:
## Powershell Portion Begins
while ($true) {
$NIC_Original_State = get-NetAdapter | ? {$_.Status -eq "Enabled"}
While ( ! $( test-connection -ComputerName 4.2.2.2 -Quiet ) ) {
$NIC_Original_State | Disable-NetAdapter -name $_.name -confirm:$false
Sleep 5
$NIC_Original_State | Enable-NetAdapter -name $_.name -confirm:$false
Sleep 5
}
sleep 60
}
You can handle this using Get-NetAdapter , Enable-NetAdapter and Disable-NetAdapter commands.

Errors running remote powershell script with PsEcec.exe

I have a powershell script on a remote windows box that finds the folder pointed to by a junction. The contents of the script looks like this:
return fsutil reparsepoint query C:\foo\bar\junction_name | where-object { $_ -imatch 'Print Name:' } | foreach-object { $_ -replace 'Print Name\:\s*','' }
When I run this on the remote box, it executes as expected :)
However, when I try to run this remotely from my local machine:
C:\Users\foo>C:\pstools\PsExec.exe \\remote_server_name "powershell D:\bar\my_script.ps1"
I get errors:
PsExec could not start powershell D:\bar\my_script.ps1 on
remote_server_name: The filename, directory name, or volume label
syntax is incorrect.
Any ideas what this error is telling me (given that I can run the script directly on the remote box with no issues)?
Thx!
1- maybe you should avoid psexec and take advantage of powershell remoting
invoke-command -computername remote_server_name -scriptblock {. "D:\bar\my_script.ps1"}
2- if you want to keep psexec, look at the starting directory switch -w
PsExec.exe \\remote_server_name -w D:\bar "powershell -file my_script.ps1"
PS Remoting would be the best way to go here and I'd actually put up a good fight for opening up TCP/5985 on your machines. The minuscule security risk is, by far, worth the management benefits you'll get with it.
Worst case scenario use the WMI Win32_Process class. Something like this might work.
$wmiParams = #{
'ComputerName' = 'Somecomputer'
'Class' = 'Win32_Process'
'Name' = 'Create'
'Args' = 'fsutil reparsepoint query C:\foo\bar\junction_name > C:\temp.txt'
}
Invoke-WmiMethod #wmiParams
Get-Content \\somecomputer\c$\temp.txt | where-object { $_ -imatch 'Print Name:' } | foreach-object { $_ -replace 'Print Name\:\s*', '' }
I managed to get the following to work:
PsExec.exe \\remote_server_name powershell.exe D:\bar\my_script.ps1
However, the powershell session did not close as expected and remained in a hanging state after my script returned so calling it via cmd as detailed here seems to fix that:
PsExec.exe \\remote_server_name cmd /c "echo . | powershell.exe D:\bar\my_script.ps1"
Thanks for all of the suggestions...

Powershell: how to get rid of CMD output while assigning a variable (nslookup)

I want to run nslookup in a powershell script, assigning the output to a string variable I can parse up. I don't want to see echos like "Non-authoritative answer:" in the powershell window from the CMD execution, but everything I have tried to pipe or redirect the output of the command exclusively to the variable have not worked or broken the variable.
Example:
PS> $temp = (& nslookup 'myip.opendns.com','resolver1.opendns.com');
Non-authoritative answer:
I've tried several work-arounds...
PS> $temp = Invoke-Expression "cmd /c nslookup myip.opendns.com resolver1.opendns.com" >$null
PS> $temp = Invoke-Expression "cmd /c #ECHO off && nslookup myip.opendns.com resolver1.opendns.com"
Maybe there's a better way to do this. The way I'm working with a string here just to get the IP address is a few more lines than I'd like.
$temp = (nslookup myip.opendns.com resolver1.opendns.com) | Out-String
$temp = $temp.split()
$tempIPs = $temp -match "^(.|\r|\n)*?\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b"
$publicIP = $tempIPs[1]
return $PublicIP
I've gone this route because using two servers, like I'm doing with nslookup, doesn't seem to work with powershell's Resolve-DnsName command. I need the two servers because I'm redirecting the lookup to get my public IP. There are other ways to do that, but this one works really well and (invoke-WebRequest ifconfig.me/ip).Content has glitched out on me while working on this script.
You can specify the server to resolve your query against by specifying the -Server parameter of Resolve-DnsName.
Resolve-DnsName -Name myip.opendns.com -Server resolver1.opendns.com
From the MSDN documentation for the Resolve-DnsName command:
-Server <String[]>
Specifies the IP addresses or host names of the DNS servers to be queried. By default the interface DNS servers are queried if this parameter is not supplied.

Windows Service operations on multiple remote servers in parallel

I have 3 servers on same network and having the same username and password to login, on which I want to perform following operations:
*Check if Service1 is running or not
*If it is running, stop the service
*Set Service1 to disable mode
*If it is not running, do nothing
*Check if Service2 is running
*If it is running, stop the service
*Set Service2 to disable mode
*If it is not running, do nothing
and so on for Service3,..4,..5...
I want to create a Master.bat file on 1st Server, which should perform above operations on all the 3 servers in parallel.
I am trying with below but not getting how i can do this for more than 1 services in same code and also its getting bit lengthy.Is there any other short method to do this in batch or powershell ?
original_serverlist.txt:
Server1
Server2
Server3
Code:
copy original_serverlist.txt serverlist.txt
:repeat
set currentserver=
for /f "eol=; tokens=1*" %%i in (serverlist.txt) do set currentserver=%%i
if "%currentserver%"=="" goto end
for /F "tokens=3 delims=: " %%H in ('SC query Service1 ^| findstr " STATE"') do (
if /I "%%H" "RUNNING" (
net stop Service1
echo Service1 stopped # %date% %time% > C:\result.txt
sc config Service1 start= disabled
echo Service1 set disabled # %date% %time% >> C:\result.txt
)
)
type serverlist.txt| find /v "%currentserver%"> serverlist1.txt
copy serverlist1.txt serverlist.txt
goto repeat
:end
del serverlist.txt
del serverlist1.txt
EDIT1
I am not that much comfortable in PS as in batch but i want to learn the things so putting my exact requirement here to learn how to implement it in powershell with code explanation.
I need to perform following same set of operations on all the three remote Servers in parallel (Server1,Server2,Server3) having Master.ps1 on Server1:
run command cmd /c iisreset/stop and set IIS service to Disabled mode
Stop service1 and set it to Disabled mode
Stop service2 and set it to Disabled mode
Stop service3 and set it to Disabled mode
Kill process jusched.exe
Kill process conhost.exe
In powershell 3.0
$services = "service1", "service2", "service3"
"server1", "server2", "server3" | % {
Get-Service -Computer $_ $services | ? State -eq "Running" | Stop-Service -Force -PassThru | Set-Service -StartupType Disabled
}
You need to enable powreshell remoting for this to work and add -Credential option anywhere you see -Computer argument if your current domain user doesn't have enough rights.
More generic option would be to use hash
$ServiceMap = #{ "server1": ("service11", "service12");
"server2": ("service21" ... ) }
You will also need to check for errors..
To achieve parallel execution you could do something like:
workflow set_services {
param(
[string[]]$Computers, [string[]]$Services
)
foreach -parallel ($computer in $computers) {
Get-Service -ComputerName $computer $services | ? State -eq "Running" | Stop-Service -Force -PassThru | Set-Service -StartupType Disabled
}
}
BTW, do not use batch scripts any more, anywhere.