I am trying to get the mibinfo for multiple dhcp servers in our infrastructure. My problem is that when i run the command
invoke-command -computername $dhcpserver -credential $Cred -scriptblock{netsh dhcp server show mibinfo}
I get MIBinfo for all the servers, but i don't get the name of the server in the output. So i need a way where i get the output as
Server1
mibinfo
server2
mibinfo
($dhcpserver has the list of all the dhcp servers.)
Is $dhcpserver an array of strings? I didn't know Invoke-Command could do this...
If so, try this:
Foreach ($server in $dhcpserver) {
$mibOutput = invoke-command -computername $server -credential $Cred -scriptblock{netsh dhcp server show mibinfo}
Write-Output "$server $mibOutput"
}
Related
I am working on a script that will connect to a list of servers, some of the servers would have issues such as being offline, winRM issues, general server health etc. I would like to attempt connection to the host, and have a timeout for winrm connectivity issues.
So far I have come up with the script below.
$list = #('server1','server2','server3')
$session = New-PSSession -ComputerName $list -ErrorAction SilentlyContinue -credential Get-Credential
$timeout = 30
$remote = Invoke-Command -Session $session -ScriptBlock {[System.Net.Dns]::GetHostName()} -AsJob
$remote | Wait-Job -Timeout $timeout
$output = $remote | Receive-Job
foreach ($server in $output)
{
invoke-sqlcmd -ServerInstance "servername" -Query "insert into mytable select '$server'"
}
What is the problem.
In the example above, I have no way of tracking servers that failed and what ends up happening is that I can see my list has server1, server2 and server3, if after checking my database I only find server1 and server2, I have to do a diff to work out that server3 must have timed out or failed.
What am i trying to achieve.
To have a script that can deal with thousands of servers, run a simple command on each host and return back the result, for servers that timeout or experience issues, log the particular server, log a progress log from the array list and as a bonus, if the script can run in parallel to speed up the progress of the execution.
I have a centralized server from which i can run the following PowerShell command to get the clustergroup of cluster servers.
Enter-pssession -computername (ip-address) -credential (domain user)
And it prompts me to enter password then i get the session and execute
get-clustergroup
Okay till this it is fine.
Now i wanted to make this fully automated by converting in to a PowerShell script
The following commands works well when i run it in Powershell ISE and gets me the output of get-clustergroup
$password = ConvertTo-SecureString "password" -AsPlainText -Force
$user = "domain\user"
$cred = New-Object System.Management.Automation.PSCredential ($user,$password)
Enter-PSSession -ComputerName IP.Add.RE.SS -Credential $cred
get-clustergroup
but when i save the about script and run with PowerShell i get the following error.
get-clustergroup: the cluster service is not running
I want to automate the process by writing script to get get-clustergroup output of four cluster servers.
i am new to PowerShell scripting. how can i save the output?
Instead of creating a session to the other server, you can run the following which will run the command on the remote computer and return the output to your console:
Invoke-Command -ComputerName <IPAddress> -ScriptBlock { Get-ClusterGroup } -Credential $cred
You can store that output into a variable if you wish for future retrieval.
Since -ComputerName can accept an array object, you can modify your command to include all four of your servers. Below shows how to use all of your computer names and store the output in the variable $Output:
$Output = Invoke-Command -ComputerName "Server1","Server2","Server3","Server4" `
-ScriptBlock {Get-ClusterGroup} -Credential $cred
$Output
Your computer names could also be stored in a variable as an array. Then that variable can be used in your -ComputerName parameter:
$Computers = "Server1","Server2","Server3","Server4"
Invoke-Command -ComputerName $Computers -ScriptBlock { Get-ClusterGroup } -Credential $cred
See Invoke-Command for more information.
The remote computer are Win-10 VM in a VLAN.
We only have a few ports open in VLAN, including 3389 for Remote Desktop, 5985 & 5986 for powershell.
Remote Desktop works well.
But I couldn't to use powershell to remote debug on those computers,
If I run
Get-WinEvent -LogName System -Credential domain\test_user -ComputerName 10.100.155.1
I get this error
Get-WinEvent : The RPC server is unavailable
If I use invoke-command to execute the same script,
Invoke-Command -ComputerName 10.100.155.1 -Credential domain\test_user -ScriptBlock {Get-WinEvent -LogName System -Credential domain\test_user -ComputerName 10.100.155.1}
I will get another error:
[10.100.155.1] Connecting to remote server 10.100.155.1 failed with the following error message : Access is denied.
I have tried many solutions on internet, unfortunately, none is working. For example, I have checked if the services are running, if the firewall allows remote event management on remote computer, they looks alright.
Any idea where could be wrong?
Your problem is two-fold.
You cannot use WinRM (Invoke-Command) with an IP address. It uses Kerberos and Kerberos requires a DNS name.
You're passing your credentials and computername twice.
This should work without a problem:
$InvokeArgs = #{
ComputerName = 'Computername.domain.com'
Credential = (Get-Credential -Credential domain\test_user)
ScriptBlock = { Get-WinEvent -LogName System }
}
Invoke-Command #InvokeArgs
Access Denied is an Authentication Issue, double check your username and password.
I was working on a similar problem, trying to fetch count of system logons. Here's what worked for me:
$fetchEvents = { Get-WinEvent -FilterHashtable #{
Logname='system'
ProviderName='Microsoft-Windows-Winlogon'
StartTime=(get-date).AddDays(-10)
ID = 7001
} | Format-Table -Property TimeCreated, UserID, ID, MachineName }
Invoke-Command -ComputerName $ServerList -Credential $creds -ScriptBlock $fetchEvents
When running the below code, i can put anything in the block at the bottom - I'm trying to copy a folder across to run an exe from a local folder and perform an install of that exe during the remote session to remote machines. I am getting Access Denied Errors. I read, i cant use the Kerberos Delegation Cmdlets which are only for a forest level of 2012 and above. Current Site has Domain Functional Level 2008 R2. Is there another way to achieve copying the files across during each remote session to the computers specified in the text file?
Thanks in advance
########################################
$Cred = Get-Credential DOMAIN\USER
$Computers = Get-Content C:\tab.txt | Where-Object { $_ }
ForEach ($Computer in $Computers)
# {
# if (Test-Connection -ComputerName $Computer -BufferSize 16 -Count 1 `
-Quiet)
{
# Creates a new remote PowerShell Session and script block - enter
the code you want to execute remotely from this block
$Session = New-PSSession $computer -Credential $cred
Invoke-Command -Session $Session -ScriptBlock {
Copy-Item -Path "\\print-server\pcclient\win\*" -Destination
"c:\pcclient" -Force -Recurse -Verbose
# Start-Sleep -s 10
# Start-Process "\\Print-Server\PCClient\win\client-local-install.exe" -ArgumentList "/SILENT"
}
}
Remove-PSSession -Session $Session
# }
This is because you're on a remote machine, trying to access another network resource. When you connect to the remote machine in PowerShell, you're effectively connected/authenticated to that machine only, (unless you specify otherwise) it doesn't have access to your credentials to access the network share, so the connection to the network share is treated as unauthenticated, hence the failure.
This article https://blogs.technet.microsoft.com/heyscriptingguy/2012/11/14/enable-powershell-second-hop-functionality-with-credssp/ covers it well, essentially in you will need to run this locally (to allow your machine to pass credentials):
Enable-WSManCredSSP -Role Client -DelegateComputer * -Force
On the server run (to allow the server to accept these credentials):
Enable-WSManCredSSP -Role Server –Force
And update your New-PSSession command to:
$Session = New-PSSession $computer -Credential $cred -Authentication CredSSP
If you want, you can share your credentials with only specific machines, or subsets of a domain using *.yourdomain.lan or whatever, if you connect to multiple machines, then it's easier to use -DelegateComputer *.
I have created a list of objects, $LIST. Each object in the list has several attributes, including FQDN and Services. FQDN is the fully qualified server name and the services are the list of services I want to check on the remote server.
I'll start with:
$LIST = <CALL to Module function to populate the server information>
Next is the call to the invoke-command
Invoke-Command -ComputerName $LIST.FQDN -ScriptBlock {
Write-Host "Working on $($env:ComputerName)"
Get-Service
}
But what I need to do is pass the list of services that correspond to -ComputerName. I know I can use the -ArgumentList and I've tried:
Invoke-Command -ComputerName $LIST.FQDN -ScriptBlock {
Param ([string[]] $ServiceList)
Write-Host "Working on $($env:ComputerName)"
($ServiceList -split(",")).trim() | %{
$svc =Get-Service $_
$Svc
}
} -ArgumentList $LIST.Services
But this passes a list of all the services for every server. I can do this:
$LIST | %{
$Server = $_
Invoke-Command -ComputerName $Server.FQDN -ScriptBlock {
Param ([string[]] $ServiceList)
Write-Host "Working on $($env:ComputerName)"
($ServiceList -split(",")).trim() | %{
$svc =Get-Service $_
$Svc
}
} -ArgumentList $($Server.SERVICES)
}
But then I loose the advantage of parallelism of the invoke-command CmdLet.
How do I pass the list of services for the specific ComputerName being processed?
If $LIST["COMPUTER"].SERVICES return list service of COMPUTER you can test in your scriptblock for every object passed..maybe This but not tested: (in pseudo-code)
Icm -comp $LIST.FQDN -Script {
Param($obj)
$c=$env:computername
$obj["$c"].services
} -arg $LIST
I don't think there is an easy way to pass your list through Invoke-Command, so perhaps you need to think of alternative approaches that will let each target computer run an identical command.
If the list of services is specific to each remote computer, and is the same every time you run the commands then you could simply store the parameter on each target computer in the registry or a file. Ideally you set that up using a configuration manager such as DSC, Puppet, or Chef.
You could dump the parameters out to files on the local computer and let each target computer connect back to a network share and fetch the file corresponding to its name. If a network share connection isn't possible then a simple web service or a database connection would be other ways you could let each computer fetch the service list.
Are there groups of targets that will receive the same list? Say you have 10 different service lists each to be sent to a group of 100 computers. In that case maybe you could choose an arbitrary computer from each group and send those computers an identical command with all of the data. Each computer you target then figures out which group it is in and distributes the identical command across all of its siblings. This would also have the benefit of increasing the parallelism.
Or just create one set of services that is the union of all the service lists, send that to every machine, and filter the results based on which you wanted. That could be the simplest solution:
PS C:\WINDOWS\system32> $allServices = 'WerSvc','WinRM','ZeroConfigService','AnotherService'
PS C:\WINDOWS\system32> Invoke-Command -ComputerName . -ScriptBlock {
Get-Service -Name $args -ErrorAction Ignore
} -ArgumentList $allServices
Status Name DisplayName PSComputerName
------ ---- ----------- --------------
Stopped WerSvc Windows Error Reporting Service localhost
Running WinRM Windows Remote Management (WS-Manag... localhost
Running ZeroConfigService Intel(R) PROSet/Wireless Zero Confi... localhost
will simply ignore any services you asked for that aren't installed on that particular machine.
For the sake of testing, I've created two objects containing a pointer to localhost, and a list of specific services to verify. Goal is to invoke background jobs that will run remotely and in parallel, and verify the provided list of services.
One of the key parts in the script below is the generated array for the Invoke-Command argumentlist, which contains the services array for the associated computer. The rest is pretty much your code. Finally I use Get-Job | Receive-Job to retrieve the output from the Invoke-Command jobs.
$LIST = #()
$Computer1 = New-Object PSObject -Property #{
FQDN = "localhost";
SERVICES = #()
}
$Computer1.SERVICES += "W32Time"
$Computer1.SERVICES += "vmms"
$LIST += $Computer1
$Computer2 = New-Object PSObject -Property #{
FQDN = "localhost";
SERVICES = #()
}
$Computer2.SERVICES += "ShellHWDetection"
$Computer2.SERVICES += "SharedAccess"
$LIST += $Computer2
$LIST | %{
$Server = $_
$arguments = #(,($Server.SERVICES))
Invoke-Command -ComputerName $Server.FQDN -AsJob -ScriptBlock {
Param ([string[]]$ServiceList)
Write-Host "Working on $($env:ComputerName)"
($ServiceList -split(",")).trim() | %{
$svc =Get-Service $_
$Svc
}
} -ArgumentList $arguments
}
Get-Job | Receive-Job
Output is this:
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
28 Job28 RemoteJob Running True localhost ...
30 Job30 RemoteJob Running True localhost ...
Working on CORSAIR-PC
Status Name DisplayName PSComputerName
------ ---- ----------- --------------
Stopped W32Time Windows Time localhost
Running vmms Hyper-V Virtual Machine Management localhost
Working on CORSAIR-PC
Running ShellHWDetection Shell Hardware Detection localhost
Stopped SharedAccess Internet Connection Sharing (ICS) localhost
So, distinct services per computer were passed to Invoke-Command which runs in parallel jobs using the -AsJob parameter.