/// <summary> /// Generate a string containing the ACK message in response to the original message. Supply a string containing the original message (or at least the MSH segment). /// </summary> /// <returns></returns> string GenerateACK(string originalMessage) { // create a HL7Message object using the original message as the source to obtain details to reflect back in the ACK message HL7Message tmpMsg = new HL7Message(originalMessage); string trigger = tmpMsg.GetHL7ItemValue("MSH-9.2")[0]; string originatingApp = tmpMsg.GetHL7ItemValue("MSH-3")[0]; string originatingSite = tmpMsg.GetHL7ItemValue("MSH-4")[0]; string messageID = tmpMsg.GetHL7ItemValue("MSH-10")[0]; string processingID = tmpMsg.GetHL7ItemValue("MSH-11")[0]; string hl7Version = tmpMsg.GetHL7ItemValue("MSH-12")[0]; string ackTimestamp = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString(); StringBuilder ACKString = new StringBuilder(); ACKString.Append((char)0x0B); ACKString.Append("MSH|^~\\&|HL7Listener|HL7Listener|" + originatingSite + "|" + originatingApp + "|" + ackTimestamp + "||ACK^" + trigger + "|" + messageID + "|" + processingID + "|" + hl7Version); ACKString.Append((char)0x0D); ACKString.Append("MSA|CA|" + messageID); ACKString.Append((char)0x1C); ACKString.Append((char)0x0D); return(ACKString.ToString()); }
private string ConstructMessageDetails(string Hl7Message) { HL7Message message = new HL7Message(Hl7Message); string[] msgID = message.GetHL7ItemValue("MSH-10"); string[] msgType = message.GetHL7ItemValue("MSH-9.1"); string[] msgTrigger = message.GetHL7ItemValue("MSH-9.2"); string msgDetailString = ""; // construct the strings if the elements exist in the message if (!((msgID == null) || (msgID.Length == 0))) { msgDetailString += "_" + msgID[0]; } if (!((msgType == null) || (msgType.Length == 0))) { msgDetailString += "_" + msgType[0]; } if (!((msgTrigger == null) || (msgTrigger.Length == 0))) { msgDetailString += "_" + msgTrigger[0]; } return(msgDetailString); }
/// <summary> /// Send each of the files provided /// </summary> protected override void ProcessRecord() { foreach (string path in paths) { // This will hold information about the provider containing the items that this path string might resolve to. ProviderInfo provider; // This will be used by the method that processes literal paths PSDriveInfo drive; // this contains the paths to process for this iteration of the loop to resolve and optionally expand wildcards. List <string> filePaths = new List <string>(); // if the path provided is a directory, expand the files in the directory and add these to the list. if (Directory.Exists(path)) { filePaths.AddRange(Directory.GetFiles(path)); } // not a directory, could be a wild-card or literal filepath else { // expand wild-cards. This assumes if the user listed a directory it is literal if (expandWildcards) { // Turn *.txt into foo.txt,foo2.txt etc. If path is just "foo.txt," it will return unchanged. If the filepath expands into a directory ignore it. foreach (string expandedFilePath in this.GetResolvedProviderPathFromPSPath(path, out provider)) { if (!Directory.Exists(expandedFilePath)) { filePaths.Add(expandedFilePath); } } } else { // no wildcards, so don't try to expand any * or ? symbols. filePaths.Add(this.SessionState.Path.GetUnresolvedProviderPathFromPSPath(path, out provider, out drive)); } // ensure that this path (or set of paths after wildcard expansion) // is on the filesystem. A wildcard can never expand to span multiple providers. if (Common.IsFileSystemPath(provider, path) == false) { // no, so skip to next path in paths. continue; } } // At this point, we have a list of paths on the filesystem, send each file to the remote endpoint foreach (string filePath in filePaths) { System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); // confirm the file exists if (!File.Exists(filePath)) { FileNotFoundException fileException = new FileNotFoundException("File not found", filePath); ErrorRecord fileNotFoundError = new ErrorRecord(fileException, "FileNotFound", ErrorCategory.ObjectNotFound, filePath); WriteError(fileNotFoundError); return; } // send the file to the endpoint using MLLP framing TcpClient tcpConnection = new TcpClient(); tcpConnection.SendTimeout = 10000; tcpConnection.ReceiveTimeout = 10000; try { // get the contents of the file string fileContents = File.ReadAllText(filePath); // save the string as a HL7Message, this will validate the file is a HL7 v2 message. HL7Message message = new HL7Message(fileContents); WriteVerbose("Connecting to " + this.hostname + ":" + this.port); // create a TCP socket connection to the reciever, start timing the elapsed time to deliver the message and receive the ACK timer.Start(); tcpConnection.Connect(this.hostname, this.port); NetworkStream tcpStream = tcpConnection.GetStream(); UTF8Encoding encoder = new UTF8Encoding(); Byte[] writeBuffer = new Byte[4096]; // get the message text with MLLP framing writeBuffer = encoder.GetBytes(message.GetMLLPFramedMessage()); tcpStream.Write(writeBuffer, 0, writeBuffer.Length); tcpStream.Flush(); WriteVerbose("Message sent"); // wait for ack unless the -NoACK switch was set string[] ackLines = null; if (!this.noACK) { WriteVerbose("Waiting for ACK ..."); Byte[] readBuffer = new Byte[4096]; int bytesRead = tcpStream.Read(readBuffer, 0, 4096); string ackMessage = encoder.GetString(readBuffer, 0, bytesRead); // look for the start of the MLLP frame (VT control character) int start = ackMessage.IndexOf((char)0x0B); if (start >= 0) { // Search for the end of the MLLP frame (FS control character) int end = ackMessage.IndexOf((char)0x1C); if (end > start) { // split the ACK message on <CR> character (segment delineter), output each segment of the ACK on a new line // remove the last <CR> character if present, otherwise the final element in the array will be empty when splitting the string string ackString = ackMessage.Substring(start + 1, end - 1); if (ackString[ackString.Length - 1] == (char)0x0D) { ackString = ackString.Substring(0, ackString.Length - 1); } ackLines = ackString.Split((char)0x0D); } } } // stop timing the operation, output the result object timer.Stop(); SendHL7MessageResult result = new SendHL7MessageResult("Successful", ackLines, DateTime.Now, message.ToString().Split((char)0x0D), this.hostname, this.port, filePath, timer.Elapsed.TotalMilliseconds / 1000); WriteObject(result); WriteVerbose("Closing TCP session\n"); tcpStream.Close(); } // if the file does not start with a MSH segment, the constructor will throw an exception. catch (ArgumentException) { ArgumentException argException = new ArgumentException("The file does not appear to be a valid HL7 v2 message", filePath); ErrorRecord fileNotFoundError = new ErrorRecord(argException, "FileNotValid", ErrorCategory.InvalidData, filePath); WriteError(fileNotFoundError); return; } // catch failed TCP connections catch (SocketException se) { ErrorRecord SocketError = new ErrorRecord(se, "ConnectionError", ErrorCategory.ConnectionError, this.hostname + ":" + this.port); WriteError(SocketError); return; } finally { tcpConnection.Close(); } // delay between sending messages if (this.delayBetweenMessages > 0) { System.Threading.Thread.Sleep(this.delayBetweenMessages * 1000); } } } }
/// <summary> /// get the HL7 item provided via the cmdlet parameter HL7ItemPosition /// </summary> protected override void ProcessRecord() { // confirm the item location parameter is valid before processing any files if (!Common.IsHL7LocationStringValid(this.itemPosition)) { ArgumentException ex = new ArgumentException(this.itemPosition + " does not appear to be a valid HL7 item"); ErrorRecord error = new ErrorRecord(ex, "InvalidElement", ErrorCategory.InvalidArgument, this.itemPosition); this.WriteError(error); return; } // confirm the filter parameter is valid before processing any files foreach (string currentFilter in this.filter) { // confirm each filter is formatted correctly if (!Common.IsFilterValid(currentFilter)) { ArgumentException ex = new ArgumentException(currentFilter + " does not appear to be a valid filter"); ErrorRecord error = new ErrorRecord(ex, "InvalidFilter", ErrorCategory.InvalidArgument, currentFilter); this.WriteError(error); return; } } // set the text encoding Encoding encoder = System.Text.Encoding.GetEncoding(this.encoding); WriteVerbose("Encoding: " + encoder.EncodingName); // expand the file or directory information provided in the -Path or -LiteralPath parameters foreach (string path in paths) { // This will hold information about the provider containing the items that this path string might resolve to. ProviderInfo provider; // This will be used by the method that processes literal paths PSDriveInfo drive; // this contains the paths to process for this iteration of the loop to resolve and optionally expand wildcards. List <string> filePaths = new List <string>(); // if the path provided is a directory, expand the files in the directy and add these to the list. if (Directory.Exists(path)) { filePaths.AddRange(Directory.GetFiles(path)); } // not a directory, could be a wildcard or literal filepath else { // expand wildcards. This assumes if the user listed a directory it is literal if (expandWildcards) { // Turn *.txt into foo.txt,foo2.txt etc. If path is just "foo.txt," it will return unchanged. If the filepath expands into a directory ignore it. foreach (string expandedFilePath in this.GetResolvedProviderPathFromPSPath(path, out provider)) { if (!Directory.Exists(expandedFilePath)) { filePaths.Add(expandedFilePath); } } } else { // no wildcards, so don't try to expand any * or ? symbols. filePaths.Add(this.SessionState.Path.GetUnresolvedProviderPathFromPSPath(path, out provider, out drive)); } // ensure that this path (or set of paths after wildcard expansion) // is on the filesystem. A wildcard can never expand to span multiple providers. if (Common.IsFileSystemPath(provider, path) == false) { // no, so skip to next path in paths. continue; } } // At this point, we have a list of paths on the filesystem, process each file. foreach (string filePath in filePaths) { // If the file does not exist display an error and return. if (!File.Exists(filePath)) { FileNotFoundException fileException = new FileNotFoundException("File not found", filePath); ErrorRecord fileNotFoundError = new ErrorRecord(fileException, "FileNotFound", ErrorCategory.ObjectNotFound, filePath); WriteError(fileNotFoundError); return; } // if the ItemPosition parameter is not in the correct format display an error and return if (!Common.IsItemLocationValid(this.itemPosition)) { ArgumentException argException = new ArgumentException("The -ItemPosition parameter does not appear to be in the correct format.", this.itemPosition); ErrorRecord parameterError = new ErrorRecord(argException, "ParameterNotValid", ErrorCategory.InvalidArgument, this.itemPosition); WriteError(parameterError); return; } // process the message try { // assume the filter is true, until a failed match is found this.filterConditionsMet = true; // load the file into a HL7Message object for processing string fileContents = File.ReadAllText(filePath, encoder); HL7Message message = new HL7Message(fileContents); // if a filter was supplied, evaluate if the file matches the filter condition if (this.filter != null) { // check to see is all of the filter conditions are met (ie AND all filters supplied). foreach (string currentFilter in this.filter) { bool anyItemMatch = false; string filterItem = Common.GetFilterItem(currentFilter); string filterValue = Common.GetFilterValue(currentFilter); // for repeating fields, only one of the items returned has to match for the filter to be evaluated as true. foreach (string itemValue in message.GetHL7ItemValue(filterItem)) { if (itemValue.ToUpper() == filterValue.ToUpper()) { anyItemMatch = true; } } // if none of the repeating field items match, then fail the filter match for this file. if (!anyItemMatch) { this.filterConditionsMet = false; } } } // if the filter supplied matches this message (or no filter provided) then process the file to optain the HL7 item requested if (filterConditionsMet) { List <HL7Item> hl7Items = message.GetHL7Item(itemPosition); // if the hl7Items array is empty, the item was not found in the message if (hl7Items.Count == 0) { WriteWarning("Item " + this.itemPosition + " not found in the message " + filePath); } // items were located in the message, so proceed with replacing the original value with the new value. else { // update all repeats/occurances of the specified item if (this.allrepeats) { foreach (HL7Item item in hl7Items) { // appeand the new value to the existing value of the item if -AppendToExistingValue switch is set if (appendValue) { this.newValue = item.ToString() + this.newValue; } // update the item value SetHL7ItemResult result = new SetHL7ItemResult(this.newValue, item.ToString(), filePath, this.itemPosition); item.SetValueFromString(this.newValue); WriteObject(result); } } // update only the first occurrance. This is the default action. else { // append the new value to the existing value of the item if -AppendToExistingValue switch is set if (appendValue) { this.newValue = hl7Items.ElementAt(0).ToString() + this.newValue; } // update the item value SetHL7ItemResult result = new SetHL7ItemResult(this.newValue, hl7Items.ElementAt(0).ToString(), filePath, this.itemPosition); hl7Items.ElementAt(0).SetValueFromString(this.newValue); WriteObject(result); } // Write changes to the file. Replace the segment delimeter <CR> with the system newline string as this is being written to a file. string cr = ((char)0x0D).ToString(); string newline = System.Environment.NewLine; if (this.ShouldProcess(filePath, "Saving changes to file")) { System.IO.File.WriteAllText(filePath, message.ToString().Replace(cr, newline), encoder); } } } } // if the file does not start with a MSH segment, the constructor will throw an exception. catch (System.ArgumentException) { ArgumentException argException = new ArgumentException("The file does not appear to be a valid HL7 v2 message", filePath); ErrorRecord invalidFileError = new ErrorRecord(argException, "FileNotValid", ErrorCategory.InvalidData, filePath); WriteError(invalidFileError); return; } } } }
/// <summary> /// Receive data from a client connection, look for MLLP HL7 message. /// </summary> /// <param name="client"></param> private void ReceiveData(object client) { // generate a random sequence number to use for the file names Random random = new Random(Guid.NewGuid().GetHashCode()); int filenameSequenceStart = random.Next(0, 1000000); TcpClient tcpClient = (TcpClient)client; NetworkStream clientStream = tcpClient.GetStream(); clientStream.ReadTimeout = TCP_TIMEOUT; clientStream.WriteTimeout = TCP_TIMEOUT; byte[] messageBuffer = new byte[4096]; int bytesRead; String messageData = ""; int messageCount = 0; while (true) { bytesRead = 0; try { // Wait until a client application submits a message bytesRead = clientStream.Read(messageBuffer, 0, 4096); } catch (Exception) { // A network error has occurred LogDebug("Connection from " + tcpClient.Client.RemoteEndPoint + " has ended"); break; } if (bytesRead == 0) { // The client has disconected LogDebug("The client " + tcpClient.Client.RemoteEndPoint + " has disconnected"); break; } // Message buffer received successfully messageData += Encoding.UTF8.GetString(messageBuffer, 0, bytesRead); // Find a VT character, this is the beginning of the MLLP frame int start = messageData.IndexOf((char)0x0B); if (start >= 0) { // Search for the end of the MLLP frame (a FS character) int end = messageData.IndexOf((char)0x1C); if (end > start) { messageCount++; try { // queue the message to sent to the passthru host if the -PassThru option has been set if (passthruHost != null) { messageQueue.Enqueue(messageData.Substring(start + 1, end - (start + 1))); } // create a HL7message object from the message recieved. Use this to access elements needed to populate the ACK message and file name of the archived message HL7Message message = new HL7Message(messageData.Substring(start + 1, end - (start + 1))); messageData = ""; // reset the message data string for the next message string messageTrigger = message.GetHL7ItemValue("MSH-9")[0]; string messageControlID = message.GetHL7ItemValue("MSH-10")[0]; //string acceptAckType = message.GetHL7Item("MSH-15")[0]; string dateStamp = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString().PadLeft(2, '0') + DateTime.Now.Day.ToString().PadLeft(2, '0') + DateTime.Now.Hour.ToString().PadLeft(2, '0') + DateTime.Now.Minute.ToString().PadLeft(2, '0'); string filename = dateStamp + "_" + (filenameSequenceStart + messageCount).ToString("D6") + "_" + messageTrigger + ".hl7"; // increment sequence number for each filename // Write the HL7 message to file. WriteMessagetoFile(message.ToString(), System.IO.Path.Combine(this.archivePath, filename)); ReceivedMessageResult resultObject = new ReceivedMessageResult(messageTrigger, System.IO.Path.Combine(this.archivePath, filename), tcpClient.Client.RemoteEndPoint.ToString()); objectQueue.Enqueue(resultObject); // send ACK message is MSH-15 is set to AL and ACKs not disbaled by -NOACK command line switch //if ((this.sendACK) && (acceptAckType.ToUpper() == "AL")) if (this.sendACK) { LogDebug("Sending ACK (Message Control ID: " + messageControlID + ")"); // generate ACK Message and send in response to the message received string response = GenerateACK(message.ToString()); // TO DO: send ACKS if set in message header, or specified on command line byte[] encodedResponse = Encoding.UTF8.GetBytes(response); // Send response try { clientStream.Write(encodedResponse, 0, encodedResponse.Length); clientStream.Flush(); } catch (Exception e) { // A network error has occurred LogDebug("An error has occurred while sending an ACK to the client " + tcpClient.Client.RemoteEndPoint); LogDebug(e.Message); break; } } } catch (Exception e) { messageData = ""; // reset the message data string for the next message LogWarning("An exception occurred while parsing the HL7 message"); LogWarning(e.Message); break; } } } } LogDebug("Total messages received:" + messageCount); clientStream.Close(); clientStream.Dispose(); tcpClient.Close(); }
/// <summary> /// get the HL7 item provided via the cmdlet parameter HL7ItemPosition /// </summary> protected override void ProcessRecord() { // confirm the item location parameter is valid before processing any files if (!Common.IsHL7LocationStringValid(this.itemPosition)) { ArgumentException ex = new ArgumentException(this.itemPosition + " does not appear to be a valid HL7 item"); ErrorRecord error = new ErrorRecord(ex, "InvalidElement", ErrorCategory.InvalidArgument, this.itemPosition); this.WriteError(error); return; } // confirm the filter parameter is valid before processing any files foreach (string currentFilter in this.filter) { // confirm each filter is formatted correctly if (!Common.IsFilterValid(currentFilter)) { ArgumentException ex = new ArgumentException(currentFilter + " does not appear to be a valid filter"); ErrorRecord error = new ErrorRecord(ex, "InvalidFilter", ErrorCategory.InvalidArgument, currentFilter); this.WriteError(error); return; } } // expand the file or directory information provided in the -Path or -LiteralPath parameters foreach (string path in paths) { // This will hold information about the provider containing the items that this path string might resolve to. ProviderInfo provider; // This will be used by the method that processes literal paths PSDriveInfo drive; // this contains the paths to process for this iteration of the loop to resolve and optionally expand wildcards. List <string> filePaths = new List <string>(); // if the path provided is a directory, expand the files in the directy and add these to the list. if (Directory.Exists(path)) { filePaths.AddRange(Directory.GetFiles(path)); } // not a directory, could be a wildcard or literal filepath else { // expand wildcards. This assumes if the user listed a directory it is literal if (expandWildcards) { // Turn *.txt into foo.txt,foo2.txt etc. If path is just "foo.txt," it will return unchanged. If the filepath expands into a directory ignore it. foreach (string expandedFilePath in this.GetResolvedProviderPathFromPSPath(path, out provider)) { if (!Directory.Exists(expandedFilePath)) { filePaths.Add(expandedFilePath); } } } else { // no wildcards, so don't try to expand any * or ? symbols. filePaths.Add(this.SessionState.Path.GetUnresolvedProviderPathFromPSPath(path, out provider, out drive)); } // ensure that this path (or set of paths after wildcard expansion) // is on the filesystem. A wildcard can never expand to span multiple providers. if (Common.IsFileSystemPath(provider, path) == false) { // no, so skip to next path in paths. continue; } } // At this point, we have a list of paths on the filesystem, process each file. foreach (string filePath in filePaths) { // If the file does not exist display an error and return. if (!File.Exists(filePath)) { FileNotFoundException fileException = new FileNotFoundException("File not found", filePath); ErrorRecord fileNotFoundError = new ErrorRecord(fileException, "FileNotFound", ErrorCategory.ObjectNotFound, filePath); WriteError(fileNotFoundError); return; } // if the ItemPosition parameter is not in the correct format display an error and return if (!Common.IsItemLocationValid(this.itemPosition)) { ArgumentException argException = new ArgumentException("The -ItemPosition parameter does not appear to be in the correct format.", this.itemPosition); ErrorRecord parameterError = new ErrorRecord(argException, "ParameterNotValid", ErrorCategory.InvalidArgument, this.itemPosition); WriteError(parameterError); return; } // process the message try { // assume the filter is true, until a failed match is found this.filterConditionsMet = true; // load the file into a HL7Message object for processing string fileContents = File.ReadAllText(filePath); HL7Message message = new HL7Message(fileContents); // if a filter was supplied, evaluate if the file matches the filter condition if (this.filter != null) { // check to see is all of the filter conditions are met (ie AND all filters supplied). foreach (string currentFilter in this.filter) { bool anyItemMatch = false; string filterItem = Common.GetFilterItem(currentFilter); string filterValue = Common.GetFilterValue(currentFilter); // for repeating fields, only one of the items returned has to match for the filter to be evaluated as true. foreach (string itemValue in message.GetHL7ItemValue(filterItem)) { // convert both values to upper case for a case insentive match if (itemValue.ToUpper() == filterValue.ToUpper()) { anyItemMatch = true; } } // if none of the repeating field items match, then fail the filter match for this file. if (!anyItemMatch) { this.filterConditionsMet = false; } } } // if the filter supplied matches this message (or no filter provided) then process the file to optain the HL7 item requested if (filterConditionsMet) { string[] hl7Items = message.GetHL7ItemValue(itemPosition); // if the hl7Items array is empty, the item was not found in the message if (hl7Items.Length == 0) { WriteWarning("Item " + this.itemPosition + " not found in the message " + filePath); } // items were returned else { SelectHL7ItemResult result = new SelectHL7ItemResult(hl7Items, filePath); WriteObject(result); } } } // if the file does not start with a MSH segment, the constructor will throw an exception. catch (System.ArgumentException) { ArgumentException argException = new ArgumentException("The file does not appear to be a valid HL7 v2 message", filePath); ErrorRecord invalidFileError = new ErrorRecord(argException, "FileNotValid", ErrorCategory.InvalidData, filePath); WriteError(invalidFileError); return; } } } }
/// <summary> /// remove identifying fields /// </summary> protected override void ProcessRecord() { // validate the that the list of locations to mask is valid. foreach (string item in this.customItemsList) { // confirm each filter is formatted correctly if (!Common.IsItemLocationValid(item)) { ArgumentException ex = new ArgumentException(item + " does not appear to be a valid HL7 location"); ErrorRecord error = new ErrorRecord(ex, "InvalidFilter", ErrorCategory.InvalidArgument, item); this.WriteError(error); return; } } // set the text encoding Encoding encoder = System.Text.Encoding.GetEncoding(this.encoding); WriteVerbose("Encoding: " + encoder.EncodingName); foreach (string path in paths) { // This will hold information about the provider containing the items that this path string might resolve to. ProviderInfo provider; // This will be used by the method that processes literal paths PSDriveInfo drive; // this contains the paths to process for this iteration of the loop to resolve and optionally expand wildcards. List <string> filePaths = new List <string>(); // if the path provided is a directory, expand the files in the directory and add these to the list. if (Directory.Exists(path)) { filePaths.AddRange(Directory.GetFiles(path)); } // not a directory, could be a wild-card or literal filepath else { if (expandWildcards) { // Turn *.txt into foo.txt,foo2.txt etc. If path is just "foo.txt," it will return unchanged. If the filepath expands into a directory ignore it. foreach (string expandedFilePath in this.GetResolvedProviderPathFromPSPath(path, out provider)) { if (!Directory.Exists(expandedFilePath)) { filePaths.Add(expandedFilePath); } } } else { // no wildcards, so don't try to expand any * or ? symbols. filePaths.Add(this.SessionState.Path.GetUnresolvedProviderPathFromPSPath(path, out provider, out drive)); } // ensure that this path (or set of paths after wildcard expansion) // is on the filesystem. A wildcard can never expand to span multiple providers. if (Common.IsFileSystemPath(provider, path) == false) { // no, so skip to next path in paths. continue; } } // At this point, we have a list of paths on the filesystem, process each file. foreach (string filePath in filePaths) { // If the file does not exist display an error and return. if (!File.Exists(filePath)) { FileNotFoundException fileException = new FileNotFoundException("File not found", filePath); ErrorRecord fileNotFoundError = new ErrorRecord(fileException, "FileNotFound", ErrorCategory.ObjectNotFound, filePath); WriteError(fileNotFoundError); return; } try { string fileContents = File.ReadAllText(filePath, encoder); HL7Message message = new HL7Message(fileContents); // if a custom list of items is provided, then mask out each nominated item if (customItemsList.Length > 0) { foreach (string item in customItemsList) { message.MaskHL7Item(item, this.maskChar); } } // otherwise mask out default items else { message.DeIdentify(this.maskChar); } char pathSeparator = System.IO.Path.DirectorySeparatorChar; string newFilename = filePath.Substring(0, filePath.LastIndexOf(pathSeparator) + 1) + "MASKED_" + filePath.Substring(filePath.LastIndexOf(pathSeparator) + 1, filePath.Length - (filePath.LastIndexOf(pathSeparator) + 1)); // if the overwrite switch is set, then use the original file name. if (this.overwriteFile) { newFilename = filePath; } // Write changes to the file. Replace the segment delimeter <CR> with the system newline string as this is being written to a file. string cr = ((char)0x0D).ToString(); string newline = System.Environment.NewLine; if (this.ShouldProcess(newFilename, "Saving changes to file")) { System.IO.File.WriteAllText(newFilename, message.ToString().Replace(cr, newline), encoder); } WriteObject("Masked file saved as " + newFilename); } // if the file does not start with a MSH segment, the constructor will throw an exception. catch (System.ArgumentException) { ArgumentException argException = new ArgumentException("The file does not appear to be a valid HL7 v2 message", filePath); ErrorRecord fileNotFoundError = new ErrorRecord(argException, "FileNotValid", ErrorCategory.InvalidData, filePath); WriteError(fileNotFoundError); return; } } } }
/// <summary> /// get the HL7 item provided via the cmdlet parameter HL7ItemPosition /// </summary> protected override void ProcessRecord() { // expand the file or directory information provided in the -Path or -LiteralPath parameters foreach (string path in paths) { // This will hold information about the provider containing the items that this path string might resolve to. ProviderInfo provider; // This will be used by the method that processes literal paths PSDriveInfo drive; // this contains the paths to process for this iteration of the loop to resolve and optionally expand wildcards. List <string> filePaths = new List <string>(); // if the path provided is a directory, expand the files in the directory and add these to the list. if (Directory.Exists(path)) { filePaths.AddRange(Directory.GetFiles(path)); } // not a directory, could be a wildcard or literal filepath else { // expand wildcards. This assumes if the user listed a directory it is literal if (expandWildcards) { // Turn *.txt into foo.txt,foo2.txt etc. If path is just "foo.txt," it will return unchanged. If the filepath expands into a directory ignore it. foreach (string expandedFilePath in this.GetResolvedProviderPathFromPSPath(path, out provider)) { if (!Directory.Exists(expandedFilePath)) { filePaths.Add(expandedFilePath); } } } else { // no wildcards, so don't try to expand any * or ? symbols. filePaths.Add(this.SessionState.Path.GetUnresolvedProviderPathFromPSPath(path, out provider, out drive)); } // ensure that this path (or set of paths after wildcard expansion) // is on the filesystem. A wildcard can never expand to span multiple providers. if (Common.IsFileSystemPath(provider, path) == false) { // no, so skip to next path in paths. continue; } } // At this point, we have a list of paths on the filesystem, process each file. foreach (string filePath in filePaths) { // If the file does not exist display an error and return. if (!File.Exists(filePath)) { FileNotFoundException fileException = new FileNotFoundException("File not found", filePath); ErrorRecord fileNotFoundError = new ErrorRecord(fileException, "FileNotFound", ErrorCategory.ObjectNotFound, filePath); WriteError(fileNotFoundError); return; } // process the message try { // load the file into a HL7Message object for processing string fileContents = File.ReadAllText(filePath); HL7Message message = new HL7Message(fileContents); // get the message trigger from MSH-9 (only interested in MSH-9.1 and MSH-9.2 - ignore any document types if included). string[] messageTrigger = message.GetHL7ItemValue("MSH-9"); string[] splitTrigger = messageTrigger[0].Split(message.ComponentDelimeter); string simplifiedTrigger; if (splitTrigger.Length > 1) { simplifiedTrigger = splitTrigger[0] + message.ComponentDelimeter + splitTrigger[1]; } else { simplifiedTrigger = splitTrigger[0]; } // get the message timestamp string[] messageDateTime = message.GetHL7ItemValue("MSH-7"); // if the hl7Items array is empty, the item was not found in the message if (messageDateTime.Length == 0) { WriteWarning("MSH-7 does not contain a value for " + filePath); } // items were returned else { string timePattern = "[0-9]{12}([0-9]{2})?"; string timezonePattern = "(?<=(/+|-))[0-9]{4}"; Match timeMatch = Regex.Match(messageDateTime[0], timePattern); Match timezoneMatch = Regex.Match(messageDateTime[0], timezonePattern); if (timeMatch.Success) { // time zone is includes if (timezoneMatch.Success) { // time includes seconds if (timeMatch.Value.Length == 14) { ShowHL7MessageTimelineResult resultListItem = new ShowHL7MessageTimelineResult(DateTime.ParseExact(timeMatch.Value + timezoneMatch.Groups[1].Value + timezoneMatch.Value, "yyyyMMddHHmmsszzzz", null), filePath, simplifiedTrigger); messageTimestampResults.Add(resultListItem); } // time only resolves to minutes else { ShowHL7MessageTimelineResult resultListItem = new ShowHL7MessageTimelineResult(DateTime.ParseExact(timeMatch.Value + timezoneMatch.Groups[1].Value + timezoneMatch.Value, "yyyyMMddHHmmzzzz", null), filePath, simplifiedTrigger); messageTimestampResults.Add(resultListItem); } } // timezone is not included else { // time includes seconds if (timeMatch.Value.Length == 14) { ShowHL7MessageTimelineResult resultListItem = new ShowHL7MessageTimelineResult(DateTime.ParseExact(timeMatch.Value, "yyyyMMddHHmmss", null), filePath, simplifiedTrigger); messageTimestampResults.Add(resultListItem); } // time only resolves to minutes else { ShowHL7MessageTimelineResult resultListItem = new ShowHL7MessageTimelineResult(DateTime.ParseExact(timeMatch.Value, "yyyyMMddHHmm", null), filePath, simplifiedTrigger); messageTimestampResults.Add(resultListItem); } } } // timestamp missing, or does not resolve down to at least minutes else { WriteWarning("Timestamp missing from " + filePath); } } } // if the file does not start with a MSH segment, the constructor will throw an exception. catch (System.ArgumentException) { ArgumentException argException = new ArgumentException("The file does not appear to be a valid HL7 v2 message", filePath); ErrorRecord invalidFileError = new ErrorRecord(argException, "FileNotValid", ErrorCategory.InvalidData, filePath); WriteError(invalidFileError); return; } } } }