My new PowerShell install script

I wanted to write a PowerShell script that can execute common activities involved in deploying software. We require signed PowerShell scripts, so it was not practical to rewrite the script for every piece of software. Instead, I moved the configuration to an XML file.

The first function below takes an object (pulled from the XML config file) that contains the uninstall information. The scenario would be that you want to uninstall a piece of software before you install something else. First I try to remove the software via WMI. If that fails, I lookup the uninstall string and use msiexe.exe to try and uninstall the software bassed on the GUID of the software.

function UninstallStep ($Step)
{
    $CurrentDisplayName= $Step.CurrentDisplayName.Value
    $CurrentVersion= $Step.CurrentVersion.Value
      gwmi win32_product -filter "Name like '%$CurrentDisplayName%'" | foreach {
        $InstalledVersion = $_.Version
        if ($InstalledVersion -ne  $CurrentVersion) {
            write-host "Trying to uninstall $CurrentDisplayName $InstalledVersion via WMI"
	        if ($_.uninstall().returnvalue -eq 0) { write-host "Successfully uninstalled $CurrentDisplayName $InstalledVersion via WMI" }
	        else {
                write-host "WMI uninstall retured an error, Trying to uninstall $CurrentDisplayName $InstalledVersion from registry entries"
	            if (-not(Test-Path ("Uninstall:"))){New-PSDrive -name Uninstall -psprovider registry -root HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall | Out-Null}
	            Get-ChildItem -Path Uninstall: | Where-Object -FilterScript { $_.GetValue("DisplayName") -like "*$CurrentDisplayName*"} | ForEach-Object -Process {
	                $CommandToRun = "msiexec"
	                $UNSTring = $_.GetValue("UninstallString").split("{")
	                $Parameters = "/X /Q {" + $UNSTring[1]
	                write-host "Running Command: " $CommandToRun $Parameters
	                Start-Process $CommandToRun $Parameters -wait -workingdirectory $WorkingDirectory | out-null
	            }
	            }
        }
    }
}

Second piece of code is a generic command to run script. This is basically just a wrapper for the Start-Process command. It can be used to run any command, but mostly I use this to start the msiexec.exe program with parameters. I can also use this command to start an setup.exe. Again, this is read from the config.xml. If there are arguments, then the second part of the conditional runs.

Function CommandToRunStep ($Step)
{
  if ($Step.Command.Value -ne "") {
    $Command = $Step.Command.Value
    if ($Step.Arguments.Value -ne "") {
      $Arguments = $Step.Arguments.Value
      write-host "Running Command: " "$Command" "$Arguments"
      Start-Process "$Command" -ArgumentList "$Arguments" -wait -workingdirectory $WorkingDirectory | out-null
    }
    Else {
      write-host "Running Command: " "$Command"
      Start-Process -FilePath "$Command" -wait -workingdirectory $WorkingDirectory | out-null
    }
  }
}

The final function takes a process name from the config xml file and kills it.

function KillStep ($Step)
{
    $ProcessName= ($Step.ProcessName.Value).split(".")[0]
    if ($ProcessName -ne "") {

    write-host "Killing: " "$ProcessName"
    Stop-Process -force -processname "$ProcessName" -ea SilentlyContinue
    }
}

The main part of this script loops through the xml file and call the correct function. The xml file can contain any number of the three types of functions above, and they are run in sequential order. This gives me the ability to create a “task sequence” in an xml file that will be run with a PowerShell script in an SCCM advertised program.

#  Main
$WorkingDirectory = Split-Path -parent $MyInvocation.MyCommand.Definition
[ xml ]$s = Get-Content $WorkingDirectory\Install.xml

foreach ($Step in $s.Install.Steps.Step)
{
switch ($Step.StepType.Value)
    {
    "UninstallOlderThan" {UninstallStep ($Step)}
    "CommandToRun" {  CommandToRunStep ($Step)}
    "KillProcess" { KillStep ($Step) }
    }
}

Updated
And an example of the XML file would be:

<Install>
<Steps>
  <Step>
	<StepType Value="UninstallOlderThan" />
	<CurrentDisplayName value="Apple Application Support" />
    	<CurrentVersion value="1.3.3" />
  </Step>
  <Step>
	<StepType Value="CommandToRun" />
	<Command Value="msiexec" />
	<Arguments Value="/i AppleApplicationSupport.msi /quiet /norestart" />
  </Step>
  <Step>
	<StepType Value="CommandToRun" />
	<Command Value="iTunesSetup.exe" />
	<Arguments Value="/quiet DESKTOP_SHORTCUTS=0" />
  </Step>
  <Step>
	<StepType Value="KillProcess" />
	<ProcessName Value="Process.exe" />
  </Step>
</Steps
</Install>

6 Responses to My new PowerShell install script

  1. Lokesh Sharma March 27, 2012 at 10:41 am #

    Thank you for the code but I created the install.xml file and I’m getting errors.
    Can you please post an example of xml file too or send it to me so I can compare where I’m missing.

    Thanks in advance.

    Regards
    Loji

  2. jbmurphy March 27, 2012 at 12:02 pm #

    I updated the bottom of the post with an example XML file. I hope that helps?

  3. Lokesh Sharma March 27, 2012 at 12:25 pm #

    Thanks a lot.
    I was using all values in steps, separating them help.

    Regards
    Lokesh

  4. jbmurphy March 27, 2012 at 12:26 pm #

    Obviously you can setup the XML anyway you want. This just made sense to me.

  5. Priyank D November 28, 2012 at 2:45 pm #

    Hello,

    I am kind of basic user of powershell,

    Recently I got task to install one of the software on every PC on entire network, where more than 200 computers are there , some of them even old one having wind xp running,

    Now,

    How would I install that software on each machine without quietly?

    What script I can use ?

    Can you help to write me general script, which I can run through powershell?

    Thank You

    Pri

  6. jbmurphy December 5, 2012 at 4:18 pm #

    Not sure. I use SCCM to do the heavy lifting. You might want to check Microsoft’s Script Center, there might be a starting script to get you %90 of what you want.