I'm fairly new to PowerShell, but I'm very much trying to figure it out. Here's the sum up of what I want to do:
- 400 computers, with no more than 5 at a physical location, connected by fairly poor speeds across VPN
- All have a single application with a single version (but on Windows XP and Windows 7) that needs to be removed due to compliance requirements
- I've tried using something like the below, with little success:
function Terminate-Process { param( [Parameter(Mandatory=$true,valuefrompipeline=$true)] [string]$compname) begin {$processname = Read-Host "Process Name I Want To Kill"} process { $result = Get-WmiObject -Class win32_Process -Filter "name='$processname'" -ComputerName (Get-Content computers.txt) | ForEach-Object { $_.Terminate() } if ($result.ReturnValue -eq 0 ) { Write-Output " $($processname) terminated on $($compname) "} else { Write-Output "could not terminate $($processname) on $($compname) "} } end{Write-Output "Script ...END"} } Start-Sleep -s 60 Get-Content Computers.txt | .\Get-InstalledSoftware.ps1 | Where {$_.AppName -match “SoftwareName” } | .\Uninstall-InstalledSoftware.ps1
============================================
The last line calls up two additional powershell scripts.
Get-InstalledSoftware.ps1 is:
[cmdletbinding()] [cmdletbinding()] param( [parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] [string[]]$ComputerName = $env:computername ) begin { $UninstallRegKey="SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall" } process { foreach($Computer in $ComputerName) { Write-Verbose "Working on $Computer" if(Test-Connection -ComputerName $Computer -Count 1 -ea 0) { $HKLM = [microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$computer) $UninstallRef = $HKLM.OpenSubKey($UninstallRegKey) $Applications = $UninstallRef.GetSubKeyNames() foreach ($App in $Applications) { $AppRegistryKey = $UninstallRegKey + "\\" + $App $AppDetails = $HKLM.OpenSubKey($AppRegistryKey) $AppGUID = $App $AppDisplayName = $($AppDetails.GetValue("DisplayName")) $AppVersion = $($AppDetails.GetValue("DisplayVersion")) $AppPublisher = $($AppDetails.GetValue("Publisher")) $AppInstalledDate = $($AppDetails.GetValue("InstallDate")) $AppUninstall = $($AppDetails.GetValue("UninstallString")) if(!$AppDisplayName) { continue } $OutputObj = New-Object -TypeName PSobject $OutputObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer.ToUpper() $OutputObj | Add-Member -MemberType NoteProperty -Name AppName -Value $AppDisplayName $OutputObj | Add-Member -MemberType NoteProperty -Name AppVersion -Value $AppVersion $OutputObj | Add-Member -MemberType NoteProperty -Name AppVendor -Value $AppPublisher $OutputObj | Add-Member -MemberType NoteProperty -Name InstalledDate -Value $AppInstalledDate $OutputObj | Add-Member -MemberType NoteProperty -Name UninstallKey -Value $AppUninstall $OutputObj | Add-Member -MemberType NoteProperty -Name AppGUID -Value $AppGUID $OutputObj# | Select ComputerName, DriveName } } } } end {}
and Uninstall-InstalledSoftware.ps1:
[cmdletbinding()] param ( [parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] [string]$ComputerName = $env:computername, [parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Mandatory=$true)] [string]$AppGUID ) try { $returnval = ([WMICLASS]"\\$computerName\ROOT\CIMV2:win32_process").Create("msiexec `/x$AppGUID `/qn") } catch { write-error "Failed to trigger the uninstallation. Review the error message" $_ exit } switch ($($returnval.returnvalue)){ 0 { "Uninstallation command triggered successfully" } 2 { "You don't have sufficient permissions to trigger the command on $Computer" } 3 { "You don't have sufficient permissions to trigger the command on $Computer" } 8 { "An unknown error has occurred" } 9 { "Path Not Found" } 9 { "Invalid Parameter"} }
I get all kinds of weird errors, and I'm not even sure the above could even work. I got most of this from techibee.com, here: http://techibee.com/powershell/powershell-uninstall-software-on-remote-computer/1400
Is there a simpler way to do this? I'm pulling my hair out a bit!! Otherwise I could RDP to 400 computers, kill the process and uninstall...but I really, really, really don't want to do that.
Invoke-Command
scriptblock on the remote host, rather than communicating everything back. 2. Is there any harm in attempting to remove the software, even if it's not installed? Rather than getting a list of installed software and checking it, which is neat and tidy, could you just attempt the uninstall, and if it fails, assume it was never installed in the first place?