How can I hardcode specific server names in powershell script - powershell

I want to reboot specific servers, I am using findstr to find specific servers in the list of 1000's of servers, however, is there any way I can hardcode servernames in a script so the script only run on a particular set of remote servers? Also, how to use for each against array variable. For e.g is below method correct?
$serverlist = "server1,server2,server3"
for each ($server in $serverlist){ $serverboot= gwmi win32_operatingsystem -comp $server
$serverboot.Reboot
}

First define a list of your servers for this the coma (,) is the array operator in PowerShell :
$serverlist = "server1","server2","server3"
Now $serverlist is an array or a collection you can use.
Then you pipe this list in the Foreach-Object Cmdlet that allow you to execute a scriptblock for each element in the list. $_ represent the current element. ; is the instruction seprator :
$serverlist | ForEach-Object {$serverboot= gwmi win32_operatingsystem -comp $_; $serverboot.Reboot()}

Related

Powershell Get-ciminstance error in foreach Loop

New to Powershell, trying to use it to update our AD inventory with Serial Numbers from all computers in the environment. I have exported a .csv with all the machine names, and am trying to run through that in a loop from my machine
The script runs fine without the loop-- if I run it and swap the $name variable with a string it works, and if I run it and define the variable and don't loop it work.When in the loop I get this error:
WS-Management could not connect to the specified destination: (#{Name="PC1"}:5985).
This is a different error than if I type a hostname that doesn't exist or one that isn't in DNS. It's getting the proper info from the .csv like "PC1". tried using start-sleep -second 2 to give it some time to connect to each machine but I don't think that's helping.
$admachines = import-csv .\Computerinventory.csv
foreach ($hostname in $admachines){
$sn = Get-CimInstance -Class win32_bios -ComputerName $hostname |select-object -expandproperty serialnumber
Set-ADComputer -identity $hostname -replace #{serialNumber = $sn}
}

PowerShell - Pass array as an optional parameter value

I'm pretty new to PowerShell.
I'm trying to pass an array of server names as an optional parameter value to get the last bootup time for a list of servers.
Example 1
$serverList = #('server1"', '"server2"', '"server3"', '"server4"', '"server5"')
Get-CimInstance -ComputerName $serverList -ClassName win32_operatingsystem | Select-Object csname, lastbootuptime
Example 2
Get-CimInstance -ComputerName server1,server2,server3,server4,server5 -ClassName win32_operatingsystem | Select-Object csname, lastbootuptime
In example 1, I get an error that says it can't connect to the
servers.
In example 2, it works.
I'm likely missing a key piece of fundamental knowledge as to why what I'm doing wasn't working. What am I missing?
Thanks for the help.
In the first example you are over-doing things with the quotes. (also server1 has an ending double quote, but no starting double quote..)
By putting the servers inside single quotes ', the text inside it is taken literally, so you are feeding the cmdlet with names like "server2", so including the double-qoute characters.
These quotes obviously don't belong to the server name.
BTW: Not an error, but you don't need the #() when creating the server names array.
This would be a better way of setting up your string array, where you can use either single or double quote characters, but not both:
$serverList = 'server1', 'server2', 'server3', 'server4', 'server5'
Get-CimInstance -ComputerName $serverList -ClassName win32_operatingsystem | Select-Object csname, lastbootuptime
You have also noticed that when used as parameters to a cmdlet, you don't even need the quotes, and the elements are interpreted as strings, as long as they do not contain space characters:
Get-CimInstance -ComputerName server1,server2,server3,server4,server5 -ClassName win32_operatingsystem | Select-Object csname, lastbootuptime

Powershell ForEach-Object {Start-Job -Scriptblock} not populating variables

Here is my code, it works and creates a job for each computer in the OU but does not populate the $Computer variable in my script block causing this to fail.
I am sure I am missing something small since I have never created jobs before in Powershell but after working on this for an hour or two I have been unable to figure out what I am missing.
#Gets all workstations that need to have software installed, if you don't want to uninstall all of the software from you will need to use a text document and Get-Content
$computers = Get-ADComputer -Filter * -SearchBase "OU=Workstation Test,OU=Workstations,OU=Workstations,DC=CONTOSO,DC=COM" | Select DNSHostName -ExpandProperty DNSHostname
$Computer
#Use Get-WMIObject to find the IdentifyingNumber
$Computers | ForEach-Object {Start-Job -Name "$Uninstall" -ScriptBlock {(Get-WmiObject -Class Win32_product -ComputerName $Computer -Filter {IdentifyingNumber LIKE '{CD95F661-A5C4-44F5-A6AA-ECDD91C2410B}'}).uninstall()}}
Instead of $computer you need to use $_.
$_ represents the current item in the pipeline.
Alternatively you could do:
ForEach ($Computer in $Computers) { Invoke-Command -ComputerName $Computer -ScriptBlock {(Get-WmiObject -Class Win32_product -Filter {IdentifyingNumber LIKE '{CD95F661-A5C4-44F5-A6AA-ECDD91C2410B}'}).uninstall()} }
Here you continue to use $Computer inside the foreach as it now gets populated with each item in the collection.
Also FYI your $computer line above the ForEach-Object is currently unnecessary (it's just outputting an empty variable, unless you've already populated it elsewhere).
Edit: per comments I also noticed that the start-job seemed redundant as -computername was being used on the wmi cmdlet. Invoke-command is preferred as it uses winrm, so I've modified it as such in my code above.

Using Wildcard with WMIC Version Query

I am an InfoSec admin with an okay amount of PowerShell experience. I'll keep it short and sweet:
([WMI] "\\$comp\root\CIMV2:CIM_DataFile.Name='$path'").Version)
I use this for calling file versions instead of using get-item VersionInfo.ProductVersion, since this does not always return an accurate value. It works well. However, when $path is equal to something like this:
C:\Windows\System32\Macromed\Flash\Flash*.ocx
The query doesn't work because the file is not found. I imagine this is due to the single quotes around the variable ignoring the wildcard.
I will admit that I did find a work around to my problem here (the answer posted by JPBlanc):
Powershell get-item VersionInfo.ProductVersion incorrect / different than WMI
However, I want to know if it is possible for me to use a wildcard with my existing script.
You can't pass a wildcard directly, but you can query the filesystem with that wildcard and then loop through the results. In both cases here, I'm assuming that you're doing this remotely.
$FlashFiles = invoke-command -computername $comp {Get-ChildItem C:\Windows\System32\Macromed\Flash\Flash*.ocx;};
foreach ($File in $FlashFiles) {
write-output "$($File.Fullname): $(([WMI] "\\$comp\root\CIMV2:CIM_DataFile.Name='$($File.FullName)'").Version)"
}
Or do it with a single pipeline:
invoke-command -computername $comp {Get-ChildItem C:\Windows\System32\Macromed\Flash\Flash*.ocx||foreach-object {write-output "$($_.Fullname): $(([WMI] "\\$comp\root\CIMV2:CIM_DataFile.Name='$($_.FullName)'").Version)"};
You can make the latter even faster by running the WMI query local to the remote computer (you could do it with the first too, but it's not as pretty)
invoke-command -computername $comp {Get-ChildItem C:\Windows\System32\Macromed\Flash\Flash*.ocx|foreach-object {write-output "$($_.Fullname): $(([WMI] "\\.\root\CIMV2:CIM_DataFile.Name='$($_.FullName)'").Version)"}};
The Name property of a CIM_DataFile can't contain wildcards. I don't believe any of them can.
However, you can specify the Drive, Path, and Extension to get a list:
Get-WmiObject -ComputerName $comp -Class CIM_DataFile -Filter "Drive='C:' AND Path='\\Windows\\System32\\Macromed\\Flash\\' AND Extension='ocx'"
The syntax of Path is a bit flaky. You need the trailing backslashes, for example.
You can also pipe to Where-Object for further filtering:
Get-WmiObject -ComputerName $comp -Class CIM_DataFile -Filter "Drive='C:' AND Path='\\Windows\\System32\\Macromed\\Flash\\' AND Extension='ocx'" |`
Where-Object { $_.FileName -like 'Flash*' } |`
ForEach-Object { $_.Name; $_.Version }

PowerShell: Service enumeration based on part of service name from multiple machines

I know that I can use PowerShell to check service status on multiple services. For example with something like this:
Get-Service -ComputerName server-a, server-b, server-c -Name MyService |
Select Name, MachineName, Status
Can somebody advice how I can modify this so that:
- Enumerate large number of servers like an array or somehow else so that make it more readable than if I put large number of servers in one line.
- Use a wildcard in service name parameter, e.g. "MYSERVICE*"
You can put your servers in a text file such as SERVERS.TXT :
Server-a
Server-b
Server-c
...
And use :
$servers = get-content SERVERS.TXT
Get-Service -ComputerName $servers -Name MyService | Select Name, MachineName, Status
You can do the same for services.
To answer your second question first, the -Name parameter of the Get-Service cmdlet supports wildcards, so you can simply do this to check several services with similar names:
Get-Service -Computer 'server-a', 'server-b', 'server-c' -Name MyService* |
select Name, MachineName, Status
The -Computer parameter accepts an array of strings, so you can read the server list from a file (containing one hostname per line), as JPBlanc suggested:
$computers = Get-Content 'C:\path\to\serverlist.txt'
Get-Service -Computer $computers -Name MyService* | ...
This is probably the best choice, as it separates data from code.
However, there are situations where it's more practical to keep data and code in the same file (e.g. when you move the script around a lot). In a situation like that you can define an array spanning multiple lines like this:
$computers = 'server-a',
'server-b',
'server-c',
...
Get-Service -Computer $computers -Name MyService* | ...