C# Microsoft InformationProtection decryption error when invoking AzureInformationProtection powershell commands

2

I'm in the process of developing a C# tool that automates PowerShell calls to the AzureInformationProtection client.

The code in the main function is as follows:

if (Path.GetExtension(f) != ".msg")
    {
         VerboseOutput("Info", "operations:file:scanning:file is not an email");
        // grab file public properties and retrieve file owner
        string FileOwner = RetrieveFileOwner(f);

        VerboseOutput("Info", "operations:file:scanning:file owner found " + FileOwner);

        // // 4. Check if owner member firm matches
        if (MemberFirmMatch(FileOwner))
        {

            // 3. If MF matches, invoke decryption routine
            VerboseOutput("Info", "operations:file:decrypting:start");
            DecryptFile2(f, DestinationPath);
        }
        else
        {
             // 7. If member firm DOES NOT match DO NOT decrypt
             VerboseOutput("Info", "operations:file:skipping:member firm does not match");
             Globals.SKIPPED_FILES += 1;
         }
    }

For illustration the code for the RetrieveFileOwner function is as follows:

   // method to retrieve a file owner by leveraging Get-AIPFileStatus command
    private static string RetrieveFileOwner(string FilePath)
    {
        try
        {

            using (PowerShell PowerShellInstance = PowerShell.Create())
            {
                // use "AddScript" to add the contents of a script file to the end of the execution pipeline.
                // use "AddCommand" to add individual commands/cmdlets to the end of the execution pipeline.
                string cmd = String.Format("Get-AIPFileStatus -File \"{0}\"", FilePath);
                PowerShellInstance.AddScript(cmd);
                // invoke execution on the pipeline (collecting output)
                Collection<PSObject> PSOutput = PowerShellInstance.Invoke();

                if (PowerShellInstance.Streams.Error.Count > 0)
                {
                    Console.WriteLine(PowerShellInstance.Streams.Error[0].Exception.ToString());
                    return "";
                }

                // loop through each output object item
                foreach (PSObject outputItem in PSOutput)
                {
                    // if null object was dumped to the pipeline during the script then a null
                    // object may be present here. check for null to prevent potential NRE.
                    if (outputItem.Members["RMSOwner"].Value != null)
                    {
                        return outputItem.Members["RMSOwner"].Value.ToString();
                    }
                }
                PowerShellInstance.Dispose();
                return "";
            }
        }
        catch (System.Exception exception)
        {
            Console.WriteLine("Error:operations:file:decrypting:" + exception.Message.Replace("\n", ""));
            return "";
        }
    }

In a similar fashion the code for DecryptFile2 is as follows:

    // method to decrypt a protected file by leveraging Unprotect-RMSFile command
    private static void DecryptFile2(string FilePath, string DestinationPath)
    {
        try
        {
            using (PowerShell PowerShellInstance = PowerShell.Create())
            {
                // use "AddScript" to add the contents of a script file to the end of the execution pipeline.
                // use "AddCommand" to add individual commands/cmdlets to the end of the execution pipeline.

                string cmd = String.Format("Unprotect-RMSFile -File \"{0}\" -OutputFolder \"{1}\"", FilePath, DestinationPath);
                PowerShellInstance.AddScript(cmd);
                PowerShellInstance.Invoke();

                if (PowerShellInstance.Streams.Error.Count > 0)
                {
                    Console.WriteLine(PowerShellInstance.Streams.Error[0].Exception.ToString());
                }
                VerboseOutput("Info", "operations:file:decrypting:ok");
            }
        }
        catch (System.Exception exception)
        {
            Console.WriteLine("Error:operations:file:decrypting:" + exception.Message.Replace("\n", ""));
        }
    }

However when i run the code the following error is returned:

Microsoft.InformationProtection.Powershell.RMS.Logging.RMSException: Error decrypting test.ptxt--C:\Users\edoardogerosa\
AppData\Local\Temp\RMSProtection\1fdgsa3e.0ut\4zirtfo5.rfl\test.ptxt with error: Cannot change thread mode after it is set. HRESULT: 0x80010106 
at Microsoft.InformationProtectionAndControl.SafeNativeMethods.ThrowOnErrorCode(Int32 hrError)
at Microsoft.InformationProtection.Powershell.Core.Protection.FileProtection.IsProtected(FileSystemInfo file)
at Microsoft.InformationProtection.Powershell.Core.Protection.Decryptor.DecryptFile(Component component, FileSystemInfo file, FileUnProtectionConfig config)
at Microsoft.InformationProtection.Powershell.Core.Protection.Decryptor.Decrypt(Component component, FileUnProtectionConfig config)

I've been grappling with this error for many hours to no avail. Even changing the PowerShellInstance.Invoke(); call within the DecryptFile2 method to PowerShellInstance.BeginInvoke(); does not fix the issue.

Grateful for any help that may be offered.

c#
powershell
runtime-error
azure-information-protection
asked on Stack Overflow Sep 23, 2018 by errantbot • edited Sep 23, 2018 by errantbot

1 Answer

0

You forgot to add 'Runspace' in the namespace System.Management.Automation.Runspaces;

private static string RetrieveFileOwner(string FilePath)
{
    try
    {
        Runspace runspace = RunspaceFactory.CreateRunspace();
        runspace.Open();
        using (PowerShell PowerShellInstance = PowerShell.Create())
        {
            // use "AddScript" to add the contents of a script file to the end of the execution pipeline.
            // use "AddCommand" to add individual commands/cmdlets to the end of the execution pipeline.
            PowerShellInstance .Runspace = runspace;
            string cmd = String.Format("Get-AIPFileStatus -File \"{0}\"", FilePath);
            PowerShellInstance.AddScript(cmd);
            // invoke execution on the pipeline (collecting output)
            Collection<PSObject> PSOutput = PowerShellInstance.Invoke();

            if (PowerShellInstance.Streams.Error.Count > 0)
            {
                Console.WriteLine(PowerShellInstance.Streams.Error[0].Exception.ToString());
                return "";
            }

            // loop through each output object item
            foreach (PSObject outputItem in PSOutput)
            {
                // if null object was dumped to the pipeline during the script then a null
                // object may be present here. check for null to prevent potential NRE.
                if (outputItem.Members["RMSOwner"].Value != null)
                {
                    return outputItem.Members["RMSOwner"].Value.ToString();
                }
            }
            PowerShellInstance.Dispose();
            return "";
        }
    }
    catch (System.Exception exception)
    {
        Console.WriteLine("Error:operations:file:decrypting:" + exception.Message.Replace("\n", ""));
        return "";
    }
}


    

 
answered on Stack Overflow Nov 19, 2020 by Nabil Sakazaki Gayl

User contributions licensed under CC BY-SA 3.0