I am trying to stop a specific set of services, using .StartsWith to find them.
Get-Service | ForEach {
$name = $_.Name
if ($name.StartsWith("FooBar")) {
# stop service
if ($_.Status -ne "Stopped") {
Stop-Service "$name" -Force
$_.WaitForStatus('Stopped', '00:01:00')
Write-Host "Service $name stopped."
}
}
}
This works fine - services FooBarBinglyBong and FooBarJingleJangle will be stopped. However when I try and do this:
[string] $input = Read-Host -prompt 'Stop services starting with'
Get-Service | ForEach {
$name = $_.Name
if ($name.StartsWith("$input")) {
...
It stops every single service. What am I doing wrong?
Changing $input to $input2 works.
My fault for using a reserved word I guess.
Related
My goal is to check the services on multiple remote machines to make sure they are running, and starting them if they are not. I would like to modify the below code to add the ability to ask the user before proceeding to the next $computerName, to display and confirm the status of group of $serviceNames that is being passed through the function.
In a text file servers.txt the contents are as follows:
server1-serviceA,ServiceB,ServiceC
server2-serviceD,ServiceE,ServiceF
server3-serviceG,ServiceH,ServiceI
And here is the powershell script, checking different services for each server using the split function
$textFile = Get-Content C:\temp\servers.txt
foreach ($line in $textFile) {
$computerName = $line.split("-")[0] #Getting computername by using Split
$serviceNames = $line.split("-")[1] #Getting Service names by using split
foreach ($serviceName in $serviceNames.split(",")) {
# Again using split to handle multiple service names
try {
Write-Host " Trying to start $serviceName in $computerName"
Get-Service -ComputerName $computerName -Name $serviceName | Start-Service -ErrorAction Stop
Write-Host "SUCCESS: $serviceName has been started"
}
catch {
Write-Host "Failed to start $serviceName in $computerName"
}
}
}
You could use the PSHostUserInterface.PromptForChoice method for this, here is an example of how you can implement it:
# Clear this variable before in case it's already populated
$choice = $null
foreach ($line in $textFile) {
$computerName = $line.split("-")[0]
$serviceNames = $line.split("-")[1]
# If previous choice was not equal to 2 (Yes to All), ask again
if($choice -ne 2) {
$choice = $host.UI.PromptForChoice(
"my title here", # -> Title
"Continue with: ${computerName}?", # -> Message
#("&Yes", "&No", "Yes to &All"), # -> Choices
0 # -> Default Choice (Yes)
)
}
# If choice was 1 (No), stop the script here
if($choice -eq 1) { return }
# Same logic here
}
New to Powershell, My goal is to go through a list of remote Computers and check to see if certain services are running on them and starting the services if they are not. what would be the best approach in creating a variable for the services on said servers?
Server1.txt - 'ServiceA ServiceB ServiceC'
Server2.txt - 'ServiceD ServiceE ServiceF'
Server3.txt - 'ServiceG ServiceH'
$services = get-content .\Server1.txt
$services | ForEach {
try {
Write-Host "Attempting to start '$($.DisplayName)'"
Start-Service -Name $.Name -ErrorAction STOP
Write-Host "SUCCESS: '$($.DisplayName)' has been started"
} catch {
Write-output "FAILED to start $($.DisplayName)"
}
}
Thank you.
In your input, you have mentioned one text file for each server which is not advisable. Also there is no computer name in your Start-service Command. Please find my input sample below.
server1-serviceA,ServiceB,ServiceC
server2-serviceD,ServiceE,ServiceF
server3-serviceG,ServiceH,ServiceI
And here is the powershell script, since you have mentioned different services for each server there is a need for using split function.
$textFile = Get-Content C:\temp\servers.txt
foreach ($line in $textFile) {
$computerName = $line.split("-")[0] #Getting computername by using Split
$serviceNames = $line.split("-")[1] #Getting Service names by using split
foreach ($serviceName in $serviceNames.split(",")) {
# Again using split to handle multiple service names
try {
Write-Host " Trying to start $serviceName in $computerName"
Get-Service -ComputerName $computerName -Name $serviceName | Start-Service -ErrorAction Stop
Write-Host "SUCCESS: $serviceName has been started"
}
catch {
Write-Host "Failed to start $serviceName in $computerName"
}
}
}
I haven't tested the script for starting the service, but the loop works properly for multiple servers and their respective services. Thanks!
let's say that I have following Powershell script that contains severall powerhsell commands
Get-Service -Name BITS
Get-Service -Name WinDefend
Get-Service -name Winmgmt
Get-Service -Name WdNisSvc
How can I make my script like that that it would ask which of 4 commands it would run like
Select which command you would like to run:
1. Get-Service -Name BITS
2. Get-Service -Name WinDefend
3. Get-Service -name Winmgmt
4. Get-Service -Name WdNisSvc
and they based of my selection it will run only wanted command
EDIT: I was now able to solve problem this far but now issue is that: how do I prompt these to user so user can select them and save the answer so I can use it after "Write-Host "Now we can perform [$input]""
$input = Read-Host -Prompt 'Select what operation you want to perform'
1. Get-Service -Name BITS
2. Get-Service -Name WinDefend
3. Get-Service -name Winmgmt
4. Get-Service -Name WdNisSvc
if ($input) {
Write-Host "Now we can perform [$input]"
**here should then answer be executed**
} else {
Write-Warning -Message "No input selected"
}
You can create a menu like below.
If you're interested in learning what's being applied on the menu:
about Do
Matching Operators
about_Switch
$services = #(
'BITS'
'WinDefend'
'Winmgmt'
'WdNisSvc'
)
$servCount = $services.Count
do
{
# Phrase this correctly so it's clear user should select a Number
'Select a Service you would like to query:'
$services | ForEach-Object -Begin { $i = 1 } -Process {
"$i. $_"; $i++
}
switch -Regex($selection = Read-Host)
{
"^[1-$servCount]{1}$" {
Get-Service $services[$selection-1]
'Press ENTER to continue...'
Read-Host
Clear-Host
break
}
"Q" { break }
Default { Write-Warning 'Invalid Selection!' }
}
}
until($selection -eq 'Q')
Can anyone figure out a clever way to grab the Hostname of a VM while it's still Off using PowerShell?
I only know how to grab the VM's Hostname while the VM is still On.
PS: I want the hostname/DNSName of the VM (not to be confused with the VM Name); which aren't the same thing.
You could try
get-vm |select-object -ExpandProperty network* |select-object -ExpandProperty ipaddresses |Resolve-DnsName
to grab the VM's IP address and do a reverse DNS lookup on it.
Bit late to the show here, but I took Greyula-Reyula's quite efficient answer and turned it into a function that gives more feedback on why you may be getting no output from it. I'm relatively new to this level of scripting, so I'm sure there's a more efficient way to do this, but I'm a fan of "verbosity" and try to make my scripts as easy-to-follow for myself as possible in case I want to mess with them again later. :)
Function Get-HVComputerName
{
[CmdletBinding()]
param(
[Alias("ServerName")][Parameter()]
$HVHostName = $env:COMPUTERNAME,
[Alias("ComputerName")][Parameter()]
[string[]]$VMName
)
#VMWare.VimAutomation.Core also has a "Get-VM" cmdlet,
#so unload that module if it's present first
If (Get-Module -Name VMware*) { Remove-Module -Name VMware* -Verbose:$false }
If (!(Get-Module -Name Hyper-V)) { Import-Module -Name Hyper-V -Verbose:$false }
$VMs = Get-VM -ComputerName $HVHostName -Name "*$VMName*"
If ($VMs)
{
$DNSNameArr = #()
If ($VMs.Count -gt 1)
{
Write-Host "`nFound the following VMs on Hyper-V server $HVHostName with name like `"`*$VMName`*`":" -ForegroundColor Green
$VMs.Name | Out-Default
Write-Host ""
}
ForEach ($VM in $VMs)
{
$Name = $VM.Name
If ($VerbosePreference -eq "Continue")
{
Write-Host ""
}
Write-Verbose "VM: $Name found on server $HVHostName"
If ($VM.State -ne "Running")
{
Write-Verbose "VM: $Name is not in a 'running' state. No IP address will be present.`n"
Continue
}
$VMNetAdapters = $VM | Select-Object -ExpandProperty NetworkAdapters
If ($VMNetAdapters)
{
Write-Verbose "VM $Name - Found the following network adapter(s)"
If ($VerbosePreference -eq "Continue")
{
$VMNetAdapters | Out-Default
}
ForEach ($NetAdapter in $VMNetAdapters)
{
$AdapterName = $NetAdapter.Name
$IPAddresses = $NetAdapter | Select-Object -ExpandProperty IPAddresses
If ($IPAddresses)
{
Write-Verbose "VM: $Name - Adapter: `"$AdapterName`" - Found the following IP address(es) on network adapter"
If ($VerbosePreference -eq "Continue")
{
$IPAddresses | Out-Default
}
ForEach ($IP in $IPAddresses)
{
$DNSName = $IP | Resolve-DnsName -Verbose:$false -ErrorAction SilentlyContinue
If ($DNSName)
{
$DNSFound = $true
$VMDNS = [PSCustomObject]#{
VMName = $Name
IP = $IP
DNSName = $DNSName.NameHost
}
$DNSNameArr += $VMDNS
}
Else
{
Write-Warning "VM: $Name - Adapter: `"$AdapterName`" - IP: $IP - No DNS name found"
Continue
}
}
If (!($DNSFound))
{
Write-Warning "VM: $Name - No DNS entries found for any associated IP addresses"
}
Else
{
$DNSFound = $false
}
}
Else
{
Write-Warning "VM: $Name - Adapter: `"$AdapterName`" - No IP address assigned to adapter"
Continue
}
}
}
Else
{
Write-Warning "VM: $Name - No Network adapters found"
Continue
}
}
If ($DNSNameArr)
{
If ($VerbosePreference -eq "Continue")
{
Write-Host ""
}
Return $DNSNameArr
}
Else
{
Write-Warning "No DNS names found for VM(s) with name like $VMName on server $HVHostName"
}
}
Else
{
Write-Warning "No VM found on server $HVHostName with name like $VMName"
}
} #End function Get-HVComputerName
Below function I want to pass multiple value in array. When I'm passing more than one value I am getting an error.
function CheckProcess([String[]]$sEnterComputerNameHere, [String[]]$sEnterProccessNameHere) {
#Write-Host " $sEnterComputerNameHere hello"
#($sEnterComputerNameHere) | ForEach-Object {
# Calling Aarray
#($sEnterProccessNameHere) | ForEach-Object {
if (Get-Process -ComputerName $sEnterComputerNameHere | where {$_.ProcessName -eq $sEnterProccessNameHere}) {
Write-Output "$_ is running"
} else {
Write-Output "$_ is not running"
}
}
}
}
$script:sEnterProccessNameHere = #("VPNUI") # Pass the process agreement here
$script:sEnterComputerNameHere = #("hostname") # Pass the process agreement here
CheckProcess $sEnterComputerNameHere $sEnterProccessNameHere
Give it a try with this one:
Function CheckProcess([String[]]$sEnterComputerNameHere,[String[]]$sEnterProccessNameHere)
{ #Write-host " $sEnterComputerNameHere"
#($sEnterComputerNameHere) | Foreach-Object {
$computer = $_
Write-Host $computer
#($sEnterProccessNameHere) | Foreach-Object {
$process = $_
Write-Host $process
try{
$x = get-process -computername $computer #Save all processes in a variable
If ($x.ProcessName -contains $process) #use contains instead of equals
{
Write-Output "$process is running"
}
else
{
Write-Output "$process is not running"
}
}
catch
{
Write-Host "Computer $computer not found" -ForegroundColor Yellow
}
}
}
}
$script:sEnterProccessNameHere = #("VPNUI","Notepad++","SMSS")
$script:sEnterComputerNameHere = #("remotecomputer1","remotecomputer2")
CheckProcess -sEnterComputerNameHere $sEnterComputerNameHere -sEnterProccessNameHere $sEnterProccessNameHere
In general, it would be great if you write the error you get in your question. That helps others to help you.
If I work with arrays and | Foreach, I always write the $_in a new variable. That helps if I have another | Foreach (like you had) to know for sure, with which object I'm working with..
EDIT: I changed the script, so it uses "-contains" instead of "-eq" and I added a try/catch block, so if the other computer is not found, it gives you a message.. It works on my network
EDIT2: Do you have access to the other computers? If you run get-process -computername "name of remote computer" do you get the processes?