-1

I have been uninstalling software via below my powerscript. But I have an issue inside powershell script. When attempting to run any software then I got the following the error message.

My error message :

PS C:\Windows\system32> doRemoveMSI -msi "msiexec.exe" -arguments "/x {EFF8AB9B-9551-4994-9FD2-D40A5A2E9B31}"
Index was outside the bounds of the array.
At line:123 char:65
+ ... Name doRemoveMSI: $msi, a0 = '$($arguments[0]),a1='$($arguments[1])'"
+                                                          ~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (:) [], IndexOutOfRangeException
    + FullyQualifiedErrorId : System.IndexOutOfRangeException
 
Remove-Symantec doRemoveMSI: msiexec.exe, a0 = '/x {EFF8AB9B-9551-4994-9FD2-D40A5A2E9B31},a1=''
Remove-Symantec doRemoveMSI: successful result is System.Diagnostics.Process, exitcode = 0
Remove-Symantec doRemoveMSI: success, return = 0
Remove-Symantec doRemoveMSI: exit
0

Here is my script:

[CmdletBinding()]
##
## rem-sep.ps1
##
[String] $logname  = 'Application'
[String] $source   = 'IntuneWinApp'
[String] $pName    = 'Remove-Symantec'
Set-StrictMode -Version Latest
Set-Variable evtError        1
Set-Variable evtWarning      2
Set-Variable evtInformation  4
Set-Variable evtAuditSuccess 8
Set-Variable evtAuditFailure 16
function NewMyEventlogSource
{
    Param
    (
        [string] $source,
        [string] $logname
    )
    [bool] $success = $false
    try
    {
        $success = [System.Diagnostics.EventLog]::SourceExists( $source )
    }
    catch [ System.Security.SecurityException ]
    {
        ## we aren't running as a privileged account so we
        ## couldn't search the security log (and maybe others).
        ## we have no choice but to try to create the $source.
        ## however, that will probably also fail.
    }
    if( -not $success )
    {
        try
        {
            [System.Diagnostics.EventLog]::CreateEventSource( $source, $logname )
            $success = $true
        }
        catch
        {
            $e = $_
            Write-Warning "Cannot create event source '$source', error $e"
        }
    }
    $success
}
function WriteMyEventlog
{
    Param
    (
        [ValidateNotNullOrEmpty()]
        [String] $logname,
        [ValidateNotNullOrEmpty()]
        [String] $source,
        [ValidateNotNullOrEmpty()]
        [String] $message,
        [ValidateSet( 1, 2, 4, 8, 16 )]
        [Int]    $type = $evtInformation,
        [ValidateRange( 1, 65535 )]
        [Int]    $eventId = 1,
        [ValidateRange( 0, 32767 )]
        [Int16]  $category = 0,
        [Bool]   $override = $false
    )
<#
    if( [String]::IsNullOrEmpty( $message ) )
    {
        $ex = New-Object System.ArgumentException( "Message parameter may not be null or empty" )
        throw $ex
    }
#>
    if( NewMyEventlogSource -source $source -logname $logname )
    {
        [System.Diagnostics.EventLog]::WriteEntry(
            $source,
            $message,
            $type,      ## [System.Diagnostics.EventLog]::EventLogEntryType enum
            $eventId,
            $category
        )
    }
    elseif( $override )
    {
        [System.Diagnostics.EventLog]::WriteEntry(
            'Application', ## 'Application' always exists in the Application log
            $message,
            $type,
            $eventId,
            $category
        )
    }
}
function log
{
    $str = $args -join ' '
    Write-Host $str
    WriteMyEventlog -logname $logname -source $source `
        -message $str `
        -type $evtInformation `
        -eventid 1 `
        -category 0 `
        -override $true
}
function logE
{
    $str = $args -join ' '
    Write-Host $str
    WriteMyEventlog -logname $logname -source $source `
        -message $str `
        -type $evtError `
        -eventid 99 `
        -category 0 `
        -override $true
}
function doRemoveMSI
{
    Param
    (
        [String] $msi,
        [String[]] $arguments
    )
    log "$pName doRemoveMSI: $msi, a0 = '$( $arguments[ 0 ] )', a1 = '$( $arguments[ 1 ] )'"
    <#
    $fileExists = Test-Path $arguments[ 1 ] -PathType Leaf
    if( -not $fileExists )
    {
        logE "$pName doMSI: file doesn't exist '$( $arguments[ 1 ] )'"
    }
    #>
    $result = Start-Process -Wait -Verb RunAs -FilePath $msi -ArgumentList $arguments -PassThru -WorkingDirectory $pwd.Path
    if( $? )
    {
        $return = 0
        if( $null -eq $result )
        {
            log "$pName successful result from Start-Process is null"
        }
        else
        {
            if( $result -is [System.Diagnostics.Process] )
            {
                $return = $result.ExitCode
                log "$pName doRemoveMSI: successful result is System.Diagnostics.Process, exitcode = $return"
                if( $return -eq 1619 )
                {
                    logE "$pName doRemoveMSI: a lie! msiexec error 1619 on '$( $arguments[ 0 ] )' '$( $arguments[ 1 ] )'"
                }
            }
            else
            {
                $return = $result.ToString()
                log "$pName doRemoveMSI: successful result is type $( $result.GetType().FullName )"
            }
        }
        log "$pName doRemoveMSI: success, return = $return"
    }
    else
    {
        $e = $error[ 0 ]
        logE "$pName doRemoveMSI: error $e"
        $return = -1
    }
    log "$pName doRemoveMSI: exit"
    return $return
}
##WriteMyEventlog $logname $source $message $type $eventId $category $override
Arbelac
  • 1,698
  • 6
  • 37
  • 90
  • `uninstall-package programname` – js2010 Feb 24 '23 at 19:43
  • Where are you calling doRemoveMSI? Are you passing one or two arguments when you make the call? – jdweng Feb 24 '23 at 20:29
  • @jdweng ,you can see my command within my error message. `doRemoveMSI -msi "msiexec.exe" -arguments "/x {EFF8AB9B-9551-4994-9FD2-D40A5A2E9B31}"` – Arbelac Feb 24 '23 at 20:35
  • 2
    I see the function, but nothing that call the function. The answer is clear from the comments. You have double quotes are the arguments so the two arguments are treated as one argument. Error indicates you are trying to get the second argument and getting an out-of-bonds error because there is only one argument. – jdweng Feb 24 '23 at 20:47
  • As an aside: It is best to avoid `Set-StrictMode -Latest` in _production code_, because future PowerShell versions could introduce additional strictness checks that can break your code. See [the docs](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/set-strictmode#parameters) – mklement0 Feb 25 '23 at 11:35

1 Answers1

1

To make your function work as designed, you must pass the arguments individually, given that the -arguments parameter expects an array ([string[]]), whose 2nd element ([1]) you're trying to access:

doRemoveMSI -msi "msiexec.exe" -arguments '/x', '{EFF8AB9B-9551-4994-9FD2-D40A5A2E9B31}'

However, note that passing this array through to Start-Process's -ArgumentList parameter as-is may fail, namely if any of your arguments contain spaces, due to a long-standing bug that won't be fixed for the sake of backward compatibility (see GitHub issue #5576).

If you need to deal with such arguments, you have two options:

  • Redesign your function to accept a single [string] only, and require passing all arguments encoded in a single string, the way you attempted ("/x {EFF8AB9B-9551-4994-9FD2-D40A5A2E9B31}"), which puts the burden on the caller to use embedded double-quoting as necessary.

  • Stick with the [string[]]-based design, but pre-process the array to enclose any elements that contain spaces in embedded "...", and if the elements themselves contain ", such instances must be escaped as "" for msiexec.exe

    $arguments = $arguments.ForEach({ 
      if ($_ -match '[ "]') { '"{0}"' -f ($_ -replace '"', '""') } else { $_ } 
    })
    
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • thanks for your reply. btw , lets say , I will use this command. `doRemoveMSI -msi "msiexec.exe" -arguments '/x', '{0442F7BD-1757-4569-9DD0-E25338EDFE15}', '/quiet', 'REBOOT=R', '/L*V "C:\msilog.log"'` As you can see , there is space `'/L*V` and `C:\msilog.log`. Am I correct ? Because , I have tested this command. There is no any issue. you are saying `-ArgumentList parameter as-is may fail` – Arbelac Feb 25 '23 at 10:04
  • Also , I have corrected my log function. `log "$pName doRemoveMSI: $msi, a0 = '$($arguments[0]),a1='$($arguments[1])',a2='$($arguments[2])',a3='$($arguments[3])',a4='$($arguments[4])'"` – Arbelac Feb 25 '23 at 10:06
  • @Arbelac, By using `'/L*V "C:\msilog.log"'` you're _bypassing_ the bug, because you're passing what should be _two_ arguments - `'/L*V'` and `'C:\msilog.log'` - as _one_, with _embedded quoting_. If you're going that route, use the first suggested solution, where you pass a single string encoding _all_ arguments: `'/x {0442F7BD-1757-4569-9DD0-E25338EDFE15} /quiet REBOOT=R /L*V "C:\msilog.log"'` – mklement0 Feb 25 '23 at 10:57