MSI INSTALLER HELP

function InstallMSI {
param([String]$strComputer, $objFile, $sysArch, $antiarch)
write-host “”
write-host “Security Installer”
write-host “”

$MSIName = [string]$objFile.name
$MSIExt = $objFile.extension
$MSIFullName = $objFile.FullName
$MSIProc = ($MSIName.trimend(".msi"))
write-host $MSIProc

$MSIProc = [string]$MSIProc

    if (($MSIName -Notmatch $sysArch) -and ($MSIName -match $antiarch))
    {
    return
    }
    
    if ($MSIName -match "ia64")
    {
    return
    }
copy-item $MSIFullName \\$strComputer\c$\$MSIName -force
      
#$install = (([WMICLASS]"\\$strComputer\ROOT\CIMV2:win32_process").Create(" msiexec.exe /I c:\$MSIName /qn /passive")) 
$install = Foreach-Object {([wmiclass]"\\$($_.trim())\root\cimv2:win32_process").Create("msiexec /i c:\$MSIName /q /n")}| Select-Object -Property ReturnValue | Format-Wide -Column 1

start-sleep -Seconds 5
    
    
    $MSItest = get-process -cn $strComputer -name "$MSIProc"
                    
    while ($MSItest -ne 0)
    {
    start-sleep -seconds 1
    write-host "waiting for MSI install to complete"
    $MSItest = get-process -cn $strComputer -name "$MSIProc" 
            
    
    }
}

Starting Job…
Waiting for 1 Jobs to Complete sleeping 5 seconds
Waiting for 1 Jobs to Complete sleeping 5 seconds
Waiting for 1 Jobs to Complete sleeping 5 seconds
Waiting for 1 Jobs to Complete sleeping 5 seconds
Waiting for 1 Jobs to Complete sleeping 5 seconds
Security Installer
KB2708437
You cannot call a method on a null-valued expression.
+ CategoryInfo : InvalidOperation: (trim:String) , RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Cannot convert value “\\root\cimv2:win32_process” to type “System.Management.ManagementClass”. Error: "Invalid parameter "
+ CategoryInfo : NotSpecified: (:slight_smile: , RuntimeException
+ FullyQualifiedErrorId : RuntimeException
Cannot find a process with the name “KB2708437”. Verify the process name and call the cmdlet again.
+ CategoryInfo : ObjectNotFound: (KB2708437:String) [Get-Process], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
Security Installer
KB2708941
You cannot call a method on a null-valued expression.
+ CategoryInfo : InvalidOperation: (trim:String) , RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Cannot convert value “\\root\cimv2:win32_process” to type “System.Management.ManagementClass”. Error: "Invalid parameter "
+ CategoryInfo : NotSpecified: (:slight_smile: , RuntimeException
+ FullyQualifiedErrorId : RuntimeException
Cannot find a process with the name “KB2708941”. Verify the process name and call the cmdlet again.
+ CategoryInfo : ObjectNotFound: (KB2708941:String) [Get-Process], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
Security Installer
KB926857 (2)
You cannot call a method on a null-valued expression.
+ CategoryInfo : InvalidOperation: (trim:String) , RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Cannot convert value “\\root\cimv2:win32_process” to type “System.Management.ManagementClass”. Error: "Invalid parameter "
+ CategoryInfo : NotSpecified: (:slight_smile: , RuntimeException
+ FullyQualifiedErrorId : RuntimeException
Cannot find a process with the name “KB926857 (2)”. Verify the process name and call the cmdlet again.
+ CategoryInfo : ObjectNotFound: (KB926857 (2):String) [Get-Process], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
Security Installer
KB926857
You cannot call a method on a null-valued expression.
+ CategoryInfo : InvalidOperation: (trim:String) , RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Cannot convert value “\\root\cimv2:win32_process” to type “System.Management.ManagementClass”. Error: "Invalid parameter "
+ CategoryInfo : NotSpecified: (:slight_smile: , RuntimeException
+ FullyQualifiedErrorId : RuntimeException
Cannot find a process with the name “KB926857”. Verify the process name and call the cmdlet again.
+ CategoryInfo : ObjectNotFound: (KB926857:String) [Get-Process], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
Total time for JOBs: 0.43 Minutes
I need help with this section of my script. I am trying to run multiple .msi against a list of machines, but I keep receiving these errors above. Could someone please help me with this issue. Also, I dont know which WMICLASS line I should use? I am new to powershell so any help or advice would be awesome!!!

You can’t start a pipeline with ForEach-Object; it’s intended to be used only when something is piped into it. Since you only have a single object to worry about in this code, there’s no need for any type of loop there, and the first “[wmiclass]” line should work better.

I haven’t tested the rest of the code, but your while loop could be revised slightly to get rid of those error messages, something like this:

copy-item $MSIFullName \\$strComputer\c$\$MSIName -force

$result = (([WMICLASS]"\\$strComputer\ROOT\CIMV2:win32_process").Create("msiexec.exe /I c:\$MSIName /qn /passive"))

if ($result.ReturnValue -eq 0)
{
    do
    {
        Start-Sleep -Seconds 1
        $process = Get-WmiObject -Class Win32_Process -ComputerName $strComputer -Filter "ProcessID = '$($result.ProcessId)'"
    }
    while ($null -ne $process)
}

Thanks Dave for that… I was wondering if you could assist with my script. I can get the .msu portion to install no problem, but when I place a .msi in the patch folder. It will not install. I am also trying to document the processID in a the out-gridview. The block comes up, but there is no ID in there to view. If you can assist that would be awesome. The code is below. I included the whole script for everyone else to use if they cut out the the MSI section it works fine. thanks for the help in advance.

####################################################################################

Mass installer

####################################################################################

####################################################################################

Scriptblock

####################################################################################

$ScriptBlock = {

param([String]$strComputer, [string]$targetfolder, [array]$FileList )

####################################################################################

Install Functions

####################################################################################

function InstallMSU {
param([String]$strComputer, $objFile, $sysArch, $antiarch)

write-host ""
write-host "MSU install"
write-host ""

$msuName = $objFile.name
$msuExt = $objFile.extension
$msuFullName = $objFile.FullName

$msuFolder = ($msuName.trimend(".msu"))

$msuCab = $msuFolder + ".cab"


    if (($msuName -Notmatch $sysArch) -and ($msuName -match $antiarch))
    {
    return
    }
    
    if ($msuName -match "ia64")
    {
    return
    }
   

$regex = [regex]"KB......."

$KB = ($regex.match($msuName)).value

        if ($kb -eq $null)
        {

        $regex = [regex]"kb......."

        $KB = ($regex.match($msuName)).value

        }


$ret = Get-WmiObject -cn $strComputer -query 'select * from win32_quickfixengineering' | where {$_.hotfixid -eq "$KB"} | foreach {$_.hotfixid}

    if ($ret -eq $null)
    {
    write-host "$KB not found on $strComputer" -ForegroundColor Red
                    
    copy-item $msuFullName \\$strComputer\c$\$msuName -force

    $install = (([WMICLASS]"\\$strComputer\ROOT\CIMV2:win32_process").Create("cmd /c md c:\$msuFolder"))
    start-sleep -seconds 1

    $install = (([WMICLASS]"\\$strComputer\ROOT\CIMV2:win32_process").Create("cmd /c expand -F:* c:\$msuName C:\$msuFolder"))
         
    $wait = test-path \\$strComputer\c$\$msuFolder\*.cab
                 
        while ($wait -eq $false)
        {
        start-sleep -seconds 1     
                            
        $wait = test-path \\$strComputer\c$\$msuFolder\*.cab    

        }
                    
    $wsuscabtest = test-path \\$strComputer\c$\$msuFolder\wsusscan.cab
    
        if ($wsuscabtest -eq $true)
        {
        remove-item \\$strComputer\c$\$msuFolder\wsusscan.cab
        }
                    
    $cabs = get-childitem \\$strComputer\c$\$msuFolder -filter "*.cab"
    
        foreach ($cab in $cabs)
        {
        $cabName = $cab.name
                        
        $install = (([WMICLASS]"\\$strComputer\ROOT\CIMV2:win32_process").Create("cmd /c DISM.exe /Online /Add-Package /PackagePath:C:\$msuFolder\$msuCab"))
        }
                    
                    
    start-sleep -Seconds 5
                    
    $dismtest = get-process -cn $strComputer -name "dismhost"
                    
        while ($dismtest -ne $null)
        {
        start-sleep -seconds 1
        #write-host "waiting for install to complete"
        $dismtest = get-process -cn $strComputer -name "dismhost" 
        }
                    
    remove-item \\$strComputer\c$\$msuName -force
    remove-item \\$strComputer\c$\$msuFolder -recurse -force
                    
    }    

    else

    {
    write-host "$KB found on $strComputer" -ForegroundColor Green
    }


}

function InstallExe {
param([String]$strComputer, $objFile, $sysArch)

}

function InstallMSI {
param([String]$strComputer, $objFile, $sysArch, $antiarch)

write-host ""
write-host "Security Installer"
write-host ""

$MSIName = [string]$objFile.name
$MSIExt = $objFile.extension
$MSIFullName = $objFile.FullName
$Process = ($MSIName.trimend(".msi"))
write-host $Process
$Process = [string]$Process


    if (($MSIName -Notmatch $sysArch) -and ($MSIName -match $antiarch))
    {
    return
    }
    
    if ($MSIName -match "ia64")
    {
    return
    }

copy-item $MSIFullName \\$strComputer\c$\$MSIName -force
      
$Install = (([WMICLASS]"\\$strComputer\ROOT\CIMV2:win32_process").Create(" msiexec.exe /I c:\$MSIName /qn /passive")) 

start-sleep -Seconds 5
                    

                    
    if ($Install.ReturnValue -eq 0)
    {
    do
    {
    start-sleep -seconds 1
    write-host "Checking endstate Process ID "
    $process = Get-WmiObject -Class Win32_Process -ComputerName $strComputer -Filter "ProcessID = '$($Install.ProcessId)'" 

    }
    while ($null -ne $process) 
}

}

function InstallJava {
param([String]$strComputer, $objFile, $sysArch, $antiarch)

write-host ""
write-host "Security Installer"
write-host ""

$JavaName = [string]$objFile.name
$JavaExt = $objFile.extension
$JavaFullName = $objFile.FullName
$JavaProc = ($JavaName.trimend(".exe"))
write-host $JavaProc

$JavaProc = [string]$JavaProc

    if (($JavaName -Notmatch $sysArch) -and ($JavaName -match $antiarch))
    {
    return
    }
    
    if ($JavaName -match "ia64")
    {
    return
    }

copy-item $JavaFullName \\$strComputer\c$\$JavaName -force
      
$install = (([WMICLASS]"\\$strComputer\ROOT\CIMV2:win32_process").Create("cmd /c c:\$JavaName /s"))

start-sleep -Seconds 5
                    
$javatest = get-process -cn $strComputer -name "$JavaProc"
                    
    while ($javatest -ne $null)
    {
    start-sleep -seconds 1
    write-host "waiting for java install to complete"
    $javatest = get-process -cn $strComputer -name "$JavaProc" 

    }

<#
$javatest = get-process -cn target1 -name “trustedinstaller.exe” -ea silentlycontinue

    while ($javatest -ne $null)
    {
    start-sleep -seconds 1
    #write-host "waiting for install to complete"
    $javatest = get-process -cn target1 -name "trustedinstaller.exe" -ea silentlycontinue 
    }

#>

}

####################################################################################

Start doing stuff!

####################################################################################

$reply = Get-WmiObject -Class Win32_PingStatus -Filter “Address=‘$strComputer’”

if ($reply.statuscode -eq 0)
{
$pingIPaddress = $reply.IPV4Address.ipaddresstostring
$PingResponse = "Success"
                
$sysArch = (Get-WmiObject -Class Win32_OperatingSystem -ComputerName $strComputer -ea 0).OSArchitecture
    if ($sysArch -eq "64-bit")
    {
    $sysArch = "x64"
    $antiarch = "x86"

    }
    if ($sysarch -eq "32-bit")
    {
    $sysArch = "x86"
    $antiarch = "x64"
    }

#######################################################################################

Disable the on-access file scanner

#######################################################################################

   if ($sysArch -eq "x86")
   {   
   $Onaccess = (([WMICLASS]"\\$strComputer\ROOT\CIMV2:win32_process").Create('"c:\Program Files\McAfee\VirusScan Enterprise\shstat.exe" -disable'))
   }
   else
   {
   $Onaccess = (([WMICLASS]"\\$strComputer\ROOT\CIMV2:win32_process").Create('"c:\Program Files (x86)\McAfee\VirusScan Enterprise\shstat.exe" -disable'))
   }

#######################################################################################

Loop through install files and run the correct install function

#######################################################################################
Foreach ($objFile in $FileList)
{

    $FileExtension = $objFile.Extension
    $Filename = $objFile.name
    
        if ($FileExtension -match ".msu")
        {
        InstallMSU $strComputer $objFile $sysArch $antiarch
        }
        
        elseif (($FileExtension -match ".exe") -and ($Filename -match "jre"))
        {
        InstallJava $strComputer $objFile $sysArch $antiarch
        }
        elseif ($FileExtension -match ".msi") 
        
        {
        InstallMSI $strComputer $objFile $sysArch $antiarch
        }
     
   }

#######################################################################################

Re-enable Onaccess scanning

#######################################################################################

   if ($sysArch -eq "x86")
   {   
   $Onaccess = (([WMICLASS]"\\$strComputer\ROOT\CIMV2:win32_process").Create('"c:\Program Files\McAfee\VirusScan Enterprise\shstat.exe" -enable'))
   }
   else
   {
   $Onaccess = (([WMICLASS]"\\$strComputer\ROOT\CIMV2:win32_process").Create('"c:\Program Files (x86)\McAfee\VirusScan Enterprise\shstat.exe" -enable'))
   }

 
 }

Else  #means we had a bad ping
{
#Report the reason for the bad ping based on WMI ping error code

    if ($reply.statuscode -eq $null)   #null status code means no DNS entry was found.  Delete that shit from ADUC (unless it's the three-star's laptop...)                 
    {                   
    $PingResponse = "No DNS Entry"
    $pingIPaddress = $null
    }
    #Report the reason for the bad ping based on WMI ping error code    
    If ($reply.statuscode -eq "11010")
    {
    #Ping timeouts still return the IP address from DNS        
    $pingIPaddress = $reply.IPV4Address.ipaddresstostring

    $PingResponse = "Request Timed Out"
    }
    #Report the reason for the bad ping based on WMI ping error code    
    If ($reply.statuscode -eq "11003")
    {
    $pingIPaddress = $reply.IPV4Address.ipaddresstostring
                    
    $PingResponse = "Unable to reach host"
    
    }

 }                  

####################################################################################

End of scriptblock

####################################################################################

        $ResultProps = @{
            ComputerName =  $strComputer
            PingResponse =  $PingResponse
            ProcessID = $Process

        }
      
      $return = New-Object PSObject -Property $ResultProps

return $return

}

####################################################################################

Pull Target Folder and Target List

Init variables

####################################################################################

#$targetList = read-host “Enter path\filename of target list”
#$targetFolder = read-host “Enter path of patch folder”

$targetList = get-content C:\targets\computers.txt
$targetFolder = “C:\targets\patch”

$BreakCounter = 0
$results = @()
$MaxConcurrentJobs = 50
$counter = 1
$starttimer = Get-Date

$FileList = Get-ChildItem -path $targetFolder -include @(“.exe",".msu”,“*.msi”) -recurse

####################################################################################

Multi thread start

####################################################################################

foreach ($machineName in $targetList)
{

Write-host "$counter `t $machineName Starting Job..."
$counter ++

start-job -name ("InstallJob-" + $machineName) -scriptblock $scriptblock -ArgumentList $machineName, $targetFolder, $FileList | out-null


    while (((get-job | where-object { $_.Name -like "InstallJob*" -and $_.State -eq "Running" }) | measure).Count -gt $MaxConcurrentJobs)
    {
    "{0} Concurrent jobs running, sleeping 5 seconds" -f $MaxConcurrentJobs
    Start-Sleep -seconds 5
    }


get-job | where { $_.Name -like "InstallJob*" -and $_.state -eq "Completed" } | % { $results += Receive-Job $_ ; Remove-Job $_ }

}


while (((get-job | where-object { $_.Name -like "InstallJob*" -and $_.state -eq "Running" }) | measure).count -gt 0)
{

get-job | where { $_.Name -like "InstallJob*" -and $_.state -eq "Completed" } | % { $results += Receive-Job $_ ; Remove-Job $_ }
    
	$jobcount = ((get-job | where-object { $_.Name -like "InstallJob*" -and $_.state -eq "Running" }) | measure).count
	Write-Host "Waiting for $jobcount Jobs to Complete sleeping 5 seconds" 
	Start-Sleep -seconds 5
    
        $BreakCounter++
    if ($BreakCounter -gt 50) {
        Write-Host "Exiting loop $jobCount Jobs did not complete"
        get-job | where-object { $_.Name -like "InstallJob*" -and $_.state -eq "Running" } | select Name
        break
        }    
}

get-job | where { $.Name -like “InstallJob*” -and $.state -eq “Completed” } | % { $results += Receive-Job $_ ; Remove-Job $_ }

####################################################################################

END OF MULTITHREAD

####################################################################################

####################################################################################

Send results to grid view

Print total runtime

####################################################################################

$results | select ComputerName, PingResponse, ProcessID | Sort-Object PingResponse | out-gridview

#Pulls end time and prints total time for actions
$stoptimer = Get-Date
“Total time for JOBs: {0} Minutes” -f [math]::round(($stoptimer - $starttimer).TotalMinutes , 2)