Powershell TCP Send and Receive response - powershell

I am using a PowerShell TCP listener accept a connection then send and receive over that connection.
I need to send:
$Ret = 0x02 + [string]"LS$(Current)" + 0x03
So an 0x02 start and 0x03 end but I cannot get it into a variable to use a:
$writer.Write($Ret)
$writer.Flush()
To transmit it over TCP
Any suggestions would help.
#Current function
Function Current {
$Now = Get-Date -format "yy:MM:dd:HH:mm:ss"
$IM = $Now -split ":"
$P1 = "|DA" + $IM[0] + $IM[1] + $IM[2]
$P2 = "|TI" + $IM[3] + $IM[4] + $IM[5] + "|"
$P3 = $P1 + $P2
Return $P3
}
$continue = $true
$port = 8471
$IPEndPoint = New-Object System.Net.IPEndPoint([IPAddress]::Any,$port)
$listener = New-Object System.Net.Sockets.TcpListener $IPEndPoint
$listener.Start()
[Byte] $B1 = 0x02
[Byte] $B2 = 0x03
while ($continue -eq $true) {
$data = $Null
$client = $listener.AcceptTcpClient()
$rEndpoint = $client.client.RemoteEndPoint
$stream = $Client.GetStream()
$client.NoDelay = $True
#Stream Prep
$reader = New-Object System.IO.StreamReader $stream
$writer = New-Object System.IO.StreamWriter $Stream
$writer.AutoFlush = $true
If($client.Connected -eq $false) {
"Not Connected"
}
$buffer = new-object System.byte[] 1024
$EncodedText = new-object System.Text.AsciiEncoding
If ($client.Connected -and $Count -lt 1) {
$R1 = "LS$(Current)"
$Ret = 0x02 + [string]"LS$(Current)" + 0x03
$writer.Write($Ret)
$writer.Flush()
Write-Host $Ret
$Count++
}
while ($client.Connected -and $stream.DataAvailable -and ($i = $stream.Read($buffer, 0, $buffer.Length)) -ne 0) {
$data += $EncodedText.GetString($buffer, 0, $i)
$stream.Flush()
}
If($Data -eq $null) {
$Data = $Reader.ReadLine()
}
Write-Host "$rEndpoint`: $data"
# Get-Variable -Name data
If($data -eq "StopIt") {
$stream.Close()
$client.Close()
$continue = $false
$listener.stop()
$Client.Close()
$stream.Close()
$listener.stop()
$reader.Close()
$writer.Close()
} ElseIf($data -match "LS") {
$Ret = "'\x02LS$(Current)\x03'"
$writer.WriteLine($Ret)
Write-Host $Ret
} ElseIf($data -match "x02LA") {
$Ret = "\x02LA$(Current)\x03"
$writer.Write($Ret)
Write-Host $Ret
} ElseIf($Data -eq $Null) {
$Data
"Not"
# $Ret = "'\x02LS$(Current)\x03'"
# $writer.WriteLine($Ret)
# Write-Host $Ret
} ElseIf($Data -match "DR") {
$Data
Write-host "DR Request"
# Resenc query to database
} ElseIf($Data -match "PS") {
$Data
Write-host "PS Request"
# Room paid query
} Else {
$Data
Write-host "Other Request"
}
$Reader.Close()
$writer.Close()
$stream.Close()
$client.Close()
start-sleep -Milliseconds 500
}
In Python it looks like this:
s = 'LS|DA220601|TI195645|'
m = b'\x02' + s.encode('ascii') + b'\x03'
Need to send the same thing over a TCP connection with PowerShell.
Thanks
Peter

$port=8471
$IPEndPoint=New-Object System.Net.IPEndPoint([IPAddress]::Any,$port)
$listener = New-Object System.Net.Sockets.TcpListener $IPEndPoint
$listener.Start()
$data = $Null
$client = $listener.AcceptTcpClient()
$rEndpoint = $client.client.RemoteEndPoint
$client.NoDelay = $True
$PS=$Client.GetStream()
#((0x02) -as [byte[]];$([System.Text.Encoding]::ASCII.GetBytes($Ret));(0x03) -as
byte[]])
$PS.Write($data1,0,$data1.Length)
$PS.Flush()
The above fixed it. Thanksall.
Peter

Related

Pass variable from one function to another in powershell

I have a function that receives a parameter which contains the file it should work on ($archivo). That same value should be passed on to another function that is called within the same function. But for some reason on the second function I'm getting a blank value.
function EXTRAER_DATA_COMIDA_Y_CREAR_WORD ($archivo) {
write-host "EXTRAER_DATA_COMIDA" -foreground green
$FILE = Join-Path -Path $root\UNB\FACTURA_FINAL\ -ChildPath $archivo
$result = switch -Regex -File $FILE {
'^([\d,.]+)\s+([\w\s]+)\s+([\d,.]+)' {
[PsCustomObject]#{
Quantity = $matches[1].Trim()
Product = $matches[2].Trim()
Price = $matches[3].Trim()
}
}
}
,$result
CREAR_DOCWORD($result,$archivo)
}
Which is the correct way to do it?
Thanks in advance !
EDIT: This is the new code as far as I can go
$results =function EXTRAER_DATA_COMIDA_Y_CREAR_WORD($archivo)
{
write-host "EXTRAER_DATA_COMIDA" -fore green
$FILE = Join-Path -Path $root\UNB\FACTURA_FINAL\ -ChildPath $archivo
$result = switch -Regex -File $FILE {
'^([\d,.]+)\s+([\w\s]+)\s+([\d,.]+)' {
[PsCustomObject]#{
Quantity = $matches[1].Trim()
Product = $matches[2].Trim()
Price = $matches[3].Trim()
}
}
}
,#($result)
Write-Host "variables que entran a docword" $results $results.GetType() $archivo
CREAR_DOCWORD $results $archivo
}
FUNCTION CREAR_DOCWORD($COMIDA,$archivo) {
$objWord = New-Object -ComObject word.application
$objWord.Visible = $True
$Path = "$root\UNB\script\Tiquete_UnBilling.docx"
$objDoc = $objWord.Documents.Open("$Path")
$objSelection = $objWord.Selection
Write-Host "variables docword" $COMIDA $COMIDA.GetType() $archivo
## ESTA FUNCION CREA LA TABLA CON LOS DATOS DE COMIDA
Write-Host "TAMAÑO ARRAY" $COMIDA.Length
Write-Host "NOMBRE ARCHIVO" $archivo
$table = $objDoc.Tables(1)
for ($i=0; $i -le $comida.Count; $i++){
Write-Host "contador" $i
$table.rows.add() | out-null
$table.cell(($i+2),1).Range.Text = $comida[$i].Quantity
$table.cell(($i+2),2).Range.Text = $comida[$i].Product
$table.cell(($i+2),3).Range.Text = $comida[$i].Price
}
}
Even using ,#($result) I get a type object that looks like System.Management.Automation.PSCustomObject so it cant be use in the for loop because it has no size.
Got it to work... the code is as following.
function EXTRAER_DATA_COMIDA_Y_CREAR_WORD($archivo)
{
write-host "EXTRAER_DATA_COMIDA" -fore green
$FILE = Join-Path -Path $root\UNB\FACTURA_FINAL\ -ChildPath $archivo
$result = switch -Regex -File $FILE {
'^([\d,.]+)\s+([\w\s]+)\s+([\d,.]+)' {
[PsCustomObject]#{
Quantity = $matches[1].Trim()
Product = $matches[2].Trim()
Price = $matches[3].Trim()
}
}
}
Write-Host "variables que entran a docword" $result $result.GetType() $archivo
&CREAR_DOCWORD -COMIDA #($result) -archivo $archivo
}
FUNCTION CREAR_DOCWORD {
Param($COMIDA,$archivo)
$objWord = New-Object -ComObject word.application
$objWord.Visible = $True
$Path = "$root\UNB\script\Tiquete_UnBilling.docx"
$objDoc = $objWord.Documents.Open("$Path")
$objSelection = $objWord.Selection
Write-Host "variables docword" $COMIDA $COMIDA.GetType() $archivo
## ESTA FUNCION CREA LA TABLA CON LOS DATOS DE COMIDA
Write-Host "TAMAÑO ARRAY" $COMIDA.Length
Write-Host "NOMBRE ARCHIVO" $archivo
$table = $objDoc.Tables(1)
for ($i=0; $i -le $comida.Count; $i++){
Write-Host "contador" $i
$table.rows.add() | out-null
$table.cell(($i+2),1).Range.Text = $comida[$i].Quantity
$table.cell(($i+2),2).Range.Text = $comida[$i].Product
$table.cell(($i+2),3).Range.Text = $comida[$i].Price
}
## ESTA FUNCION SUSTITUYE TEXTO
Write-Host "ESTA FUNCION SUSTITUYE TEXTO" -fore White
$consecutivo_fact =get-random -maximum 100
$fecha= Get-Date -Format "dd/MM/yyyy"
$hora= Get-Date -Format "HH:mm tt"
$CODIGO_UNBILLING= -join ((0x30..0x39) + ( 0x41..0x5A) + ( 0x61..0x7A) | Get-Random -Count 8 | % {[char]$_})
Write-Host "ARCHIVO " $archivo -fore White
$content = Get-Content $root\UNB\FACTURA_FINAL\$archivo
for($i = 0; $i -lt $content.Count; $i++)
{
$line = $content[$i]
Write-Host $line
if ($line.Contains('%SER'))
{
$SERVICIO=$line.Split(' ')[-1]
}
elseif ($line.Contains('SubTotal'))
{
$SUBTOTAL=$line.Split(' ')[-1]
}
elseif ($line.Contains('Descto'))
{
$DCTO=$line.Split(' ')[-1]
}
elseif ($line.Contains('TOTALES :'))
{
$TOTALFACTURA=$line.Split(' ')[-1]
}
elseif ($line.Contains('%IVA'))
{
$IVA=$line.Split(' ')[-1]
}
elseif ($line.Contains('Mesa #'))
{
$MESA=$line.Split(' ')[4]
}
else {
$DCTO="0.00"
}
}
$hash = #{"[CONS]" = "$consecutivo_fact"; "[FECHA]"="$fecha"; "[HORA]"="$hora"; "[CODIGO]"="$CODIGO_UNBILLING".ToUpper();"[CarSer]"="$SERVICIO";"[TV]"="$SUBTOTAL";"[TD]"="$DCTO";
"[TVN]"="$TOTALFACTURA";"[IVA]"="$IVA";"[TOTAL]"="$TOTALFACTURA";"[MESA]"="$MESA"}
$objSelection = $objWord.Selection
$MatchCase = $false
$MatchWholeWord = $true
$MatchWildcards = $false
$MatchSoundsLike = $false
$MatchAllWordForms = $false
$Forward = $true
$wrap = $wdFindContinue
$wdFindContinue = 1
$Format = $false
$ReplaceAll = 2
foreach($value in $hash.Keys) {
$ReplaceWith = $hash[$value]
$FindText = $value
$objSelection.Find.Execute($FindText, $MatchCase, $MatchWholeWord, $MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $wrap, $Format, $ReplaceWith, $ReplaceAll)
}
}

Powershell - How would I return appname from a foreach loop only if status code -ne 200?

The title says it all. I have been returning output from every iteration of both of the below foreach loops (see the Write-Host and Write-Output lines), but the application that is using this script (Nagios) can't handle that much data. Therefore, I would like to only return 1 output at a time. Basically "All apps okay" or "app(s) down: then list the apps not returning 200 response code".
I have no idea how to do this as getting the foreach loops to work in the first place was quite the challenge for me.
$ok = 0
$warning = 1
$critical = 2
$unknown = 3
$appPool = get-webapplication
$errorcode = 0
$time_errorcode = 0
foreach($a in $appPool) {
$app = $a.Attributes[0].Value;
$url = "http://localhost$app/apitest/index"
$HTTP_Request = [System.Net.WebRequest]::Create($url)
$HTTP_Response = try{ $HTTP_Request.GetResponse() }catch {$exceptionMessage = $_.Exception.Message
$exceptionItem = $app}
[int]$HTTP_Response.StatusCode -ne 200
$statuscode = [int]$HTTP_Response.StatusCode
Write-Host "$app status code: $statuscode"
if ($HTTP_Response.StatusCode.value__ -ne 200) {
[int]$errorcode = 1
}
}
foreach($t in $appPool){
$app = $t.Attributes[0].Value;
$url = "http://localhost$app/apitest/index"
$output = "$PSScriptRoot\10meg.test"
$start_time = Get-Date
try {Invoke-WebRequest -Uri $url -OutFile $output} catch {
$exceptionMessage = $_.Exception.Message
$exceptionItem = $app
Write-Output "$app error: $exceptionMessage"}
Write-Output "$app Time taken: $((Get-Date).Subtract($start_time).milliSeconds) millisecond(s)"
$timetaken = $((Get-Date).Subtract($start_time).milliSeconds)
if ($timetaken.StatusCode.value__ -ge 500) {
[int]$time_errorcode = 1
}
}
#Uncomment for testing
#Write-Output $time_errorcode
#Write-Output $errorcode
if (($errorcode -eq 0 -and $time_errorcode -eq 0)){exit $ok}
if (($errorcode -eq 1 -and $time_errorcode -eq 0)){exit $critical}
if (($errorcode -eq 0 -and $time_errorcode -eq 1)){exit $warning}
if (($errorcode -eq 1 -and $time_errorcode -eq 1)){exit $critical}
else {exit $unknown}
Here's my approach. UNTESTED. Just to give you an idea to work with.
$appPool = Get-WebApplication
$errorcode = 0
$time_errorcode = 0
# Using a hashset ensures every app is contained only once
$appsDown = New-Object "System.Collections.Generic.HashSet[string]"
foreach($a in $appPool) {
$app = $a.Attributes[0].Value;
$url = "http://localhost$app/apitest/index"
### Test response code ###
$HTTP_Request = [System.Net.WebRequest]::Create($url)
$HTTP_Response = $null
try {
$HTTP_Response = $HTTP_Request.GetResponse()
} catch {
# for test
Write-Host $_
}
if ($null -eq $HTTP_Response -or [int]$HTTP_Response.StatusCode -ne 200 ) {
[int]$errorcode = 1
[void]$appsDown.Add($app)
}
### Test response time ###
$output = "$PSScriptRoot\10meg.test"
$start_time = Get-Date
$timetaken = -1
try {
Invoke-WebRequest -Uri $url -OutFile $output
$timetaken = ((Get-Date) - $start_time).TotalMilliSeconds
} catch {
# for test
Write-Host $_
}
if ($timetaken -lt 0 -or $timetaken -ge 500) {
[int]$time_errorcode = 1
[void]$appsDown.Add($app)
}
}
# Output the results here
if ($appsDown.Count -eq 0) {
Write-Output "All apps okay"
}
else {
Write-Output ($appsDown.Count.ToString() + "app(s) down")
$appsDown | sort | foreach {
Write-Output $_
}
}
if (($errorcode -eq 0 -and $time_errorcode -eq 0)){exit $ok}
if (($errorcode -eq 1 -and $time_errorcode -eq 0)){exit $critical}
if (($errorcode -eq 0 -and $time_errorcode -eq 1)){exit $warning}
if (($errorcode -eq 1 -and $time_errorcode -eq 1)){exit $critical}
else {exit $unknown}
Explanations:
$appsDown = New-Object "System.Collections.Generic.HashSet[string]"
Create a new instance of a .NET HashSet to hold the app names. (It's an unordered collection where every value is stored only once.)
[void]$appsDown.Add($app)
Add the app name to the collection. [void] is there to prevent the method's return value to be sent to the pipeline.
This may help you:
$list = #()
Foreach(x in y){
$item = #{}
If(x.error -eq 200){
$item.Name = x.Name
}
$obj = New-Object PSObject -Property $item
$list += $obj
}
Adding these parts will leave you with a list of appsnames in the variable $list

Export table object to CSV

We extracted the required tables from word doc, but can someone help... that how can I export this table object $LETable to CSV, or export values which we have fetched below in CSV in table format.
$objWord = New-Object -Com Word.Application
$filename = 'D:\Files\Scan1.doc'
$objDocument = $objWord.Documents.Open($filename)
$LETable = $objDocument.Tables.Item(4)
$LETableCols = $LETable.Columns.Count
$LETableRows = $LETable.Rows.Count
$obj = New-Object -TypeName PSCustomObject
Write-Output "Starting to write... "
for($r=1; $r -le $LETableRows; $r++) {
for($c=1; $c -le $LETableCols; $c++) {
#Write-Host $r "x" $c
$content = $LETable.Cell($r,$c).Range.Text
Write-Host $content
}
}
$objDocument.Close()
$objWord.Quit()
# Stop Winword Process
$rc = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objWord)
Not quite ready a solution but I have no more time ATM.
The script outputs all fields enclosed in double quotes and delimited with commas per row and stores in a variable $RawCSV which then is passed to ConvertFrom-Csv
I had trouble with a cr/lf and char 7 in the cell values which I replace with nothing
## Q:\Test\2018\07\17\SO_51385204.ps1
$CsvName = '.\Test.csv'
$filename = (Get-Item ".\Test-text.docx").FullName
$tableNum = 4
$delimiter = ','
$objWord = New-Object -Com Word.Application
$objWord.Visible = $true # $false
$objDocument = $objWord.Documents.Open($filename)
$LETable = $objDocument.Tables.Item($tableNum)
$LETableCols = $LETable.Columns.Count
$LETableRows = $LETable.Rows.Count
Write-Output "Starting to write... "
# "Table rows:{0} cols:{1}" -f $LETableRows,$LETableCols
$RawCSV = for($r=1; $r -le $LETableRows; $r++) {
$content= #()
for($c=1; $c -le $LETableCols; $c++) {
#Write-Host ("R:{0},C:{1}" -f $r,$c)
$content += ("`"{0}`"" -f $LETable.Cell($r,$c).Range.Text -replace "(`r|`n|`t)|$([char]7)?")
}
$Content -join $delimiter
}
$Csv = $RawCSV | ConvertFrom-Csv
$objDocument.Close()
$objWord.Quit()
# Stop Winword Process
$rc = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objWord)
$Csv
$Csv | Export-Csv $CsvName -NoTypeInformation

use powershell socket server to get remote command

I want use a powershell socket server to get remote command.
But I only can get the remote command once.
Can someone give me a help? thanks.
Here is my code:
$endpoint = new-object System.Net.IPEndPoint([system.net.ipaddress]::any, 12346)
$listener = new-object System.Net.Sockets.TcpListener $endpoint
while($true)
{
$listener.Start()
$client = $listener.AcceptTcpClient()
[System.IO.StreamReader]$stream = new-object System.IO.StreamReader -argumentList $client.GetStream()
while($true)
{
$line = $stream.ReadLine()
while($line -ne $null){
Write-Host $line -ForegroundColor Yellow
}
}
$client.Close()
$listener.Stop()
}
The problem is that your while check ($line -ne $null) will always be true because $line is not assigned the new value after initial assignment,
try this:
$endpoint = new-object System.Net.IPEndPoint([system.net.ipaddress]::any, 12346)
$listener = new-object System.Net.Sockets.TcpListener $endpoint
while($true)
{
$listener.Start()
$client = $listener.AcceptTcpClient()
[System.IO.StreamReader]$stream = new-object System.IO.StreamReader -argumentList $client.GetStream()
while($true)
{
do {
$line = $stream.ReadLine()
Write-Host $line -ForegroundColor Yellow
}while($line -ne $null)
}
$client.Close()
$listener.Stop()
}

How do I time out a REGQUERY command in Powershell?

I am trying to find a way (maybe with a job?) to timeout system jobs. It seems my regquery will normally time out after 42 seconds if the computer is not online, and the code can't reach the registry. I am looking to limit the query to around 5 seconds as I have a tonne of computers in our environment. I have tried to play around with creating jobs, a stopwatch, etc. but no luck :( Please help!
$File = Import-Csv 'c:\temp\regcomplist.txt'
$Results=""
$text="Machine Name,Regkey Value, Runtime"
$fileout = "C:\Temp\regquery.csv"
Write-host $text
Out-File -FilePath $fileout -InputObject $text -Force
$timeout = new-timespan -Seconds 5
$swtotal = [Diagnostics.Stopwatch]::StartNew()
foreach ($line in $file)
{
TRY{
$regkey = ""
$keyValue = ""
$machinename = $line.machinename
#trap [Exception] {continue}
$key = "SYSTEM\\CurrentControlSet\\Control\\Print\\Environments\\Windows x64\\Drivers\\Version-3\\Lexmark Universal v2 XL"
$sw = [Diagnostics.Stopwatch]::StartNew()
#while ($sw.elapsed -lt $timeout){
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("LocalMachine",$MachineName)
$regkey = $reg.opensubkey($key)
$keyValue = $regKey.GetValue('Help File')
# return
#}
#start-sleep -seconds 5
#if ($ok -ne "OK"){$keyValue = "TIMED OUT: "+$sw.elapsed}
}
Catch{
$keyValue = "Error Opening Registry"
}
$text = $machinename+","+$keyValue+","+$sw.elapsed
$Results += $text
#Output Below Here:
Write-host $text
Out-File -InputObject $text -FilePath $fileout -Append
}
Write-host "Total time run:"$swtotal.elapsed
Thanks! That was exactly what I needed. I set the count to 1 ping, and it's MUCH faster than 42 second timeouts. Here is the code for anyone this might help...
$File = Import-Csv 'c:\temp\powershell\regcomplist.txt'
$Results=""
$text="Machine Name,Regkey Value, Runtime"
$fileout = "C:\Temp\powershell\regquery.csv"
Write-host $text
Out-File -FilePath $fileout -InputObject $text -Force
$timeout = new-timespan -Seconds 5
$swtotal = [Diagnostics.Stopwatch]::StartNew()
foreach ($line in $file){
$regkey = ""
$keyValue = ""
$machinename = $line.machinename
#trap [Exception] {continue}
$key = "SYSTEM\\CurrentControlSet\\Control\\Print\\Environments\\Windows x64\\Drivers\\Version-3\\Lexmark Universal v2 XL"
$sw = [Diagnostics.Stopwatch]::StartNew()
$pingtest=Test-Connection -ComputerName $machinename -Quiet -Count 1
if ($pingtest -eq $true ){
TRY{
#while ($sw.elapsed -lt $timeout){
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("LocalMachine",$MachineName)
$regkey = $reg.opensubkey($key)
$keyValue = $regKey.GetValue('Help File')
# return
#}
#start-sleep -seconds 5
#if ($ok -ne "OK"){$keyValue = "TIMED OUT: "+$sw.elapsed}
}
Catch{
$keyValue = "Error Opening Registry"
}
$text = $machinename+","+$keyValue+","+$sw.elapsed
$Results += $text
#Output Below Here:
Write-host $text
Out-File -InputObject $text -FilePath $fileout -Append
}
else {write-host $machinename",doesn't ping!"}
}
Write-host "Total time run:"$swtotal.elapsed
I use a Tcp Test before querying registry:
if((Test-ComputerPort $ComputerName 445)) {
[Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $ComputerName).OpenSubKey("SYSTEM\CurrentControlSet\Control\Session Manager\Environment").GetValue('TEMP')
}
with Test-ComputerPort() :
function Test-ComputerPort($ComputerName,$port){
try {
$ip = [System.Net.Dns]::GetHostAddresses($ComputerName).IPAddressToString # confirm DNS resolving
if([system.Net.Sockets.TcpClient]::new().BeginConnect($ComputerName, $port, $null, $null).AsyncWaitHandle.WaitOne(40, $false) -or [system.Net.Sockets.TcpClient]::new().BeginConnect($ComputerName, $port, $null, $null).AsyncWaitHandle.WaitOne(80, $false)){ # with retry if down
return $ComputerName
}
return $false # tcp-port is down !
} catch {
return $null # conputername not resolved !
}
}