Using Invoke-Command, display which machine responded

On a conference call today and my team was asked to look into why another teams machine BSOD’d since they couldn’t find anything. Found out dump files were off entirely. Got me wanting to check all our servers we monitor (3 months in to job) to find out if any of our servers have dumps disabled.

I have the below, but I’m wanting to inject which server responded. Any help would be appreciated.

 

#-------------- To check multiple key values ---------------
# Change your OU, Path, and Keys as needed
$Computers = (Get-ADComputer -Filter * -SearchBase "DC=Lombardi,DC=local").Name
$Path = 'HKLM:\System\CurrentControlSet\Control\CrashControl'
$Key1 = 'CrashDumpEnabled'
$Key2 = 'AlwaysKeepMemoryDump'
$Key3 = 'Overwrite'

# Script/Command to run against each machine found within the given OU
Foreach ($Computer in $Computers)
{
Invoke-Command -ScriptBlock {Get-ItemProperty -path $Path | Format-Table $Key1, $Key2, $Key3}
}


#-------------- To check a single keys value ---------------
# Change your OU, Path, and Key as needed
$Computers = (Get-ADComputer -Filter * -SearchBase "DC=Lombardi,DC=Local").Name
$Path = 'HKLM:\System\CurrentControlSet\Control\CrashControl'
$Key = 'CrashDumpEnabled'

# Script/Command to run against each machine found within the given OU
Foreach ($Computer in $Computers)
{
Invoke-Command -ScriptBlock {Get-ItemPropertyValue -path $Path -Name $Key}
}

By default invoke-command returns property PSComputerName. You have to add parameter -HideComputerName to have it not return it. Now if it isn’t showing in the default output, you can ask for it.

$results = Invoke-Command -ComputerName 'SomeServer' -ScriptBlock {$PSVersionTable}
$results | select *
$results | select pscomputername

Output:

PSComputerName : SomeServer
RunspaceId     : 189d3ebd-2f2e-48c3-a495-b0bf652e7f91
IsReadOnly     : False
IsFixedSize    : False
IsSynchronized : False
Keys           : {PSRemotingProtocolVersion, BuildVersion, PSVersion, PSCompatibleVersions...}
Values         : {2.3, 10.0.14409.1018, 5.1.14409.1018, 1.0 2.0 3.0 4.0 5.0 5.1.14409.1018...}
SyncRoot       : System.Object
Count          : 8

PSComputerName
--------------
SomeServer

Hope this helps

Also, just as a side note, you are looping though the computers but not adding a -ComputerName param and it’s invoking the command on the local machine? Next, you may want to look at about_Remote_Variables as you are passing external variables into the scriptblock that is executing remotely. Those setting should be managed by GPO, so you may want to validate those policy settings, OU links and servers are in the correct OU.

[quote quote=227863]By default invoke-command returns property PSComputerName. You have to add parameter -HideComputerName to have it not return it. Now if it isn’t showing in the default output, you can ask for it.

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Hope this helps

[/quote]

I think I may have figured out another option. I had another command I ran to check versions of PowerShell on systems and I threw the $Computer command in there. Originally on this code it didn’t like it. I made it part of it’s own label/result now and it doesn’t complain anymore.

 

Test Environment Results:

Input:

#-------------- To check multiple key values ---------------
# Change your OU, Path, and Key as needed
$Computers = (Get-ADComputer -Filter * -SearchBase "DC=Lombardi,DC=Local").Name
$Path = 'HKLM:\System\CurrentControlSet\Control\CrashControl'
$Key1 = 'CrashDumpEnabled'
$Key2 = 'AlwaysKeepMemoryDump'
$Key3 = 'Overwrite'

# Script/Command to run against each machine found within the given OU
Foreach ($Computer in $Computers)
{
Invoke-Command -ScriptBlock {Get-ItemProperty -path $Path | Format-Table @{Label='Server';e={$Computer}},$Key1, $Key2, $Key3}
}

 

Output:

Server CrashDumpEnabled AlwaysKeepMemoryDump Overwrite
------ ---------------- -------------------- ---------
PS01                  7                    0         0

Server CrashDumpEnabled AlwaysKeepMemoryDump Overwrite
------ ---------------- -------------------- ---------
DC01                  7                    0         0

Server CrashDumpEnabled AlwaysKeepMemoryDump Overwrite
------ ---------------- -------------------- ---------
DB01                  7                    0         0

Server CrashDumpEnabled AlwaysKeepMemoryDump Overwrite
------ ---------------- -------------------- ---------
FS01                  7                    0         0

 

Using it as Format-List (in lieu of table) returns the following, so it shows good either way I want to utilize the info. I’ll likely stick with a table.

Server               : PS01
CrashDumpEnabled     : 7
AlwaysKeepMemoryDump : 0
Overwrite            : 0

Server               : DC01
CrashDumpEnabled     : 7
AlwaysKeepMemoryDump : 0
Overwrite            : 0

Server               : DB01
CrashDumpEnabled     : 7
AlwaysKeepMemoryDump : 0
Overwrite            : 0

Server               : FS01
CrashDumpEnabled     : 7
AlwaysKeepMemoryDump : 0
Overwrite            : 0

[quote quote=227908]Also, just as a side note, you are looping though the computers but not adding a -ComputerName param and it’s invoking the command on the local machine? Next, you may want to look at about_Remote_Variables as you are passing external variables into the scriptblock that is executing remotely. Those setting should be managed by GPO, so you may want to validate those policy settings, OU links and servers are in the correct OU.

[/quote]

 

Not sure if you are asking me or telling me, sorry. So I am only running the command against the local machine and not against the other computers?

Sorry, that was a statement, not a question. You are executing the same code on your local machine, not the remote machine. Try something like this:

$Computers = (Get-ADComputer -Filter * -SearchBase "DC=Lombardi,DC=local").Name
$Path = 'HKLM:\System\CurrentControlSet\Control\CrashControl'
$Key1 = 'CrashDumpEnabled'
$Key2 = 'AlwaysKeepMemoryDump'
$Key3 = 'Overwrite'

# Script/Command to run against each machine found within the given OU
$results = Foreach ($Computer in $Computers) {
    Invoke-Command -ScriptBlock {Get-ItemProperty -path $using:Path -ComputerName $computer | 
    Select-Object -Property $using:Key1, $using:Key2, $using:Key3}
}

$results

[quote quote=227935]Sorry, that was a statement, not a question. You are executing the same code on your local machine, not the remote machine. Try something like this:

$Computers = (Get-ADComputer -Filter * -SearchBase "DC=Lombardi,DC=local").Name
$Path = 'HKLM:\System\CurrentControlSet\Control\CrashControl'
$Key1 = 'CrashDumpEnabled'
$Key2 = 'AlwaysKeepMemoryDump'
$Key3 = 'Overwrite'

# Script/Command to run against each machine found within the given OU
$results = Foreach ($Computer in $Computers) {
Invoke-Command -ScriptBlock {Get-ItemProperty -path $using:Path -ComputerName $computer |
Select-Object -Property $using:Key1, $using:Key2, $using:Key3}
}

$results

[/quote]

It doesn’t seem to like the use of the $Using variable. I’ll need to check it out more.

 

A Using variable cannot be retrieved. A Using variable can be used only with Invoke-Command, Start-Job, or InlineScript in the 
script workflow. When it is used with Invoke-Command, the Using variable is valid only if the script block is invoked on a 
remote computer.
At line:9 char:34
+ ... criptBlock {Get-ItemProperty -path $using:Path -ComputerName $compute ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : UsingWithoutInvokeCommand

I figured it out. I pulled the -ComputerName $Computer portion out of the ScriptBlock.

Input:

$Computers = (Get-ADComputer -Filter * -SearchBase "DC=Lombardi,DC=local").Name
$Path = 'HKLM:\System\CurrentControlSet\Control\CrashControl'
$Key1 = 'CrashDumpEnabled'
$Key2 = 'AlwaysKeepMemoryDump'
$Key3 = 'Overwrite'

# Script/Command to run against each machine found within the given OU
$results = Foreach ($Computer in $Computers) {
Invoke-Command -ComputerName $computer -ScriptBlock {Get-ItemProperty -path $using:Path | 
Select-Object -Property $using:Key1, $using:Key2, $using:Key3}
}

$results

Output:

CrashDumpEnabled : 7
AlwaysKeepMemoryDump : 0
Overwrite : 0
PSComputerName : PS01
RunspaceId : 534c0596-c23c-47b9-b10c-457ab6634bd4

CrashDumpEnabled : 0
AlwaysKeepMemoryDump : 0
Overwrite : 1
PSComputerName : DC01
RunspaceId : 6b268179-e8c2-48f0-9c6a-23bd4360e8ec

CrashDumpEnabled : 7
AlwaysKeepMemoryDump : 
Overwrite : 1
PSComputerName : DB01
RunspaceId : 72812eeb-d771-4942-8291-09b0c891fcfc

CrashDumpEnabled : 1
AlwaysKeepMemoryDump : 0
Overwrite : 1
PSComputerName : FS01
RunspaceId : 6cc158a6-bc79-4c46-91a3-db56a3de04a1

 

I guess my question would be, what is the major benefit of doing it the way I did versus this?

 

 

First, sorry for the incorrect placement of the Computer param, was juggling multiple things. The major benefit is the code works. :slight_smile: The only reason the code you were running was working was it was local. When you execute the script block, that is all that the remote computer sees, basically:

Get-ItemProperty -path | Format-Table @{Label='Server';e={$Computer}},,,}
#or
Get-ItemProperty -path NULL | Format-Table @{Label='Server';e={$Computer}},NULL, NULL, NULL

This would work:

$Computers = (Get-ADComputer -Filter * -SearchBase "DC=Lombardi,DC=local").Name

# Script/Command to run against each machine found within the given OU
$results = Foreach ($Computer in $Computers) {
Invoke-Command -ComputerName $Computer -ScriptBlock {
    $Path = 'HKLM:\System\CurrentControlSet\Control\CrashControl'
    $Key1 = 'CrashDumpEnabled'
    $Key2 = 'AlwaysKeepMemoryDump'
    $Key3 = 'Overwrite'

    Get-ItemProperty -path $using:Path -ComputerName $computer |
    Select-Object -Property $using:Key1, $using:Key2, $using:Key3
}

$Using basically replaces those variables with values when sending to the remote session, otherwise the remote system has no idea what any of those variables are as they are outside of the script block.

Gotcha. Thanks for clarifying.