Communicate with a Powershell service executable

Hello Ironsman’s,

Is there a easy and secure way to communicate service, that’s created with Powershell Pro Tools? As a simple example:

I created a tool, that will run a code to check multiple repository’s if a package must be installed, updated or removed or skipped. It’s a small executable around 6 MB (I think), but the tool checks around 60 different packages.

This tool runs at startup and checks every 2 hours if any new package is available, but a small executable package from “6 MB x 60 packages” = “360 MB” every 2 hour and I want to try to set it up as a service.

So it doesn’t need to load the “6 MB x 60 packages” = “360 MB” every 2 hours again, and again and again. There is not a performance problem, but I think a service that’s receiving a command and outputs the result will save a lot resources and will make it faster.

And it needs to be a executable, the main deployment tools will ask the code to check a package id, on a repository and the tool will run and returns just simple a exit code (1 install, 2 update and 3 remove).

Also I can think for more scenario’s I can create and use a Powershell service to communicate with. So I hope someone have a quick and simple tip for me, before I spend hours and late night on something I think someone already knows.

Please let me know, when it’s finished I can share the code’s.

Kind regards,
ARKO

Hi Arko
I’m not sure where the communication bit comes into play, do you mean in addition to the service running every 2 hours, you would like to also have the ability to tell it to check for package updates on demand?
Cheers
Keir

1 Like

You can use Named Pipes to communicate between processes or scripts. I use it to trigger an action from a running script as a Service. Let me know if you are interested in exploring this to send you a sample code.

1 Like

Hi guys,

Thanks for the reply and I’m sorry that I didn’t reply, because some other project liked to eat all of my time…

@KG-droid
Thats also sounds like a good idea, can you explain / share both options? That will be great to know both option, so I can learn by “trial and error” what will be the best option and in which circumstances.

I think it can be useful for other members too.

@banyula

Let me know if you are interested in exploring this to send you a sample code.
That will be really great and can help me into the right direction!

I love this new Powershell life :smiling_face_with_three_hearts:

It works like this, you have a pipe server and a pipe client, the client connects to the server, and sends a string back to it. The server in your case could be your service, and the client a GUI or something that the user can trigger.

Server Script:

#Setup the Server pipe
$PipeName = "Example"
$PipeSecurity = [System.IO.Pipes.PipeSecurity]::new()
$NetworkSID = [system.Security.Principal.SecurityIdentifier]::new( [system.Security.Principal.wellknownsidType]::Networksid, $null) 
$UsersSID = [system.Security.Principal.SecurityIdentifier]::new([system.Security.Principal.wellknownsidType]:: Builtinuserssid, $null) 
$AdminsSID = [system.Security.Principal.SecurityIdentifier]:: new([System.Security.Principal.wellknownsidType]:: BuiltinAdministratorssid, $null) 
$PipeSecurity.AddAccessRule([System.IO.Pipes.PipeAccessRule]::new($NetworkSID, [System.IO.Pipes.PipeAccessRights]:: Fullcontrol, [System.Security.AccessControl.AccessControlType]:: Deny)) 
$PipeSecurity.AddAccessRule([System.IO.Pipes.PipeAccessRule]::new($AdminsSID, [System.IO.Pipes.PipeAccessRights]:: FullControl, [System.Security.AccessControl.AccessControlType]:: Allow)) 
$PipeSecurity.AddAccessRule([system.IO.Pipes.PipeAccessRule]::new($usersSID, [System.IO.Pipes.PipeAccessRights]:: FullControl, [system.Security.AccessControl.AccessControlType]::Allow))
$pipe = [System.IO.Pipes.NamedPipeServerstream]::new("\\.\pipe\$($PipeName)", [System.IO.Pipes.PipeDirection]:: Inout, 1, [System.IO.Pipes.PipeTransmissionMode]:: Message, [System.IO.Pipes.PipeOptions]::writeThrough, 1024, 1024, $PipeSecurity)

#Wait for connection
$Wait = $pipe.WaitForConnectionAsync()
$Count = 0
DO {
Start-Sleep -Seconds 1
$Count ++
} while (($Wait.Status -eq 'Running') -or ($count -gt 60))
If ($Wait.Status -ne 'RanToCompletion')
{
    #do something here
}

#Pipe Connected, wait to receive data
$sr = New-Object System.IO.StreamReader($Pipe)
$PipeReceived = $sr.ReadLine()

#Message received, close the pipe and reader
$sr.close()
$sr.dispose()
$pipe.Close()
$pipe.Dispose()

#Output what the pipe received
$PipeReceived

Client script:

#Setup the client Pipe
$PipeName = "Example"
$Pipe = New-Object System.IO.Pipes.NamedPipeClientStream("\\.\pipe\$($PipeName)")
$Pipe.Connect((New-TimeSpan -Minutes 5).TotalMilliseconds)
$sw = New-Object System.IO.StreamWriter($Pipe)
$sw.AutoFlush = $True
$sw.WriteLine("Some text here you want to send to the server Pipe")

#Message Sent, close the pipe and reader
$sw.close()
$sw.dispose()
$pipe.Close()
$pipe.Dispose()

So if you run that script in two separate powershell windows, you should see the string output on the server one from the client one. Run the Server one first, then the client one. In your actual script you would send something relevant to triggering the service to do something.

The pipe security controls what/who can use the pipe, its set to local users and admins there, and denies pipes from the network.

I have a similar code than KG-droid, so it would be redundant. The only difference is that I don’t use the async call and start a separate thread to handle timeout if no connection from client.

Besides de above, the client code can also be replaced by a DOS command:

echo [message string] > “\\.\pipe\[pipe name]”

where [pipe name] is “Example” in KG-droid example.

Thanks for sharing! I will give it a try, and let you know if I get it working!

:ok_hand: