Powershell | get a value from 2 nested invoke commands - powershell

i want to transfer the values from the invoke commands to local. I have problems to get the values from the second invoke command. I want $computers and $tasks in the textbox. Any Ideas? I have tried with return but then i can only get the values from first invoke command.
EDITED:
$session = New-PSSession -ComputerName $remote -Credential $cred
Invoke-Command -Session $session -ScriptBlock {
### get all computers in Domain ###
$computers = dsquery computer "DC=kanzlei,DC=local" -o rdn
Write-Host ("In dieser Domäne gibt es die folgenden Server:")
write-host $computers
#configure all computers
foreach($computer in $computers) {
$session3 = New-PSSession -ComputerName $remote -Credential $cred_session
Invoke-Command -Session $session3 -ScriptBlock {
write-host "Tasks for $env:computername gonna be activated"
#### acitivate tasks ####
$tasks = Get-ScheduledTask -TaskPath "\RA-MICRO_Update_Routine\" | Enable-ScheduledTask | FL Taskname,State }
write-host "$tasks"
}
}
}
##### I want vriable $Computers and $Tasks here on Local ####
do anything with $tasks
do anything with $computers

Related

Powershell | second Invoke Using:Variable

i have a simple question. I want to use a variable in an invoke-command and pass this to the second invoke-command. In the second invoke-command the variable is empty
here is my code:,
$WaitSeconds = 1234
Invoke-Command -ComputerName $remote -Credential $cred -ScriptBlock {
$computer = dsquery computer "DC=domain,DC=local" -o rdn
$computers = $computer -replace ('"', '')
write-host $computers
foreach ($computer in $computers) {
if ($computer -notmatch "AZUREADSSOACC")
{
Invoke-Command -ComputerName $computer -Credential $using:cred -ScriptBlock {
#### here script
shutdown -s -t $using:waitseconds
}
}
}
}
In the second invoke-command the variable is empty
That's because the variable doesn't exist inside the calling session (the first Invoke-Command call's execution context).
Make sure you first instruct PowerShell to copy the variable to the "outer" Invoke-Command call:
$WaitSeconds = 1234
Invoke-Command {
# PowerShell will now copy the $WaitSeconds variable value from the calling scope to this remote session
$WaitSeconds = $using:WaitSeconds
# ...
Invoke-Command {
# This will now resolve the variable value correctly
shutdown -s -t $using:WaitSeconds
}
}
i got it
my solution is:
$WaitSeconds = 1234
Invoke-Command {
param($WaitSeconds)
$WaitSeconds = $WaitSeconds
# ...
Invoke-Command {
param($WaitSeconds)
shutdown -s -t $WaitSeconds
} -ArgumentList $WaitSeconds
} -ArgumentList $WaitSeconds

Run Remote Command via Powershell

I'm trying to invoke discrete CLI commands on a series of remote systems via a script, and I can't get any PowerShell commands to accept them. Rather than try to explain the specifics of the issue, I'll provide some pseudocode of what I'm trying to do below.
Please note that this is just a simple example. Using the stop-service command is not an option. These are explicit commands used via CLI with via the Splunk program that I need to run in this order.
In short, I just can not figure out how to tell PowerShell to run a CLI command verbatim on a remote machine.
foreach ($server in $list)
cd C:\Program Files\SplunkUniversalForwarder\bin
splunk stop
splunk clone-prep-clear-config
splunk start
Bunch of ways you can do this. Using WMI c/o Powershell:
Starting,Stopping and Restarting Remote Services with PowerShell
You can also use Windows remoting, but I'd start here.
You could try...
Foreach($server in $list)
{
Invoke-command -computername $server -scripblock {
$splunkpath = 'c:\program files\splunkuniversalforwarder\bin\splunk.exe'
Start-process -filepath $splunkpath -argumentlist 'stop' -wait -nonewwindow
Start-process -filepath $splunkpath -argumentlist 'clone-prep-clear-config' -wait -nonewwindow
Start-process -filepath $splunkpath -argumentlist 'start' -wait -nonewwindow
}
}
Note: you may need to remove the -wait and/or -nonewwindow from the commands depending on how your process behaves.
There are also output redirection parameters checkout the docs below for more.
Invoke-command
Start-process
I literally just did this this morning. This is the main part I came up with.
foreach($server in $servers){
Write-Host "From " -nonewline; Write-Host "$server" -ForegroundColor Yellow
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe stop } -Credential $cred
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe clone-prep-clear-config } -Credential $cred
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe start } -Credential $cred
}
my full code is below:
#Author: Christopher Boillot
#Clear config of Splunk Forwarder
[CmdletBinding()]
Param ([Parameter(Mandatory=$False,Position=0)]
[String[]]$servers = (Get-Content C:\ClearConfig.txt))
Set-Location $PSScriptRoot
#User login
$User = "user.txt"
$FileExists = Test-Path $User
If ($FileExists -eq $False) {
Write-Host "Enter your user name. This will be saved as $User"
read-host | out-file $User
}
$Pass = "securepass.txt"
$FileExists = Test-Path $Pass
If ($FileExists -eq $False) {
Write-Host "Enter your password. This will be saved as an encrypted sting as $Pass"
read-host -assecurestring | convertfrom-securestring | out-file $Pass
}
$username = cat $User
$password = cat $Pass | convertto-securestring
$cred = new-object -typename System.Management.Automation.PSCredential `
-argumentlist $username, $password
#go through each server in list
foreach($server in $servers){
Write-Host "From " -nonewline; Write-Host "$server" -ForegroundColor Yellow
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe stop } -Credential $cred
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe clone-prep-clear-config } -Credential $cred
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe start } -Credential $cred
}

Sending out lockdown or general message to all active users in domain, cross-architecture

I'm trying to setup a script which will message all users in domain - Mixture, some are on Windows 10 Surface Pro's, some Citrix VDI.
The Citrix Part at the bottom isnt quite right, when starting a session, i seem to need to import the Citrix modules to the DDC, even though i'm connect via a PS Session (new-pssession) to the controller. The message on the VDI users desktop isn't appearing and, not sure why...
$Cred = Read-Host "enter-username e.g. domain\user.name"
$computers = Get-Content C:\Scripts\allcomputers.txt #| Where-Object { $_ }
#foreach ($computer in $computers) {
# Invoke-Command -computername $computer -scriptblock {msg * "INSERT MESSAGE TO STAFF HERE"} -Credential $cred
}
# Import-Module Citrix.XenDesktop.Admin?
# Add-PSSnapin Citrix?
$s = New-PSSession -cn DDC -Credential DOMAIN\Cred
Invoke-Command -Session $s -ScriptBlock { $sessions = Get-BrokerSession -UserName DOMAIN\User ;
Send-BrokerSessionMessage $sessions -MessageStyle Information -Title TestTitle -Text TestMessage
}
Get-PSSession | Remove-PSSession
If i use the command in the script block in an interactive session, the modules don't appear to be installed, hence the commented out 2 lines... :S
Thanks for the help - Working Code that will send out a message to all Citrix XDT sessions via PowerShell:
$s = New-PSSession -cn CitrixDDC -Credential Domain\Administrator
Invoke-Command -Session $s -ScriptBlock { import-module
Citrix.XenDesktop.Admin; Add-PSSnapin Citrix.*;
$sessions = Get-BrokerSession -UserName Domain\* `
Send-BrokerSessionMessage $sessions -MessageStyle Information -Title
TestTitle -Text TestMessage
}
Get-PSSession | Remove-PSSession

Remote management with powershell

I'm trying to get some information from several machines on the network but I get loads of entries of the local machine.. for each entry in the text file I get an entry from the local machine.
Any idea where I'm going wrong.. winrm is configured on the remote machines and running.
$Username = Read-Host "Please enter Username"
$Password = read-host "please enter Password"
$pass = ConvertTo-SecureString -AsPlainText $Password -Force
$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$pass
$computers = gc c:\test\file.txt
foreach ($Computer in $computers)
{
Invoke-command -ComputerName $computers -credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'ipconfig'" | out-file c:\test\output.txt -append}
}
cls
Thanks in advance :)
Invoke-Command will take an array for the ComputerName param so you can use $computers instead of using a foreach loop (assuming that you have one computer name per-line in the file).
I've also used Get-Credential to prompt for the full credential in one go rather than asking for username and password individually.
$Cred = Get-Credential
$computers = Get-Content c:\test\file.txt
Invoke-Command -ComputerName $computers -Credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'ipconfig'" | Out-File c:\test\output.txt -Append}
The reason you are only seeing a single computers info in c:\test\output.txt is because the output of the the ipconfig command is being saved to the remote computer... so you will have a c:\test\output.txt file on each computer you run the command against.
EDIT:
To take the output of each remote command and save it to your local computer just move the Out-File outside the Invoke-Command like this:
$Cred = Get-Credential
$computers = Get-Content c:\test\file.txt
Invoke-Command -ComputerName $computers -Credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'ipconfig'"} | Out-File c:\test\output.txt -Append
The issue is you are iterating one by one but you are not passing one by one to the invoke-command, $computer will have each value at a time in the foreach loop.
Instead of this:
foreach ($Computer in $computers)
{
Invoke-command -ComputerName $computers -credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'ipconfig'" | out-file c:\test\output.txt -append}
}
Do this:
foreach ($Computer in $computers)
{
Invoke-command -ComputerName $computer -credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'ipconfig'" | out-file c:\test\output.txt -append}
}
Further improvement:
You do not have to give Invoke-Expression -Command:"cmd.exe /c 'ipconfig'"
Instead of this,you can directly use ipconfig inside the scriptblock.

Remote Registry using Enter-PSSession

I am trying to read strings in a remote registry. When I run the script I am working on, it connects to the workstation in the list, but it only reads the local computer when running, not the remote. any Ideas?
#create open dialog box
Function Get-FileName($initialDirectory)
{
[void] [Reflection.Assembly]::LoadWithPartialName( 'System.Windows.Forms' );
$d = New-Object Windows.Forms.OpenFileDialog;
$d.ShowHelp = $True;
$d.filter = "Comma Separated Value (*.csv)| *.csv";
$d.ShowDialog( ) | Out-Null;
$d.filename;
}
# Set Variables with arguments
$strFile = Get-FileName;
$strComputer = Get-Content $strFile;
$date = Get-Date -Format "MM-dd-yyyy";
$outputFile = "C:\PowerShell\Reports";
$cred = Get-Credential
foreach($computer in $strComputer)
{
Enter-PSSession $computer -Credential $cred
Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability
$systemInfo = Get-Item -Name LastComputerName
Write-Host $systemInfo
}
foreach($computer in $strComputer)
{
Enter-PSSession $computer -Credential $cred
..
..
}
The above code won't work. Enter-PSSession is not for using in a script. Anything written after that in a script won't run.
Instead, use Invoke-Command and pass rest of the script block as a parameter value. For example,
foreach ($computer in $strComputer) {
Invoke-Command -ComputerName $computer -Credential $cred -ScriptBlock {
Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability
$systemInfo = Get-Item -Name LastComputerName
Write-Host $systemInfo
}
}
As the comments already explained, Enter-PSSession is for interactive use. To read remote registry entries, there are several ways.
Use plain reg.exe, it works well enough. Like so,
foreach($computer in $strComputers) {
reg query \\$computer\hklm\software\Microsoft\Windows\CurrentVersion\Reliability /v LastComputerName
}
Use PSSessions. Create a session and Invoke-Command to read registry. Like so,
function GetRegistryValues {
param($rpath, $ivalue)
Set-Location $rpath
$systemInfo = (Get-ItemProperty .).$ivalue
Write-Host $systemInfo
}
$session = New-PSSession -ComputerName $computer
Invoke-Command -Session $session -Scriptblock ${function:GetRegistryValues} `
-argumentlist "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability",`
"LastComputerName"
Remove-PSSession $session
Use .Net classes, Microsoft.Win32.RegistryKey. Like so,
$sk = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $server)
$k = $sk.opensubkey("SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability", $false)
write-host $k.getvalue("LastComputerName")