0

OK, I'm piggybacking off my previous question Powershell script to get IIS app pool recycling time from servers and wondering what I'm doing wrong

I have a list of IIS app pools (apppools.txt) and a list of servers (servers.txt)

When I run it as written below, the only output I get is the FIRST app pool from the list for each node. Can anybody help me find my (probably very simple) mistake?

Output example:

"ServerName","AppPool","RecycleTime"
"serverS26","Pool1","04:10:00"
"serverS27","Pool1","04:10:00"

When I would expect to get about 10 app pools and their respective recycling times. I'm sure it's something stupid with my ICM Params or arguments.

$apppools =gc c:\temp\apppools.txt
$servers = Get-Content C:\temp\servers.txt
foreach ($server in $servers){
Invoke-Command -ComputerName $server -argumentlist @($apppools) -scriptblock {

param($apppools)
$servername = hostname
$infoObject = New-Object PSObject

import-module webadministration

foreach ($a in $apppools){

$recycle = (Get-ItemProperty -Path "IIS:\AppPools\$a" -Name recycling.periodicRestart.schedule.collection).value.tostring()}


Add-Member -inputObject $infoObject -memberType NoteProperty -name "ServerName" -value $Servername
Add-Member -inputObject $infoObject -memberType NoteProperty -name "AppPool" -value $a
Add-Member -inputObject $infoObject -memberType NoteProperty -name "RecycleTime" -value $recycle

$infoObject
} | Select-Object * -ExcludeProperty PSComputerName, RunspaceId, PSShowComputerName | Export-Csv -append -path  "C:\temp\recycling.csv" -NoTypeInformation 

}
11
  • 1
    There's an odd workaround for invoke-command and array arguments (,$apppools) see stackoverflow.com/questions/7152740/… Commented Dec 13, 2024 at 20:00
  • Yeah, I'm obviously not a PS expert. thanks for the link. I tried adding the , but no luck. You mentioned an odd workaround-- how should I have done it? I cobbled this together from other scripts. Commented Dec 13, 2024 at 20:13
  • 1
    Also invoke-command -computername $servers would run faster. Commented Dec 14, 2024 at 21:46
  • 1
    @dbutts, please don't fundamentally change your question after answers have been given, as it invalidates the latter. After solving the initial problem - as noted in my comments, passing (, $apppools) is enough - you ran into an unrelated follow-up problem, which you can simply solve as follows: place the $infoObject = New-Object PSObject statement inside your foreach ($a in $apppools) loop. Commented Dec 16, 2024 at 12:34
  • 1
    I missed that you also need to move the $infoObject statement into the foreach loop; here's a minimal example: foreach ($a in 1..3) { $infoObject = new psobject; $infoObject | Add-Member foo ('bar'+$a) ; $infoObject } Commented Dec 16, 2024 at 13:00

1 Answer 1

1

I suspect your parameters to Invoke-Request are getting splatted. Basically you need to be more explicit defining variable types to avoid these types of issues. When running Invoke-Command on a remote system your single array of strings variable is interpreted as multiple positional variables being passed to the script block. As your only defining a single named argument param($apppools) in your script block your only seeing the 1st value in the original array.

I've made a few changes to your code below that i think should solve your issue:

  1. Forcing $apppools to be of type [string[]] (instead of Object[]).
  2. Specifying the type of the value passed to -ArgumentList - Using ([Object[]] @(,$apppools)) instead of @($apppools) ensures you pass an [Object[]] ie an object array with 1 element. And that element is your array of app pool name strings (of type [string[]]).
  3. Ive set the type of $apppools inside the script block to [String[]]
  4. GC is Get-Content so updated for consistency only. The type of $servers doesnt really matter as that doesn't get passed to your script block, but again updated for consistency.
[string[]] $apppools = Get-Content c:\temp\apppools.txt
[string[]] $servers = Get-Content C:\temp\servers.txt
foreach ($server in $servers){
  Invoke-Command -ComputerName $server -ArgumentList ([Object[]] @(,$apppools)) -ScriptBlock {
    param([String[]] $apppools)

(im not sure if only #2 might actually be required, but the rest is good practice to avoid weird issues with type conversion :)


As a side note, if you litter your code with write-host's, you can get any variables type, and if its an array, you can get its length like this:

Write-Host $apppools.GetType()
Write-Host $apppools.Length

I think to get any output from the script block you would need to include Start-Transcript -Path $logfilepath at the start of the block. The path/filename in $logfilepath will be created on the remote computer though.

Sign up to request clarification or add additional context in comments.

6 Comments

Good analysis of the original problem, but none of the casts are needed, as this example demonstrates: Invoke-Command { param($apppools) foreach ($ap in $apppools) { "[$ap]" } } -ArgumentList (, ('foo', 'bar'))
My assumption was the -ComputerName $server part is changing the behavior somehow. The OP said they tried -argumentlist (, $apppools) (where $apppools is of type Object[] from GC) but it didnt work? The linked answer is only executing stuff locally, so i assumed theres a type conversion gone bad somewhere, but im unable to test
No, the use of -ComputerName and the resultant remote execution don't make a difference, given that [string] values are serialized with type fidelity. You can test this with "loopback remoting" from an elevated session as follows: Invoke-Command { param($apppools) foreach ($ap in $apppools) { "[$ap]" } } -ArgumentList (, ('foo', 'bar')) -ComputerName localhost, localhost
Thank you @MisterSmith I have reposted the script above along with the errors it now throws. And the output file still only shows the first app pool of each server.
@dbutts: As noted in the comments on the question (which I've reverted to its previous state to avoid confusion), the error you're seeing now is an unrelated follow-on error, the solution to which is noted above.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.