Powershell Invoke-Command & IISConfigCollection

powershell invoke-command credentials
powershell invoke-command runasadministrator
powershell invoke-command cmd
powershell invoke-command run exe with parameters
powershell invoke-command return value
powershell invoke-command slow
powershell invoke-command timeout
invoke-command scriptblock variable

I want to get Informations about IIS Application Pools from another Server.

This should be possible with Invoke-Command. But theres a behavior i do not unterstand...

When i execute on the local machine the script block looks like this:

# get the values recorded under Recycle
$ConfigSection = Get-IISConfigSection -SectionPath "system.applicationHost/applicationPools"
$SitesCollection = Get-IISConfigCollection -ConfigElement $ConfigSection
$Site = Get-IISConfigCollectionElement -ConfigCollection $SitesCollection -ConfigAttribute @{"name" = "$AppPool"}
$recycling = Get-IISConfigElement -ConfigElement $Site -ChildElementName "recycling"
$flags = $recycling.Attributes["logEventOnRecycle"].Value

$onRecycle = @{
    'Time'           = [bool]($flags -band 1)     # Specific Time
    'Requests'       = [bool]($flags -band 2)     # Request Limit Exceeded
    'Schedule'       = [bool]($flags -band 4)     # Regular Time Interval
    'Memory'         = [bool]($flags -band 8)     # Virtual Memory Limit Exceeded
    'IsapiUnhealthy' = [bool]($flags -band 16)    # Isapi Reported Unhealthy
    'OnDemand'       = [bool]($flags -band 32)    # Manual Recycle
    'ConfigChange'   = [bool]($flags -band 64)    # Application Pool Configuration Changed
    'PrivateMemory'  = [bool]($flags -band 128)   # Private Memory Limit Exceeded
}

This works, i can use this as "$onRecycle.Time"...

But no i want to get the Information from a Remote computer.

My first thought was to just wrap the whole thing into a $command variable. Of course it didnt work.. It generates the following errors:

  • Cannot validate argument on parameter 'ConfigElement'. The argument is null. Provide a valid value for the argument, and then try running the command again.

  • Cannot index into a null array.

Then i thought ill do it step for step. Starting with:

$s = "chvmes01"    
$command1 = { Get-IISConfigSection -SectionPath "system.applicationHost/applicationPools" }
    $ConfigSection = Invoke-Command -ComputerName $s -ScriptBlock $command1

This works and gets the desired information, but already on the next step there are troubles again:

$command2 = { param($ConfigSection)(Get-IISConfigCollection -ConfigElement $ConfigSection) }
$SitesCollection = Invoke-Command -ComputerName $s -ScriptBlock $command2 -ArgumentList $ConfigSection

Here i try to include the Variable $ConfigSection but its giving me the following error back:

Cannot bind parameter 'ConfigElement'. Cannot convert the "Microsoft.Web.Administration.ConfigurationSection" value of type "Deserialized.Microsoft.Web.Administration.ConfigurationSection" to type "Microsoft.Web.Administration.ConfigurationElement".

I thought maybe the reason is that i need Import-Module WebAdministration, but it has no effect. Still the same error.. As already the second step doenst work i cant continue..

Any ideas?

The Get-IISConfigCollection cmdlet gets a ConfigurationCollection object from either a ConfigurationSection or a ConfigurationElement.

It is advisable to not to assign this value to a parameter and pass it in the pipeline to the next cmdlet since Windows PowerShell cannot interpret this object. This is due to the fact that ConfigurationCollection implements IEnumarable and the pipeline processor enumrates each single element when used this way. Instead either pass the whole Get-IISConfigCollection cmdlet in the pipeline or pass it as a parameter.

Example:

$ScriptBlock= { Get-IISConfigSection -SectionPath "system.applicationHost/applicationPools" | Get-IISConfigCollection }
$SitesCollection = Invoke-Command -ComputerName $s -ScriptBlock $ScriptBlock

Invoke-Command: The Best Way to Run Remote Code, Invoke-Command may also be used on a local computer to evaluate or run a string in a script block as a command. PowerShell converts the script block to a  Windows PowerShell Invoke-Command. PowerShell’s Invoke-Command is ideal for running a quick command on a remote computer. This is similar to using Invoke-Expression for string commands.

Suggestion : You can use Enter-PsSession command to enter in Remote Computer and then you can run commands over there.

Enter-PSSession -ComputerName "Remote-Computer-name"

** your Commands like local.

Invoke-Command - PowerShell, Invoke-Expression is a sister PowerShell cmdlet useful for mimicking the CMD dos box. A typical scenario is where you can typing command-line  Invoke-Command may also be used on a local computer to evaluate or run a string in a script block as a command. PowerShell converts the script block to a command and runs the command immediately in the current scope, instead of just echoing the string at the command line.

Now i found the solution for my problem, thanks to @Kirill Pashkov who led me in the right direction!

It now looks like this:

$s = "chvmes01"
$AppPool = "DefaultAppPool"       

$command1 = {
param($AppPool)
Get-IISConfigSection -SectionPath "system.applicationHost/applicationPools" |
Get-IISConfigCollection |
Get-IISConfigCollectionElement -ConfigAttribute @{"name" = $AppPool} |
Get-IISConfigElement -ChildElementName "recycling"
}

$recycling = Invoke-Command -ComputerName $s -ScriptBlock $command1 -ArgumentList $AppPool

$flags = Invoke-Command -ComputerName $s -ScriptBlock {param($recycling)$recycling.RawAttributes.logEventOnRecycle} -ArgumentList $recycling

$command2 = {
    param($flags)
    @{
    'Time'           = [bool]($flags -band 1)     # Specific Time
    'Requests'       = [bool]($flags -band 2)     # Request Limit Exceeded
    'Schedule'       = [bool]($flags -band 4)     # Regular Time Interval
    'Memory'         = [bool]($flags -band 8)     # Virtual Memory Limit Exceeded
    'IsapiUnhealthy' = [bool]($flags -band 16)    # Isapi Reported Unhealthy
    'OnDemand'       = [bool]($flags -band 32)    # Manual Recycle
    'ConfigChange'   = [bool]($flags -band 64)    # Application Pool Configuration Changed
    'PrivateMemory'  = [bool]($flags -band 128)   # Private Memory Limit Exceeded
    }
}

$onRecycleLog = Invoke-Command -ComputerName $s -ScriptBlock $command2 -ArgumentList $flags

Finally i got the right output saved in the $onRecycleLog Variable which looks like this:

Thank you Kirill for your support!

PowerShell Basics: Invoke-command -scriptBlock -filePath, This cmdlet allows you to execute PowerShell commands on multiple remote computers that contain cmdlets that don't feature the -  Invoke-Command cmdlet has many useful implementations (you can find more examples in the provided link). You can use it to run a command, a set of commands, on a local computer, on a remote computer, on several computers. For remoting you also can check the Cmdlet of “New-PSSession”. As of Powershell 6.0 you also can connect to remote

Use PowerShell Invoke-Command to run scripts on remote , Running commands remotely. So, what I would strongly recommend, is that before you use Invoke-Command, you enable PowerShell remoting  PowerShell Remoting depends on Windows Remote Management (WinRM), which is Microsoft’s implementation of the WS-Management (WS-Man) protocol. The protocol relies on HTTP or HTTPS and uses the TCP ports 5985 and 5986, respectively. WS-Management encrypts all PowerShell communication even if you only work with HTTP.

Using Invoke-Command in PowerShell - Defrag This, PowerShell Remoting lets you run PowerShell commands or access full To run a command on the remote system, use the Invoke-Command  By using the PowerShell Remoting feature, The Invoke-Command cmdlet is a commonly used PowerShell cmdlet that allows the user to execute code inside of a PSSession. This PSSession can either be one created previously with the New-PSSession cmdlet or it can quickly create and tear down a temporary session as well.

How to Run PowerShell Commands on Remote Computers, Instead of this: Invoke-Command -ComputerName $MyPC -Credential $mycreds -ScriptBlock {& "C:\Users\MyPC\Desktop\scripts\Script1.ps1"}. As documented, Invoke-Command returns all command output, so you could use Write-Output instead of Write-Host and pipe the returned output into a file. There's no fancy coloring with Write-Output, though.

Comments
  • First a question about this: Do you know if your suggested way is faster in processing? as i already build my whole script on the base of invoke-command i would like to stay with this. But i realized that my script is a little slow now, so if i can gain speed with "Enter-PSSession", i could think about rewriting everything again
  • still you can use your script after entering in pssession.No need to change it Invoke-Command -Command $command