我对 PowerShell 还很陌生,但我非常想弄清楚。以下是我想要做的事情的总结:
- 400 台计算机,其中物理位置不超过 5 台,通过 VPN 连接,速度较慢
- 所有操作系统都只有一个版本(但适用于 Windows XP 和 Windows 7)的单一应用程序,由于合规性要求,需要将其删除
- 我尝试过使用类似下面的方法,但收效甚微:
函数终止进程{ 参数( [参数(强制=$true,来自管道的值=$true)] [字符串]$公司名称) 开始 {$processname = Read-Host “我想要终止的进程名称”} 过程 { $result = Get-WmiObject -Class win32_Process -Filter “name='$processname'” -ComputerName (Get-Content computer.txt) | ForEach-Object { $_.Terminate() } 如果 ($result.ReturnValue -eq 0 ) { Write-Output“$($processname) 终止于 $($compname)”} else { Write-Output“无法终止$($compname) 上的$($processname)”} } 结束{Write-Output“脚本...结束”} } 开始-睡眠 -s 60 获取内容 Computers.txt | .\Get-InstalledSoftware.ps1 | 其中 {$_.AppName -match “SoftwareName” } | .\Uninstall-InstalledSoftware.ps1
============================================
最后一行调用了两个额外的 powershell 脚本。
Get-InstalledSoftware.ps1 是:
[cmdletbinding()] [cmdletbinding()] 参数( [参数(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] [string[]]$ComputerName = $env:computername ) 开始 { $UninstallRegKey="SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\卸载" } 过程 { foreach($ComputerName 中的 $Computer) { 详细写入“正在 $Computer 上工作” 如果(测试连接-计算机名称$计算机-计数1-ea 0){ $HKLM = [microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$computer) $UninstallRef = $HKLM.OpenSubKey($UninstallRegKey) $应用程序 = $UninstallRef.GetSubKeyNames() foreach ($App 在 $Applications 中) { $AppRegistryKey = $UninstallRegKey + "\\" + $App $AppDetails = $HKLM.OpenSubKey($AppRegistryKey) $AppGUID = $App $AppDisplayName = $($AppDetails.GetValue("显示名称")) $AppVersion = $($AppDetails.GetValue("显示版本")) $AppPublisher = $($AppDetails.GetValue("发布者")) $AppInstalledDate = $($AppDetails.GetValue("安装日期")) $AppUninstall = $($AppDetails.GetValue("卸载字符串")) 如果 (!$AppDisplayName) { 继续 } $OutputObj = 新对象-类型名称 PSobject $OutputObj | 添加成员-成员类型 NoteProperty-名称 ComputerName-值 $Computer.ToUpper() $OutputObj | 添加成员-MemberType NoteProperty-名称 AppName-值$AppDisplayName $OutputObj | 添加成员-MemberType NoteProperty-名称 AppVersion-值$AppVersion $OutputObj | 添加成员-MemberType NoteProperty-名称 AppVendor-值$AppPublisher $OutputObj | 添加成员-成员类型 NoteProperty -名称 InstalledDate -值 $AppInstalledDate $OutputObj | 添加成员-MemberType NoteProperty-名称 UninstallKey-值$AppUninstall $OutputObj | 添加成员-MemberType NoteProperty-名称 AppGUID-值$AppGUID $OutputObj# | 选择计算机名称、驱动器名称 } } } } 结尾 {}
和 Uninstall-InstalledSoftware.ps1:
[cmdletbinding()] 参数( [参数(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] [字符串]$ComputerName = $env:计算机名称, [参数(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Mandatory=$true)] [字符串]$AppGUID ) 尝试 { $returnval = ([WMICLASS]“\\$computerName\ROOT\CIMV2:win32_process”)。创建(“msiexec `/x$AppGUID `/qn”) } 抓住 { write-error“无法触发卸载。请查看错误消息” $_ 出口 } 开关 ($($returnval.returnvalue)){ 0 { “卸载命令已成功触发” } 2 { “您没有足够的权限在 $Computer 上触发命令” } 3 { “您没有足够的权限在 $Computer 上触发命令” } 8 { “发生未知错误” } 9 {“未找到路径”} 9 {“无效参数”} }
我遇到了各种奇怪的错误,我甚至不确定上面的方法是否有效。我从 techibee.com 上找到了大部分错误信息,如下所示: http://techibee.com/powershell/powershell-uninstall-software-on-remote-computer/1400
有没有更简单的方法可以做到这一点?我有点抓狂了!!否则我可以通过 RDP 连接到 400 台计算机,终止进程并卸载...但我真的真的真的不想这么做。
答案1
虽然这在技术上是可行的,但可能有更好的方法来实现它。
说到更好的解决方法,您可以在 GPO 中使用几行代码作为启动或关闭脚本来执行此操作,这就是我处理此问题的方法。再多几行代码,您就可以记录检查此东西是否存在和/或卸载它的结果,这无疑对您的合规性工作大有裨益。
如果出于某种原因无法使用 GPO 链接的启动/关闭脚本,我认为我会使用 PSExec 来终止从文件读取的计算机列表上的进程,然后使用适当的语言编写卸载脚本。例如,在我看来,这在 VB 中要容易得多。
a=WshShell.RegRead("HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{2318C2B1-4965-11d4-9B18-009027A5CD4F}\UninstallString")
If a<>"" Then
WshShell.Run(a&" /S"),1,True
i=i+1
end if
(再见了 Google 工具栏,这个例子是我几年前写的或复制的。可能也是复制的。我比较懒。)
在没有调试您复制的 PS 脚本的情况下,我想指出您可能正在运行不同的 PS 版本,安装/加载了不同的 PS 模块和/或您的 XP 机器可能没有安装某些依赖项,从而导致问题。