Unexpected Token with service script - powershell

I wrote a script that manages services on the server and starts/stops etc...depending on the Task in the csv file, as well as changes the startuptype, again depending on the start up type in the csv file.
CSV file:
Server,Service,Startup Type,Task
server1,SQL Server Analysis Services (MSSQLSERVER),automatic,start
server2,"SQL Server Analysis Services (MSSQLSERVER), SQL Server Analysis Services (MSSQLSERVER) CEIP",Manual,stop
Script
$csvFile = Import-CSV .\SSAS_services.csv
$ServiceState = Get-Service -Name
$ServiceStartupType = Get-Service | select -property name,starttype
ForEach ($row in $csvFile)
{
#checking if service in csv file exists on server
if (Get-Service $row.Service | Select-Object Name, StartType, Status -ComputerName $row.Server -ErrorAction SilentlyContinue)
{
"$row.Service not found on $row.Server!" | out-file .\SSAS_services.txt -Append
}
else
{
Get-Service $row.Service | Select-Object Name, StartType, Status -ComputerName $row.Server | select machinename,name | format-table -AutoSize
}
# Change the service on the server
if ($row.Task -eq "stop" -and $row.Server $ServiceState $row.Service -ne "stop")
{
Invoke-Command -ScriptBlock { Stop-Service $using:row.Service } -ComputerName $row.Server -ArgumentList $row
Start-Sleep 60
}
elseif ($row.Task -eq "start" -and $row.Server $ServiceState $row.Service -ne "start")
{
Invoke-Command -ScriptBlock { Start-Service $using:row.Service } -ComputerName $row.Server -ArgumentList $row
Start-Sleep 60
}
elseif ($row.Task -eq "pause" -and $row.Server $ServiceState $row.Service -ne "pause")
{
Invoke-Command -ScriptBlock { Suspend-Service $using:row.Service } -ComputerName $row.Server -ArgumentList $row
Start-Sleep 60
}
elseif ($row.Task -eq "Restart")
{
Invoke-Command -ScriptBlock { Restart-Service $using:row.Service } -ComputerName $row.Server -ArgumentList $row
Start-Sleep 60
}
#changing startup type if different
if ($row."Startup Type" -eq $ServiceStartupType -ComputerName $row.Server)
{
"Changing Startup Type from '$ServiceStartupType' to $row.'Startup Type'"
Invoke-Command -ScriptBlock { Set-Service $using:row.Service -StartupType $using:row."Startup Type" } -ComputerName $row.Server -ArgumentList $row
}
} | Tee-object .\SSAS_services.txt -Append
I am getting the following errors:
Unexpected token '$ServiceState' in expression or statement.
+ if ($row.Task -eq "stop" -and $row.Server $ServiceState $row.Serv ...
Missing closing ')' after expression in 'if' statement.
+ ... if ($row.Task -eq "stop" -and $row.Server $ServiceState $row.Service ...
Missing closing '}' in statement block or type definition.
+ ... sk -eq "stop" -and $row.Server $ServiceState $row.Service -ne "stop")
+
Unexpected token ')' in expression or statement.
+ ... elseif ($row.Task -eq "start" -and $row.Server $ServiceState $row.Se ...
~
Unexpected token '$ServiceState' in expression or statement.
+ elseif ($row.Task -eq "start" -and $row.Server $ServiceState $row ...
+
Unexpected token '$row' in expression or statement.
+ ... -eq "start" -and $row.Server $ServiceState $row.Service -ne "start")
+ Unexpected token ')' in expression or statement.
+ ... elseif ($row.Task -eq "pause" -and $row.Server $ServiceState $row.Se ...
+
~~~~~~~~~~~~~ Unexpected token '$ServiceState' in expression or statement. Not all parse errors were reported. Correct
the reported errors and try again.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken ~

The if statement with -and $row.Server $ServiceState $row.Service -ne "stop" isn't valid powershell syntax (the expression should evaluate to boolean). You have write a function or use invoke-expression to evaluate the service state.
E.g.
$serviceName = "WSearch"
$command = "get-service $serviceName"
if ((invoke-expression $command).Status -eq "Running") {
# do something...
}

Related

If not run after get-service in powershell

I'm trying to access the service status of the remote server. i wrote this
$ServerList = get-content -Path "c:\users\cont015\Desktop\ServerList.txt"
ForEach ($ServerName in $ServerList)
{
$Status= Get-Service -ComputerName $ServerName | ?{$_.DisplayName -like "SQL Server (*"} | select Status | format-wide
if($st -eq "Running")
{
$SeverName
$Status
}
else
{
}
}
it is showing
$Status= Get-Service -ComputerName $ServerName | ?{$_.DisplayName -li ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-Service], InvalidOperationException
+ FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.PowerShell.Commands.GetServiceCommand
in error. i don't know what i am missing. but when i run without if condition if shows proper output.
$ServerList = Get-Content -Path "c:\users\cont015\Desktop\ServerList.txt"
ForEach ($ServerName in $ServerList)
{
$Status= #(
Get-Service -ComputerName $ServerName -DisplayName "SQL Server (*" |
Select-Object -ExpandProperty Status)
if ("Running" -in $Status)
{
[PSCustomObject]#{
Server = $ServerName
Status = $Status
}
}
else
{
}
}
Explanation:
Get-Service docs: -DisplayName
Specifies, as a string array, the display names of services to be retrieved. Wildcards are permitted (used instead of Where-Object as such filtering is always faster).
Array subexpression operator #( ). -
Returns the result of one or more statements as an array. The result is always an array of 0 or more objects (i.e. force Powershell to always return an array when a call returns only one object or even $null)
Used [PSCustomObject]#{} in output instead of a sequence of strings (learn advantages at Everything you wanted to know about PSCustomObject).

PowerShell get output in CSV format

I am seeking help to get output in csv format. I have written powershell code and would want to tweak the output to get in csv format as shown in below pic.
$servers = Get-Content 'C:\Temp\listofservers.txt'
foreach ($server in $servers)
{
#DHCP
if (((Get-Service -ComputerName $server -ServiceName 'DHCPServer' -ErrorAction SilentlyContinue).Status) -eq 'Running')
{
if ((((Get-DhcpServerv4Scope -ComputerName $server | Get-DhcpServerv4Lease -ComputerName $server) | Measure-Object).Count) -ge 1)
{
Write-Host "DHCP present on $server and in use"
}
else
{
Write-Host "DHCP present on $server and not in use"
}
}
else
{
Write-Host("DHCP is not present on $server")
}
#Certificate authority
if (((Get-Service -ComputerName $server -ServiceName 'CertSvc' -ErrorAction SilentlyContinue).Status) -eq 'Running')
{
Write-Host "Certificate Authority is present on $server"
}
else
{
Write-Host "Certificate Authority is not present on $server"
}
}
Send all outputs to a custom object then export them:
$servers = get-content "C:\Temp\listofservers.txt"
$ExportPath = 'c:\temp\results.csv'
$Servers | ForEach-Object {
Write-Host "Checking $_"
# DHCP status
# Use Try....Catch to trap the errors - it's more robust than
# If...Then and prevents a wall of red text if something goes wrong
Try {
$DHCPStatus = Get-Service -ComputerName $_ -Name 'DHCPServer' -ErrorAction Stop
If ($DHCPStatus.Status -eq "Running") {
Try {
If ((((Get-DhcpServerv4Scope -ComputerName $_ -ErrorAction Stop | Get-DhcpServerv4Lease -ComputerName $_ -ErrorAction Stop) | Measure-Object).Count) -ge 1) {
$DHCPResult = "DHCP present on, in use"
}
Else {
$DHCPResult = "DHCP present, not in use"
}
}
Catch {
$DHCPResult = "DHCP present - error obtaining details: $_"
}
}
}
Catch {
$DHCPResult = "DHCP is not present"
}
#Certificate authority
Try {
If (((Get-Service -ComputerName $_ -ServiceName 'CertSvc' -ErrorAction Stop).Status) -eq "Running") {
$CAResult = "Certificate Authority is present"
}
}
Catch {
$CAResult = "Certificate Authority is not present"
}
[pscustomobject]#{ComputerName = $_;DHCP = $DHCPResult;CA=$CAResult}
} | Export-Csv -Path $ExportPath -NoTypeInformation
Use a hashtable to build your object, adding key/values for each property along the way. Then convert the hashtable to a [PSCustomObject] and output it capturing in a variable ($results). Finally, export it to csv using Export-Csv
$servers = Get-Content 'C:\Temp\listofservers.txt'
$results = foreach ($server in $servers) {
# Create hashtable to build object and add ComputerName property
$output = [ordered]#{ComputerName = $server }
#DHCP
if (((Get-Service -ComputerName $server -ServiceName 'DHCPServer' -ErrorAction SilentlyContinue).Status) -eq 'Running') {
if ((((Get-DhcpServerv4Scope -ComputerName $server |
Get-DhcpServerv4Lease -ComputerName $server) |
Measure-Object).Count) -ge 1) {
# add Dhcp property if present, in use
$output.Add('Dhcp', 'Present, in use')
}
else {
# add Dhcp property if present, not in use
$output.Add('Dhcp', 'Present, not in use')
}
}
else {
# add Dhcp property if not present
$output.Add('Dhcp', 'Not present')
}
#Certificate authority
if (((Get-Service -ComputerName $server -ServiceName 'CertSvc' -ErrorAction SilentlyContinue).Status) -eq 'Running') {
# add CA property if present
$output.Add('CA', 'Present')
}
else {
# add CA property if not present
$output.Add('CA', 'Not present')
}
# Convert hashtable to pscustomobject and output it
[PSCustomObject]$output
}
# output results to screen
$results
# export results to csv file
$results | Export-Csv -Path c:\temp\server_dhcp_ca_check.csv -NoTypeInformation

How to execute command on remote server using Invoke-Command as Domain Administrator?

I am trying to modify a script that used to work when executed on each of the servers manually to generate the DFS replication then send an email, so it can be executed once from one location then remotely connect to each and every server.
Invoke-Command:
$ComputerName = Get-DfsrMember | Select-Object -ExpandProperty ComputerName -Unique | Sort-Object
$ComputerName | ForEach-Object {
Try {
$session = New-PSSession -ComputerName $_ -ErrorAction Stop
Invoke-Command -ErrorAction Stop -Session $session -ScriptBlock {
## Script body starts here....
Write-Host "Processing on server $($_) `n" -ForegroundColor Yellow
Param (
[String[]]$ReplicationGroupList = ("")
)
....
}
}
Catch [System.UnauthorizedAccessException] {
Write-Warning "You do not have the proper access to this system!"
Break
}
Catch [System.Runtime.InteropServices.COMException] {
Write-Warning "Communications Exception occurred!"
Break
}
}
This is the error I have received:
The term 'Param' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:7 char:9
+ Invoke-Command -ErrorAction Stop -Session $session -ScriptBlo ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Param:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
+ PSComputerName : PRDDC01-VM
The actual Powershell script that used to be working, but must be manually executed in each of the server RDP session:
Param (
[String[]]$ReplicationGroupList = ("")
)
$RGroups = Get-WmiObject -Namespace "root\MicrosoftDFS" -Query "SELECT * FROM DfsrReplicationGroupConfig"
#If replication groups specified, use only those.
if ($ReplicationGroupList) {
$SelectedRGroups = #()
foreach ($ReplicationGroup IN $ReplicationGroupList) {
$SelectedRGroups += $rgroups | Where-Object { $_.ReplicationGroupName -eq $ReplicationGroup }
}
if ($SelectedRGroups.count -eq 0) {
Write-Error "None of the group names specified were found, exiting"
exit
}
else {
$RGroups = $SelectedRGroups
}
}
$ComputerName = $ENV:ComputerName
$Succ = 0
$Warn = 0
$Err = 0
Start-Transcript -path "$([Environment]::GetFolderPath("Desktop"))\dfsr1.txt"
foreach ($Group in $RGroups) {
$RGFoldersWMIQ = "SELECT * FROM DfsrReplicatedFolderConfig WHERE ReplicationGroupGUID='" + $Group.ReplicationGroupGUID + "'"
$RGFolders = Get-WmiObject -Namespace "root\MicrosoftDFS" -Query $RGFoldersWMIQ
$RGConnectionsWMIQ = "SELECT * FROM DfsrConnectionConfig WHERE ReplicationGroupGUID='" + $Group.ReplicationGroupGUID + "'"
$RGConnections = Get-WmiObject -Namespace "root\MicrosoftDFS" -Query $RGConnectionsWMIQ
foreach ($Connection in $RGConnections) {
$ConnectionName = $Connection.PartnerName#.Trim()
if ($Connection.Enabled -eq $True) {
if (((New-Object System.Net.NetworkInformation.ping).send("$ConnectionName")).Status -eq "Success") {
foreach ($Folder in $RGFolders) {
$RGName = $Group.ReplicationGroupName
$RFName = $Folder.ReplicatedFolderName
if ($Connection.Inbound -eq $True) {
$SendingMember = $ConnectionName
$ReceivingMember = $ComputerName
$Direction = "inbound"
}
else {
$SendingMember = $ComputerName
$ReceivingMember = $ConnectionName
$Direction = "outbound"
}
$BLCommand = "dfsrdiag Backlog /RGName:'" + $RGName + "' /RFName:'" + $RFName + "' /SendingMember:" + $SendingMember + " /ReceivingMember:" + $ReceivingMember
$Backlog = Invoke-Expression -Command $BLCommand
$BackLogFilecount = 0
foreach ($item in $Backlog) {
if ($item -ilike "*Backlog File count*") {
$BacklogFileCount = [int]$Item.Split(":")[1].Trim()
}
}
if ($BacklogFileCount -eq 0) {
$Color = "white"
$Succ = $Succ + 1
}
elseif ($BacklogFilecount -lt 10) {
$Color = "yellow"
$Warn = $Warn + 1
}
else {
$Color = "red"
$Err = $Err + 1
}
Write-Output "$BacklogFileCount files in backlog $SendingMember->$ReceivingMember for $RGName"
} # Closing iterate through all folders
} # Closing If replies to ping
} # Closing If Connection enabled
} # Closing iteration through all connections
} # Closing iteration through all groups
Write-Output "$Succ successful, $Warn warnings and $Err errors from $($Succ+$Warn+$Err) replications."
Stop-Transcript
$file = "$([Environment]::GetFolderPath("Desktop"))\dfsr1.txt"
get-content $file |
Select-Object -Skip 18 |
set-content "$file-temp"
Move-Item "$file-temp" $file -Force
$emailrecipients = "boss#it.com";
$emailbody = Get-Content -Path "$([Environment]::GetFolderPath("Desktop"))\dfsr1.txt" -Raw
Send-MailMessage -to $emailrecipients -smtpserver smtp.domain.COM -from "$env:COMPUTERNAME#$env:userdnsdomain" -subject "DFSR Report for $(get-date -format dd/MM/yyyy) from $env:COMPUTERNAME" -body $emailbody;
Remove-Item "$([Environment]::GetFolderPath("Desktop"))\dfsr1.txt"
Theo is correct, the Param() code needs to be first thing in the script block. You can find more information about script blocks here: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_script_blocks?view=powershell-7

Not able to convert from PScustomobject to Arraylist

I am trying to get all the list of patches from multiple servers. I am using invoke command with -asjob parameter to get the patch list from all servers. Running the below code.
I am getting the below error. I have tried with
Get-CIMInstance -Class Win32_QuickFixEngineering
and with
Get-WmiObject -Class Win32_QuickFixEngineering
but keep getting same error.
$Servers = Get-Content "C:\Users\Suman.Ghosh\Servers.txt"
[System.Collections.ArrayList]$All_Jobs = #()
[System.Collections.ArrayList]$Updated_Servers_List = #()
[System.Collections.ArrayList]$Jobs_Output = #()
$Patches_to_lookfor = #(
'KB4462926',
'KB4462941'
)
foreach ($S in $Servers) {
if (Test-Connection -ComputerName $S -Count 1 -Quiet) {
$Updated_Servers_List += $S
$All_Jobs += Invoke-Command -ComputerName $S -ScriptBlock {Get-HotFix} -AsJob
} else {
Write-Warning "Computer $S is not running"
}
}
Write-Host "below Jobs are running" -ForegroundColor Cyan
$All_Jobs
Write-Host "waiting for jobs to finish" -ForegroundColor Cyan
$All_Jobs | Wait-Job
$temp = #()
$flag = $false
foreach ($job in $All_Jobs) {
$Jobs_Output += Get-Job $job.Id | Receive-Job | Select HotFixID, CSNAME
}
foreach ($Job_output in $Jobs_Output) {
Write-Host $Job_output -ForegroundColor Green
### DO some stuff
}
Cannot convert value "#{HotFixID=KB4020449; CSName=mit1epxa2}" to type
"System.Collections.ArrayList".
Error: "Cannot convert the "#{HotFixID=KB4020449; CSName=mit1epxa2}" value
of type "Selected.System.Management.Automation.PSCustomObject" to type
"System.Collections.ArrayList"."
At line:1 char:10
+ foreach ($Job_output in $Jobs_Output) {
+ ~~~~~~~~~~~
+ CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
+ FullyQualifiedErrorId : RuntimeException
Ok, let's see if my second answer gets deleted (with no notification) by people who don't know the topic. I believe you have run a command like this on $job_output (no "s"):
[collections.arraylist]$job_output = #()
Then in the loop at the bottom, an exception is created because a pscustomobject can't be cast to a collections.arraylist with the $job_output variable. $jobs_output (with the "s") is an arraylist of [pscustomobjects]'s created by select.
foreach ($Job_output in $Jobs_Output) {
Write-Host $Job_output -ForegroundColor Green
### DO some stuff
}

How to remove the error from the powershell report

i have created a powershell script to run image validation remotely and when any of the service found in stopped state this will fail the script.I am getting below error while failing the script.Is there anyway so that I can hide these error from the report?
+ Invoke-Command -ScriptBlock {
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], RuntimeException
+ FullyQualifiedErrorId : ScriptHalted
This is the script i used to fail when the service is in stopped state.
$EMService = get-wmiobject win32_service | where-object {($_.Name -eq 'HP12cAgent') -or ($_.Name -eq 'HPagent12c2Agent') -or ($_.Name -eq 'HPagent10gAgent') -or ($_.Name -eq 'FarmEM10gAgent') -or ($_.Name -eq 'FarmEM11gAgent')} | format-list name | Out-String
$Servicename = $EMService.Split(":")[1].Trim()
$EMStatus1 = get-wmiobject win32_service | where-object {$_.Name -eq $Servicename} | format-list state | Out-String
$ServiceStatus = $EMStatus1.Split(":")[1].Trim()
if ($Servicename -eq $null)
{
$Servicename = "Unavailable"
}
else
{
$Servicename = "$Servicename"
}
if ($ServiceStatus -eq "Stopped")
{
throw
}
Else
{
exit 0
}
You can always try wrapping stuff in a try/catch block.
try { some powershell stuff }
catch { Write-Host $_ ; or do nothing }