Search code examples
powershellbase64rights-management

base64 encoded powershell "Cannot index into a null array." but runs from ISE


We're working on protecting files with RMS in our environment. We have to use PowerShell.

I can't even use WDS server with MDT joined to the domain as the psxml files it uses aren't signed.

I have to run PS scripts as single line commands or as encoded commands using the [convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($code)) line with my script wrapped in $code = {}.

This script works when run from PowerShell ISE.

$lines = Get-Content E:\folder\list.txt | Select-String -Pattern "Success Message" -AllMatches -Context 1,0 | % $_.Context.PreContext[0]
    foreach ( $line in $lines ) {
        $file = $line.ToString().TrimStart("chars. ")
        Protect-RMSFile -File $file -InPlace -DoNotPersistEncryptionKey All -TemplateID "template-ID" -OwnerEmail "[email protected]" | Out-File -FilePath E:\folder\logs\results.log -Append
        }

Batch script:

"e:\folder\command.exe -switches" > "E:\folder\list.txt" 

powershell.exe -EncodedCommand encodedBlob

Output:

Cannot index into a null array.
At line:3 char:1
+ $lines = Get-Content E:\folder\list.txt | Select-String      -Pattern "S ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

I saw on another question an exception log of some sort may be of assistance...

$Error.Exception | Where-Object -Property Message -Like "Cannot index into a null array." | Format-List -Force | Out-File -FilePath E:\folder\err.log

Output:

ErrorRecord                 : Cannot index into a null array.
StackTrace                  :    at CallSite.Target(Closure , CallSite , Object , Int32 )
                             at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
                             at System.Management.Automation.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
                             at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
                             at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
WasThrownFromThrowStatement : False
Message                     : Cannot index into a null array.
Data                        : {System.Management.Automation.Interpreter.InterpretedFrameInfo}
InnerException              : 
TargetSite                  : System.Object CallSite.Target(System.Runtime.CompilerServices.Closure, System.Runtime.CompilerServices.CallSite, System.Object, 
                              Int32)
HelpLink                    : 
Source                      : Anonymously Hosted DynamicMethods Assembly
HResult                     : -2146233087

Thinking it was something as simple as NTFS permissions, I took owner and replaced all permissions on this folder structure with admin and me full control. No change in the error.

Any tips? Am I overlooking something simple?


Solution

  • Your ForEach-Object call (% $_) doesn't make any sense and was causing the issue.

    $Lines = Select-String -LiteralPath 'E:\folder\list.txt' -Pattern 'success\smessage' -AllMatches -Context 1,0
    
    ForEach ($Line in $Lines.Context.PreContext)
    {
        $File = $Line.TrimStart('chars. ')
        Protect-RMSFile -File $File -InPlace -DoNotPersistEncryptionKey 'All' -TemplateID 'template-ID' -OwnerEmail '[email protected]' |
            Out-File -FilePath 'E:\folder\logs\results.log' -Append
    }
    

    One-liner-esque (suitable for encoding):

    SLS 'success\smessage' 'E:\folder\list.txt' -AllMatches -Context 1,0 |
      % { Protect-RMSFile -File $_.Context.PreContext.TrimStart('chars. ') -InPlace -DoNotPersistEncryptionKey 'All' -TemplateID 'template-ID' -OwnerEmail '[email protected]' |
      Out-File 'E:\folder\logs\results.log' -Append
    

    In this example, I've utilized aliases and positionally-bound parameters to make the code shorter.