PowerShell command to locate software on all PC's on AD group - powershell

We have swapped over to a new virus protection and I'm trying to track down all the machines with our old McAfee software on it. We are in a domain group, and all the PC's are listed in active directory.
$list = Get-ADComputer -Filter *
foreach($PC in $list){
$data = Get-WmiObject -ComputerName $PC -Class Win32_Product | sort-object Name |
Select-Object Name | Where-Object { $_.Name -like "*McAfee*"}
if($data){
Write-Output "$PC has $($data.name) installed" |
out-file C:\Users\username\Desktop -Append
}
}
I'm a bit amateur when it comes to powershell.
Im getting this error over and over again
Get-WmiObject : The RPC server is unavailable.
At line:4 char:13
+ $data = Get-WmiObject -ComputerName $PC -Class Win32_Product | so ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
I've read it's likely a firewall setting in the group policy. Before I try and get that changed is this the most effective way to do this? I'm avoiding using a list of computer names for simplicity, but I can do if necessary.

You are right, there is a firewall setting blocking the Powershell remote access. It seems like a very common security setting in a lot of places since it's easier to turn it all off than to try to tune it to just allow specific people to use.
If you don't have access to SCCM or any other inventory/configuration management software like AdminOfThings commented, then this is a reasonable way to get the information you're looking for. I used a similar method to track RAM and CPU usages on some of our computers, but I had to modify each computer with the code at the link codaamok posted. It was an opt-in program so that method worked for me.
It's probably going to depend on how your Group Policy Admins want to handle it, if they want to allow this sort of remote access or not.

Related

Attempting to query all Windows servers to find those that have media loaded in the CD-ROM drive

I'm trying to build a command to query all Windows servers in AD and report if they have media loaded in the CD-ROM drive. I pieced together a command that I thought was correct and now I'm stuck at it reporting and RPC error. Note: The CD-ROM drive does not have the same assigned drive letter on every server.
Command:
$Computers = Get-ADComputer -filter 'operatingsystem -like "server" -and enabled -eq "true"'
foreach($Computer in $Computers){GET-WmiObject –query 'SELECT * from win32_logicaldisk where DriveType = "5"' –computername $Computer | Select Displayname,DeviceID,Size,VolumeName}
I receive the following error when executing it.
GET-WmiObject : The RPC server is unavailable.
At line:2 char:34
... $Computers){GET-WmiObject –query 'SELECT * from win32_logicaldisk whe ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
I've never used the Get-WmiObject command before and I'm in unfamiliar territory. Any assistance would be greatly appreciated.
Thank you
Get-AdComputer doesn't return computer names you can use directly with -ComputerName, try:
–computername $Computer.Name

I am trying to get event logs from multiple server but getting error

When I have 1 computer in $ComputerName it works but when I add another computer name it gives error.[Code & Error][1]
Sorry about that, Following is the code:
$ComputerName = 'Server1','Server2'
ForEach($Computer in $ComputerName){
$Info = Get-WinEvent -ComputerName $Computer -FilterHashTable #{Logname='System';ID=1074,6008,1076} | Sort-Object MachineName, TimeCreated, ID
| Group-Object MachineName, TimeCreated, ID, Message | Select-Object #{N="Computer";E={$_.Group[0].MachineName}},
#{N="TimeCreated"; E={$.Group[0].TimeCreated}}, #{N="Error ID";E={$_.Group[0].ID}},
#{N="Message"; E={$.Group[0].Message.Replace("r",' ').Replace("n",' ')}} `
| Export-Csv -NoTypeInformation -Path C:\ServerLogs\events3.csv;}
ERROR:
Get-WinEvent : The RPC server is unavailable
At C:\EventLogs\TEST.ps1:3 char:9
$Info = Get-WinEvent -ComputerName $Computer -FilterHashTable #{Logn ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : NotSpecified: (:) [Get-WinEvent], EventLogException
FullyQualifiedErrorId : System.Diagnostics.Eventing.Reader.EventLogException,Microsoft.PowerShell.Commands.GetWinEventCommand
"The RPC server is unavailable" usually indicates your RPC connection was blocked, either to Firewall or permissions issues. Rarely the RPC services have stopped on the remote host.
Windows Firewall is most common in my experience and you can look to ensure your Firewall policy is set to allow 'Remote Event Log Management (RPC)' and that the rule is Enabled.
There's a built-in rule to allow this. You shouldn't need to build a custom one. And I'd avoid the 'Remote Assistance' rule that some blogs mention. That can be a dangerous level of access.

Powershell Profile Removal - Windows 7

I am running the below script on Windows 10 without problems. So i am attempting to run it on Windows 7. However I get this weird error. The piece before the pipe to Remove-CimInstance works fine. Just something wrong when it hits the pipe
Get-CimInstance -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('\')[-1] -eq $pullUser } | Remove-CimInstance
However, i am getting the error below
Remove-CimInstance : The parameter is incorrect.
At line:1 char:104
+ ... LocalPath.split('\')[-1] -eq "useridhere" } | Remove-CimInstance
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (Win32_UserProfi...6-100815088...):CimInstance) [Remove-CimInstance], CimException
+ FullyQualifiedErrorId : HRESULT 0x80070057,Microsoft.Management.Infrastructure.CimCmdlets.RemoveCimInstanceCommand
EDIT
So as it turns out, there was an issue with a WMI on the device i was testing on. I originally created this script for Win10 and have been moving backwards to make it work on Windows 7. The premise of the entire script is to create a TASK JOB to delete a user profile on Startup.
For whatever reason, the script in its entirety works fine when running from a Powershell ISE Window with Admin rights, the TASK JOB is set to run as system, however it is failing the most basic of commands (almost as if the cmdlets are not loaded). I will be posting a new question on this if I cannot figure out what the problem is.
Tyr this to see all details of this action.
# Get the stack information and the full error message if any
Trace-Command -Name metadata,parameterbinding,cmdlet -Expression {
Get-CimInstance -Class Win32_UserProfile |
Where-Object {
$_.LocalPath.split('\')[-1] -eq 'TestUser'} |
Remove-CimInstance -Verbose -WhatIf
} -PSHost
$Error[0] |
Select-Object -'*' |
Format-List -Force

How can I search for software by filepath and then install it if it's missing using PowerShell

I'm trying to write a PowerShell script that will allow me to search for an old antivirus program on each computer in my domain, and if it has that program, run the Competitor Removal Tool that was given to us by our new AntiVirus software vendor. I also want the script to search for our new AV software, and if it's missing, install it. Both the Competitor Removal Tool and the .exe for the installer are stored on a Domain Controller and accessed via network share. I'm enabling PowerShell remoting in my organization, and I'm hoping that will give me more flexibility. Here's what I have so far:
#Retrieves list of all computers tied to Active Directory
$computers = Get-Content -Path 'C:\Sophos Results\ADComputers.txt'
#Paths to Sophos Installation and the Sophos Competitor Removal Tool
$SophosInstallPath = Get-ChildItem -File \\DC-02\netlogon\SophosInstall\Sophos-Installation.bat
$KasperskyRemove = Get-ChildItem -File \\DC-02\netlogon\SophosInstall\AVRemoveW.exe
#Loops through each AD Computer and tests for proper software installation
ForEach ($computer in $computers)
{
#Variables that store the path to 32-bit and 64-bit versions of Sophos
$Sophos64 = Test-Path "\\$computer\c$\Program Files\Sophos"
$Sophos32 = Test-Path "\\$computer\c$\Program Files (x86)\Sophos"
#Variables that store the path to 32-bit and 64-bit versions of Kaspersky
$Kaspersky64 = Test-Path "\\$computer\c$\Program Files\Kaspersky Lab"
$Kaspersky32 = Test-Path "\\$computer\c$\Program Files (x86)\Kaspersky Lab"
#The following block will run the Sophos Installation batch file, removing any instance of Kaspersky and installing Sophos
If ($Sophos64 -eq $false -or $Sophos32 -eq $false)
{
Start-Process -FilePath $SophosInstallPath -Verbose
Write-Host "Beginning Sophos Installation on $computer"
}
#The following block will remove Kaspersky from a machine if it is present and Sophos is already installed.
Elseif (($Kaspersky64 -eq $true -or $Kaspersky32 -eq $true) -and ($Sophos64 -eq $true -or $Sophos32 -eq $true))
{
Start-Process -FilePath $KasperskyRemove -Verbose
Write-Host "Removing Kaspersky from $computer"
}
#The last block will only be executed if Sophos is installed and Kaspersky isn't, and makes no changes to the machine.
else {Write-Host "$computer has the proper AV software installation"}
}
At the moment, when I run this against a group of test computers, I don't get any errors, and I know that the script is correctly determining whether or not Kaspersky/Sophos is installed, but it won't launch the Competitor Removal Tool or the install file. I know once PowerShell remoting is enabled there will be a better way to do this, I'm just not sure what that way is. Any suggestions? Thanks in advance
Update:
I enabled PS Remoting on my local machine and tried the following:
Invoke-Command -ComputerName localhost -ScriptBlock { *Script from above* }
I got the following errors:
Access is denied
+ CategoryInfo : PermissionDenied: (\\dc-02\net...nstallation.bat:String) [Get-ChildItem], UnauthorizedAccessException
+ FullyQualifiedErrorId : ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
+ PSComputerName : localhost Cannot find path '\\dc-02\netlogon\SophosInstall\Sophos-Installation.bat' because it does not exist.
+ CategoryInfo : ObjectNotFound: (\\dc-02\net...nstallation.bat:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
+ PSComputerName : localhost Access is denied
+ CategoryInfo : PermissionDenied: (\\dc-02\net...l\AVRemoveW.exe:String) [Get-ChildItem], UnauthorizedAccessException
+ FullyQualifiedErrorId : ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
+ PSComputerName : localhost Cannot find path '\\dc-02\netlogon\SophosInstall\AVRemoveW.exe' because it does not exist.
+ CategoryInfo : ObjectNotFound: (\\dc-02\net...l\AVRemoveW.exe:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
+ PSComputerName : localhost Cannot validate argument on parameter 'FilePath'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
+ CategoryInfo : InvalidData: (:) [Start-Process], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.StartProcessCommand
+ PSComputerName : localhost
I'm running PowerShell from my domain admin account so I'm not sure why it would say access denied. Thanks for your help, I'm a bit new to both IT and PowerShell. Two months in on my first job
My last question: When I'm ready to do this on a larger scale, say my test group which has 3 computers (1 with Kaspersky, 1 With Sophos, and 1 with neither) The following should work, yes?:
$computers = Get-Content -Path 'C:\Sophos Results\TestGroup.txt'
Invoke-Command -ComputerName $computers -ScriptBlock { *Original Script here* }
Any preference between Invoke-Command and Enter-PSSession when dealing with multiple computers? In the description of Invoke-Command it says "To run a single command on a remote computer, use the ComputerName parameter. To run a series of related commands that share data, use the New-PSSession cmdlet" So if I do use Invoke-Command (which seems more straightforward to me) Should I save my script and then call it in the scriptblock? And then that leads me to wonder how I would call a script from my local machine on the remote machine? I apologize for so many questions, my head is just spinning the further I get down the rabbit hole here.
Update 7/19/2018:
Running into one more issue, hoping this is the last one. I copied the files from the remote server on to my local machine to get rid of the second hop problem. I will just copy the files from my local machine to all remote machines in the script. Problem is when I copy from local to remote, it only works when I specify the computer name like so :
Copy-Item -Path C:\Temp\AVInstall -Destination '\\Computer1\c$\Temp\AVInstall' -Recurse
If I try and use a computer variable, like below, I get a network path not found error:
Copy-Item -Path C:\Temp\AVInstall -Destination '\\$computer\c$\Temp\AVInstall' -Recurse
Any reason why that might be?
As EBGreen touched on, you are currently running this on the local machine.
You would need to run it on the remote machine either via an interactive PSSession or via invoking the script.
To use Invoke-Command you can place the script to be executed on the remote machine into a scriptblock. This is then invoked on each machine within the string array within the -computername argument.
I can't test this, however I think you may encounter a double-hop problem when trying to retrieve the items $SophosInstallPathand$KasperskyRemove. If this does happen it will most likely manifest along the lines of "access denied". If this occurs the easiest solution would most likely be to copy the items to the machine first, either via copy-item or the more robust robocopy.exe and then remove them once complete.
#Retrieves list of all computers tied to Active Directory
$computers = Get-Content -Path 'C:\Sophos Results\ADComputers.txt'
$scriptblock = {
#Paths to Sophos Installation and the Sophos Competitor Removal Tool
$SophosInstallPath = Get-Item -File "\\DC-02\netlogon\SophosInstall\Sophos-Installation.bat"
$KasperskyRemove = Get-Item -File "\\DC-02\netlogon\SophosInstall\AVRemoveW.exe"
#Variables that store the path to 32-bit and 64-bit versions of Sophos
$Sophos64 = Test-Path "\Program Files\Sophos"
$Sophos32 = Test-Path "\Program Files (x86)\Sophos"
#Variables that store the path to 32-bit and 64-bit versions of Kaspersky
$Kaspersky64 = Test-Path "\Program Files\Kaspersky Lab"
$Kaspersky32 = Test-Path "\Program Files (x86)\Kaspersky Lab"
#The following block will run the Sophos Installation batch file, removing any instance of Kaspersky and installing Sophos
If ($Sophos64 -eq $false -or $Sophos32 -eq $false)
{
Start-Process -FilePath $SophosInstallPath -Verbose
Write-Host "Beginning Sophos Installation on $computer"
}
#The following block will remove Kaspersky from a machine if it is present and Sophos is already installed.
Elseif (($Kaspersky64 -eq $true -or $Kaspersky32 -eq $true) -and ($Sophos64 -eq $true -or $Sophos32 -eq $true))
{
Start-Process -FilePath $KasperskyRemove -Verbose
Write-Host "Removing Kaspersky from $env:computer"
}
#The last block will only be executed if Sophos is installed and Kaspersky isn't, and makes no changes to the machine.
else
{
Write-Host "$env:computer has the proper AV software installation"
}
}
Invoke-Command -ComputerName $computers -ScriptBlock $scriptblock

When removing software "you cannot call a method on a null-valued expressions" error

I know there are other threads with this question but they all involve code that I don't understand. I know very little of scripting and I'm looking for someone to help me with an easy to understand answer.
I am trying to remove a program with PowerShell (the program doesn't have an uninstaller file).
I can remove it with Control Panel → Programs and Features, but I would like to do this remotely with a PSSession. So after some searching on Google I found the following script.
I first run
Get-WmiObject -Class Win32_Product | Select-Object -Property Name
Which gets me the name of the program I want to delete: "OpenOTP-CP (64 bit)"
I then run the script:
$app = Get-WmiObject -Class Win32_Product | Where-Object {
$_.Name -match "OpenOTP-CP (64 bit)"
}
$app.Uninstall()
I then get the following error
You cannot call a method on a null-valued expression.
At C:\Users\Administrator\Desktop\Remote2.ps1:4 char:1
+ $app.Uninstall()
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Could someone maybe help me by telling me what is wrong or providing me with the correct code?
OS: Windows Server 2012 R2
Source for the script: http://lifeofageekadmin.com/how-to-uninstall-programs-using-powershell/
It sounds like $app may be an empty variable. I would add a temporary write-host "app is: $app" before you call $app.uninstall() to check if that is the case.
Alternatively, you could add some logic like this:
If ($app){
$app.Uninstall()
}else{
write-host "app was not found"
}
The reason $app might be empty is because the -match operator uses regular expressions, so it's likely treating the brackets as special characters. Try using -like instead of -match and surrounding it with asterisks:
$app = Get-WmiObject -Class Win32_Product | Where-Object {
$_.Name -like "*OpenOTP-CP (64 bit)*"
}
You could do it this way and it would be faster. I'm assume it's an msi provider.
get-package "*OpenOTP-CP (64 bit)*" | uninstall-package