powershell ping with loop does not return StatusCode - powershell

Powershell 4.0 on Windows 7
My IP address is 192.168.0.102 and it does reply to ping from cmd prompt.
I am trying to run the following code which does not behave well:
[int]$intPing = 4
[string]$intNetwork = "192.168.0.102"
for ($i=1;$i -le $intPing; $i++)
{
$strQuery = "select * from win32_pingstatus where address = '" + $intNetwork + $i + "'"
$wmi = get-wmiobject -query $strQuery
#"Pinging $intNetwork attempt $i..."
"Pinging $intNetwork $i ... "
if ($wmi.statuscode -eq 0)
{"success"}
else
{"error: " + $wmi.StatusCode}
this is an example I found in a book, but is not working for some reason.
By supplying my IP it prints an error, but does not return the error code. The same problem without the error code happens if I use a bad IP address. If I use 127.0.0.1 it returns a "success". If I remove the stuff related to the looping it works fine.
The purpose is to learn about looping using "for", so I'm less interested in the best way to do this. I am interested in trying to keep this code as is so that I can learn from it.
So what have I done wrong? And how can I fix it?

Try changing this
$strQuery = "select * from win32_pingstatus where address = '" + $intNetwork + $i + "'"
to this
$strQuery = "select * from win32_pingstatus where address = '$intNetwork'"
The original contained the increment number, which was causing all of your pings to fail.

Related

Advanced Powershell Error Handling for Microsoft Modules (eg Lync)

I have a fairly complex script that includes Lync functionality. For this I import the PSSession.
When one of these commands errors, my error handling returns the line and command within the Lync module it fails on (eg line 2055 $steppablePipeline.End() ) instead of the line and command in my code (eg line 18 Enable-CSUser)
Is there some way to capture my calling command and line?
The following is a simplified example of the script
Function Main
{
Try
{
LyncTest
MailboxTest
}
Catch {$rtn = ReturnErrorCatch $_ ; Return $rtn} #Return Failure
}
Function MailboxTest
{
$script:callline = (Get-PSCallStack)[1].ScriptLineNumber
Get-Mailbox "kfsjlxghkjsdh" -ErrorAction:Stop
}
Function LyncTest
{
$script:callline = (Get-PSCallStack)[1].ScriptLineNumber
Enable-CSUser "kfsjlxghkjsdh" -ErrorAction:Stop
}
Function ReturnErrorCatch ($catch)
{
If ($catch.InvocationInfo.InvocationName -eq "throw"){$errorreturn = $catch.Exception.Message.ToString()}
Else
{
$line = "Line: " + $catch.InvocationInfo.ScriptLineNumber.ToString()
$exception = $catch.Exception.Message.ToString() -replace "`n"," "
$command = "Command: " + ($catch.InvocationInfo.Line.ToString() -replace "`t","").Trim()
$activity = " (Activity: " + $catch.CategoryInfo.Activity +")"
$line = $line + "(" + $callline.ToString() + ")"
$errorreturn = $line + " " + $exception + "`r`n" + $command + $activity
}
$Output = New-Object PSObject -Property #{Result=1;ResultReason=$errorreturn}
Return $Output
}
$result = Main
$result | fl
This returns:
Result : 1
ResultReason : Line: 2055(5) If SIP address type (SipAddressType) is set to None or is not set, you must specify the SIP address (SipAddress).
Command: $steppablePipeline.End() (Activity: Enable-CsUser)
Within my script, I am able to get the calling line by putting the $script:callline line within every subfunction (better ways to do this?), so if I comment out the LyncTest, and run the mailboxtest, I get the expected error return with erroring command, the line it failed on, and the line the function was called from.
As this is for Exchange 2010, I cannot use any Powershell V3 functionality, it must be V2.

Powershell Novice - Get all httpd processes and loop through them

How do I get all processes in power-shell and loop through them and restart them if their memory has reached a X threshold?
For example, I know of this command
PS C:\Users\me> gwmi -ComputerName "localhost" -Class Win32_PerfFormattedData_PerfProc_Process -Filte
r "name like 'httpd%'"
This will give me all httpd processes (httpd, httpd#1, ...).
I would like to loop through these and check if they memory consumption threshold has been reached and if so, restart that process.
My question is primarily how to write the loop, not about how to stop and restart the service. Please explain as I never wrote a power-shell script before.
UPDATE:
I added more information to better explain what my issue is. Below code has comments showing where is see problems (PROBLEM 1 and PROBLEM 2):
$ServiceExe="httpd#1"
$ServiceEXE2="httpd"
# Service to restart ('short' service name from Service's property)
$Service="httpd.exe"
# Working set threshold of 0.2 GB
$Threshold = 200000000
# Get service processes 'httpd' and 'httpd#1'
$Process = Get-WmiObject -ComputerName "localhost" -Class Win32_PerfFormattedData_PerfProc_Process -Filter "Name='$ServiceExe'"
$Process2 = Get-WmiObject -ComputerName "localhost" -Class Win32_PerfFormattedData_PerfProc_Process -Filter "Name='$ServiceExe2'"
# Get working set memory usage for both processes and convert to GB
$wsm = $Process.WorkingSet /1024/1024/1024;
$wsm2 = $Process2.WorkingSet /1024/1024/1024;
$thgb = $Threshold/1024/1024/1024
# Format to 3 dec places
$Fwsm = $("{0:0.000}" -f $wsm);
$Fthgb =$("{0:0.000}" -f $thgb);
echo $("WorkingSet : "+ $Fwsm + " GB / Threshold : " + $Fthgb + " GB.") >> C:\temp\pslog.txt;
if($Process.workingset -gt $Threshold)
{
#PROBLEM 1: THIS WILL ONLY EXECUTE ONCE PROCESS CAPS MAX MEMORY (2GB)
stop-process -name $Service -force
stop-Service apache2.2;
start-Service apache2.2;
echo "Restarted" >> C:\temp\pslog.txt;
}
else
{
#PROBLEM 2: THIS WILL NEVER EXECUTE FOR SOME REASON
$delta = $("{0:0.000}" -f ($thgb - $wsm));
echo $("No Restarting as " + $delta + " GB remains.");
}
I was thinking to replace variables holding process 'httpd' and 'httpd#1' with a single set that I could loop through but realized that Apache may have more than 2 'httpd' processes (i.e. 'httpd', 'httpd#1', 'httpd#2', 'httpd#3', 'httpd#4', ... ). Plus, I discovered that I have the 2 problems marked in the code in update above.
Any idea what I am doing wrong in the code above and how to rewrite it to use a loop to loop through all apache processes that might be initiated, not just 2 like in example above.
UPDATE 2:
So, I rewrote my ps script and I got most of it working but I am running into an issue, hopefully last one.
In my power-shell script, I have defined variable that has my service name like this:
$ServiceName = "APACHESRV[DBx14]";
APACHESRV[DBx14] service exists in my Windows->Services.
Then in my power-shell script, I use stop-service, start-service to start the service:
echo $("Stopping: " + $ServiceName) >> C:\temp\pslog.txt;
stop-Service $ServiceName;
echo $("Starting: " + $ServiceName) >> C:\temp\pslog.txt;
start-Service $ServiceName;
$stamp = Get-Date
echo $($stamp + " Started: " + $ServiceName) >> C:\temp\pslog.txt;
This echoes everything properly and power-shell shows no errors (red-lines), however my service is not started.
Much appreciated
At this point, I think you are just missing your loop. You are retrieving the two process objects, but you are only working on the first one. I took the liberty of restructuring it to work on all http processes. Try this:
# Working set threshold of 0.2 GB
$Threshold = 200000000
$thgb = $Threshold/1024/1024/1024
$Fthgb =$("{0:0.000}" -f $thgb)
# Get service processes 'httpd' and 'httpd#1' Get-WmiObject -ComputerName "localhost" -Class Win32_PerfFormattedData_PerfProc_Process | where { $_.Name -like "httpd*" } | foreach {
$procobj = $_
# Get working set memory usage for both processes and convert to GB
$wsm = $procobj.WorkingSet /1024/1024/1024;
# Format to 3 dec places
$Fwsm = $("{0:0.000}" -f $wsm)
echo $("WorkingSet : "+ $Fwsm + " GB / Threshold : " + $Fthgb + " GB.") >> C:\temp\pslog.txt;
if($procobj.workingset -gt $Threshold)
{
stop-process -name $procobj.Name -force #check this, probably wrong name
stop-Service apache2.2;
start-Service apache2.2;
echo "Restarted" >> C:\temp\pslog.txt;
}
else
{
$delta = $("{0:0.000}" -f ($thgb - $wsm));
echo $("No Restarting as " + $delta + " GB remains.");
}
}
This should do it...
ps | where { $_.name -like "httpd*" } | foreach {
# interrogate the System.Diagnostics.Process object in $_ and do stuff with it
$_
}
Get all the httpd processes with the Get-Process cmdlet, loop through them with the ForEach-Object cmdlet:
# Set a threshold, eg. 120MB
$Threshold = 120 * 1024 * 1024
# Loop through the processes
Get-Process httpd* | ForEach-Object {
if($_.WS -gt $Threshold){
# Working set exceeded threshold, restart relevant service
}
}

Loop through a query in powershell TFS

I am new to TFS and powershell scripting.As a part of my assignment I got a task in which
I have an array with TFS workitem ID's and I need to loop through and
get the details of those id's and display the result.
As a part of it I tried as shown below
$TFSSERVER = "https://server"
$WId = #("1", "2", "3", "4")
$arr = #("")
$i = 0
Function Get-WorkItemData($WId)
{
foreach($Id in $WId)
{
$i++
$query = "SELECT [System.Id]
FROM WorkItemLinks " +
"WHERE [Source].[System.id] = $Id" +
"AND [System.Links.LinkType] = 'Parent'"
if($WId.length -ge $i)
{
$arr+= $query
}
}
$wiData = tfpt query /collection:$TFSSERVER /wiql:$arr
$wiData | out-file "C:\Path"
}
Here is the error i get when i run the script
TFPT.EXE : Expecting end of string. The error is caused by ½SELECT╗.
At line:28 char:22
+ $wiData = tfpt <<<< query /collection:$TFSSERVER /wiql:$b
+ CategoryInfo : NotSpecified: ( Expecting end ...ed by ½SELECT╗.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
Can anyone please help me to how to resolve the error and get list of all details. Please help me.
I do not know if this will resolve your error, but you at the very least have syntax issues on the line that starts with $query= as well as the following line. To fix this I would probably go with long single lined string (which in effect is what you are doing as is) or a HereString (if your executable allows for that).
A single lined string would work for you, and while it is long and a bit more troublesome to read it does avoid issues like what you are running into.
$query = "SELECT [System.Id] FROM WorkItemLinks WHERE [Source].[System.id] = $id AND [System.Links.LinkType] = 'Parent'"
A HereString is formatted similarly to what you have above, but may not be compatible with your application. It is formatted where the first line is #" with nothing after it, then however many lines of text that you want, then a line starting with "#. So in your case it would look like:
$query = #"
SELECT [System.Id]
FROM WorkItemLinks
WHERE [Source].[System.id] = $Id
AND [System.Links.LinkType] = 'Parent'
"#
This may not work for your needs, as I don't know if your TFPT.EXE application will accept a multi-line string as input for the query (and have serious doubts about it allowing it).
If you really, really want to continue formatting it like you have you can continue to do so, you just need to fix the first and second lines of that section at the least:
$query = "SELECT [System.Id] " +
"FROM WorkItemLinks " +
"WHERE [Source].[System.id] = $Id " +
"AND [System.Links.LinkType] = 'Parent';"

Powershell error - GetHostByAddress

Stumped on a problem here - running Powershell 1.0
Code (Assume an ip address which is valid is being passed in):
$ips = #(Import-CSV $attachmentLocation)
foreach ($ip in $ips){
$ipAddress = $ip.IPAddress
$length = $ipaddress.length
write-host "Length is: ($length)"
if(Test-Connection -ComputerName $ipAddress -Count 1 -ea silentlycontinue) {
write-host $ipAddress
$hostData = ([Net.Dns]::GetHostByAddress($ipAddress)).HostName
}
}
Output:
Length is: (11)
10.xx.xx.xx
Exception calling "GetHostByAddress" with "1" argument(s): "The requested name is valid, but no data of the requested type was found"
At FileName:13 char:43
+ $hostData = ([Net.Dns]::GetHostByAddress <<<< ($ipAddress)).HostName
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
If I run the following it works fine - seems to be data type issue (im passing in a string value):
$hostData = ([Net.Dns]::GetHostByAddress("10.xx.xx.xx")).HostName
Working Code:
$ipAddress = "10.xx.xx.xx"
$hostData = ([Net.Dns]::GetHostByAddress($ipAddress)).HostName
Answer:
Issue was with the ActiveDirectory Domain DNS resolution not the command, while some IP addresses were pingable they were not resolving properly on machine where the script was run. This was causing the error 'no data of the requested type was found' refers to the fact it couldn't resolve the IP to a DNS name.
I've got two ideas you could try:
GetHostByAddress() supports string and ipaddress. So try casting to ipaddress-type before running the function.
if(Test-Connection -ComputerName $ipAddress -Count 1 -ea silentlycontinue) {
write-host $ipAddress
$hostData = ([Net.Dns]::GetHostByAddress(([ipaddress]$ipAddress))).HostName
}
If you're on PS 1.0, then your first priority should be to upgrade the machines to at least PowerShell 2.0. Nothing works well in PS 1.0.
Running PS3, I get the error shown when traversing subnets on our domain. Especially remote locations.
I'm checking 5 different C-class subnets on our domain to make sure there aren't devices we don't have in AD.
It's also possible some devices aren't PCs with a hostname: routers, switches, firewalls, scanners, and the like.
When my code gets to my local office, no error.
I'm not using a file, instead I generate the subnets via code in the script.

Concatenating PowerShell variables

$timeout = new-timespan -Minutes 1
$sw = [diagnostics.stopwatch]::StartNew()
$path = "d:\powershell\test.csv"
"Processor Load, Available Memory(MB), Max Memory(Bytes)" >> $path
while ($sw.elapsed -lt $timeout)
{
$a = gwmi -query "Select * from win32_processor"
$b = gwmi -query "Select * from win32_perfrawdata_perfOS_memory"
$c = gwmi -query "Select * from win32_physicalmemory"
$date = Get-Date -format s
$a.loadpercentage + "," + $b.availableMbytes + "," + $c.capacity >> $path
start-sleep -seconds 5
}
So I'm just looking to get a minute long snapshot of what's going on. I'm not just opening this in perfmon for reasons. Basically I'd expect to get a comma-delimited output in the CSV file mentioned. It works for a single variable, but when I try to add a second variable, or text I get the following error.
Cannot convert value ", test" to type "System.Int32". Error: "Input string was not in a
correct format."
At D:\powershell\VDIPerfMon.ps1:14 char:21
+ $a.loadpercentage + <<<< ", test" >> $path
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException
How can I fix this problem?
When you use the + operator PowerShell looks on the left hand side to determine the resulting type of the expression. It is seeing an int on the left of the + and a string (that can't be converted to an int) on the right. Try it this way:
"$($a.loadpercentage), $($b.availableMbytes), $($c.capacity)" >> $path
Also where you write your headers, you might not want to append i.e. in order to overwrite old attempts:
"Processor Load, Available Memory(MB), Max Memory(Bytes)" > $path
The error is because $a.loadpercentage is an int. You are then trying to add an int and a string.
One workaround is to explicitly call .ToString()
$a.loadpercentage.ToString() + "," + $b.availableMbytes.ToString() + "," + $c.capacity.ToString() >> $path
Another way is the PowerShell array join operator. It is quick easy, and types do not matter:
($a.loadpercentage, $b.availableMbytes, $c.capacity) -join "," |
Add-Content $path
Yet another way is with a string formatter. This will easily let you control the precision and display of each value:
'{0},{1},{2}' -f $a.loadpercentage, $b.availableMbytes, $c.capacity