I have a PowerShell script which removes LogMeIn (or any program where you search by name) from add/remove programs.
This works perfectly however I would like to remove all instances of LMI, meaning any version that has been installed locally via plug-ins etc.
The only way I thought of doing this was to delete the respective registry entries and app data - however querying the HKEY_USERS hive instead of HKCU hive is proving troublesome.
Anyone had to do something similar, where they have a search term in registry they want to blitz off?
I have tried the mapping HKEY_USERS to a PS-Drive to query but just cant get the terminology right.
function ForceUninstall {
Stop-Process -processname LMIGuardian*
Stop-Process -processname LogMeIn*
Stop-Process -processname LogMeInSystray*
Stop-Process -processname ramaint*
$null = New-PSDrive -PSProvider Registry -Name HKEY_USERS -Root HKEY_USERS
cd HKEY_USERS:/
$objects = get-childItem HKEY_USERS:\ -ErrorAction SilentlyContinue
foreach ($object in $objects){
$testpath = "$($object.name)\Software\LogMeIn"
$testpath = $testpath -replace [Regex]::Escape("HKEY_USERS\"),'HKEY_USERS:\'
$testpath2 = "$($object.name)\Software\LogMeIn Ignition"
$testpath2 = $testpath2 -replace [Regex]::Escape("HKEY_USERS\"),'HKEY_USERS:\'
If (test-path $testpath) {
$PathsToDelete += $testpath
}
If (test-path $testpath2) {
$PathsToDelete += $testpath2
}
}
foreach ($Path in $PathsToDelete){
write-host "removing $path"
(Get-ChildItem $Path).PsPath |Remove-Item -Recurse
"Deleted registry key"
}
$LocalPaths = #("HKEY_LOCAL_MACHINE:\System\Current Control Set\Services\LMIInfo",
"HKEY_LOCAL_MACHINE:\SOFTWARE\LogMeIn"
"HKEY_LOCAL_MACHINE:\System\Current Control Set\Services\LMIMaint",
"HKEY_LOCAL_MACHINE:\System\Current Control Set\Services\LMImirr",
"HKEY_LOCAL_MACHINE:\System\Current Control Set\Services\LMIRfsClientNP",
"HKEY_LOCAL_MACHINE:\System\Current Control Set\Services\LMIRfsDriver",
"HKEY_LOCAL_MACHINE:\System\Current Control Set\Services\LogMeIn")
$Location = New-PSDrive -PSProvider Registry -Name HKEY_LOCAL_MACHINE -Root HKEY_LOCAL_MACHINE
cd HKEY_LOCAL_MACHINE:/
foreach ($Path in $LocalPaths){
write-host "removing $path"
(Get-ChildItem $Path).PsPath |Remove-Item -Recurse
"Deleted registry key"
}
Remove-ItemProperty -Path "HKEY_LOCAL_MACHINE:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" -Name "LogMeIn GUI"
write-host "removed LogMeIn GUI file"
}
Related
I am working on creating a script to uninstall Firefox from multiple locations. I have a script that I've created and it works to an extent. I have made changes to my original script based on the answer below plus some other changes
$LocalUsers = (Get-ChildItem -Path "C:\Users").name
# Uninstalling from Program Files
if (Test-Path "${env:ProgramFiles(x86)}\Mozilla Firefox\uninstall\helper.exe"){
Start-Process -FilePath "${env:ProgramFiles(x86)}\Mozilla Firefox\uninstall\helper.exe" -ArgumentList '/S' -Verbose #-ErrorAction SilentlyContinue
}
if (Test-Path "${env:ProgramFiles}\Mozilla Firefox\uninstall\helper.exe"){
Start-Process -FilePath "${env:ProgramFiles}\Mozilla Firefox\uninstall\helper.exe" -ArgumentList '/S' -Verbose #-ErrorAction SilentlyContinue
}
# Uninstalling for each user
ForEach ($LocalUser in $LocalUsers){
$Userpath = "C:\Users\" + $LocalUser
if (Test-Path "$Userpath\AppData\Local\Mozilla Firefox\uninstall\helper.exe"){
Start-Process -FilePath "$Userpath\AppData\Local\Mozilla Firefox\uninstall\helper.exe" -ArgumentList '/S' -Verbose #-ErrorAction SilentlyContinue
}
Start-Sleep 20
# Remove shortcuts from appdata
Remove-Item -Path "$userpath\AppData\Local\Mozilla" -Force -Recurse -Verbose #-ErrorAction SilentlyContinue
Remove-Item -Path "$userpath\AppData\LocalLow\Mozilla" -Force -Recurse -Verbose #-ErrorAction SilentlyContinue
Remove-Item -Path "$userpath\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Firefox.lnk" -Force -Verbose #-ErrorAction SilentlyContinue
Remove-Item -Path "$userpath\desktop\firefox.lnk" -Force -Verbose #-ErrorAction SilentlyContinue
}
# Remove related registry keys
$pathToRemove = #(
'HKLM:\Software\Mozilla'
'HKLM:\SOFTWARE\mozilla.org'
'HKLM:\SOFTWARE\MozillaPlugins'
'HKLM:\SOFTWARE\WOW6432Node\Mozilla'
'HKLM:\SOFTWARE\WOW6432Node\mozilla.org'
'HKLM:\SOFTWARE\WOW6432Node\MozillaPlugins'
'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Firefox.lnk'
)
foreach($path in $pathToRemove) {
if(Test-Path $path) {
try {
Remove-Item $path -Recurse -Force -Verbose #-ErrorAction SilentlyContinue
}
catch {
Write-Warning $_.Exception.Message
}
}
}
The script has worked on some machines where it uninstalls the application, however, for others trace of it is being left behind in Windows Program Files. It is appearing as a dead link. I know it is a dead link because it is missing the Firefox logo. The strange thing is its points to %localappdata%\Mozilla Firefox\uninstall\helper.exe per the error
What the app should look like if installed (ignoring the version just a screenshot from online):
I'm assuming the problem is your chained if \ elseif \ else conditions, what could be happening is that if the first condition was $true you're only removing the first registry key and then exiting the chained conditions (this is by design):
# only results in 'hello if' and then exits the chained conditions
if($true) {
'hello if'
}
elseif($true) {
'hello elseif'
}
What you can do in this case is store all the paths in an array and then loop over them, testing if the path exists and, if it does, remove it:
$pathToRemove = #(
'HKLM:\Software\Mozilla'
'HKLM:\SOFTWARE\mozilla.org'
'HKLM:\SOFTWARE\MozillaPlugins'
'HKLM:\SOFTWARE\WOW6432Node\Mozilla'
'HKLM:\SOFTWARE\WOW6432Node\mozilla.org'
'HKLM:\SOFTWARE\WOW6432Node\MozillaPlugins'
'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Firefox.lnk'
)
foreach($path in $pathToRemove) {
if(Test-Path $path) {
try {
Write-Verbose "Attempting to remove: $path" -Verbose
Remove-Item $path -Recurse -Force
Write-Verbose "Successfully removed: $path" -Verbose
}
catch {
Write-Warning $_.Exception.Message
}
}
}
This doesnt work
function ImportProcess{
param(
[Parameter()]
[string]$XMLPath
)
$sourcePath = $XMLPath
$DestPath = split-path "$sourcePath" -Parent #this gives format without slash at and and makes powerShell *very happy*
write-host "connecting to Dir"
New-PSDrive -Name "Drive" -PSProvider FileSystem -Credential $global:cred -Root "$DestPath" | Out-Null
write-host "done"
write-host "getting all xml files"
$temp1 = Get-ChildItem -Path $sourcePath
}
I want to put this inside a function and access the files in the path and this below works. I got this methode from using credentials to get-childitem on other server
$sourcePath = "path"
$DestPath = split-path "$sourcePath" -Parent #this gives format without slash at and and makes powerShell *very happy*
write-host "connecting to Dir"
New-PSDrive -Name "Drive" -PSProvider FileSystem -Credential $global:cred -Root "$DestPath" | Out-Null
write-host "done"
write-host "getting all xml files"
$temp1 = Get-ChildItem -Path $sourcePath
I tried different scopes in New-PSDrive and set-location before get-childitem, aswell as setting the Path to the Drive name + needed subdir
i removed the part where i get the credentials, because all works but as soon as i put the process in a function i get "Get-ChildItem : Access is denied"
I'm new to Powershell. I have 80 servers that I need to connect to and run a Pshell script on remotely to find files recursively in one share by last access date and move them to another \server\share for archiving purposes. I also need the file creation, last accessed etc. timestamps to be preserved.
I would welcome any help please
thank you
You need to test this thoroughly before actually using it on all 80 servers!
What you could do if you want to use PowerShell on this is to use Invoke-Command on the servers adding admin credentials so the script can both access the files to move as well as the destination Archive folder.
I would suggest using ROBOCOPY to do the heavy lifting:
$servers = 'Server1', 'Server2', 'Server3' # etcetera
$cred = Get-Credential -Message "Please supply admin credentials for archiving"
$scriptBlock = {
$SourcePath = 'D:\StuffToArchive' # this is the LOCAL path on the server
$TargetPath = '\\NewServer\ArchiveShare' # this is the REMOTE path to where the files should be moved
$LogFile = 'D:\ArchivedFiles.txt' # write a textfile with all fie fullnames that are archived
$DaysAgo = 130
# from a cmd box, type 'robocopy /?' to see all possible switches you might want to use
# /MINAGE:days specifies the LastWriteTime
# /MINLAD:days specifies the LastAccessDate
robocopy $SourcePath $TargetPath /MOVE /MINLAD:$DaysAgo /COPYALL /E /FP /NP /XJ /XA:H /R:5 /W:5 /LOG+:$logFile
}
Invoke-Command -ComputerName $servers -ScriptBlock $scriptBlock -Credential $cred
If you want to do all using just PowerShell, try something like this:
$servers = 'Server1', 'Server2', 'Server3' # etcetera
$cred = Get-Credential -Message "Please supply admin credentials for archiving"
$scriptBlock = {
$SourcePath = 'D:\StuffToArchive' # this is the LOCAL path on the server
$TargetPath = '\\NewServer\ArchiveShare' # this is the REMOTE path to where the files should be moved
$LogFile = 'D:\ArchivedFiles.txt' # write a textfile with all fie fullnames that are archived
$refDate = (Get-Date).AddDays(-130).Date # the reference date set to midnight
# set the ErrorActionPreference to Stop, so exceptions are caught in the catch block
$OldErrorAction = $ErrorActionPreference
$ErrorActionPreference = 'Stop'
# loop through the servers LOCAL path to find old files and move them to the remote archive
Get-ChildItem -Path $SourcePath -File -Recurse |
Where-Object { $_.LastAccessTime -le $refDate } |
ForEach-Object {
try {
$target = Join-Path -Path $TargetPath -ChildPath $_.DirectoryName.Substring($SourcePath.Length)
# create the folder in the archive if not already exists
$null = New-Item -Path $target -ItemType Directory -Force
$_ | Move-Item -Destination $target -Force
Add-Content -Path $LogFile -Value "File '$($_.FullName)' moved to '$target'"
}
catch {
Add-Content -Path $LogFile -Value $_.Exception.Message
}
}
$ErrorActionPreference = $OldErrorAction
}
Invoke-Command -ComputerName $servers -ScriptBlock $scriptBlock -Credential $cred
This identical code has been used in 3 servers, and only one of them does it silently fail to move the items (it still REMOVES them, but they do not appear in the share).
Azure-MapShare.ps1
param (
[string]$DriveLetter,
[string]$StorageLocation,
[string]$StorageKey,
[string]$StorageUser
)
if (!(Test-Path "${DriveLetter}:"))
{
cmd.exe /c "net use ${DriveLetter}: ${StorageLocation} /u:${StorageUser} ""${StorageKey}"""
}
Get-Exclusion-Days.ps1
param (
[datetime]$startDate,
[int]$daysBack
)
$date = $startDate
$endDate = (Get-Date).AddDays(-$daysBack)
$allDays =
do {
"*"+$date.ToString("yyyyMMdd")+"*"
$date = $date.AddDays(-1)
} until ($date -lt $endDate)
return $allDays
Migrate-Files.ps1
param(
[string]$Source,
[string]$Filter,
[string]$Destination,
[switch]$Remove=$False
)
#Test if source path exist
if((Test-Path -Path $Source.trim()) -ne $True) {
throw 'Source did not exist'
}
#Test if destination path exist
if ((Test-Path -Path $Destination.trim()) -ne $True) {
throw 'Destination did not exist'
}
#Test if no files in source
if((Get-ChildItem -Path $Source).Length -eq 0) {
throw 'No files at source'
}
if($Remove)
{
#Move-Item removes the source files
Move-Item -Path $Source -Filter $Filter -Destination $Destination -Force
} else {
#Copy-Item keeps a local copy
Copy-Item -Path $Source -Filter $Filter -Destination $Destination -Force
}
return $True
The job step is type "PowerShell" on all 3 servers and contains this identical code:
#Create mapping if missing
D:\Scripts\Azure-MapShare.ps1 -DriveLetter 'M' -StorageKey "[AzureStorageKey]" -StorageLocation "[AzureStorageAccountLocation]\backup" -StorageUser "[AzureStorageUser]"
#Copy files to Archive
D:\Scripts\Migrate-Files.ps1 -Source "D:\Databases\Backup\*.bak" -Destination "D:\Databases\BackupArchive"
#Get date range to exclude
$exclusion = D:\Scripts\Get-Exclusion-Days.ps1 -startDate Get-Date -DaysBack 7
#Remove items that are not included in exclusion range
Remove-Item -Path "D:\Databases\BackupArchive\*.bak" -exclude $exclusion
#Move files to storage account. They will be destroyed
D:\Scripts\Migrate-Files.ps1 -Source "D:\Databases\Backup\*.bak" -Destination "M:\" -Remove
#Remove remote backups that are not from todays backup
Remove-Item -Path "M:\*.bak" -exclude $exclusion
If I run the job step using SQL then the files get removed but do not appear in the storage account. If I run this code block manually, they get moved.
When I start up PowerShell on the server, I get an error message: "Attempting to perform the InitializeDefaultDrives operation on the 'FileSystem' provider failed." However, this does not really impact the rest of the operations (copying the backup files to BackupArchive folder, for instance).
I should mention that copy-item also fails to copy across to the share, but succeeds in copying to the /BackupArchive folder
Note sure if this will help you but you could try to use the New-PSDrive cmdlet instead of net use to map your shares:
param (
[string]$DriveLetter,
[string]$StorageLocation,
[string]$StorageKey,
[string]$StorageUser
)
if (!(Test-Path $DriveLetter))
{
$securedKey = $StorageKey | ConvertTo-SecureString -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential ($StorageUser, $securedKey)
New-PSDrive -Name $DriveLetter -PSProvider FileSystem -Root $StorageLocation -Credential $credentials -Persist
}
Apparently I tricked myself on this one. During testing I must have run the net use command in an elevated command prompt. This apparently hid the mapped drive from non-elevated OS features such as the Windows Explorer and attempts to view its existence via non-elevated command prompt sessions. I suppose it also was automatically reconnecting during reboots because that did not fix it.
The solution was as easy as running the net use m: /delete command from an elevated command prompt.
I need to run a powershell script that disables autorun for ALL drives on a computer.
It can be done manually as described here, but I need to do it for multiple computers (with Windows XP and 7) using a WDS server.
Give this a try:
$path ='HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\Explorer'
Set-ItemProperty $path -Name NoDriveTypeAutorun -Type DWord -Value 0xFF
you can try this:
function Disable-AutoRun
{
$item = Get-Item `
"REGISTRY::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\IniFileMapping\AutoRun.inf" `
-ErrorAction SilentlyContinue
if (-not $item) {
$item = New-Item "REGISTRY::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\IniFileMapping\AutoRun.inf"
}
Set-ItemProperty $item.PSPath "(default)" "#SYS:DoesNotExist"
}
and this to re-enable:
function Enable-AutoRun
{
Remove-Item "REGISTRY::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\IniFileMapping\AutoRun.inf" -Force
}
Explication.