PowerShell uninstall script

This topic contains 9 replies, has 4 voices, and was last updated by  Andrew 2 weeks, 3 days ago.

  • Author
    Posts
  • #76511

    Andrew
    Participant

    I am trying to write a script to remotely find Microsoft Office applications (from a list), and then uninstall them to prepare for installing Office 365. I have written the following so far, which seems to work (or at least doesn't throw any errors), but it doesn't uninstall anything. Can anyone take a look and tell me what I have wrong? Thanks in advance!

    #Gather hostname of remote PC
        $PC = Read-Host "Enter the hostname to uninstall from"
        IF ($Cred -eq $Null) {$Cred = Get-Credential "$env:USERDOMAIN\$env:USERNAME"}
    
    #Enable RemoteRegistry service
        Get-Service RemoteRegistry -ComputerName $PC | start-service
    
    #Enable WinRM service
        Get-Service WinRM -ComputerName $PC | Start-Service
    
    #Disable remote firewall
        PsExec -accepteula \\$($PC) netsh advfirewall set allprofiles state off
    
    #Enter remote session
        Enter-PSSession -ComputerName $PC -Credential $Cred
    
    #Uninstall old versions
        $OfficeApps = Get-WmiObject -Class Win32_Product | Where-Object {
            $_.Name -match "Microsoft Office" -or
            $_.Name -match "Microsoft Office Professional Plus 2010" -or
            $_.Name -match "Microsoft Office Professional Plus 2013" -or
            $_.Name -match "Microsoft Office Standard 2007" -or
            $_.Name -match "Microsoft Office Standard 2010"
            }
        ForEach ($App in $OfficeApps) {
            Write-Host "Uninstalling" $App.Name
            $App.Uninstall()
            }
    
    #Close remote session
        Exit-PSSession
    
  • #76519

    Don Jones
    Keymaster

    That is a lot of work.

    For one, there's no real need to so all the Remoting. Get-WmiObject has a -ComputerName parameter and it can do all of this by itself. Newer machines – Win10, notably – would use Get-CimInstance and Invoke-CimMethod instead, but same thing. And the Cim commands works against older machines, too.

    But, broadly, Enter-PSSession isn't what you want. It's odd – this is literally the third time this week this has come up.

    Invoke-Command -Script {
        $OfficeApps = Get-WmiObject -Class Win32_Product | Where-Object {
            $_.Name -match "Microsoft Office" -or
            $_.Name -match "Microsoft Office Professional Plus 2010" -or
            $_.Name -match "Microsoft Office Professional Plus 2013" -or
            $_.Name -match "Microsoft Office Standard 2007" -or
            $_.Name -match "Microsoft Office Standard 2010"
            }
        ForEach ($App in $OfficeApps) {
            Write-Host "Uninstalling" $App.Name
            $App.Uninstall()
            }
    } -ComputerName $PC -Credential $Cred
    

    That's probably more what you're thinking of.

    Broadly, starting WinRM isn't going to be helpful. If Remoting is enabled WinRM will be started. If Remoting isn't enabled, WinRM isn't going to set up Remoting (which is a distinct thing), so Invoke-Command wouldn't work. It also feels... dirty, somehow, to be using PSExec to disable the firewall. I assume you've a good reason for disabling it (it's not Remoting; Remoting, when enabled, sets up the proper firewall exceptions), but... gosh, if you've got PSExec, why not just have it run a little PowerShell script, instead of using Invoke-Command?

    • #76569

      js
      Participant

      If the name matched "Microsoft Office", wouldn't it match all the other ones?

    • #76584

      Andrew
      Participant

      js-
      What I was going for here (which I may not have achieved), is to have it find the specific program name in the quotes, as opposed to what "Microsoft Office*" would find. The reason for this, is some of the systems have Visio, Project, etc installed, and I want to address those systems differently.

      Thanks,

      Andrew

    • #76578

      Andrew
      Participant

      Thanks for the input Don. To answer a few of the topics you addressed:

      I chose to do the remoting, as I wanted to ensure that when I execute the $App.Uninstall command, that it is run on the target machine, and not the machine executing the script. It sounds like there are simpler ways to do this, but I still consider myself a little bit new to Powershell, so I wanted to avoid shooting myself in the foot. In the end, I am interested in whatever method makes the most sense.

      I actually started writing the script with the Remoting and Get-WmiObject portions, and added the RemoteRegistry, WinRM, and firewall portions because I wasn't able to get the PSSession to connect. I think it's a fair assumption to say that remoting isn't set up in our environment, as I am the first person to do this type of thing here (we're a fairly small company). When I tested, neither of the RemoteRegistry or WinRM services were started.

      PsExec- I guess this is just what I ended up at. I usually try to stick with powershell commands, but I probably just didn't dig deep enough to find the command I needed.

      You mentioned Cim commands- I don't think I have ever used anything Cim related, so I am very unfamiliar with everything there. I'm not opposed to digging into it though, if it would be a good solution.

      I believe I had tried Invoke-Command at one point, and it didn't work for some reason, possibly the same reason why the PSRemoting was failing. I'll give that another try and see how it goes. I'm guessing that to enable remoting, I just need to use Enable-PSRemoting. Can that be done remotely, or would it need to be done locally, through a GPO, etc?

      A couple things to note, if it would make any difference- Our environment contains Win10 and Win7 machines, and so far I have been testing with a Win10 virtual machine.

      Thanks,

      Andrew

  • #76520

    Will Prather
    Participant

    Fwiw, I've found these scripts to be useful, with almost zero config. You'll need to square away the remoting, but this might help.

    https://github.com/OfficeDev/Office-IT-Pro-Deployment-Scripts

  • #76581

    Don Jones
    Keymaster

    Remoting is never enabled on clients by default; you have to run Enable-PSRemoting. And yes, both Invoke-Command and Enter-PSSession rely on Remoting. WMI does not, but the commands are deprecated; the CIM commands can "talk" via WS-MAN (newer machines) and DCOM (older machines) protocols to get you to the WMI repository, and that's the way I'd go. Win10 will want CIM/WS-MAN, Win7 will want DCOM.

    But merely starting the WinRM service will not enable Remoting. Remoting uses WinRM, but that's not all it is. See, "Secrets of PowerShell Remoting" on our eBooks menu.

    You should be able to do this with a single call, per machine, to New-CimSession (passing a CimSessionOption object to designate the WSMAN or DCOM protocol as appropriate), then Invoke-CimMethod (passing the CIM object). There's a roughly similar example in "The PowerShell Scripting & Toolmaking Book" (on LeanPub.com) that shows how you can code to try one protocol and then the other if the first one fails.

    • #76602

      Andrew
      Participant

      I tried the script using the Invoke-Command method (run from an administrative instance of the ISE, same as before), and that seems to have worked better... at least in part.

      Before running the script, the command below returns the results listed:

      Get-WmiObject -Class Win32_Product | Where-Object {$_.Name -match "Microsoft Office"} | Select -Property Name

      Name
      —-
      Microsoft Office Standard 2007
      Microsoft Office Shared Setup Metadata MUI (English) 2007
      Microsoft Office Excel MUI (English) 2007
      Microsoft Office Shared 64-bit Setup Metadata MUI (English) 2007
      Microsoft Office PowerPoint MUI (English) 2007
      Microsoft Office Outlook MUI (English) 2007
      Microsoft Office Office 64-bit Components 2007
      Microsoft Office Shared 64-bit MUI (English) 2007
      Microsoft Office Word MUI (English) 2007
      Microsoft Office Proofing (English) 2007
      Microsoft Office Shared MUI (English) 2007
      Microsoft Office Proof (English) 2007
      Microsoft Office Proof (Spanish) 2007
      Microsoft Office Proof (French) 2007

      After the script completes, the following program remains:

      Name
      —-
      Microsoft Office Standard 2007

      Looking in the start menu, all of the Office applications are still listed, but won't open. Office is also still listed in programs and features, but trying to uninstall it again from there produces the following error message. I also tried rebooting to see if that would help, but it didn't seem to make a difference.

      "The language of this installation package is not supported by your system."

      Do you have any thoughts on this?

  • #76603

    Don Jones
    Keymaster

    As a fine-tune, consider using the -filter parameter of Get-WmiObject.

    -filter "Name LIKE '%Microsoft Office%'"

    Rather than Where-Object. It'll be a bit faster.

    It's likely that your remaining one simply refused to complete the uninstall. That can happen; Remoting doesn't provide a user context, and a lot of installers, especially older ones, will fail if they're not run in a full user context. The Start menu is an entirely different thing. Keep in mind – you're attaching as an Admin user, but these icons are persisted in all the individual users' home folders. If the uninstaller doesn't enumerate those and clean them up, then you'll have to do that on your own.

    PowerShell isn't so tricky. What's tricky is Windows' way of isolating user accounts and profile information. Until you start messing with PowerShell, you just don't realize how protected you've been from all the ugly under the hood. Deeply understanding how installers work, how users are isolated, and how profile data is kept – that's all key.

  • #76605

    Andrew
    Participant

    Here's another thought- would it produce a cleaner uninstall to package the installer for the version I want to uninstall, but just call the uninstall switch if it is available, instead of having it install like you would with a normal install package? It might be more work in the long run, but I'm hoping to fully automate this process if possible.

    Thanks,

    Andrew

You must be logged in to reply to this topic.