I'm running a script to gather info for running apps on a terminal server. I would like to get the remote ComputerName of the user running the app but I'm only able to get the ComputerName of the Terminal Server instead. Any idea on how I could achieve that? Here's the part of my script to gather the info.
Get-WmiObject Win32_Process -ComputerName MYTSSERVER | Where-Object {
$_.mainwindowhandle -ne 0 -and
$_.Name -eq "WINWORD.exe"
} | Select-Object CSName, ProcessName
You can't get the client hostname or IP address from the Word process, because that process is running locally on the Remote Desktop server. Remote Desktop login information is recorded in the eventlog, so you need to extract it from there. However, you need the remote username for finding the correct logon session, so you still need to run the WMI query first.
Example for a single Word process running on the Remote Desktop server:
$server = '...'
$p = Get-WmiObject Win32_Process -Computer $server -Filter "Name='WINWORD.exe'"
$u = $p.GetOwner().User
$fltr = "*logon type:`t`t`t10*new logon:*account name:`t`t$u"
$addr = Get-EventLog -Computer $server -LogName Security -InstanceId 4624 -Message $fltr -Newest 1 |
Where-Object { $_.Message -match 'source network address:\s*(.*)' } |
ForEach-Object { $matches[1] }
The filter for the eventlog query matches the most recent Remote Desktop login (event ID 4626, logon type 10) of the user who started the Word process (account name:`t`t$u).
That will just give you the client's IP address, though. If you require the hostname you need to resolve it via a reverse DNS lookup or get it from the host itself with another WMI query:
$hostname = Get-WmiObject Win32_OperatingSystem -Computer $addr |
Select-Object -Expand CSName
Related
How to enable remote in Windows Management Instrumentation (WMI) on authenticated users on remote computers programmatically through CMD or POWERSHELL?
When I try to write some script then it throws errors like 'access is denied' and 'RPC server is unavailable '.
And when I enable PS Remoting then it is working.
$servers = Get-Content file name
foreach( $server in $servers) {
Write-host "Processing Server $Server"
Get-WmiObject -Class Win32_Product -Impersonation 3 -Credential username -ComputerName $Server | select __SERVER, Name, Version, InstallDate -ErrorAction SilentlyContinue
}
What I want to achieve is, I want to do this through script only not manually. Can anyone please explain?
I have been stuck at this stage of my little project.
What I try to do is list the applications that are installed and choose one of the apps to uninstall, the issue I have is that not all the apps appear, so I can't select them. For example Google chrome is not appearing while I'm using it right now to write this question.
I use this function to get all the apps:
Get-WmiObject Win32_Product -ComputerName $ComputerName | Select-Object -Property Name | Out-GridView -Title "All apps on destination Computer"
and this is whole script:
$ComputerName = Read-Host -Prompt 'Input the computer name' # the name of the computer to remove the app from
Get-WmiObject Win32_Product -ComputerName $ComputerName | Select-Object -Property Name | Out-GridView -Title "All apps on destination Computer"
$Name = Read-Host -Prompt 'Input name of the application (has to be exact name)' #name of the application
$Application = Get-WmiObject Win32_Product -ComputerName $ComputerName | Where-Object {$_.Name -eq $Name} #choose the object, this will be the app that we will delete
if ($Application) {
$Application.Uninstall()
"The removal was successful"
}
else {
$Name + ' is not installed on ' + $ComputerName
}
Start-Sleep -Seconds 10
I'm not that good with PowerShell so excuse me if this is a stupid question
Or get-package, which should be faster. Uninstall-package only works on msi providers. Powershell 5.1 only. Metadata['uninstallstring'] has the uninstall string for Programs providers. It can take wildcards and arrays as arguments. Install-package works with msi files, but without any extra options.
get-package
I have a task to check the username and password on multiple servers and report the result.
So basically i have a list of IP's And I want I have the same user and password and need to see which authenticate and which don't.
This is what I found so far but it doesn't seems to work it prompts me for password every-time.
$listofServers = Import-Csv '.\Windows Servers.csv'
$username = username
$password = password
foreach($server in $listofServers.ip)
{
try{
$Credentials = Get-Credential $server\$username $password
}
Catch
{
$errorMsg = $_.Exception.Message
}
}
As said more than once, but never too much, you should NOT store a password in plain text. Probably the simplest of the many ways you can store it as a clixml file encrypted by a specific account. You can limit access to the location it's saved to that same account that can decrypt it.
You'll need to use the same username/password in combination with the computer name/IP to build an actual PSCredential object. I assume IP as your code shows $listofservers.ip - if the CSV header is not IP, update the code accordingly. I added some feedback to show you which computer and user connected and the fact that it's able to run the command remotely proves the connection was successful.
$username = 'localadmin'
$password = ConvertTo-SecureString 'PlaintextIsaNoNo' -AsPlainText -Force
Import-Csv '.\Windows Servers.csv' | ForEach-Object {
$cred = New-Object System.Management.Automation.PSCredential ("$($_.ip)\$username", $password)
Try
{
Invoke-Command -ComputerName $_.ip -ScriptBlock {
Write-Host Sucessfully connected to $env:computername as $(whoami) -ForegroundColor Green
} -Credential $cred
}
Catch
{
$PSItem.Exception.Message
}
}
The problem with the above code is it will run one PC at a time. Invoke-Command runs asynchronously if you just give it a list of computers (up to 32 by default on PS5.1) If you change the structure, this will run much faster. This requires a pretty well known trick which is to provide the username as .\username which designates it's a local account. I've tested and it works for me, so please let me know if you see otherwise.
$username = 'localadmin'
$password = ConvertTo-SecureString 'PlaintextIsaNoNo' -AsPlainText -Force
$serverlist = Import-Csv '.\Windows Servers.csv'
$cred = New-Object System.Management.Automation.PSCredential (".\$username", $password)
Try
{
Invoke-Command -ComputerName $serverlist.ip -ScriptBlock {
Write-Host Sucessfully connected to $env:computername as $(whoami) -ForegroundColor Green
} -Credential $cred
}
Catch
{
$PSItem.Exception.Message
}
Update
Removing the previous answer because of our threads below.
Here's your issue.
You cannot do things the way you are trying because of how Windows security boundaries proper works and you'd also have to set up PowerShell Remoting properly.
You have not said whether you are in a domain or in a Workgroup scenario. Hence the previous statement about setting up PSRemoting properly.
Because you are using a local account, this is like using Workgroup mode in PSRemoting and that requires additional settings to be in place. See the details regarding 'TrustedHosts'.
about_Remote_Troubleshooting - PowerShell | Microsoft Docs
Doing a logon to a remote host as you are trying will popup the Logon dialog (Gina) by design.
On your admin machine, try it this way... (tested and validated as working)
### PSRemoting - using local machine accounts
$Creds = Get-Credential -Credential $env:USERNAME
Enable-PSRemoting -SkipNetworkProfileCheck -Force
Get-Item -Path 'WSMan:\localhost\Client\TrustedHosts'
Set-Item -Path 'WSMan:\localhost\Client\TrustedHosts' -Value '*' -Force
Get-Item -Path 'WSMan:\localhost\Client\TrustedHosts'
$TargetList = 'Lab01','172.0.0.10'
$TargetList |
ForEach-Object {
"Validating logon for $($Creds.Username) on target $PSItem"
Try
{
New-PSSession -ComputerName $PSItem -Credential $Creds
Get-PSSession | Remove-PSSession
}
Catch {$PSItem.Exception.Message}
}
Set-Item -Path 'WSMan:\localhost\Client\TrustedHosts' -Value '' -Force
# Results
<#
Validating logon for postanote on target Lab01
Id Name ComputerName ComputerType State ConfigurationName Availability
-- ---- ------------ ------------ ----- ----------------- ------------
26 WinRM26 Lab01 RemoteMachine Opened Microsoft.PowerShell Available...
Validating logon for postanote on target 172.0.0.10
27 WinRM27 172.0.0.10 RemoteMachine Opened Microsoft.PowerShell Available...
#>
Update
Here's a tweak to Doug and my approach and dropping the need to have PSRemoting proper to be involved at all. Again, tested and validated. Except for the one time prompt for the creds, no embedded plain text passwords/files/registry/CredMan storage and retrieval, etc needed.
$Creds = Get-Credential -Credential $env:USERNAME
$TargetList |
ForEach-Object {
"Processing hostname $PSItem"
Try
{
$cred = New-Object System.Management.Automation.PSCredential ("$PSItem\$($Creds.UserName)", $Creds.Password)
(Get-HotFix -ComputerName $PSItem -Credential $cred)[0]
}
Catch {$PSItem.Exception.Message}
}
# Results
<#
Processing hostname Lab01
Source Description HotFixID InstalledBy InstalledOn
------ ----------- -------- ----------- -----------
Lab01 Update KB4576478 NT AUTHORITY\SYSTEM 9/10/2020 12:00:00 AM
Processing hostname 172.0.0.10
Lab01 Update KB4576478 NT AUTHORITY\SYSTEM 9/10/2020 12:00:00 AM
#>
• Tip: Work Remotely with Windows PowerShell without using Remoting or
WinRM
https://technet.microsoft.com/en-us/library/ff699046.aspx
Some cmdlets have a –ComputerName parameter that lets you work with a remote
computer without using Windows PowerShell remoting. This means you can use
the cmdlet on any computer that is running Windows PowerShell, even if the
computer is not configured for Windows PowerShell remoting. These cmdlets
include the following:
• Get-WinEvent
• Get-Counter
• Get-EventLog
• Clear-EventLog
• Write-EventLog
• Limit-EventLog
• Show-EventLog
• New-EventLog
• Remove-EventLog
• Get-WmiObject
• Get-Process
• Get-Service
• Set-Service
• Get-HotFix
• Restart-Computer
• Stop-Computer
• Add-Computer
• Remove-Computer
• Rename-Computer
• Reset-ComputerMachinePassword
I am writing a script where I need to check specific applications if installed or not on a remote server. I am fairly new to PowerShell, but here is the script I have written
ForEach ($computers in $computer){
Get-WMIObject -Class win32_product -Filter {Name like "%Microsoft%"} -ComputerName $computers -ErrorAction STOP | Select-Object -Property Name,Version | export-csv "C:\progrms.csv"
}
The problem I am facing here is I can get details of only Microsoft application which are installed and if I give multiple names for filter parameter like "Microsoft", "SQL", "app1" so on. This script does not seem to work.
Please let me know what has gone wrong and what needs to be done in order to get the list of specific software's that are installed. Also, note that I will be using this script for both Windows 2008 and 2012 servers.
Remove the -Filter {Name like "%Microsoft%"} part of the script to have it return all installed software.
You probably want to be doing ForEach ($computer in $computers) rather than the other way around, assuming you're creating a $computers variable somewhere above this code with the list of computer names.
You also need to -Append to the Export-CSV command as otherwise each computers output will overwrite the output of the previous, however another issue you'll then have is knowing which software comes from which computer. You can address this by using a Calculated Property to add in the computer name to the output, as follows:
ForEach ($Computer in $Computers){
Get-WMIObject -Class win32_product -ComputerName $Computer -ErrorAction Stop |
Select-Object -Property #{N='Computer';E={$Computer}},Name,Version |
Export-Csv "C:\progrms.csv" -Append
}
all
I implemented my first PowerShell script, that does some setup, sets registry keys and at then end needs to restart services. The problem is that I have only have name of the executable, but not service name. Restart-Service can work only with name of the service. Googling (well Binging also) around didn't give me much result.
I was wondering whether there is a way to restart service by executable name?
I know that I can get process by executable name, but just killing the process and starting it again is NOT good choice, since service Start/Stop functions are not called and it may not work properly.
Thanks.
You can try using wmi and do something like this:
(gwmi win32_service | ?{$_.pathname -match "\\executable.exe "}) | Restart-Service
Get-WmiObject -Class Win32_Service -Filter "PathName LIKE '%PartOfTheName%'" -ComputerName PC1 | Foreach-Object{
$_.StopService()
$_.StartService()
}
You can do this using WMI:
$process = Get-Process sqlservr| select -ExpandProperty Id
Get-WmiObject win32_Service|
where {$process -contains $_.ProcessId}|
foreach {Restart-Service $_.Name}
Edit: Changed script to restart service, not just stop it.
#set by logic to determine if the service will restart or not
$global:ServerWillRestart=$true
#can be found using the name column of Get-services cmdlet
$serviceName="Set name of the service"
if($global:ServerWillRestart){
$service =Get-Service | where{ $_.Name -eq $serviceName}
do{
Write-output "The service $ServiceName will is being stopped"
Stop-Service $service
Start-Sleep -s 2
}
while($service.WaitForStatus("Stopped"))
do{
Write-Output "The service $ServiceName will is being started"
Start-Service $service
Start-Sleep -s 2
}
while($service.WaitForStatus("Running"))