PSPipe.psm1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
<#
    ===========================================================================
     Created with: SAPIEN Technologies, Inc., PowerShell Studio 2015 v4.2.93
     Created on: 28/09/2015 10:09 PM
     Created by: Wil Taylor
     Organization:
     Filename: PSPipe.psm1
    -------------------------------------------------------------------------
     Module Name: PSPipe
    ===========================================================================
#>


<#
    .SYNOPSIS
    Tests if a pipe is open.
 
    .DESCRIPTION
    Tests if a pipe is open.
 
    .INPUT
    Name of pipe to test if open or not.
 
    .PARAMETER Name
    Name of pipe to test if open or not.
 
    .OUTPUTS
    Returns $true if pipe is active or $false if its not.
 
    .EXAMPLE
    C:\> Test-PSPipe -Name "TestPipe"
 
    .EXAMPLE
    c:\> "TestPSPipe" | Test-Pipe
#>

function Test-PSPipe
{
    [CmdletBinding()]
    param ([Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [string]$Name)
    
    process
    {        
        (Get-PSPipes | where Name -eq $Name) -ne $null
    }
}

<#
    .SYNOPSIS
    Creates a new named pipe.
 
    .DESCRIPTION
    Creates a named pipe and waits for a client to connect.
 
    .PARAMETER Name
    Name to give to pipe.
 
    .OUTPUTS
    Custom pipe object that can be passed to other cmdlets in this module.
 
    .EXAMPLE
    $pipe = new-PSPipe -Name
 
#>

function New-PSPipe
{
    [CmdletBinding()]
    param ([Parameter(Mandatory=$true)][string]$Name)
    
    process
    {        
        Write-Verbose "Creating pipe server for pipe named $Name"
        $rd = [PSCustomObject]@{
            Pipe = new-object System.IO.Pipes.NamedPipeServerStream($Name, [System.IO.Pipes.PipeDirection]::InOut)
            Name = $Name
            Reader = $null
            Writer = $null
        }
        
        Write-Verbose "Waiting for client to connect..."
        
        $rd.Pipe.WaitForConnection()
        Write-Verbose "Client connect."
        
        $rd.Reader = new-object System.IO.StreamReader($rd.Pipe)
        $rd.Writer = New-Object System.IO.StreamWriter($rd.Pipe)
        $rd.Writer.AutoFlush = $true
        Write-Verbose "Attached Stream writer and reader"
        
        $rd
        Write-Verbose "Pipe ready!"
    }
}

<#
    .SYNOPSIS
    Writes a PSObject to pipe.
 
    .DESCRIPTION
    Serialises a PSObject and sends it over a pipe. PSObject will be reconstructed with Read-PSPipe.
 
    .INPUT
    PSObject to be serialised.
 
    Note: Usual psobject serialisation requirements apply.
 
    .PARAMETER Object
    Object to be seriealised.
 
    .PARAMETER Pipe
    Pipe object to write the object to. This can be created by New-PSPipe or Connect-PSPipe.
 
    .EXAMPLE
    C:\> "Hi how are you?" | Write-PSPipe -Pipe $pipe
 
    .EXAMPLE
    C:\> Write-PSPipe -Object (Get-Process) -Pipe $pipe
#>

function Write-PSPipe
{
    [CmdletBinding()]
    param
    (
        [parameter(Mandatory = $true, ValueFromPipeline = $true)]
        $Object,
        [parameter(Mandatory = $true)]
        $Pipe
    )
    
    process
    {        
        $text = $Object | ConvertTo-Base64
        $Pipe.Writer.WriteLine($text)
    }
}

<#
    .SYNOPSIS
    Reads a PSObject from a pipe.
 
    .DESCRIPTION
    deserialises psobject from a pipe and returns it.
 
    Note: Usual psobject serialisation requirements apply.
 
    .PARAMETER Pipe
    The pipe object to retrive the object from. If no pipe object exists in pipe
    powershell will wait.
 
    .OUTPUTS
    PSObject deseriealised from pipe.
 
    .EXAMPLE
    C:\> $data = Read-PSPipe -Pipe $Pipe
#>

function Read-PSPipe
{
    [CmdletBinding()]
    param ([parameter(Mandatory = $true)]
        $Pipe)
    
    process
    {    
        $Pipe.Reader.ReadLine() | ConvertFrom-Base64
    }
    
}

<#
    .SYNOPSIS
    Closes pipe.
 
    .DESCRIPTION
    Closes a pipe connection. Works on pipes created by either New-PSPipe or Connect-PSPipe
#>

function Disconnect-PSPipe
{
    [CmdletBinding()]
    param ([Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        $Object)
    process
    {
        $Object.Dispose()
    }    
}

<#
    .SYNOPSIS
    Connects to an existing pipe.
 
    .DESCRIPTION
    Connects to an existing pipe created by New-PSPipe.
 
    Warning: Do not connect to other processes pipes or you will get unexpected results.
 
    .PARAMETER Name
    Name of the pipe to connect to.
 
    Note: You don't need to pass in the full path. For pipe \\.\pipes\mypipe you would only
    need to pass in mypipe.
 
    .PARAMETER ComputerName
    The name of the computer you want to connect to. If not specified localhost is used.
 
    .OUTPUTS
    Returns a customobject which can be used with Read-PSPipe and Write-PSPipe to interact with the pipe.
 
    .EXAMPLE
    C:\> $pipe = Connect-PSPipe -Name MyPipe
 
    .EXAMPLE
    C:\> $pipe = Connect-PSPipe -Name MyPipe -ComputerName RemoteHost01
#>

function Connect-PSPipe
{
    [CmdletBinding()]
    param ([Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$ComputerName = ".")
    
    process
    {
        $rd = [pscustomobject]@{
            Pipe = new-object System.IO.Pipes.NamedPipeClientStream($ComputerName, $Name, [System.IO.Pipes.PipeDirection]::InOut,
            [System.IO.Pipes.PipeOptions]::None,
            [System.Security.Principal.TokenImpersonationLevel]::Impersonation)
            Name = $PipeName
            Reader = $null
            Writer = $null
        }
        
        $rd.Pipe.Connect()
        $rd.Reader = new-object System.IO.StreamReader($rd.Pipe)
        $rd.Writer = New-Object System.IO.StreamWriter($rd.Pipe)
        $rd.Writer.AutoFlush = $true
        $rd
    }
}

<#
    .SYNOPSIS
    Returns current active pipes on the system.
 
    .DESCRIPTION
    Returns a list of open pipes on the system. This includes pipes opened by other processes.
 
    .OUTPUTS
    Custom objects that contain the name of the pipe and its path.
 
    .EXAMPLE
    C:\> Get-PSPipe
#>

function Get-PSPipe
{
    [CmdletBinding()]
    param ()
    
    process
    {
        $pipes = [System.io.directory]::getfiles("\\.\pipe\")
        
        foreach ($p in $pipes)
        {
            [PSCustomObject]@{
                Name = $p.Replace("\\.\pipe\", "")
                Path = $p
            }
        }
    }
}

<#
    .SYNOPSIS
    Converts a PSObject ot Base64 string.
 
    .DESCRIPTION
    This function is used internally by the module to convert a psobject to a base64 string.
 
    .INPUT
    PSObject to serialise.
 
    .PARAMETER Object
    PSObject to serailise
 
    .OUTPUTS
    A base64 string that can be deserialised by ConvertFrom-Base64 back into a psobject.
 
    .EXAMPLE
    C:\> $text = Get-Process | ConvertTo-Base64
#>

function ConvertTo-Base64
{
    [CmdletBinding()]
    param ([Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        $Object)
    
    process
    {
        $data = $object | ConvertTo-Json -Compress
        $bytes = [System.Text.Encoding]::Unicode.GetBytes($data)
        [Convert]::ToBase64String($Bytes)
    }
    
}

<#
    .SYNOPSIS
    Converts Base64 string back into a PSObject.
 
    .DESCRIPTION
    Converts string created by ConvertTo-Base64 back into its deserialised PSObject.
 
    .INPUT
    Base64 encoded string of PSObject created by ConvertTo-Base64.
 
    .PARAMETER Text
    Base64 encoded string of PSObject created by ConvertTo-Base64.
 
    .OUTPUTS
    PSObject deserialised from base64 string.
 
    .EXAMPLE
    C:\> $myvar = $text | ConvertFrom-Base64
#>

function ConvertFrom-Base64
{
    [CmdletBinding()]
    param ([Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        $Text)
    
    process
    {
        $json = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($text))
        $json | ConvertFrom-Json
    }
}

Export-ModuleMember Connect-PSPipe
Export-ModuleMember ConvertFrom-Base64
Export-ModuleMember ConvertTo-Base64
Export-ModuleMember Disconnect-PSPipe
Export-ModuleMember Get-PSPipe
Export-ModuleMember New-PSPipe
Export-ModuleMember Read-PSPipe
Export-ModuleMember Test-Pipe
Export-ModuleMember Write-PSPipe