Installing .MSU Via Powershell & PSexec

This topic contains 17 replies, has 5 voices, and was last updated by  Mahmoud Abdelrahman 1 year, 3 months ago.

  • Author
    Posts
  • #15013

    Mahmoud Abdelrahman
    Participant

    Hey Guys Am one of the Newbies to PowerShell I really love it but I am having some problems with writing my first script and I'd love to have a hand from the expertise in here.

    I am trying to install one of Microsoft updates which is the "Windows Management Framework4.0" which we can't install via WSUS. The update extension is .MSU so am trying to write a script which gonna copy the update and a batch file I've created to the remote machines. The batch file will trigger the .MSU file on the remote machine using the PSexec via the Powershell gonna execute the batch file to run the update. The problem is we have different architecture and I tried to include that in the script but for some reason it doesn't work properly.

    #Variables

    $Computers = Get-Content -Path "F:\WindowsManagementFramework4.0\Computer Lists\Test List.txt"
    $HotFix_32bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x86-MultiPkg.msu"
    $HotFix_64bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x64-MultiPkg.msu"
    $BatchFile_32bit = "F:\WindowsManagementFramework4.0\Update\WUSA-32Bit.cmd"
    $BatchFile_64bit = "F:\WindowsManagementFramework4.0\Update\WUSA-64Bit.cmd"
    $BatchDest = "\\$computer\C$\Update"
    $Connection = Test-Connection -Cn $Computer -quiet

    foreach ($Computer in $Computers)
    {{

    $OSArch = (Get-WMIObject -ComputerName $Computer win32_operatingSystem -ErrorAction Stop).OSArchitecture
    }

    ####### Checking the Archetiture and Copying files ########

    if ($OSArch -like "*64-bit*")

    {
    New-Item $BatchDest -type directory
    Copy-Item $HotFix_64bit -Destination $BatchDest
    Copy-Item $BatchFile_64bit -Destination $BatchDest
    }

    ########### Testing Connection and Installing Update ############

    if ($Connection -like "True" -and $OSArch -like "64-bit")
    {
    & set-alias psexec "F:\WindowsManagementFramework4.0\PSTools\PSEXEC.exe"
    psexec 2> $null -i -s \\$Computer cmd /c "c:\update\wusa-64bit.cmd"
    } else {
    "$Computer is not online"
    }

    if ($OSArch -like "*32-bit*")
    {
    New-Item $BatchDest -type directory
    Copy-Item $HotFix_32bit -Destination $BatchDest
    Copy-Item $HotFix_32bit -Destination $BatchDest
    }

    ########### Testing Connection and Installing Update ############
    if ($Connection -like "True" -and $OSArch -like "32-bit")
    {
    & set-alias psexec "F:\WindowsManagementFramework4.0\PSTools\PSEXEC.exe"
    psexec 2> $null -i -s \\$Computer cmd /c "c:\update\wusa-32bit.cmd"
    } else {
    "$Computer is not online"
    }
    }

    And this is the outcome when I run this script and by the way the folder doesn't exist on the remote machine but i'd love to know how to overwrite even if it's there. The other thin is that the script copied to the laptop which is the x86 and ignored the other desktop x64 eventhough it was online and I was remoting into it.

    PS C:\> #Variables

    $Computers = Get-Content -Path "F:\WindowsManagementFramework4.0\Computer Lists\Test List.txt"
    $HotFix_32bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x86-MultiPkg.msu"
    $HotFix_64bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x64-MultiPkg.msu"
    $BatchFile_32bit = "F:\WindowsManagementFramework4.0\Update\WUSA-32Bit.cmd"
    $BatchFile_64bit = "F:\WindowsManagementFramework4.0\Update\WUSA-64Bit.cmd"
    $BatchDest = "\\$computer\C$\Update"
    $Connection = Test-Connection -Cn $Computer -quiet

    foreach ($Computer in $Computers)
    {{

    $OSArch = (Get-WMIObject -ComputerName $Computer win32_operatingSystem -ErrorAction Stop).OSArchitecture
    }

    ####### Checking the Archetiture and Copying files ########

    if ($OSArch -like "*64-bit*")

    {
    New-Item $BatchDest -type directory
    Copy-Item $HotFix_64bit -Destination $BatchDest
    Copy-Item $BatchFile_64bit -Destination $BatchDest
    }

    ########### Testing Connection and Installing Update ############

    if ($Connection -like "True" -and $OSArch -like "64-bit")
    {
    & set-alias psexec "F:\WindowsManagementFramework4.0\PSTools\PSEXEC.exe"
    psexec 2> $null -i -s \\$Computer cmd /c "c:\update\wusa-64bit.cmd"
    } else {
    "$Computer is not online"
    }

    if ($OSArch -like "*32-bit*")
    {
    New-Item $BatchDest -type directory
    Copy-Item $HotFix_32bit -Destination $BatchDest
    Copy-Item $HotFix_32bit -Destination $BatchDest
    }

    ########### Testing Connection and Installing Update ############
    if ($Connection -like "True" -and $OSArch -like "32-bit")
    {
    & set-alias psexec "F:\WindowsManagementFramework4.0\PSTools\PSEXEC.exe"
    psexec 2> $null -i -s \\$Computer cmd /c "c:\update\wusa-32bit.cmd"
    } else {
    "$Computer is not online"
    }
    }

    $OSArch = (Get-WMIObject -ComputerName $Computer win32_operatingSystem -ErrorAction Stop).OSArchitecture

    Dell19550 is not online

    Directory: \\Delllap16010\C$

    Mode LastWriteTime Length Name
    —- ————- —— —-
    d—- 5/05/2014 4:50 PM Update

    $OSArch = (Get-WMIObject -ComputerName $Computer win32_operatingSystem -ErrorAction Stop).OSArchitecture

    Delllap16010 is not online
    New-Item : Item with specified name \\Delllap16010\C$\Update already exists.
    At line:41 char:1
    + New-Item $BatchDest -type directory
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ResourceExists: (\\Delllap16010\C$\Update:String) [New-Item], IOException
    + FullyQualifiedErrorId : DirectoryExist,Microsoft.PowerShell.Commands.NewItemCommand

    PS C:\>

  • #15021

    Tore Groneng
    Participant

    hi,

    Give this a go. I have not tested it, no time sorry

    
    $Computers = Get-Content -Path "F:\WindowsManagementFramework4.0\Computer Lists\Test List.txt"
    $HotFix_32bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x86-MultiPkg.msu"
    $HotFix_64bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x64-MultiPkg.msu"
    $BatchFile_32bit = "F:\WindowsManagementFramework4.0\Update\WUSA-32Bit.cmd"
    $BatchFile_64bit = "F:\WindowsManagementFramework4.0\Update\WUSA-64Bit.cmd"
    $BatchDest = "\\$computer\C$\Update"
    # Added the count parameter to only test once, default is 4 times I think
    $Connection = Test-Connection -ComputerName $Computer -quiet -Count 1 
    
    foreach ($Computer in $Computers)
    {
        # Check if online before we try to copy and check OSarchitecture, Test-Connection returns a Boolean value
        if($Connection -eq $true)
        {
            # I am using a bad practice here, you should prevent using write-host, look into write-verbose in a function with [cmdletbinding()] set
            Write-host "Running install for $Computer" 
             
            $OSArch = (Get-WMIObject -ComputerName $Computer win32_operatingSystem -ErrorAction Stop).OSArchitecture
            if ($OSArch -like "*64-bit*")
            {
                
                if(-not(Test-Path $BatchDest))
                {
                    # Folder does not exists, creating
                    New-Item $BatchDest -type directory | Out-Null
                }
                # Added the force parameter to ALWAYS copy the files and piping output to device null
                Copy-Item $HotFix_64bit -Destination $BatchDest -Force | Out-Null
                Copy-Item $BatchFile_64bit -Destination $BatchDest -Force | Out-Null
            }
    
            ########### Installing Update 64-bit ############
            if ($OSArch -like "64-bit")
            {
                & set-alias psexec "F:\WindowsManagementFramework4.0\PSTools\PSEXEC.exe"
                psexec 2> $null -i -s \\$Computer cmd /c "c:\update\wusa-64bit.cmd"
            }
    
            if ($OSArch -like "*32-bit*")
            {
                # Added the force parameter to ALWAYS copy the files and piping output to device null
                if(-not(Test-Path $BatchDest))
                {
                    # Folder does not exists, creating
                    New-Item $BatchDest -type directory | Out-Null
                }
                Copy-Item $HotFix_32bit -Destination $BatchDest -Force | Out-Null
                Copy-Item $HotFix_32bit -Destination $BatchDest -Force | Out-Null
            }
    
            ########### Installing Update 32-bit ############
            if ($OSArch -like "32-bit")
            {
                & set-alias psexec "F:\WindowsManagementFramework4.0\PSTools\PSEXEC.exe"
                psexec 2> $null -i -s \\$Computer cmd /c "c:\update\wusa-32bit.cmd"
            } 
        }
        else 
        {
            # See comment about using write-host
            "$Computer is not online"
        }
    }
    
    
    • #15037

      Mahmoud Abdelrahman
      Participant

      Hey Tore

      Thanks for your quick reply I did try the new script you wrote to me but unfortunately it still didn't work. I tried to break the script down to parts then I found out that the script doesn't run the command to the computer list which is the "test list.txt" it just run it one individual machine. I tried to run the " (Get-WMIObject -ComputerName $Computer win32_operatingSystem -ErrorAction Stop).OSArchitecture " for this list in separate PS windows it ran fine but in the middle of the whole script doesn't work. Also the " If condition doesn't work because "Get-Wmi-object" didnt work properly in the first place". I even Tried this

      $OSArch = (Get-WMIObject -ComputerName dell19550 win32_operatingSystem -ErrorAction Stop).OSArchitecture
      {
      if ($OSArch -Like "64-Bit")
      {
      New-Item \\dell19550\C$\Update -type directory
      }
      }

      And still doesn't work so I don't understand what is going on.

  • #15102

    Peter Jurgens
    Participant

    you definitely have an issue with connecting to some of those machines in that case. you're going to have to sort that out before continuing on.

    to troubleshoot the issue with running the package, i would connect to the remote machine first by rdp, and run the command that we are trying to run from the remote powershell console, locally on a powershell console on that machine. verify that the package runs and installs without issue. then you can rest assured that the command we are trying to run on the remote computers should work.

    eg. RDP to your x64 machine that you referred to, and run

    Start-Process -FilePath wusa.exe -ArgumentList "\\myserver\dfs\Update\Windows6.1-KB2819745-x64-MultiPkg.msu" -Wait

    from a powershell console. See what happens. This should result in the windows update installer dialogue coming up and asking for user input. If that works then I would take to the next step and add the /quiet switch. So:

    Start-Process -FilePath wusa.exe -ArgumentList "\\myserver\dfs\Update\Windows6.1-KB2819745-x64-MultiPkg.msu /quiet" -Wait

    and verify after the installer finishes that the product has been installed successfully.

    FYI you are likely not seeing anything on the remote machine's console even after removing the "/quiet" switch as the installation is being run under the context of the user that is running the powershell console from the remote machine.

    • #15120

      Mahmoud Abdelrahman
      Participant

      Hey Peter

      Well I definitely don't have any issues with my connection to these machines 🙂 however I did all what you said and connected via RDP to the machine and ran the command locally from PS session and it did work perfectly and installed the package then I had to remove it to continue on with my script. I even put 1 single computer only in the "test list" and I removed the "AMD64" line to make sure it'll rung against this single machine and this only architecture, and when I ran it remotely it didn't work I gave it few minutes then I've checked the update, it wasn't installed, restarted the computer then did one more check and still the update didn't exist.

      The Script I ran

      
       $cmd={
      
        Switch ($env:PROCESSOR_ARCHITECTURE){
      
            "x86" {Start-Process -FilePath wusa.exe -ArgumentList "\\rrg.local\dfs\setup\update\Windows6.1-KB2819745-x86-MultiPkg.msu /quiet" -Wait}
        }
      
      }
      
      Invoke-Command -ComputerName $(Get-Content "F:\WindowsManagementFramework4.0\Computer Lists\Test List.txt") -ScriptBlock $cmd
      

      This was the outcome

      
       PS C:\> $cmd={
      
        Switch ($env:PROCESSOR_ARCHITECTURE){
      
            "x86" {Start-Process -FilePath wusa.exe -ArgumentList "\\rrg.local\dfs\setup\update\Windows6.1-KB2819745-x86-MultiPkg.msu /quiet" -Wait}
        }
      
      }
      
      Invoke-Command -ComputerName $(Get-Content "F:\WindowsManagementFramework4.0\Computer Lists\Test List.txt") -ScriptBlock $cmd
      
      PS C:\> 
      

      So I don't really know what is the problem and as I mentioned before I ran it perfectly with the PSEXEC.exe against 1 single machine and it did execute the ".cmd" file and all of that without using conditional "if" in the script. The problem is that it doesn't work on multiple machines. Another thing is when I use conditional "if" in simple script still doesn't work.

      This simple script to create a new folder and copy couple of files based on the Architecture.

      
      #Variables
      $Computers = Get-Content "F:\WindowsManagementFramework4.0\Computer Lists\test list.txt"
      $HotFix_32bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x86-MultiPkg.msu"
      $HotFix_64bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x64-MultiPkg.msu"
      $BatchFile_32bit = "F:\WindowsManagementFramework4.0\Update\WUSA-32Bit.cmd"
      $BatchFile_64bit = "F:\WindowsManagementFramework4.0\Update\WUSA-64Bit.cmd"
      $OSArch = {Get-OSArchitecture -ComputerName $computer}
      
      foreach ($computer in $Computers)
      {
      
      if ($OSArch -eq "64-Bit")
      {
      New-Item \\$computer\c$\update -ItemType directory
      Copy-Item $HotFix_64bit -Destination \\$computer\C$\Update
          }
          Else {
      New-Item \\$computer\c$\update -ItemType directory
      Copy-Item $BatchFile_32bit -Destination \\$computer\c$\update
      }
          }
      

      The "test list.txt" has 2 machines 1 x86 and the other x64 so it creates the folders perfectly fine and when it gets to the copy it just copy this file "$BatchFile_32bit" to both of the machines so it totally ignored the check and didn't complete the command of copying the $HotFix_64bit file. This issue is really bothering me and I don't know what is wrong?? ..

  • #15125

    Peter Jurgens
    Participant

    oh come onnnn... what's wrong with the code tags?!?!

  • #22034

    kiquenet kiquenet
    Participant

    Any final solution about it ?

    Ideal world in Powershell

    Target; install/uninstall Remote Server Administration Tools for Windows 8.1 silent using powershell

    steps:
    Programmatically save the download package to a local computer or share

    Detect appropriate for your computer's architecture: Windows8.1-KB2693643-x64.msu or Windows8.1-KB2693643-x86.msu

    Install programmatically silent Windows8.1-KB2693643-x64.msu or Windows8.1-KB2693643-x86.msu (Installation and Uninstallation of MSU in silent mode)

    Activate feature programmatically using Powershell Active Directory Module for Windows PowerShell

  • #50696

    Ferdush Zahan
    Participant

    Mahmoud,
    What is inside the cmd file such as WUSA-64Bit.cmd. I think you probably have some batch file inside it.

    • #50716

      Mahmoud Abdelrahman
      Participant

      Hi mate yeah it's just some commands and I had to make the file .cmd cause powershell didn't use to execute batch files not sure if still doesn't or not was 2 years ago :). This is what in the .cmf file.

      @echo off
      Color 80
      
      @echo ***********************************************
      @echo ******************	***********************
      @echo Please Don't Close This Window just Minimize it
      @echo ****************** 	***********************
      @echo ***********************************************
      if not "%minimized%"=="" goto :minimized
      set minimized=true
      start /min cmd /C "%~dpnx0"
      goto :EOF
      :minimized
      
      WUSA C:\Update\Windows6.1-KB2819745-x64-MultiPkg.msu /quiet /norestart
      
      rmdir /s /q "c:\Update"
      

      This part is just to run it in minimized window so it doesn't interfere with what the end user doing, and if it did they have the message asking to minimize the window.

      if not "%minimized%"=="" goto :minimized
      set minimized=true
      start /min cmd /C "%~dpnx0"
      goto :EOF
      :minimized

      Then the last part is just to execute the update on the target machine then removing the folder that called "update".

      WUSA C:\Update\Windows6.1-KB2819745-x64-MultiPkg.msu /quiet /norestart
      
      rmdir /s /q "c:\Update"
  • #50718

    Ferdush Zahan
    Participant

    I wanted to use your script to install other MSU file on multiple PC. .Net Framework is not the one I wanted. Do you have such script that will copy the .msu file & install multiple pc?

  • #51282

    Mahmoud Abdelrahman
    Participant

    Hi mate if you look at comment #15298 in this thread you will find the working script where you can copy and install whatever you want. You have to change the names of the files to the ones you will need to install and it should work fine.

  • #15061

    Peter Jurgens
    Participant

    I think this should work for you even without using PSExec.

    $cmd={
    Switch ($env:PROCESSOR_ARCHITECTURE){
    "AMD64" {Start-Process -FilePath wusa.exe -ArgumentList "\\server\share\Windows6.1-KB2819745-x64-MultiPkg.msu /quiet" -Wait}
    "x86" {Start-Process -FilePath wusa.exe -ArgumentList "\\server\share\Windows6.1-KB2819745-x86-MultiPkg.msu /quiet" -Wait}
    }
    }
    Invoke-Command -ComputerName $(Get-Content "F:\WindowsManagementFramework4.0\Computer Lists\Test List.txt") -ScriptBlock $cmd

    This is about the simplest I could make it. If you can put the msu packages on a network share that's accessible from all of the target servers that makes life really easy. This also assumes that your Test List.txt file has the servers listed one per line obviously. There's no error handling as such, but you could always add -ErrorAction SilentlyContinue to the Invoke-Command if you don't want to see any red in your console. To be honest, with the WMF4.0 package I've found that even when it doesn't install (i.e. .Net4.5 not installed) it doesn't give an error, and it actually seems as though it's installed, so for me personally I wouldn't worry too much about error handling here.

    Disclaimer: I haven't tested this myself, but I have used similar methods to install update packages and other windows installer packages on a handful of remote machines with good results.

    EDIT: For some reason the post editor kept substituting my backtick for a code tag so I took out the backticks essentially, if the UNC path to your MSU package contains any spaces, add a backtick-doublequote to the start and end of the path inside the argumentlist parameter above. Hope that's clear enough...

  • #15090

    Mahmoud Abdelrahman
    Participant

    Thank you Peter for replying....

    Am afraid that this didn't work either. I put the updates in an accessible share folder on the server and surely changed to our server name, when I ran the script it triggered the update on the x64bit machine and created that folder "2f707890fd73bf7dfcfb0e43f5dcc3ae" which is the extraction of the package but no installation I even removed the /quite switch to see what exactly what is happening but actually no installation for the update, about the .Net Framework I made sure that it's already installed before hand and am running 4.5 ver. About the x86 machine it bounced back by an error " Connecting to the remote server $computer failed " even though I ran the "winrm quickconfig" to receive requests.
    I can get it working on single machine and it works perfectly fine as I want, but when it comes to multiple it stuff up specially during the check of the (x64 and x86) but on one single machine it copied the file and ran the batch.cmd file and installed the update and works fine. So any more suggestions ??

    PS C:\> $cmd={

    Switch ($env:PROCESSOR_ARCHITECTURE){

    "AMD64" {Start-Process -FilePath wusa.exe -ArgumentList "\\myserver\dfs\Update\Windows6.1-KB2819745-x64-MultiPkg.msu" -Wait}

    "x86" {Start-Process -FilePath wusa.exe -ArgumentList "\\myserver\dfs\Update\Windows6.1-KB2819745-x86-MultiPkg.msu" -Wait}

    }

    }

    Invoke-Command -ComputerName $(Get-Content "F:\WindowsManagementFramework4.0\Computer Lists\Test List.txt") -ScriptBlock $cmd
    [Delllap16010] Connecting to remote server Delllap16010 failed with the following error message : The WS-Management service cannot process the request. Cannot find the Microsoft.PowerShell
    session configuration in the WSMan: drive on the Delllap16010 computer. For more information, see the about_Remote_Troubleshooting Help topic.
    + CategoryInfo : OpenError: (Delllap16010:String) [], PSRemotingTransportException
    + FullyQualifiedErrorId : InvalidResourceUri,PSSessionStateBroken

  • #15124

    Peter Jurgens
    Participant

    My apologies I forgot to mention that you must have CredSSP enabled in your environment in order to access a network share from a remote machine. This involves running Enable-WSManCredSSP on the remote machines as well as your machine. I set CredSSP via group policy in my environment. All the same, you have to add "-Authentication CredSSP" as well as a credential to the Invoke-Command cmdlet for it to work.

    There also seems to be an issue with executing wusa.exe on remote machines. HERE

    That last KB offers a helpful suggestion though, to extract the contents of the msu and install the cab via DISM. I've tested the following and it does work.

    $creds=Get-Credential
    $cmd={
    
    Switch ($env:PROCESSOR_ARCHITECTURE){
        "AMD64" {
            Start-Process wusa.exe -ArgumentList '"\\server\share\Windows6.1-KB2819745-x64-MultiPkg.msu" /extract:C:\MSU\' -Wait
    
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2809215-x64.cab /NoRestart' -Wait
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2872035-x64.cab /NoRestart' -Wait
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2872047-x64.cab /NoRestart' -Wait
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2819745-x64.cab /NoRestart' -Wait
    
            Remove-Item C:\MSU -Recurse -Force
    
            Restart-Computer -Force
        }
        "x86" {
            Start-Process wusa.exe -ArgumentList '"\\server\share\Windows6.1-KB2819745-x86-MultiPkg.msu" /extract:C:\MSU\' -Wait
    
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2872035-x86.cab /NoRestart' -Wait
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2872047-x86.cab /NoRestart' -Wait
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2819745-x86.cab /NoRestart' -Wait
    
            Remove-Item C:\MSU -Recurse -Force
    
            Restart-Computer -Force
        }
    }
    
    }
    
    Invoke-Command -ComputerName $(Get-Content "F:\WindowsManagementFramework4.0\Computer Lists\test list.txt") -ScriptBlock $cmd -Authentication Credssp -Credential $creds

    I suppose the only thing you will have to tackle is either enable CredSSP on your machines, or put the install packages local on the machines.

    To incorporate your method of copying the package over, you could do something like this, and it would not require CredSSP:

    $HotFix_32bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x86-MultiPkg.msu"
    $HotFix_64bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x64-MultiPkg.msu"
    
    ForEach($computer in $(Get-Content "F:\WindowsManagementFramework4.0\Computer Lists\test list.txt")){
    
    If($(Get-WmiObject Win32_OperatingSystem).OSArchitecture -eq "64-bit"){
    
        Copy-Item $HotFix_64bit "\\$computer\c$" -Force
    
        $cmd={
            Start-Process wusa.exe -ArgumentList '"C:\Windows6.1-KB2819745-x64-MultiPkg.msu" /extract:C:\MSU\' -Wait
    
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2809215-x64.cab /NoRestart' -Wait
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2872035-x64.cab /NoRestart' -Wait
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2872047-x64.cab /NoRestart' -Wait
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2819745-x64.cab /NoRestart' -Wait
    
            Remove-Item C:\MSU -Recurse -Force
    
            Restart-Computer -Force
        }
    
    }ElseIf($(Get-WmiObject Win32_OperatingSystem).OSArchitecture -eq "32-bit"){
    
        Copy-Item $HotFix_32bit "\\$computer\c$" -Force
    
        $cmd={
            Start-Process wusa.exe -ArgumentList '"C:\Windows6.1-KB2819745-x86-MultiPkg.msu" /extract:C:\MSU\' -Wait
    
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2872035-x86.cab /NoRestart' -Wait
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2872047-x86.cab /NoRestart' -Wait
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2819745-x86.cab /NoRestart' -Wait
    
            Remove-Item C:\MSU -Recurse -Force
    
            Restart-Computer -Force
        }
    }
    
    Invoke-Command -ComputerName $computer -ScriptBlock $cmd
    
    }

    Actually come to think of it, WMF4 requires Win7, Win2008R2 or Win2012. The only one of those offered in x86 is Win7, but you said it's a server OS? Just curious about that, as perhaps this will not work regardles...

  • #15148

    Mahmoud Abdelrahman
    Participant

    Hey Peter I've just checked what you wrote first I want to thank you very much and I will try it on Monday and will let you know how did it go. I read both of the scripts you wrote and bit optimistic that at lease one of them going to work for me. Thanks again and appreciate your help alot. Yeah it's frustrating sometimes with the codes on here 😀

  • #15271

    Mahmoud Abdelrahman
    Participant

    Hey Peter

    First am sorry for the late reply and I want to thank you really for your great help I've tried the second script you wrote and it didn't work as I wanted. The idea of extracting the package and using the DISM is brilliant but again it just worked on one computer. The only change i've made to your script I removed the restart option. After I ran the script it copied the "$Hotfix_64Bit" to both (x86 -x64) machines and it works perfectly fine on the (x64) machine and install the update and all working fine. On the other hand with the (x86) machine nothing has been installed because it copied the wrong file which was "Hotfix_64Bit" and surely couldn't be installed on the "32Bit" machine. However I sorted it out with the PSEXEC I managed to make it work properly and it worked on both of the machines and it did copy the right files as well on each architecture plus it had a successful installation for the update.

    
    
    #Variables
    $Computers = Get-Content "F:\WindowsManagementFramework4.0\Computer Lists\test list.txt"
    $HotFix_32bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x86-MultiPkg.msu"
    $HotFix_64bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x64-MultiPkg.msu"
    $BatchFile_32bit = "F:\WindowsManagementFramework4.0\Update\WUSA-32Bit.cmd"
    $BatchFile_64bit = "F:\WindowsManagementFramework4.0\Update\WUSA-64Bit.cmd"
    
    foreach ($computer in $Computers)
    
                #### Checking the OS Architecture for the Machines ####
    $OSArch = (Get-WmiObject -Class Win32_Operatingsystem -ComputerName $computer).OSArchitecture
    
    if ($OSArch -eq "64-bit")
        ### Copying the Batch file and the Update Package ###
    {
    New-Item \\$computer\c$\Update -ItemType directory
    Copy-Item $HotFix_64bit -Destination \\$computer\C$\Update
    Copy-Item $BatchFile_64bit -Destination \\$computer\C$\Update
    
           #### Using the PSEXEC to excute the .cmd file on the Remote machine #### 
        & set-alias psexec "F:\WindowsManagementFramework4.0\PSTools\PSEXEC.exe"
    psexec 2> $null -i -s \\$Computer cmd /c "c:\Update\wusa-64bit.cmd"
         } 
          else
    {
    New-Item \\$computer\c$\Update -ItemType directory
    Copy-Item $HotFix_32bit -Destination \\$computer\C$\Update
    Copy-Item $BatchFile_32bit -Destination \\$computer\C$\Update
    
        & set-alias psexec "F:\WindowsManagementFramework4.0\PSTools\PSEXEC.exe"
    psexec 2> $null -i -s \\$Computer cmd /c "c:\Update\wusa-32bit.cmd"
            }
        }
    

    I am trying to add the cmdlet "Test-Connection" to test the connection before it hits the machine to copy the files plus logging all of this actions on the script I tried to add this part of the "Test-Connection"

    
    #Variables
    $Computers = Get-Content "F:\WindowsManagementFramework4.0\Computer Lists\Computers.txt"
    $HotFix_32bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x86-MultiPkg.msu"
    $HotFix_64bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x64-MultiPkg.msu"
    $BatchFile_32bit = "F:\WindowsManagementFramework4.0\Update\WUSA-32Bit.cmd"
    $BatchFile_64bit = "F:\WindowsManagementFramework4.0\Update\WUSA-64Bit.cmd"
    
    foreach ($computer in $Computers)
    
       ###### Checking the connection to the machines ######
        {
    $Connection = Test-Connection -ComputerName $Computer -Quiet -Count 1 | Out-File -FilePath F:\Script-Log.txt
        
         if ($Connection -eq "True") 
    
    {Write-Host "$Computer is Online"} Else {
    Write-Host "$Computer is Offline"}
        }
    

    So I've tested it separately and it did work perfectly on the testing side but it didn't log anything in the "Script-Log.txt" file. What I found in the .txt after the script has been finished was 1 single entry which was true that was it :). I will be so thankful if I can get any help about that.

  • #15297

    Peter Jurgens
    Participant

    Gosh I must have been sleeping when I wrote my last post... I see what I did wrong, essentially I did not set the computername parameter for Wet-WMIObject therefore the OS architecture would always come up as the architecture of the machine you're running the script on and not the remote machines. Here I've updated the script for you to try again:

    
    
    $HotFix_32bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x86-MultiPkg.msu"
    $HotFix_64bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x64-MultiPkg.msu"
    
    ForEach($computer in $(Get-Content "F:\WindowsManagementFramework4.0\Computer Lists\test list.txt")){
    
    If($(Get-WmiObject Win32_OperatingSystem -ComputerName $computer).OSArchitecture -eq "64-bit"){
    
        Copy-Item $HotFix_64bit "\\$computer\c$" -Force
    
        $cmd={
            Start-Process wusa.exe -ArgumentList '"C:\Windows6.1-KB2819745-x64-MultiPkg.msu" /extract:C:\MSU\' -Wait
    
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2809215-x64.cab /NoRestart' -Wait
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2872035-x64.cab /NoRestart' -Wait
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2872047-x64.cab /NoRestart' -Wait
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2819745-x64.cab /NoRestart' -Wait
    
            Remove-Item C:\MSU -Recurse -Force
    
            Restart-Computer -Force
        }
    
    }ElseIf($(Get-WmiObject Win32_OperatingSystem -ComputerName $computer).OSArchitecture -eq "32-bit"){
    
        Copy-Item $HotFix_32bit "\\$computer\c$" -Force
    
        $cmd={
            Start-Process wusa.exe -ArgumentList '"C:\Windows6.1-KB2819745-x86-MultiPkg.msu" /extract:C:\MSU\' -Wait
    
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2872035-x86.cab /NoRestart' -Wait
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2872047-x86.cab /NoRestart' -Wait
            Start-Process dism.exe -ArgumentList '/online /add-package /PackagePath:C:\MSU\Windows6.1-KB2819745-x86.cab /NoRestart' -Wait
    
            Remove-Item C:\MSU -Recurse -Force
    
            Restart-Computer -Force
        }
    }
    
    Invoke-Command -ComputerName $computer -ScriptBlock $cmd
    
    }
    

    Sorry about that... Go ahead and try again.

    Have you thought about my question? What version of Windows is your 32-bit server running?

    In response to your last post, I don't see how the $connection variable would have anything in it as there is no output from out-file. Try replacing that line with this:

    
    Test-Connection -ComputerName $Computer -Quiet -Count 1 | Tee-Object -Variable connection | Out-File -FilePath F:\Script-Log.txt -Append
    

    note that tee-object requires at least Powershell v3.

    Also since you're using out-file, out-file overwrites a previously existing file, hence why you are only seeing one entry in the log. Either add -Append to the out-file, or use add-content instead.

    You could also put the test-connection cmdlet into the if statement.

    
    if(test-connection -computername $computer -count 1 -quiet){
       "$computer is online"
       add-content -path F:\Script-Log.txt -value "$computer is online"
    }Else{
       "$computer is offline"
       add-content -path F:\Script-Log.txt -value "$computer is offline"
    }
    
  • #15298

    Mahmoud Abdelrahman
    Participant

    Hey Peter

    Really mate don't know how to thanks you, I was gonna reply today to tell you that mission accomplished 🙂 and I'm ready for the mass deploy. I finished writing the script yesterday and I've added the "test-connection" as well exactly as you wrote it today which will give me more confidence when I perform the mass deploy. Am not processing the deployment from a server it's a my normal Windows 8.1 Enterprise and it's x64 OS. I managed as well to write the output it's not professionally though but I think it'll do as per it's my first script to write. Believe me or not I've never learned any scripting language and first scripting thing was Powershell. I watched the Microsoft Powershell Jump Start and wrote this script all of that in less than a month :). Am so glad and appreciate your help guys. Below is my final script I've tested it to 5 machines 4 of them x86 and the last one is x64 but I turned off 2 of the x86 to see if the "test-connection" working properly and everything is logged or not.

    
    
    #Variables
    $Computers = Get-Content "F:\WindowsManagementFramework4.0\Computer Lists\test list.txt"
    $HotFix_32bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x86-MultiPkg.msu"
    $HotFix_64bit = "F:\WindowsManagementFramework4.0\Update\Windows6.1-KB2819745-x64-MultiPkg.msu"
    $BatchFile_32bit = "F:\WindowsManagementFramework4.0\Update\WUSA-32Bit.cmd"
    $BatchFile_64bit = "F:\WindowsManagementFramework4.0\Update\WUSA-64Bit.cmd"
    
    foreach ($computer in $Computers)
    
        ###### Checking the connection to the machines ######
        {
    $Connection = Test-Connection -ComputerName $Computer -Quiet -Count 1 
        
         if ($Connection -eq "True") 
         {
    Write-Host "$Computer is Online" 
        Write-Output "$Computer is Online" |Out-File -FilePath F:\Script-Log.txt -Append
        } Else {
    Write-Host "$Computer is Offline"
        Write-Output "$Computer is Offline" | Out-File -FilePath F:\Script-Log.txt -Append
        }
       
        #### Hide the Errors of the Offline Machine ####
    $ErrorActionPreference = "SilentlyContinue"
    
        #### Checking the OS Architecture for the Machines ####
    $OSArch = (Get-WmiObject -Class Win32_Operatingsystem -ErrorAction SilentlyContinue -ComputerName $computer).OSArchitecture
    
    if ($OSArch -eq "64-bit")
        ### Copying the Batch file and the Update Package ###
    {
    New-Item \\$computer\c$\Update -ItemType directory -ErrorAction SilentlyContinue
    Copy-Item $HotFix_64bit -Destination \\$computer\C$\Update -ErrorAction SilentlyContinue
    Copy-Item $BatchFile_64bit -Destination \\$computer\C$\Update -ErrorAction SilentlyContinue
    
           #### Using the PSEXEC to excute the .cmd file on the (x64) Remote machine #### 
        & set-alias psexec "F:\WindowsManagementFramework4.0\PSTools\PSEXEC.exe"
    psexec 2> $null -i -s \\$Computer cmd /c c:\Update\wusa-64bit.cmd
         } 
          else
    {
    New-Item \\$computer\c$\Update -ItemType directory -ErrorAction SilentlyContinue
    Copy-Item $HotFix_32bit -Destination \\$computer\C$\Update  -ErrorAction SilentlyContinue
    Copy-Item $BatchFile_32bit -Destination \\$computer\C$\Update -ErrorAction SilentlyContinue
    
            #### Using the PSEXEC to excute the .cmd file on the (x86) Remote machine ####
    
        & set-alias psexec "F:\WindowsManagementFramework4.0\PSTools\PSEXEC.exe"
    psexec 2> $null -i -s \\$Computer cmd /c c:\Update\wusa-32bit.cmd
            
            ###### Logging the file copy ######
    }
            if ($Connection -eq "Ture") 
        {
        Write-Output "Copied Successfully to $Computer" |Out-File -FilePath F:\Script-Log.txt -Append
        }
        Else { 
    Write-output "Can't Copy... $Computer is Offline"|Out-File -FilePath F:\Script-Log.txt -Append}
        }
    

    Once again thank you for your great support and am still amazed by your brilliant idea of using the DISM.exe and am sure am gonna use it some other time.

You must be logged in to reply to this topic.