Find if a program is installed on remote computer - windows

I am trying to connect to remote computers with Active Directory and see if a single program is installed. I have tried a couple tutorials I found on the Internet, but with no success:
http://windowsitpro.com/powershell/what-applications-are-installed-computers-your-network
http://community.spiceworks.com/scripts/show/2170-get-a-list-of-installed-software-from-a-remote-computer-fast-as-lightning
I cannot get them to work properly, and they are not exactly what I am looking for.
An example of what I want to do: say I have 3 computers on my network:
123-abc
123-bcd
123-cde
and I want to see if the executable C:\Program Files (x86)\Mozilla Firefox\Firefox.exe exists. Can someone please explain how I can go about this in PowerShell?

The simplest way, provided you have domain admin privileges and administrative shares are enabled and accessible on the target computers, would be this:
$computers = '123-abc', '123-bcd', '123-cde'
$path = 'C$\Program Files (x86)\Mozilla Firefox\Firefox.exe'
$computers | % {
'{0}: {1}' -f $_, (Test-Path -LiteralPath "\\$_\$path")
}

There are a handful of ways to check for installed software. Some better suited than others. But if you're certain on the file path on each machine, the Test-Path CmdLet could be an easy approach.
Invoke-Command -ComputerName 123-abc -ScriptBlock {Test-Path 'C:\Program Files (x86)\Mozilla Firefox\Firefox.exe'}
You could probably throw that into a loop with a custom object so you can work with it as well.

For example, your code could look like this.
$pass = "password";
$secpass = ConvertTo-SecureString $pass -AsPlainText -Force;
$creds = New-Object System.Management.Automation.PSCredential("domain\login", $secpass);
Invoke-Command -ComputerName 123-abc, 123-bcd, 123-cde -Credential $creds -ScriptBlock {
Test-Path "C:\Program Files (x86)\Mozilla Firefox\Firefox.exe"
};
There are multiple ways of running powershell commands on remote computers.
Many commands support string[] parameter -ComputerName to which you can pass multiple computer names
You can use the Enter-PSSession cmdlet to enter a Telnet-like session on the remote machine
And finally, you can use the Invoke-Command cmdlet to run a script block against multiple remote hosts.

Related

Install Offline Windows Updates(.msu) to remote servers

I'm trying to get a script together to remotely install some windows updates on some remote servers that are connected in an offline domain.
I have tried regular PS Remoting and after some research, I think what I am trying to do isnt supported by microsoft. When checking my event logs I have a bunch of these errors.
Edit
I wanted to add that I have tried running the .\Install2012R2.ps1 script from my local computer, modified to have the Invoke-Command in that and have it run the update portion of the original Install2012R2.ps1 and I would get the same errors.
I was hoping that by placing the script on each server that it would like that more.
End Edit
Windows update could not be installed because of error 2147942405 "Access is denied."
(Command line: ""C:\Windows\System32\wusa.exe" "C:\Updates\windows8.1-kb4556853-x64.msu" /quiet /norestart")
I have tried running Invoke-Command as credentialed to an administrator account on the servers but I have been having no luck and was looking for some advice if someone has maybe tried/done this before.
$Servers = #("V101-Test1","V101-Test2")
$Username = 'admin'
$Password = 'Password'#not actual password
$pass = ConvertTo-SecureString -AsPlainText $Password -Force
$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$pass
Get-PSSession | Remove-PSSession
New-PSSession -ComputerName $Servers
foreach($Server in $Servers){
Get-ChildItem -Path C:\Source\Temp -Recurse | Copy-Item -Destination "\\$Server\c$\Updates\" -Force
}
Invoke-Command $Servers -Credential $Cred -ScriptBlock{
& "C:\Updates\Install2012R2.ps1"
}
EDIT 2
Here is the actual install code of the Install2012R2.ps1 script
$updatedir= "./"
$files = Get-ChildItem $updatedir -Recurse
$msus = $files | ? {$_.extension -eq ".msu"}
$exes = $files | ? {$_.extension -eq ".exe"}
foreach ($file in $msus){
$KBCtr++
$fullname = $file.fullname
# Need to wrap in quotes as folder path may contain space
$fullname = "`"" + $fullname + "`""
$KBN = $fullname.split('-')[1]
# Need to wrap in quotes as folder path may contain space
$fullname = "`"" + $fullname + "`""
# Specify the command line parameters for wusa.exe
$parameters = $fullname + " /quiet /norestart"
# Start services and pass in the parameters
$install = [System.Diagnostics.Process]::Start( "wusa",$parameters )
$install.WaitForExit()
}
I'm not sure why wusa.exe is failing here with Access Denied, but here is a PowerShell-native approach you can try. If nothing else, it should give you a clearer indication via the captured error information as to what the underlying issue is:
Add-WindowsPackage -Path C:\Updates\OurHeroicUpdate.msu -Online -PreventPending -NoRestart
-Path is the path to the msu file
-Online tells Add-WindowsPackage to modify the currently "mounted image" (the running version) of Windows (as opposed to an offline disk image you could also apply it to)
-PreventPending prevents installing the msu if there is already a pending change, like needing to reboot for updates.
Add-WindowsPackage is part of the DISM module available under Windows PowerShell, and is the functional equivalent of dism /packagepath:"cabfile", although it can take an msu where dism.exe only allows a cab.

How to check network folder exist with credentials using powershell 5

Lest say there is a network folder \\my_server\my_root\my_dir.
To access this folder these credentials required username: my_doman\my_user password: my_password.
Now in my program first it try to map network folder to a local drive. If there is a exception, it consider as folder not exist. I think this is not a good way.
Is there a way to check this folder exist without try to map to a local drive? I'm looking for something like
[System.IO.Path]::Exist("\\my_server\my_root\my_dir","my_doman\my_user","my_password")
I'm using Powershell 5
This is how I map the drive now
try{
$net = new-object -ComObject WScript.Network
$net.MapNetworkDrive($free_drive, $network_dir, $false, "domain\user", "password")
}catch{
Write-host: "folder does not exist"
}
Using New-PSDrive:
New-PSDrive -Name Q -PSProvider FileSystem -Root \\my_server\my_root\my_dir -Credential my_domain\my_user -Persist
Old School method using cmdline utility:
net use \\my_server\my_root\my_dir /user:my_domain\my_user my_password
start \\my_server\my_root\my_dir
For mapping you can use this:
$net = New-Object -comobject Wscript.Network
$net.MapNetworkDrive("Q:","\\my_server\my_root\my_dir",0,"my_domain\my_user","my_password")
For testing the path, you can use:
Test-Path \\my_server\my_root\my_dir
Note:You will get a boolean value in return from the test path.
Hope it helps.
Assuming that on the machine executing the script you're able to log in as the user under which you want to connect to the remote share, you could use Invoke-Command to invoke Test-Path as another user:
$pathExists = Invoke-Command -ComputerName . -Credential $credentials -ScriptBlock {
Test-Path -Path "\\my_server\my_root\my_dir"
}
if ($pathExists)
{
# my_dir\ exists
}
else
{
# my_dir\ is inaccessible/non-existent
}
I'm not in a position to test this at present but I suspect you may need to include -Authentication Credssp as a parameter to Invoke-Command (assuming the necessary environment for that is in place) due to the double-hop problem.
Of course, if you're checking for the existence of that directory under another user in order to make decisions for future filesystem operations to be executed as that same user, you would then need to Invoke-Command another batch of operations or include them after Test-Path. At that point you might be better off connecting to the share under alternate credentials in the usual way. It's just the difference between executing as another user and connecting as another user, each with their own pros and cons.
I was having the same problem checking the folder and/or file existence on a remote server before copying the file from deployment server. Nothing worked for me and ended up in a huge frustration.
I then tried this...
$pathExists = Invoke-Command -ComputerName <remoteServerName> -Credential $credentials
-ScriptBlock {
Test-Path -Path <AbsolutePath> "UNC path does not work here and you must use Absolute
path. eg. instead of \\Server use D:\Dir1 or D:\Dir1\File1.bat"
}
if (-not ($pathExists))
{
write-host "Directory or File does not exist"
}
else
{
write-host "Directory or File exist"
}
This worked just fine for me after using the absolute path in the Test-Path. For some reason the UNC path does not work! Hope, this helps someone!

PSExec on Windows Server Startup Script

I'm programatically launching a Google Cloud Compute Instance running Windows Server 2016 with a start up script.
The executable in the start up script requires to be launched as a specific user, so I'm trying to launch it with psexec to simulate said user:
C:/psexec.exe \\\\WIN-SERVER-2016 -u WIN-SERVER-2016\\customuser -p custompassword -accepteula -w "c:/app" cmd /c node index.js
c:/app/index.js contains a simple hello world, which should write to a file.
If I log in as any user and launch this exact command from cmd, the file is written. Launching from the startup script (supplied as windows-startup-script-cmd in the Google Cloud Compute Engine Instance) results in no file written.
What could be the solution? Is there a more efficient way to execute a start-up script as a specific user?
Looking at the concern , I would not recommend you to use PSEXEC .
NOrmally, we use PSExec in order to invoke a GUI in the remote system which PS doesn't support by native.
In your case, I would suggest you to run using the Invoke-Command
Something like this:
$username = 'WIN-SERVER-2016\customuser'
$password = "custompassword"
$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr
$Script_block = {cmd /c node index.js}
Invoke-Command -ComputerName WIN-SERVER-2016 -Credential $cred -ScriptBlock $Script_block
This should also take it from the Metadata key if you are using windows-startup-script-cmd
Note: I have not considered the accepteula -w "c:/app" part. Please incorporate the placeholders accordingly.
Hope it helps...!!!

Handle command for remote pc

I want to run handle for a specific folder for a remote pc at my network so to know which processes are locking the folders.
tried:
handle /accepteula \\remotePcName\c:\myFolder
handle /accepteula \\remotePcName\User(name of the account)\c:\myFolder
and some other combinations with no luck getting
No matching handles found.
Is it possible to do this? Run handle for a remote pc?
Could you please try like this:
c:\powershell\Tools\psexec.exe \\remotePcName C:\handle.exe c:\myFolder
How about using invoke-command to execute 'handles' remotely?
$serverName = 'serverName'
$pathtoCheck = 'C:\temp' # folder you want to check on the remote server.
$pathtoHandle = 'c:\temp\handle.exe' #location of handle.exe on the remote server.
Invoke-command -ComputerName $serverName -Scriptblock {
param(
[string]$handles,
[string]$pathToCheck
)
"$handles /accepteula $pathToCheck" | Invoke-Expression
} -ArgumentList $pathtoHandle,$pathtoCheck

Install .net remotely via powershell

I’m attempting to install the .net framework on a windows server 2008 r2 machine remotely via PowerShell. Reading about it seems that this cannot be achieved through an existing PowerShell session but credentials need to be explicitly passed in (any idea why this is?). However, I'm still getting permission errors.
For example, If I run:
$cred = Get-Credential -Credential 10.20.0.13\administrator
$Session=New-PsSession -ComputerName 10.20.0.13 -Credential $cred
Invoke-command -ScriptBlock {Start-Process -FilePath c:\installers\dotNetFx40_Full_x86_x64.exe -ArgumentList "/q /norestart /log c:\" -Wait} -Credential $cred -ComputerName 10.20.0.13
I can see on the remote machine that the installer runs (in task manager), the temporary folder is created on the root of c:\, the files extracted and then I get a 700kb log file. At the foot of that log file I get:
OS Version = 6.1.7601, Platform 2, Service Pack 1 OS Description =
Win2K8R2 - x64 Standard Edition Service Pack 1 CommandLine =
C:\b65da67b927bfb71c84adcecefc019\Setup.exe /q /norestart /log c:\
/x86 /x64 TimeZone = GMT Standard Time Initial LCID = 2057 Using
Simultaneous Download and Install mechanism Operation: Installing
Package Name = Microsoft .NET Framework 4 Setup Package Version =
4.0.30319 User Experience Data Collection Policy: Disabled Number of applicable items: 11 Exe
(C:\b65da67b927bfb71c84adcecefc019\SetupUtility.exe) succeeded. Exe
Log File: dd_SetupUtility.txt ServiceControl operation succeeded!
ServiceControl operation succeeded! Exe
(C:\b65da67b927bfb71c84adcecefc019\Windows6.1-KB958488-v6001-x64.msu)
failed with 0x5 - Access is denied. . Final Result: Installation
failed with error code: (0x00000005), "Access is denied. " (Elapsed
time: 0 00:01:12).
So access is denied. However, using the exact same credentials I can perform other tasks (add server roles in Powershell, add windows features via powershell etc) and I can RDP onto the box using the same username/password and run the installer there (which completes fine).
I’m missing something somewhere, but can’t seem to find out what it is. I can see its worked for someone else (http://social.technet.microsoft.com/Forums/windowsserver/ar-SA/3045eb24-7739-4695-ae94-5aa7052119fd/install-dotnet-framework-4-using-powershell?forum=winserverpowershell) so no idea why I’m getting this.
Any help much appreciated.
Thanks
You're creating a session but never using it?
I haven't tried this on a remote computer beforey, but try to run the process "as admin" by using -Verb RunAs, like this:
$cred = Get-Credential -Credential 10.20.0.13\administrator
$Session=New-PsSession -ComputerName 10.20.0.13 -Credential $cred
Invoke-command -ScriptBlock {Start-Process -FilePath c:\installers\dotNetFx40_Full_x86_x64.exe -ArgumentList "/q /norestart /log c:\" -Wait -Verb RunAs } -Session $Session
While installation of .NET framework 4.0, It installs some updates as well (.msu) files.
But when we are installaing .NET 4.0 remotely, It fails because of these updates. The reason behind that is, it's not allowable to install these updates remotely. Please find the KB article here. This article also mentioned the workaround for this.
you have servername in textfile or machine names in OU based. create .bat which has .exe to run C:\temp\xxx.exe /S /qn
$ou='OU=subou3,OU=subou2,OU=subou1,DC=domain,DC=com'
$filter = #("machinename1", "machinename2")
$compute= Get-ADComputer -Filter * -SearchBase $ou | where-object{$filter -contains $_.name}
$comp=$compute.name
foreach ($Computer in $Comp) {
Write-Host "Processing $Computer"
{
Write-Host " Installing application on $Comp"
psexec $Compter path\XXX.bat /S /qn
}
}

Resources