Microsoft.PowerShell.ISECommon A strongly-typed resource class, for looking up localized strings, etc. Returns the cached ResourceManager instance used by this class. Overrides the current thread's CurrentUICulture property for all resource lookups using this strongly typed resource class. Looks up a localized string similar to To open multiple files, provide a single list of individual file names that are separated by commas.. Looks up a localized string similar to Provide a value for the following option: {0}.. Looks up a localized string similar to Unable to retrieve the full path corresponding to the following name: {0}.. Looks up a localized string similar to There is no option with the following name: {0}.. Helper that parses command line arguments Help switch string Smallest unambiguous substring of the Help switch Alternative for the help switch string mta switch string Smallest unambiguous substring of the mta switch noprofile switch string Smallest unambiguous substring of the noprofile switch Files switch string Smallest unambiguous substring of the Files switch value indicating whether we are using the MTA option in PowerShellTabs Value indicating we should not run the profile value indicating whether we run the profile for PowerShellTabs Files passed to the command line Value indicating the -file option has already been processed Parses the arguments setting the value used in internal properties of this class command line arguments For any parsing error. Returns true if matches . The argument (no dash) we want to check for matches The switch candidate like "help" The smallest substring of switchCandidate that is large enough to disambiguate switchCandidate from any other switch true if matches . Gets the full path corresponding to filePath or null if it could not be retrieved path we want to retrieve the full path from the full path corresponding to filePath or null if it could not be retrieved Adds currentFile to the list if able to retrieve a full path from it otherwise returns an error message file to be added to the list null if there were no errors Splits commaSeparatedFiles into the individual files list of files separated by comma Calls GetFileNames and checks/sets hasProcessedFiles comma separated list of files Gets a value indicating whether we use the MTA option in PowerShellTabs Gets a value indicating whether we run the profile for PowerShellTabs Gets a value indicating whether we should diaplay a help message Gets the files passed to the command line Helper class defining special characters and providing char matching methods Type of dash #1 Type of dash #2 Type of dash #3 left double quotation mark right double quotation mark low double left quote used in german. Returns true if c is a dash or slash character character to check true if c is a dash or slash character Returns true if c is a double quote character character to check true if c is a double quote character Sends a message to the namemed pipe server with a file to open. The thought behind not throwing exceptions from the named pipe functionality is to go ahead with a fresh instance of GPowerShell if for some reason the named pipes did not work. This is a static class as opposed to a class that would call CreateFile in one Method/Constructor and a WriteFile in another because a client CreateFile will block the Server in a ReadFile so the client always has to follow a succeded CreateFile with a WriteFile. Client timeout in milliseconds to wait for the server to be free Pipe handle used in SendString() Event allowing tests to pause the listening stages of the server. Event allowing tests to pause untill the server is about to wait on testServerPauseEvent Tries to send a string through the pipe. That is the only relyable way to know if the server is available. A client call to CreateFile will put the server in a blocked call to ReadFile so the propper way to test the server is by both creating the file and sending a string. To just test the presence of a server this method should be called with NLStrings.PipeNoOp that will be sent to the server and ignored by the server. string to be sent true if we succeeded sending the string Informs tests it is about to wait on testClientPauseEvent by setting testPauseEvent and waits on this.testClientPauseEvent, if both events are present. Retrieves the existing pipe name or null if there is no current pipe name the existing pipe name or null if there is no current pipe name. Gets the pipe handle used in SendString Gets or sets an event allowing tests to pause the stages of the client. This should be set before calling SendString. Gets or sets an event allowing tests to pause untill the client is about to wait on testClientPauseEvent. This should be set before calling SendString. Interop methods, constants and structures needed for named pipes. The pipe is bi-directional; both server and client processes can read from and write to the pipe. This mode gives the server the equivalent of GENERIC_READ and GENERIC_WRITE access to the pipe. The client can specify GENERIC_READ or GENERIC_WRITE, or both, when it connects to the pipe using the CreateFile function. The flow of data in the pipe goes from server to client only. This mode gives the server the equivalent of GENERIC_WRITE access to the pipe. The client must specify GENERIC_READ access when connecting to the pipe. If the client must change pipe settings by calling the SetNamedPipeHandleState function, the client must specify GENERIC_READ and FILE_WRITE_ATTRIBUTES access when connecting to the pipe. The flow of data in the pipe goes from client to server only. This mode gives the server the equivalent of GENERIC_READ access to the pipe. The client must specify GENERIC_WRITE access when connecting to the pipe. If the client must read pipe settings by calling the GetNamedPipeInfo or GetNamedPipeHandleState functions, the client must specify GENERIC_WRITE and FILE_READ_ATTRIBUTES access when connecting to the pipe. Data is written to the pipe as a stream of bytes. This mode cannot be used with PIPE_READMODE_MESSAGE. Data is written to the pipe as a stream of messages. This mode can be used with either PIPE_READMODE_MESSAGE or PIPE_READMODE_BYTE. Mode used for Asynchronous IO Blocking mode is enabled. When the pipe handle is specified in the ReadFile, WriteFile, or ConnectNamedPipe function, the operations are not completed until there is data to read, all data is written, or a client is connected. Use of this mode can mean waiting indefinitely in some situations for a client process to perform an action. Nonblocking mode is enabled. In this mode, ReadFile, WriteFile, and ConnectNamedPipe always return immediately. Note that nonblocking mode is supported for compatibility with Microsoft LAN Manager version 2.0 and should not be used to achieve asynchronous I/O with named pipes. Data is read from the pipe as a stream of bytes. This mode can be used with either PIPE_TYPE_MESSAGE or PIPE_TYPE_BYTE. Data is read from the pipe as a stream of messages. This mode can be only used if PIPE_TYPE_MESSAGE is also specified. Connections from remote clients can be accepted and checked against the security descriptor for the pipe. Connections from remote clients are automatically rejected. Constant that can be used in the nMaxInstances parameter of CreateNamedPipe. Error result when the message is longer than the read buffer or when the size of the data passes the 64K named pipe write limit There is a process on other end of the pipe. Overlapped I/O event is not in a signaled state. Overlapped I/O operation is in progress. The pipe is being closed. The pipe has been ended. error returned when a pipe exists but all instances are busy. Infinite timeout Specifies that the desired access is read Specifies that the desired access is write Specifies that the desired access is execute Specifies that the desired access is all Creates a new file. If the specified file exists, the function fails and the last-error code is set to ERROR_FILE_EXISTS (80). Creates a new file, always. If the specified file exists, the function overwrites the file, clears the existing attributes, combines the specified file attributes and flags with FILE_ATTRIBUTE_ARCHIVE, but does not set the security descriptor that the SECURITY_ATTRIBUTES structure specifies. The function succeeds and last-error code is set to ERROR_ALREADY_EXISTS (183). Opens a file. If the specified file does not exist, the function fails and the last-error code is set to ERROR_FILE_NOT_FOUND (2). For more information, see the Remarks section of this topic. Opens a file, always. If the specified file does not exist, the function creates a file as if dwCreationDisposition is CREATE_NEW. If the specified file exists, the function succeeds and last-error code is set to ERROR_ALREADY_EXISTS (183). Opens a file and truncates it so that its size is zero (0) bytes. If the specified file does not exist, the function fails and the last-error code is set to ERROR_FILE_NOT_FOUND (2). The calling process must open the file with the GENERIC_WRITE access right. Constant used to query for token information Constant specifying the token group attribute corresponding to the logon sid Constant used to retrieve the token groups Creates an instance of a named pipe and returns a handle for subsequent pipe operations. A named pipe server process uses this function either to create the first instance of a specific named pipe and establish its basic attributes or to create a new instance of an existing named pipe. The unique pipe name. This string must have the following form: \\.\pipe\pipename The open mode. The function fails if dwOpenMode specifies anything other than 0 or the flags in "pipe open mode" below. The pipe mode. The function fails if dwPipeMode specifies anything other than 0 or the flags listed in "pipe mode" below. The maximum number of instances that can be created for this pipe. The first instance of the pipe can specify this value; the same number must be specified for other instances of the pipe. Acceptable values are in the range 1 through PIPE_UNLIMITED_INSTANCES (255). The number of bytes to reserve for the output buffer. The number of bytes to reserve for the input buffer. The default time-out value, in milliseconds, if the WaitNamedPipe function specifies NMPWAIT_USE_DEFAULT_WAIT. Each instance of a named pipe must specify the same value. A pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new named pipe and determines whether child processes can inherit the returned handle. If lpSecurityAttributes is NULL, the named pipe gets a default security descriptor and the handle cannot be inherited. If the function succeeds, the return value is a handle to the server end of a named pipe instance. If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError. Retrieves the results of an overlapped operation on the specified file, named pipe, or communications device. A handle to the file, named pipe, or communications device. This is the same handle that was specified when the overlapped operation was started by a call to the ReadFile, WriteFile, ConnectNamedPipe, TransactNamedPipe, DeviceIoControl, or WaitCommEvent function. A pointer to an OVERLAPPED structure that was specified when the overlapped operation was started. A pointer to a variable that receives the number of bytes that were actually transferred by a read or write operation. For a TransactNamedPipe operation, this is the number of bytes that were read from the pipe. For a DeviceIoControl operation, this is the number of bytes of output data returned by the device driver. For a ConnectNamedPipe or WaitCommEvent operation, this value is undefined. If this parameter is TRUE, the function does not return until the operation has been completed. If this parameter is FALSE and the operation is still pending, the function returns FALSE and the GetLastError function returns ERROR_IO_INCOMPLETE. If the function succeeds, the return value is true. If the function fails, the return value is false. To get extended error information, call GetLastError. Retrieves the current process handle The current process handle Retrieves the current process token. process handle token access process token The current process token. Gets token information. token to retrieve information from Kind of information to retrieve information retrieved length of information to be retrieved length of information actually retrieved token information Enables a named pipe server process to wait for a client process to connect to an instance of a named pipe. A client process connects by calling either the CreateFile or CallNamedPipe function. A handle to the server end of a named pipe instance. This handle is returned by the CreateNamedPipe function. pointer to an OVERLAPPED structure. If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError. If a client connects before the function is called, the function returns zero and GetLastError returns ERROR_PIPE_CONNECTED. This can happen if a client connects in the interval between the call to CreateNamedPipe and the call to ConnectNamedPipe. In this situation, there is a good connection between client and server, even though the function returns zero. Waits until either a time-out interval elapses or an instance of the specified named pipe is available for connection (that is, the pipe's server process has a pending ConnectNamedPipe operation on the pipe). The name of the named pipe. The string must include the name of the computer on which the server process is executing. A period may be used for the servername if the pipe is local. The following pipe name format is used: \\servername\pipe\pipename The number of milliseconds that the function will wait for an instance of the named pipe to be available. You can used one of the following values instead of specifying a number of milliseconds. If an instance of the pipe is available before the time-out interval elapses, the return value is nonzero. If an instance of the pipe is not available before the time-out interval elapses, the return value is zero. To get extended error information, call GetLastError. Disconnects the server end of a named pipe instance from a client process. A handle to an instance of a named pipe. This handle must be created by the CreateNamedPipe function. If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError. Closes an open object handle. A valid handle to an open object. If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError. If the application is running under a debugger, the function will throw an exception if it receives either a handle value that is not valid or a pseudo-handle value. This can happen if you close a handle twice, or if you call CloseHandle on a handle returned by the FindFirstFile function. Reads data from a file, and starts at the position that the file pointer indicates. You can use this function for both synchronous and asynchronous operations. A handle to the file to be read. The file handle must be created with the GENERIC_READ access right. For more information, see File Security and Access Rights. For asynchronous read operations, hFile can be any handle that is opened with the FILE_FLAG_OVERLAPPED flag by the CreateFile function, or a socket handle returned by the socket or accept function. A pointer to the buffer that receives the data read from a file. The maximum number of bytes to be read. A pointer to the variable that receives the number of bytes read. If lpOverlapped is NULL, lpNumberOfBytesRead cannot be NULL. If lpOverlapped is not NULL, lpNumberOfBytesRead can be NULL. A pointer to an OVERLAPPED structure. This structure is required if hFile is created with FILE_FLAG_OVERLAPPED. The ReadFile function returns when one of the following conditions occur: A write operation completes on the write end of the pipe. The number of bytes requested is read. An error occurs. If the function succeeds, the return value is nonzero. If the function fails, the return value is zero (0). To get extended error information, call GetLastError. If the return value is nonzero and the number of bytes read is zero (0), the file pointer is beyond the current end of the file at the time of the read operation. However, if the file is opened with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, the return value is zero (0) and GetLastError returns ERROR_HANDLE_EOF when the file pointer goes beyond the current end of file. Writes data to the specified file at the position specified by the file pointer. This function is designed for both synchronous and asynchronous operation. A handle to the file. The file handle must have been created with the GENERIC_WRITE access right. For more information, see File Security and Access Rights. A pointer to the buffer containing the data to be written to the file. The number of bytes to be written to the file. A value of zero specifies a null write operation. The behavior of a null write operation depends on the underlying file system. To truncate or extend a file, use the SetEndOfFile function. Named pipe write operations across a network are limited to 65,535 bytes. A pointer to the variable that receives the number of bytes written. WriteFile sets this value to zero before doing any work or error checking. If lpOverlapped is NULL, lpNumberOfBytesWritten cannot be NULL. If lpOverlapped is not NULL, lpNumberOfBytesWritten can be NULL. If this is an overlapped write operation, you can get the number of bytes written by calling GetOverlappedResult. If hFile is associated with an I/O completion port, you can get the number of bytes written by calling GetQueuedCompletionStatus. If I/O completion ports are used and you are using a callback routine to free the memory allocated to the OVERLAPPED structure pointed to by the lpOverlapped parameter, specify NULL as the value of this parameter to avoid a memory corruption problem during the deallocation. This memory corruption problem will cause an invalid number of bytes to be returned in this parameter. A pointer to an OVERLAPPED structure. This structure is required if hFile was opened with FILE_FLAG_OVERLAPPED. If hFile was opened with FILE_FLAG_OVERLAPPED, the lpOverlapped parameter must not be NULL. It must point to a valid OVERLAPPED structure. If hFile was opened with FILE_FLAG_OVERLAPPED and lpOverlapped is NULL, the function can incorrectly report that the write operation is complete. If hFile was opened with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, the write operation starts at the offset specified in the OVERLAPPED structure and WriteFile may return before the write operation has been completed. In this case, WriteFile returns FALSE and the GetLastError function returns ERROR_IO_PENDING. This allows the calling process to continue processing while the write operation is being completed. The event specified in the OVERLAPPED structure is set to the signaled state upon completion of the write operation. The caller must adjust the position of the file pointer upon completion. If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError. Creates or opens a file, file stream, directory, physical disk, volume, console buffer, tape drive, communications resource, mailslot, or named pipe. The function returns a handle that can be used to access the object. The name of the object to be created or opened. In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path. For more information, see Naming a File. For information on special device names, see Defining an MS-DOS Device Name. To specify a COM port number greater than 9, use the following syntax: "\\.\COM10". This syntax works for all port numbers and hardware that allows COM port numbers to be specified. To create a file stream, specify the name of the file, a colon, and then the name of the stream. For more information, see File Streams. The access to the object, which can be read, write, or both. You cannot request an access mode that conflicts with the sharing mode that is specified in an open request that has an open handle. If this parameter is zero (0), the application can query file and device attributes without accessing a device. This is useful for an application to determine the size of a floppy disk drive and the formats it supports without requiring a floppy in a drive. It can also be used to test for the existence of a file or directory without opening them for read or write access. See the "CreateFile desired access" below. The sharing mode of an object, which can be read, write, both, or none. You cannot request a sharing mode that conflicts with the access mode that is specified in an open request that has an open handle, because that would result in the following sharing violation: ERROR_SHARING_VIOLATION. If this parameter is zero (0) and CreateFile succeeds, the object cannot be shared and cannot be opened again until the handle is closed. For more information, see the Remarks section of this topic. The sharing options remain in effect until you close the handle to an object. To enable a process to share an object while another process has the object open, use a combination of one or more of the following values to specify the access mode they can request to open the object. A pointer to a SECURITY_ATTRIBUTES structure that determines whether or not the returned handle can be inherited by child processes. If lpSecurityAttributes is NULL, the handle cannot be inherited. The lpSecurityDescriptor member of the structure specifies a security descriptor for an object. If lpSecurityAttributes is NULL, the object gets a default security descriptor. The access control lists (ACL) in the default security descriptor for a file or directory are inherited from its parent directory. The target file system must support security on files and directories for this parameter to have an effect on them, which is indicated when GetVolumeInformation returns FS_PERSISTENT_ACLS. CreateFile ignores lpSecurityDescriptor when opening an existing file, but continues to use the other structure members. An action to take on files that exist and do not exist. See "CreateFile creation disposition" below The file attributes and flags. This parameter can include any combination of the file attributes. All other file attributes override FILE_ATTRIBUTE_NORMAL. When CreateFile opens a file, it combines the file flags with existing file attributes, and ignores any supplied file attributes. A handle to a template file with the GENERIC_READ access right. The template file supplies file attributes and extended attributes for the file that is being created. This parameter can be NULL. When opening an existing file, CreateFile ignores the template file. When opening a new EFS-encrypted file, the file inherits the DACL from its parent directory. If the function succeeds, the return value is an open handle to a specified file. If a specified file exists before the function call and dwCreationDisposition is CREATE_ALWAYS or OPEN_ALWAYS, a call to GetLastError returns ERROR_ALREADY_EXISTS, even when the function succeeds. If a file does not exist before the call, GetLastError returns zero (0). If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError. Sets the specified event object to the signaled state. A handle to the event object. The CreateEvent or OpenEvent function returns this handle. The handle must have the EVENT_MODIFY_STATE access right. For more information, see Synchronization Object S ecurity and Access Rights. If the function succeeds, the return value is true. If the function fails, the return value is false. To get extended error information, call GetLastError. Creates or opens a named or unnamed event object. A pointer to a SECURITY_ATTRIBUTES structure. If this parameter is NULL, the handle cannot be inherited by child processes. If this parameter is TRUE, the function creates a manual-reset event object, which requires the use of the ResetEvent function to set the event state to nonsignaled. If this parameter is FALSE, the function creates an auto-reset event object, and system automatically resets the event state to nonsignaled after a single waiting thread has been released. If this parameter is TRUE, the initial state of the event object is signaled; otherwise, it is nonsignaled. The name of the event object. The name is limited to MAX_PATH characters. Name comparison is case sensitive. If the function succeeds, the return value is a handle to the event object. If the named event object existed before the function call, the function returns a handle to the existing object and GetLastError returns ERROR_ALREADY_EXISTS. If the function fails, the return value is NULL. To get extended error information, call GetLastError. Waits until one or all of the specified objects are in the signaled state or the time-out interval elapses. The number of object handles in the array pointed to by lpHandles. The maximum number of object handles is MAXIMUM_WAIT_OBJECTS. An array of object handles.The array can contain handles to objects of different types. I t may not contain multiple copies of the same handle. If one of these handles is closed while the wait is still pending, the function's behavior is undefined.The handles must have the SYNCHRONIZE access right. For more information, see Standard Access Rights. If this parameter is TRUE, the function returns when the state of all objects in the lpHandles array is signaled. If FALSE, the function returns when the state of any one of the objects is set to signaled. In the latter case, the return value indicates the object whose state caused the function to return. The time-out interval, in milliseconds. The function returns if the interval elapses, even if the conditions specified by the bWaitAll parameter are not met. If dwMilliseconds is zero, the function tests the states of the specified objects and returns immediately. If dwMilliseconds is INFINITE, the function's time-out interval never elapses. If the function succeeds, the return value indicates the event that caused the function to return. It can be one of the following values. (Note that WAIT_OBJECT_0 is defined as 0 and WAIT_ABANDONED_0 is defined as 0x00000080L.) Sid and attributes structure. A pointer to a SID structure. Specifies attributes of the SID. This value contains up to 32 one-bit flags. Its meaning depends on the definition and use of the SID. This is not equivalent to TOKEN_GROUPS For that we would need Groups to be defined as: [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] To reflect the legacy ANYSIZE_ARRAY but that would only allow us to read the first array element. Count of groups PlaceHolder for the real IntPtr retrieved by doing some calculation This is the structure returned from a GetTokenInformation asking for TokenGroups Count of groups ARRAY_ANYSIZE is the actual unmanaged size, which is defined as 1 Security attributes The size, in bytes, of this structure. Set this value to the size of the SECURITY_ATTRIBUTES structure. A pointer to a security descriptor for the object that controls the sharing of it. A Boolean value that specifies whether the returned handle is inherited when a new process is created. Initializes a new instance of the SECURITY_ATTRIBUTES class SafeHandle class for named pipes Prevents a default instance of the NamedPipeSafeHandle class from being created. Calls NativeMethods.CloseHandle(handle) the return of NativeMethods.CloseHandle(handle) Listens to a specific named pipe for messages to open new files. Error treatment: The thoght behind not throwing exceptions from the named pipe functionality is to go ahead with a fresh instance of PowerShell ISE if, for some reason, the named pipes did not work. Client and Server Dynamic: Each instance that receives no file name as a parameter starts a new server. If the instance received a file name as a parameter, it will try to send the file name to an existing instance. If it succeded, it terminates itself before creating a window. If it did not succede, it creates a new window and a new server, so that any window of the ISE that is UP has a server running. This means that when an instance of powershell_ise.exe is closed, any other instance still running, will be listening for future files sent to the pipe. A client never just opens the pipe. It always opens the pipe and sends a string since an open will cause the server to get out of its ConnectNamedPipe and go to its ReadFile which would make it unavailable to recieve further connection/mesages. Pipe Security: The pipe has to be secured with the current logon sid, since the same user can use remote desktop to connect to the same machine (at least in Windows Server 2003). This is the recommended way to secure named pipes in the Named Pipe documentation. IntPtr.Zero would cause even other users logged on to the same box to be able to open the pipe and send file names to be opened on the instance of powershell.exe runing under the current user. Pipe Name: Because the pipe is secured with the logon sid, the same name, like "PowerShellISEPipeName" cannot be used for the pipe in all logon sids. This would cause the second user logged on to get access denied to the pipe, which would mean it would not be able to create a pipe server, and would not be able to receive pipe messages. We could name the pipe with the logon sid, but it is unclear if this is priviledged information and pipe names are very public. The recommendation to prevent pipe name squatting is to use a guid for the name, but the name also has to be published to the pipe clients. The solution is to create a file in a well known place that publishes the name of the pipe. The file path includes the logon sid, so clients within that logon sid have a per logon session place to look for the current pipe name. The fact that the file is opened under the application local storage of the current user (the file has access rights to the current user) will prevent other users to see the logon sid of the current user. HKCU in the registry would also work. All servers share the same pipe name except for the detail below. Detail on the pipe name: There are 2 pipe names actually, since if we are running as admin, a different name is used than when running as a regular user. This is not a security feature, but it lets "powershell_ise.exe filename.ps1" send filename.ps1 to an admin powershell_ise.exe when it is started from an application running as admin, which is a nice feature. Clearing up the file used to publish the logon name: Each server cannot directly delete the file that publishes the pipe name, since other servers might be answering for the same pipe name (See Client and Server Dynamic). This means that each server increments a reference count to the file (which is actually maintained inside the file). When the count is zero (or one before the decrement) the file can be deleted. When the file is deleted, if the file parent's directory (which is named after the logon sid) has no other files (it can have up to 2 files, one for admin and another for non admin as mentioned in the Pipe Name session detail), it is also deleted. If, when a server starts it could not send a message to an existing server, it will assume it is the first server and reset the reference count in the file that publishes the pipe name to 1. This allows for a new instance to delete previous files created by other instances (in the same logon session) that have been terminated forcefully before decrementing their reference count. Stopping the server operation: The NamedPipeServer is asynchronous and yet it is not. It is asynchronous because it uses the overlapped structure that makes it asynchronous. It is not asynchronous because after each operation it locks on a WaitForMultipleObjects that is going to have 2 handles: the pipeHandle and the cacelEvent handle. The only reason why this code deals with the extra trouble of asynchronous IO is to be able to set the stopListeningEvent and abort the server listening process. A synchronous server has the issue of getting locked in a ConnectToNamedPipe or in a ReadFile. Once it is locked, the thread cannot be stopped and the exe hangs arround. Previous synchronous alternatives that caused problems where: 1) Set a flag and use the client to connect and send data through the pipe so that the server gets out of its synchronous calls. This fails when we have more than one instance since the pipe has the same name and another instance might get the client message. 2) Set a flag and then use the CancelSynchronousIO API. This worked fine, but this API is not available in XP and CancelIO, which is available in XP did not work. Using unmanaged API's to abort the managed thread was not even tried because it sounded risky. The .NET 3.5 API's with the same asynchronous logic used here (waiting on 2 events) also worked fine in tests and produced simpler code. .NET 3.5 was not used in the exe because it is supposed to check for .NET presence. We did not move the client and server to the DLL because it would take the same startup time (mostly depending on DLL loading) to start up a client. Moving just the server side to the DLL would have worked, but having half the solution in interop and half in .NET is not ideal. Alternatives to consider in the future: - One name per server can allow more predictability on what server receives the client messages (there is none right now) but the cleaning up of the files not propperly deleted by their ow n servers might requiring sending a message to each pipe instead of the current one messag e to the current pipe we send in the beginning to reset the pipe name reference count. .NET 3.5 SP1 has NamedPipe API's that might simplify some of this code and make the asynchronous pipe easier to write, but most of the complexity here dealing with the files that publish pipe names, will still remain. The size of the Server read buffer. .NET API's should be limited to MAX_PATH Even if file names we are passing through the pipe are larger than 512 unicode characters, multiple reads are performed in the server and multiple writes happen automatically on the client. tracer for both server and client named pipe functionality. Caches the retrieved logon sid value indicating the server/client should use a test pipe name Thread used in StartListening The event used to cancel the listening on the server Method to be called to open a file Handle to the pipe initilized after a succesfull call to CreateNamedPipe Pointer to the file used to publish the pipe name. We keep this so we can delete the file. The event used in the overlapped structure to signal events on the pipe. Event allowing tests to pause the listening stages of the server. Event allowing tests to pause untill the server is about to wait on testServerPauseEvent Callback called to communicate each result of the listening stage to test. Initializes a new instance of the NamedPipeServer class Method to be called to open files Gets the array with the path up to the logon sid. the array with the path up to the logon sid. Gets the beginning of the pipe namethat does not include a guid he beginning of the pipe namethat does not include a guid Gets the DirectoryInfo corresponding to path starting at application data or null if it does not exist path to be retrieved The DirectoryInfo corresponding to path starting at application data or null if it does not exist. Searches for a FileInfo starting with in . Directory to search for start of file name to serach for A FileInfo starting with in or null if not present. A stopListening flag is used and checked in the server loop when we want to abort the server thread. Since the server might be stopped into a synchronous IO call we interrupt that call with the unmanaged API CancelSynchronousIo. Calls CreateNamedPipe to start the server true if no previous server was detected so we can restart the reference count true if it succeded in the pipe creation Starts a thread that will run the server loop. Calls file.CreateText returning false if an exception is thrown. file to call CreateText on return value from CreateText false if an exception is thrown calling CreateText Calls file.OpenText returning false if an exception is thrown. file to call OpenText on return value from OpenText false if an exception is thrown calling OpenText Tries to get the current reference count value from file file we want to get the reference count from. returned refernece count true if succeded getting the reference count Tries to set the current reference count value in file. file we want to set the reference count. refernece count true if succeded setting the reference count Retrieves the logon sid used to secure the named pipe. The logon sid used to secure the named pipe Calls the DirectoryInfo constructor returning null if an exception was thrown. The directory is not garanteed to be created on the return of this function. Path to the directory to be created A DirectoryInfo corresponding to or null if an exception was thrown Based on an esisting creates a child directory corresponding to if it doesn't already exists. existing parent directory child path to be created The created child directory. Creates all elements in path starting at application data. path to be created The childmost Directory info or null if it could not be created. Called by the server to Create a pipe name if necesssary. The file used to publish the pipe name pipe name, or null if it could not be created. Returns true if we are running as administrator true if we are running as administrator Returns a security descriptor allowing the sid full control sid to be allowd full control a security descriptor allowing the sid full control Gets security attributes with the security descriptor. Security Descriptor security attributes with the security descriptor Deletes a file returning true if it could be deleted file to be deleted true if it could be deleted Deletes directory returning true if it could be deleted directory to be deleted true if it could be deleted Starts the loop listening to clients. This is aborted when this.StopListening() is called. Calls the testResultCallBack, if it is present. result to be passed to the callback Informs tests it is about to wait on testServerPauseEvent by setting testPauseEvent and waits on this.testServerPauseEvent, if both events are present. Called when the final string reaches the server to call this.openMethod string accumulated so far final string segment Decrements the count of servers listening to the named pipe and deletes the file that publishes the named pipe name if this is the last server tries to delete this.pipeNameFile and its parent folder if no more servers are still up advertising that file name Gets the cached logon sid Gets or sets a value indicating whether the server/client should use a test pipe name Gets or sets an event allowing tests to pause the listening stages of the server. This should be set before calling StartListening. Gets or sets an event allowing tests to pause untill the server is about to wait on testServerPauseEvent. This should be set before calling StartListening. Gets or sets a callback called to communicate each result of the listening stage to test. This should be set before calling StartListening. Results to be communicated to test test value test value test value This is one of 2 test values that cannot yet be tested since if the server is waiting and the client does the first thing it can withy the pipe, which is a CreateFile, the connection will succede. test value test value test value test value test value test value test value test value test value test value This is also untested. test value Contains all the strings that should not be localized. The comments in each field are the justification for the strings not to be localized String that is ignored when received by the pipe server. Literally: PowerShellISEPipeName PowerShell ISE NamedPipe Server Literally: \\.\pipe\ Literally: Microsoft Literally: PowerShell Literally: ISE Literally: Windows