Author Posts

February 1, 2018 at 8:22 am

Hi

A former colleague created a module for the company that did various bits and pieces. He left the company a while back and no one else really knows PowerShell. I know some basic stuff but that is all.

The issue is when attempting to run this function:

Function Restore-CompanySoftDeletedMailboxes {
    

    [cmdletbinding(
    )]

    Param(
        $ModifyUsername=$false,
        
        $TenantId
    )

    Begin {
        365CmdletInit
    } #end Begin

    Process {
        
        # Get the onmicrosoft.com domain as a string
        $MsolDomains = Get-MsolDomain

        # This regex matches .onmicrosoft.com where  does not include a dot.
        $regex = '^[^.]*\.onmicrosoft\.com$'
        $Domain = $MsolDomains |
            Where-Object Name -Match $regex |
            Select-Object -ExpandProperty Name |
            Select-Object -First 1

        if (-not $Domain) {
            throw "No onmicrosoft.com domain found"
        }

        # Get all soft deleted mailboxes
        $Mailboxes = Get-Mailbox -SoftDeletedMailbox

        foreach ($mailbox in $Mailboxes) {
            
            $Alias = $mailbox.Alias
            Write-Verbose "[Restore-CompanySoftDeletedMailboxes] Found soft deleted mailbox: $Alias"
            
            if ($ModifyUsername) {
                # Generate the new username - leaver_alias@domain.onmicrosoft.com
                $Username = 'leaver_{0}@{1}' -F $Alias,$Domain
                Write-Verbose "[Restore-CompanySoftDeletedMailboxes] New Username: $Username"
            } else {
                # Generate the new username - alias@domain.onmicrosoft.com
                $Username = '{0}@{1}' -F $Alias,$Domain
                Write-Verbose "[Restore-CompanySoftDeletedMailboxes] New Username: $Username"
            } #end else

            # Restoring the deleted mailbox creates an In Cloud user account
            # Undo-SoftDeletedMailbox screws up badly if it has a bad password
            # So we start with a "safe" password (terrible to use the same for all mailboxes).
            # This should be changed later.
            $Password = "22fvghRff3
            34t23a!"
            $SecurePassword = (ConvertTo-SecureString -String $Password -AsPlainText -Force)
    
            Write-Verbose "[Restore-CompanySoftDeletedMailboxes] Undoing soft-delete..."
            Undo-SoftDeletedMailbox $mailbox.alias -WindowsLiveID $username -Password $SecurePassword

            

        } #end foreach ($mailbox in $Mailboxes)

        Write-Warning "You should change the passwords for all restored mailboxes immediately.  Set-CompanyLeaverMailbox will set a random password for you."

    } #end Process

} #end Function Set-CompanyLeaver

We get this error:

Error on proxy command 'Undo-SoftDeletedMailbox -WindowsLiveID:'user@company.onmicrosoft.com' -Password:'System.Security.SecureString' -SoftDeletedObject:'user' -Confirm:$False' to server
AM2PR07MB0804.eurprd07.prod.outlook.com: Server version 15.20.0464.0000, Proxy method PSWS:
Cmdlet error with following error message:
System.Management.Automation.ParentContainsErrorRecordException: Cannot process argument transformation on parameter 'Password'. Cannot convert the "System.Security.SecureString" value of type "System.String" to type
"System.Security.SecureString"...
    + CategoryInfo          : NotSpecified: (:) [Undo-SoftDeletedMailbox], CmdletProxyException
    + FullyQualifiedErrorId : Microsoft.Exchange.Configuration.CmdletProxyException,Microsoft.Exchange.Management.RecipientTasks.UndoSoftDeletedMailbox
    + PSComputerName        : outlook.office365.com

I'm not sure what is wrong with it, my Google search though admittedly brief didn't yield the answer I need.

Any help would be greatly appreciated.

February 1, 2018 at 6:36 pm

That is not an "issue," that is a "problem." Magazines have issues.

The problem is that you're passing a password as a plain-text string, and the command wants a SecureString (e.g., ConvertTo-SecureString).

Reading tour code, $SecurePassword -should- be a SecureString, but that's where I'd start troubleshooting. Drop a breakpoint right after $SecurePassword is created, and then in debug mode pipe $SecurePassword to Get-Member to confirm the data type in the variable.

February 1, 2018 at 6:39 pm

Could be a problem with the line break in the password string. Get rid of line 56 and have the whole password on line 55.

February 1, 2018 at 6:40 pm

Oh, indeed – I'd assumed that was just a paste issue here in the forum, but if that's how the script is, then it's borking your code.

February 1, 2018 at 7:01 pm

Don't you mean a "problem" Don?

February 1, 2018 at 7:02 pm

No, that'd be an issue. Like, when you sneeze "ISH-SHOOO!" while pressing Ctrl+V and you mess up the paste.

February 2, 2018 at 11:37 am

Line 56 was an error on my part while editing the code to post here.

It took me a while because I didn't know how to use breakpoints and I stupidly kept trying to run it as a script but I managed to do as you suggested Don.

$SecurePassword | Get-Member


   TypeName: System.Security.SecureString

Name         MemberType Definition                                
----         ---------- ----------                                
AppendChar   Method     void AppendChar(char c)                   
Clear        Method     void Clear()                              
Copy         Method     securestring Copy()                       
Dispose      Method     void Dispose(), void IDisposable.Dispose()
Equals       Method     bool Equals(System.Object obj)            
GetHashCode  Method     int GetHashCode()                         
GetType      Method     type GetType()                            
InsertAt     Method     void InsertAt(int index, char c)          
IsReadOnly   Method     bool IsReadOnly()                         
MakeReadOnly Method     void MakeReadOnly()                       
RemoveAt     Method     void RemoveAt(int index)                  
SetAt        Method     void SetAt(int index, char c)             
ToString     Method     string ToString()                         
Length       Property   int Length {get;}                         

I did also try making this amendment to the code:

            $Password = ConvertTo-SecureString "22fvghRff334t23a!" -AsPlainText -Force
    
            Write-Verbose "[Restore-CompanySoftDeletedMailboxes] Undoing soft-delete..."
            Undo-SoftDeletedMailbox $mailbox.alias -WindowsLiveID $username -Password $Password

But that didn't seem to work either. I'm just puzzled to why this did work and now it doesn't, we've just not needed to use it for a few months. I am truly out of my depth with this but I guess it's going to be a good learning experience.