Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import-PSGsuiteConfig failing on macOS - 7.0.0 -- All versions #263

Closed
phatmandrake opened this issue Feb 17, 2020 · 12 comments
Closed

Import-PSGsuiteConfig failing on macOS - 7.0.0 -- All versions #263

phatmandrake opened this issue Feb 17, 2020 · 12 comments
Assignees
Labels
Milestone

Comments

@phatmandrake
Copy link

phatmandrake commented Feb 17, 2020

Describe the bug

The Cmdlet completes successfully, but it only succeeds in partially importing the data. Distinctly it does set the first letter of appemail, adminemail, customerid, domain, and preference.

image

Setting the -Temporary parameter results in a successful import.

This issue doesn't seem to be happening on Windows 10.

Environment

  • OS: macOS Catalina
  • PowerShell Version: 7.0.0-rc.2
  • PSGSuite Version: 2.35.1
@scrthq
Copy link
Member

scrthq commented Feb 19, 2020

heyo @phatmandrake ! Thanks for sending this in! Just to confirm, Import-PSGSuiteConfig is failing when trying to import a config from JSON if it involves saving it back to the config file as well, otherwise using the Temporary switch to just update the $script:PSGSuite variable in the current session works fine?

If you open the config file on that Mac, do you see the same info there? Since you should have already saved it at this point, you can test by...

  1. Start a new PowerShell session
  2. Import-Module PSGSuite
  3. Show-PSGSuiteConfig

After the above, does it show the same thing you're seeing now?

If that is the only config on that machine, you can also try clearing it out and reimporting:

Remove-Item (Show-PSGSuiteConfig).ConfigPath -Force
Import-PSGSuiteConfig $configJson

@scrthq scrthq self-assigned this Feb 19, 2020
@scrthq
Copy link
Member

scrthq commented Feb 19, 2020

also - if you look at the JSON you're importing, does it have an array for the AppEmail, AdminEmail, CustomerId, Domain, and Preference values? Or is it a single string on the JSON as expected?

@phatmandrake
Copy link
Author

phatmandrake commented Feb 20, 2020

The answer to your first question is Yes.

Interestingly, the config file does not exist at the configpath.

/Users/phatmandrake/.config/powershell/AnonymousModules/PSGSuite/Configuration.psd1

It instead exists here:

/Users/phatmandrake/.config/powershell/SCRT HQ/PSGSuite/Configuration.psd1

[UPDATE:] So I deleted the file (I swear I already did this), and it now recreates it in the anticipated directory. Under SCRT HQ rather than AnonymousModules. So chased my tail on that trying to make that make sense longer than I care to admit 😅


Pretend I didn't say any of that.

I did some digging and here's what I'm finding.

Import-PSGsuiteConfig successfully imports the config file. Set-PSGsuiteConfig is called, and the information is then Encrypted with the private Encrypt function, and the config is successfully exported. Get-PSGsuiteConfig is called and this where things get murky:

Write-Verbose "Retrieved configuration '$choice'"
        if (!$NoImport) {
            $script:PSGSuite = $decryptedConfig
        }

$decryptedConfig outputs the same as the import file, so the failure seems to be stemming from the decrypt function.

I found this:

https://docs.microsoft.com/en-us/archive/blogs/besidethepoint/decrypt-secure-strings-in-powershell

The article suggest the following as an example:

        function Decrypt-SecureString {
            param( 
                [Parameter(ValueFromPipeline=$true,Mandatory=$true,Position=0)] 
                [System.Security.SecureString] $sstr
                )
                $marshal = [System.Runtime.InteropServices.Marshal]
                $ptr = $marshal::SecureStringToBSTR( $sstr )
                $str = $marshal::PtrToStringBSTR() $ptr )
                $marshal::ZeroFreeBSTR( $ptr )
                $str
            }

It is currently:

        function Decrypt {
            param($String)
            
            if ($String -is [System.Security.SecureString]) {
                [System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
                    [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR(
                        $String)
                        )
            }
            else {
                $String
            }
        }

[System.Runtime.InteropServices.Marshal]::PtrToStringAuto() for some reason in PWSH 7 this method terminates after the first character. In 5.1 and 6 this behaves as exactly as expected.

https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.ptrtostringauto?view=netframework-4.8

I haven't yet found a way around this yet, other than using PtrToStringBSTR(). This might be preferred since we know that it will always be a BSTR.

I'm not sure why most examples for this specific use case use PtrToStringAuto() really.

@phatmandrake
Copy link
Author

phatmandrake commented Feb 21, 2020

Every other char is treated as a NULL value...hmm 🤔

Related(?) dotnet/runtime#12343

@scrthq
Copy link
Member

scrthq commented Feb 21, 2020

@phatmandrake - Weird and interesting findings!!! On your JSON, is the ConfigPath listed? If it is, that should be pulled from the Export-PSGSuiteConfig process as that may be breaking import.

For the Decrypt bit, you mention PowerShell 7. Is it behaving the same way on PS7 outside of Mac? I'm not able to replicate it on PS7-rc2 on Windows 10 personally:

>> [System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
>>     [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR(
>>         (ConvertTo-SecureString 'hello' -AsPlainText -Force)
>>     )
>> )
hello

@phatmandrake
Copy link
Author

phatmandrake commented Feb 21, 2020

The config path listed was listed as the anonymousmodules path shown in my first screenshot; however, by deleting the config file in SCRT HQ I was able to re-import the configuration and have it show as being in the correct SCRT HQ path. By deleting and reimporting, I could replicate this preferred behavior multiple times. I think what happens is when there is an existing config.psd1 the path changes, but even still the modules goes to the right location (SCRT HQ) ultimately when looking for a config to load even if it lists it wrong. I also think this only happens when the config fails to load properly.

I noticed when I would Import-Module -Force that the "anonymousmodules" path would be injected after Import-SpecificConfiguration is called. Haven't dug into why it's not idempotent (boy I never thought I would get to use that word lol).

As for the decrypt bit (ha). It works just fine in Windows 10. I run macOS and Windows in a VM so I bounce between environments all day. This is only a PS7 on MacOS issue that I can tell right now.

https://stackoverflow.com/questions/11022555/manipulating-c-strings-with-multiple-null-characters-in-memory

Some of the discussion leads me to believe the issue is related to UTF-16 on MacOS I don't understand why this is now an issue when it's not in previous versions.

@scrthq
Copy link
Member

scrthq commented Feb 22, 2020

Super strange!

What version of the Configuration module do you have installed on your Mac?

Get-Module Configuration

@phatmandrake
Copy link
Author

phatmandrake commented Feb 23, 2020

Version 1.3.1 -- but the issue related to that could be because of something I did while I was searching for the PtrToStringAuto() problem. I am unable to replicate the behavior where the wrong configpath is being specified now.

RC3 has the same issue where null chars are being added between each char in the secure string on macOS, which is impacting PtrToStringAuto() to function the way we'd like on macOS.

@phatmandrake phatmandrake changed the title Import-PSGsuiteConfig failing on macOS - 7.0.0-rc.2 Import-PSGsuiteConfig failing on macOS - 7.0.0 -- All versions Feb 24, 2020
@phatmandrake
Copy link
Author

I opened an issue here: PowerShell/PowerShell#11953

@phatmandrake
Copy link
Author

phatmandrake commented Feb 26, 2020

Well @mklement0 (+1 this guy is great) confirmed the behavior for me, and reaffirmed that using PtrToStringBSTR would be most appropriate for resolving the issue in place using the existing code structure. (Along with a different approach using [NetworkCredential])

Is there any room here for adopting a new secrets model in preparation for version 7? I feel like I remember seeing something on secrets management recently 🤔

Short term it would be trivial to update the decrypt function to utilize the PtrToStringBSTR function though, but I would love to see universal encryption come to the module.

https://stackoverflow.com/questions/60404847/are-you-able-to-use-ptrtostringauto-to-decrypt-a-secure-string-in-powershell-7-o

@scrthq
Copy link
Member

scrthq commented Feb 26, 2020

Thank you @phatmandrake + @mklement0 ❤️ I'll get that change in as soon as I can!

@scrthq scrthq added the bug label Feb 27, 2020
@scrthq scrthq added this to the 2.36.0 milestone Feb 27, 2020
@scrthq scrthq mentioned this issue Feb 28, 2020
@scrthq scrthq closed this as completed in daaae47 Feb 28, 2020
@scrthq
Copy link
Member

scrthq commented Feb 28, 2020

@phatmandrake Deployed! Also just seeing your note about possibly moving to the new Secrets storage. I'm definitely interested in exploring that, but I want to ensure that being able to retrieve the configuration is reliably the same across platform. I'm keeping an eye on it though 🙂

scrthq added a commit that referenced this issue Mar 2, 2020
## 2.36.1 - 2020-03-02

* [Issue #263](#263)
    * Fixed `[SecureString]` decryption on Unix machines running PowerShell 7 (found additional bugs)
    * Migrated private `Encrypt` and `Decrypt` to `EncryptionHelpers.ps1` in the Private folder to allow a single place to update.
scrthq added a commit that referenced this issue Mar 2, 2020
## 2.36.1 - 2020-03-02

* [Issue #263](#263)
    * Fixed `[SecureString]` decryption on Unix machines running PowerShell 7 (found additional bugs)
    * Migrated private `Encrypt` and `Decrypt` to `EncryptionHelpers.ps1` in the Private folder to allow a single place to update.
scrthq added a commit that referenced this issue Mar 2, 2020
## 2.36.1 - 2020-03-02

* [Issue #263](#263)
    * Fixed `[SecureString]` decryption on Unix machines running PowerShell 7 (found additional bugs)
    * Migrated private `Encrypt` and `Decrypt` to `EncryptionHelpers.ps1` in the Private folder to allow a single place to update.
scrthq added a commit that referenced this issue Mar 3, 2020
## 2.36.2 - 2020-03-02

* [Issue #263](#263)
    * Cleaned up decryption logic for encrypted config.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants