Invoke-Command with ScriptBlock Works on Local Server - Remotely Resultset is Empty - citrix

When trying to obtain the Citrix XenApp 6.5 server status by using the following code, a resultset is returned when run in PowerShell locally on a Zone Data Collector:
$serverName = "SOMECITRIXSERVER"
$Invoke-Command -ScriptBlock {Add-PSSnapin Citrix.XenApp.Commands}
$serverStatus = Get-XAServer | select ServerName,#{n="InMaintenanceMode";e={ if($_.LogOnMode -like "Prohibit*"){$true}elseif($_.LogOnMode -eq "AllowLogons"){$false} }} | where {$_.ServerName -eq $serverName} | Select InMaintenanceMode}
Write-Output "Status: $serverStatus.InMaintenanceMode"
Status: false
The same scriptblock is then executed in PowerShell with computername set to a ZDC and credentials supplied. No exceptions are thrown and the resultset is empty:
$zoneDataCollector = "SOMEZDCHOST"
$serverName = "SOMECITRIXSERVER"
$key = (somekeyvaluehere)
$passwordZDC = cat CredentialFile.txt | convertto-securestring -key $key
$credZDC = new-object -typename System.Management.Automation.PSCredential -argumentlist $usernameZDC, $passwordZDC
$ZDCSession = New-PSSession -ComputerName $zoneDataCollector -Credential $credZDC
$Invoke-Command -Session $ZDCSession -ScriptBlock {Add-PSSnapin Citrix.XenApp.Commands}
$serverStatus = Invoke-Command -Session $ZDCSession -ScriptBlock {Get-XAServer | select ServerName,#{n="InMaintenanceMode";e={ if($_.LogOnMode -like "Prohibit*"){$true}elseif($_.LogOnMode -eq "AllowLogons"){$false} }} | where {$_.ServerName -eq $serverName} | Select InMaintenanceMode}
Write-Output "Status: $serverStatus.InMaintenanceMode"
Status:
Running a Wireshark network packet capture is not very helpful because the WinRM traffic payload is encrypted.
Any ideas as to why the command within the scriptblock would work locally, but return an empty resultset without throwing exceptions?
Thanks!
ds

When you using the invoke-command on a remote server, and you need to call a variable from the local machine, then you need to add params to the scriptblock and argumentslist
So your code should look like
$serverStatus = Invoke-Command -Session $ZDCSession -ScriptBlock {param($serverName) Get-XAServer | select ServerName,#{n="InMaintenanceMode";e={ if($_.LogOnMode -like "Prohibit*"){$true}elseif($_.LogOnMode -eq "AllowLogons"){$false} }} | where {$_.ServerName -eq $serverName} | Select InMaintenanceMode} –argumentlist $serverName

Related

Invoke-Command does not kill process on remote machine

Before deployment, I'm trying to kill processes that lock files using PowerShell Invoke-Command
This is my code:
$password = ConvertTo-SecureString "password" -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PsCredential("Admin",$password)
$scriptBlock = {Get-Process | Where-Object { $_.MainWindowTitle -like 'MyApp*'} | Stop-Process}
Invoke-Command -computername Agent1 -Credential $credentials -scriptblock $scriptBlock
Unfortunately it does not do anything and no errors are thrown.
On the machine, this works fine:
Get-Process | Where-Object { $_.MainWindowTitle -like 'MyApp*'} | Stop-Process
As described above create a PS session object:
$ErrorActionPreference = "Stop"
$password = ConvertTo-SecureString "password" -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PsCredential("Admin",$password)
$scriptBlock = {
$process = Get-Process
$process | Where-Object { $_.MainWindowTitle -like 'MyApp*'} | Stop-Process}
$process
}
$session = New-PsSession -ComputerName "Agent1" -Credentials $credentials
$remoteProcess = Invoke-Command -Session $session -Credential $credentials -scriptblock $scriptBlock
$remoteProcess | format-table
Above code will also return you a list processes running on the remote host. Based on $remoteProcess you'll see if the process to kill was running or not. I also set the ErrorActionPreference to stop which forces above code to stop on the first error (in case of the session could not be created).
Hope that helps

Unable to fetch IIS status from Remote server using Powershell

I am trying to fetch IIS status from remote server using powershell.
I have used command Get-Service but i don't recieve any output from this command.
Below is my code block.
$pass='pass'|ConvertTo-SecureString -AsPlainText -Force;
$Credentials = New-Object
System.Management.Automation.PsCredential("user",$pass);
$Service=invoke-command -computername "server" -credential $Credentials -
scriptblock {Get-Service|Where-Object Name -eq 'IISADMIN'}
if($Service.Status -eq 'Running')
{
write-host "IIS Running"
}
else
{
throw "IIS not running or Not installed"
}
I Checked your code and did not see any problem with it, Did you checked the service exists locally using Get-Service or Service Manager?
Anyway you don't have to use Invoke-Command for this, you can use the built in -ComputerName parameter of the Get-Service cmdlet,
And if you need to provide credentials, you can use WMI:
$Credential = New-Object System.Management.Automation.PsCredential($username, $encrypted)
$Service = Get-WmiObject -Class win32_service -ComputerName Server -Filter 'Name = "W3SVC"' -Credential $Credentials
Try using a WMI call instead, I have found it far more reliable when working with remote servers.
$Service = Get-WmiObject -Computername $computer -Credential $credentials Win32_service -ErrorAction Continue | Where {$_.Name -eq 'IISADMIN'}

Getting a specific service recovery option for a list of servers

Apologies in advance for errors. I'm still learning Powershell.
I'm trying to check a specific service recovery options for a list of servers in AD
$credential = Get-Credential
$servers = Get-ADComputer -Filter * -properties * | ?{$_.OperatingSystem -match "server"} | ft name -hidetableheaders | out-string
$Results = #()
foreach ($Server in $Servers)
{
Invoke-command -cn $server -credential $credential -ScriptBlock {Get-WMIObject win32_service |
Where-Object {$_.description -imatch "nscli" -and $_.startmode -eq "Auto"}; foreach ($service in $services){sc.exe qfailure $service.name}}
}
I'm getting the following error
Invoke-command : One or more computer names are not valid. If you are trying to pass a URI, use the -ConnectionUri parameter, or pass URI objects
instead of strings.
At line:1 char:32
+ foreach ($Server in $Servers) {Invoke-command -cn $server -credential $credentia ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (System.String[]:String[]) [Invoke-Command], ArgumentException
+ FullyQualifiedErrorId : PSSessionInvalidComputerName,Microsoft.PowerShell.Commands.InvokeCommandCommand
If I run the command directly on each server, I don't have any issues.
Invoke-command -cn EXCHANGE -credential $credential -ScriptBlock {$services = Get-WMIObject win32_service | Where-Object {$_.description -imatch "nscli" -and $_.startmode -eq "Auto"}; foreach ($service in $services){sc.exe qfailure $service.name}}
[SC] QueryServiceConfig2 SUCCESS
SERVICE_NAME: NSClientpp
RESET_PERIOD (in seconds) : 0
REBOOT_MESSAGE :
COMMAND_LINE :
FAILURE_ACTIONS : RESTART -- Delay = 120000 milliseconds.
RESTART -- Delay = 120000 milliseconds.
Because I'm using sc.exe, I'm unsure how to output the list into a csv format but at least, I can get some information of which servers the service failure restart aren't set accordingly
Thanks in advance
Cheers
G
Since Invoke-Command doesn't support the -WhatIf switch, your best bet is to echo the server name on console to see the server name that causes failure. In the debugging statement, the server name is enclosed withing single quotes ' for, say, extra whitespace is easier to see. Like so,
foreach ($Server in $Servers)
{
Write-host $("Now processing server '{0}' " -f $Server)
Invoke-command ...
}
You could also try to write the Invoke-Command statements to console and copy-paste those to another a Powershell session to see which, if any, is the failing one.
For what it is worth, you seem to use variables $Server and $server (note the upper/lowercase difference). Though variable names are not case sensitive in Powershell, you might have uninitialized variables caused by simple typos. To guard against such, use Set-StrictMode. It will cause Powershell to complain about uninitialized variables, which commonly are caused by mistyping variable names.
Got it working. Should have responded earlier. Thanks guys.
# Get the credential
$Credential=Get-Credential
# Collect the server list
$Servers = Get-ADComputer -Filter * -Properties operatingsystem | Where operatingsystem -match 'server'
$Results = #()
## Check service status
$Results = foreach ($Server in $Servers)
{Invoke-Command -ComputerName $Server.Name –Ea 0 -Credential $Credential {Get-Service |?{$_.DisplayName –match “nscli”} }}
## Create a csv report
$Results| Sort PSComputerName | select PSComputerName, DisplayName, Name, Status |Export-Csv nsclient_service.csv -NoTypeInformation -UseCulture
# Check the recovery options for NSclient service on each Server
foreach ($Server in $Servers)
{ write-host "Checking " $Server.Name;
Invoke-Command -ComputerName $Server.Name –Ea 0 -Credential $Credential `
{$services = Get-WMIObject win32_service | Where-Object {$_.name -imatch "nscli" -and $_.startmode -eq "Auto"}; `
foreach ($service in $services){sc.exe qfailure $service.name}}
}

Powershell Kill all processes except system

In powershell, I would like to kill all processes for all users, except explorer and processes used by the system
This is where I am including the errors that are given:
$Cred = Get-Credential;
Invoke-Command -ComputerName localhost -Credential $Cred -ScriptBlock { Get-Process $env:ALLUSERSPROFILE | Where-Object -FilterScript {$_.Name -ne "SYSTEM, NETWORK SERVICE, LOCAL SERVICE"} | Where-Object -filterscript {$_.Name -ne "explorer"} | Stop-Process -WhatIf }
Cannot find a process with the name "C:\ProgramData". Verify the process name and call the cmdlet again.
+ CategoryInfo : ObjectNotFound: (C:\ProgramData:String) [Get-Process], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
+ PSComputerName : localhost
Here, this should work for you.
Function Stop-UserProcesses{
Param([string]$Computer = "localhost")
$Cred = Get-Credential
Invoke-Command -ComputerName $Computer -Credential $Cred -ScriptBlock {
Get-Process -IncludeUserName | Where{!($_.UserName -match "NT AUTHORITY\\(?:SYSTEM|(?:LOCAL|NETWORK) SERVICE)") -and !($_.ProcessName -eq "explorer")}|Stop-Process -WhatIf
}
}
Once you are convinced that it is functional remove the -WhatIf. Then just call it as Stop-UserProcesses to end everything locally, or Stop-UserProcesses SomeComputer01 to end everything on a remote system (assuming you have remote sessions enabled in your environment).
Edit: Well then, evidently the -IncludeUserName switch is new in v4. So, in order to do what you want we have to jump through hoops and use Get-WMIObject on the win32_process class, then execute the GetOwner() method for each process. Probably want to filter it so we don't end up with things like Idle throwing errors when they don't have an owner, so we'll make sure that the CommandLine property exists.
Function Stop-UserProcesses{
Param([string]$Computer = "localhost")
$Cred = Get-Credential
Invoke-Command -ComputerName $Computer -Credential $Cred -ScriptBlock {
#Get all processes
$Processes = get-wmiobject win32_process|Where{![string]::IsNullOrEmpty($_.commandline)}|Select *,#{l='Owner';e={$_.getowner().user}}
#Filter out System and service processes
$Processes = $Processes | Where { !($_.Owner -match "(?:SYSTEM|(?:LOCAL|NETWORK) SERVICE)") }
#Get processes and filter on the Process ID and name = explorer, then pipe to stop-process
Get-Process | Where { $Processes.ProcessID -contains $_.id -and $_.name -ne "explorer" } | Stop-Process -WhatIf
}
}

Getting back TIME information by Powershell

I have the below code that looks at OS system and based on the build type it returns the NTP server they point to.
However, it works fine on a match of 7601 (Windows Server 2008 R2) - but, for Windows Server 2003 servers I always get an error. For Windows Server 2003 servers you need to read a registry key.
If I did the same query on the registry key locally on a server it works fine...although it reports back other stuff aswell as the registry key..
here is the error:
NTPSource Server
--------- ------
The following error occurred: The procedure number is ou... SERV1
Here is the code:
$servers = #('SERV1','SERV2')
$version = Get-WmiObject Win32_OperatingSystem -computer $servers | select buildnumber
foreach ($server in $servers){
if ($version -match '7601')
{
$ntps = w32tm /query /computer:$server /source
new-object psobject -property #{
Server = $Server
NTPSource = $ntps
}
}
elseif($version -match '3790')
{
Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Parameters' -Name Type
}
}
Personally I use this to retrieve NTP server (Windows Server 2000/2003/2008/2008r2):
$Servers = (gc Computers.txt) # list of servers name
$pw = Get-Credential
$HKLM = 2147483650
foreach( $Server in $Servers )
{
$reg = GWMI -list -namespace root\default -computername $server -Credential $pw |
where-object { $_.name -eq "StdRegProv" }
$key = $reg.GetStringValue($HKLM,"SYSTEM\CurrentControlSet\Services\W32Time\Parameters","NtpServer")
write-host "$server `t$($key.svalue)"
}