MSI INSTALLER HELP

This topic contains 2 replies, has 3 voices, and was last updated by  Chris Romano 3 years, 10 months ago.

  • Author
    Posts
  • #11500

    Chris Romano
    Participant

    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: (:) [], 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: (:) [], 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: (:) [], 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: (:) [], 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!!!

  • #11502

    Dave Wyatt
    Moderator

    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)
    }
    
  • #11536

    Chris Romano
    Participant

    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)

You must be logged in to reply to this topic.